diff --git a/DEPS b/DEPS
index 974f739..5aee75c 100644
--- a/DEPS
+++ b/DEPS
@@ -267,7 +267,7 @@
   # pathname relative to build/config/siso/backend_config, or absolute path.
   'reapi_backend_config_path': Str(''),
   # siso CIPD package version.
-  'siso_version': 'git_revision:49dcca5d2be985d8ac6d512e59ee59e315264fb8',
+  'siso_version': 'git_revision:6839895535a2a5e91fb3ddfae03e95aded998244',
 
   # reclient options.
   # download reclient binaries, required for 'use_reclient` gn arg.
@@ -312,7 +312,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '07dc97655915230e26ef96cc41ac7193d6dd356c',
+  'skia_revision': '82fff05cc62168683f5e94e65a63c49ec210bf47',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -332,7 +332,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': '8c7d12999b5bcce52f6e47f06906173fdc56d6a1',
+  'boringssl_revision': '1524d7be010cf0949d5d55d809a1a411de407c88',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Fuchsia sdk
   # and whatever else without interference from each other.
@@ -400,7 +400,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': 'bee483082d01ffc91dd4dd192bda7d9267c45ddd',
+  'devtools_frontend_revision': '7116806a8572358c8424600a0111972d925f48aa',
   # 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.
@@ -424,7 +424,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': '04dab8177931725bd88271eb4d2de43d8e1b6601',
+  'dawn_revision': '75461721fdeecd4db2654fcedaa22b20acdbfc36',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -1206,7 +1206,7 @@
       'packages': [
           {
               'package': 'chromium/chrome/android/orderfiles/arm64',
-              'version': '02MUt478Jt6RV1joqRun9iNmiHNJ8-NO7KsLRLZI5V4C',
+              'version': 'fOWvPpN_c2TXJgU4W9ou3L6hsZOGCNYQrAboQau1CacC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -1624,7 +1624,7 @@
 
   'src/clank': {
     'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' +
-    '696228be97b40a0a6389a8e36c4404ac88b22927',
+    'c600588721e3fccf9df6df3194ae84d3811d2eb7',
     'condition': 'checkout_android and checkout_src_internal',
   },
 
@@ -1633,7 +1633,7 @@
   },
 
   'src/ios/third_party/earl_grey2/src': {
-      'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + 'd67ae75220c564eff015db2ac35c7e31cdd8159c',
+      'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + 'df685be0513ad0849abdf91e2eb5435eb29fb649',
       'condition': 'checkout_ios',
   },
 
@@ -1724,7 +1724,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'dUYDoYVH-NzyM8K7wLLtKL4FIBeid3P4p_gbwEOapJ4C',
+          'version': 'mcHe4tag6-fHpR1zaCJh4eb0BUN9qmgCoFzMBfuQ1_MC',
       },
     ],
     'condition': 'checkout_android and non_git_source',
@@ -2042,7 +2042,7 @@
     Var('chromium_git') + '/external/github.com/google/cpu_features.git' + '@' + '936b9ab5515dead115606559502e3864958f7f6e',
 
   'src/third_party/cpuinfo/src':
-    Var('chromium_git') + '/external/github.com/pytorch/cpuinfo.git' + '@' + '161a9ec374884f4b3e85725cb22e05f9458fdc93',
+    Var('chromium_git') + '/external/github.com/pytorch/cpuinfo.git' + '@' + 'ff24ffee8340fbd9001cce6a9ef41cdd16aa2bd3',
 
   'src/third_party/crc32c/src':
     Var('chromium_git') + '/external/github.com/google/crc32c.git' + '@' + 'd3d60ac6e0f16780bcfcc825385e1d338801a558',
@@ -2060,7 +2060,7 @@
     Var('chromium_git') + '/chromium/web-tests.git' + '@' + Var('crossbench_web_tests_revision'),
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'b48cbb3e60a0f96597657c7b66738ead6b50a229',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '7c09ebfd12c9470ec2ff6c02685c3a157a9290b7',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -2610,7 +2610,7 @@
     Var('pdfium_git') + '/pdfium.git' + '@' +  Var('pdfium_revision'),
 
   'src/third_party/perfetto':
-    Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + '7307480b25c072cc68e359067e1d09aae90111d0',
+    Var('chromium_git') + '/external/github.com/google/perfetto.git' + '@' + '43be17dba6e57a47f1f71d0b6ff072f3179e54a6',
 
   'src/base/tracing/test/data': {
     'bucket': 'perfetto',
@@ -3203,7 +3203,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/android_deps/autorolled',
-              'version': '9R8fWVmsKuKcqHXSeHqxli9lpGpS0lfH7vaahigg53gC',
+              'version': 'P5Qp6C9G4XPQxoe2blfRDwVKbBga3m8_zYiFJdatwokC',
           },
       ],
       'condition': 'checkout_android and non_git_source',
@@ -3687,7 +3687,7 @@
 
   'src/components/optimization_guide/internal': {
       'url': Var('chrome_git') + '/chrome/components/optimization_guide.git' + '@' +
-        'b8ccce3600d400ae32ed129caa42fdf0282b0118',
+        '81611cb4974460c7328b226e2d44d79ea2023304',
       'condition': 'checkout_src_internal',
   },
 
@@ -3759,7 +3759,7 @@
 
   'src/ios_internal':  {
       'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' +
-        '37a0c1f41e948f23b572d150e5dba5927d68ce17',
+        '5cfcae409eb3a15e16dea856a258b3cabe9e39c9',
       'condition': 'checkout_ios and checkout_src_internal',
   },
 
diff --git a/android_webview/browser/gfx/overlay_processor_webview.cc b/android_webview/browser/gfx/overlay_processor_webview.cc
index 1caf320c..7dc7103 100644
--- a/android_webview/browser/gfx/overlay_processor_webview.cc
+++ b/android_webview/browser/gfx/overlay_processor_webview.cc
@@ -1028,6 +1028,10 @@
   return overlays_.contains(frame_sink_id);
 }
 
+bool OverlayProcessorWebView::ShouldCreatePrimaryPlane() const {
+  return false;
+}
+
 OverlayProcessorWebView::ScopedSurfaceControlAvailable::
     ScopedSurfaceControlAvailable(OverlayProcessorWebView* processor,
                                   GetSurfaceControlFn surface_getter)
diff --git a/android_webview/browser/gfx/overlay_processor_webview.h b/android_webview/browser/gfx/overlay_processor_webview.h
index 7d4f81cd..6e843d2 100644
--- a/android_webview/browser/gfx/overlay_processor_webview.h
+++ b/android_webview/browser/gfx/overlay_processor_webview.h
@@ -68,6 +68,10 @@
   // OverlaysInfoProvider implenentation:
   bool IsFrameSinkOverlayed(viz::FrameSinkId frame_sink_id) override;
 
+ protected:
+  // viz::OverlayProcessorUsingStrategy overrides:
+  bool ShouldCreatePrimaryPlane() const override;
+
  private:
   class Manager;
 
diff --git a/android_webview/test/data/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt b/android_webview/test/data/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
index f6d3d40..f84e5b1 100644
--- a/android_webview/test/data/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/android_webview/test/data/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -1692,6 +1692,7 @@
     getter linkColor
     getter links
     getter onabort
+    getter onanimationcancel
     getter onanimationend
     getter onanimationiteration
     getter onanimationstart
@@ -1913,6 +1914,7 @@
     setter fullscreenEnabled
     setter linkColor
     setter onabort
+    setter onanimationcancel
     setter onanimationend
     setter onanimationiteration
     setter onanimationstart
@@ -3395,6 +3397,7 @@
     getter offsetTop
     getter offsetWidth
     getter onabort
+    getter onanimationcancel
     getter onanimationend
     getter onanimationiteration
     getter onanimationstart
@@ -3531,6 +3534,7 @@
     setter lang
     setter nonce
     setter onabort
+    setter onanimationcancel
     setter onanimationend
     setter onanimationiteration
     setter onanimationstart
@@ -5295,6 +5299,7 @@
     getter dataset
     getter nonce
     getter onabort
+    getter onanimationcancel
     getter onanimationend
     getter onanimationiteration
     getter onanimationstart
@@ -5407,6 +5412,7 @@
     setter autofocus
     setter nonce
     setter onabort
+    setter onanimationcancel
     setter onanimationend
     setter onanimationiteration
     setter onanimationstart
@@ -7383,6 +7389,7 @@
     getter dataset
     getter nonce
     getter onabort
+    getter onanimationcancel
     getter onanimationend
     getter onanimationiteration
     getter onanimationstart
@@ -7497,6 +7504,7 @@
     setter autofocus
     setter nonce
     setter onabort
+    setter onanimationcancel
     setter onanimationend
     setter onanimationiteration
     setter onanimationstart
@@ -11296,6 +11304,7 @@
     getter offscreenBuffering
     getter onabort
     getter onafterprint
+    getter onanimationcancel
     getter onanimationend
     getter onanimationiteration
     getter onanimationstart
@@ -11515,6 +11524,7 @@
     setter offscreenBuffering
     setter onabort
     setter onafterprint
+    setter onanimationcancel
     setter onanimationend
     setter onanimationiteration
     setter onanimationstart
diff --git a/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt b/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt
index 20d7772b..bee49be 100644
--- a/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/android_webview/test/data/web_tests/webexposed/global-interface-listing-expected.txt
@@ -1913,6 +1913,7 @@
     getter linkColor
     getter links
     getter onabort
+    getter onanimationcancel
     getter onanimationend
     getter onanimationiteration
     getter onanimationstart
@@ -2144,6 +2145,7 @@
     setter fullscreenEnabled
     setter linkColor
     setter onabort
+    setter onanimationcancel
     setter onanimationend
     setter onanimationiteration
     setter onanimationstart
@@ -3759,6 +3761,7 @@
     getter offsetTop
     getter offsetWidth
     getter onabort
+    getter onanimationcancel
     getter onanimationend
     getter onanimationiteration
     getter onanimationstart
@@ -3898,6 +3901,7 @@
     setter lang
     setter nonce
     setter onabort
+    setter onanimationcancel
     setter onanimationend
     setter onanimationiteration
     setter onanimationstart
@@ -5762,6 +5766,7 @@
     getter focusgroup
     getter nonce
     getter onabort
+    getter onanimationcancel
     getter onanimationend
     getter onanimationiteration
     getter onanimationstart
@@ -5876,6 +5881,7 @@
     setter focusgroup
     setter nonce
     setter onabort
+    setter onanimationcancel
     setter onanimationend
     setter onanimationiteration
     setter onanimationstart
@@ -8085,6 +8091,7 @@
     getter focusgroup
     getter nonce
     getter onabort
+    getter onanimationcancel
     getter onanimationend
     getter onanimationiteration
     getter onanimationstart
@@ -8201,6 +8208,7 @@
     setter focusgroup
     setter nonce
     setter onabort
+    setter onanimationcancel
     setter onanimationend
     setter onanimationiteration
     setter onanimationstart
@@ -12225,6 +12233,7 @@
     getter offscreenBuffering
     getter onabort
     getter onafterprint
+    getter onanimationcancel
     getter onanimationend
     getter onanimationiteration
     getter onanimationstart
@@ -12450,6 +12459,7 @@
     setter offscreenBuffering
     setter onabort
     setter onafterprint
+    setter onanimationcancel
     setter onanimationend
     setter onanimationiteration
     setter onanimationstart
diff --git a/base/byte_size.h b/base/byte_size.h
index 28b772c..2d1b445e 100644
--- a/base/byte_size.h
+++ b/base/byte_size.h
@@ -194,6 +194,7 @@
     return ByteSize(std::numeric_limits<int64_t>::max());
   }
 
+  constexpr bool is_positive() const { return InBytes() > 0; }
   constexpr bool is_zero() const { return InBytes() == 0; }
 
   constexpr bool is_max() const { return *this == Max(); }
diff --git a/base/byte_size_unittest.cc b/base/byte_size_unittest.cc
index 4d07dec5..084eec35 100644
--- a/base/byte_size_unittest.cc
+++ b/base/byte_size_unittest.cc
@@ -303,6 +303,12 @@
   }
 }
 
+TEST(ByteSizeTest, IsPositive) {
+  EXPECT_FALSE(ByteSize(0).is_positive());
+  EXPECT_TRUE(ByteSize(2).is_positive());
+  EXPECT_TRUE(ByteSize::Max().is_positive());
+}
+
 TEST(ByteSizeTest, IsZero) {
   EXPECT_TRUE(ByteSize(0).is_zero());
   EXPECT_FALSE(ByteSize(2).is_zero());
diff --git a/base/process/process_metrics.h b/base/process/process_metrics.h
index cf41bb5e..5a6105d 100644
--- a/base/process/process_metrics.h
+++ b/base/process/process_metrics.h
@@ -15,7 +15,6 @@
 #include <string_view>
 
 #include "base/base_export.h"
-#include "base/byte_count.h"
 #include "base/byte_size.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/raw_ptr.h"
@@ -316,7 +315,7 @@
 // Data about system-wide memory consumption. Available on Windows, Mac, Linux,
 // Android and Chrome OS.
 //
-// The values are kept in ByteCount but depending on the platform, the
+// The values are kept in ByteSize but depending on the platform, the
 // granularity might be at the KB level or higher.
 //
 // Total memory are available on all platforms that implement
@@ -331,12 +330,10 @@
   SystemMemoryInfo(const SystemMemoryInfo& other);
   SystemMemoryInfo& operator=(const SystemMemoryInfo& other);
 
-  // TODO(crbug.com/458489438): Migrate all generic ByteCount usages in
-  // base/system and base/memory to the new types.
-  ByteCount total;
+  ByteSize total;
 
 #if !BUILDFLAG(IS_WIN)
-  ByteCount free;
+  ByteSize free;
 #endif
 
 #if BUILDFLAG(IS_WIN)
@@ -345,7 +342,7 @@
   // size of the standby, free, and zero lists." (MSDN).
   // Standby: not modified pages of physical ram (file-backed memory) that are
   // not actively being used.
-  ByteCount avail_phys;
+  ByteSize avail_phys;
 #endif
 
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || \
@@ -355,42 +352,42 @@
   // NOTE: this is ONLY valid in kernels 3.14 and up.  Its value will always
   // be 0 in earlier kernel versions.
   // Note: it includes _all_ file-backed memory (active + inactive).
-  ByteCount available;
+  ByteSize available;
 #endif
 
 #if !BUILDFLAG(IS_APPLE)
-  ByteCount swap_total;
-  ByteCount swap_free;
+  ByteSize swap_total;
+  ByteSize swap_free;
 #endif
 
 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
     BUILDFLAG(IS_AIX) || BUILDFLAG(IS_FUCHSIA)
-  ByteCount buffers;
-  ByteCount cached;
-  ByteCount active_anon;
-  ByteCount inactive_anon;
-  ByteCount active_file;
-  ByteCount inactive_file;
-  ByteCount dirty;
-  ByteCount reclaimable;
+  ByteSize buffers;
+  ByteSize cached;
+  ByteSize active_anon;
+  ByteSize inactive_anon;
+  ByteSize active_file;
+  ByteSize inactive_file;
+  ByteSize dirty;
+  ByteSize reclaimable;
 #endif  // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) ||
         // BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_AIX) BUILDFLAG(IS_FUCHSIA)
 
 #if BUILDFLAG(IS_CHROMEOS)
-  ByteCount shmem;
-  ByteCount slab;
+  ByteSize shmem;
+  ByteSize slab;
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
 #if BUILDFLAG(IS_APPLE)
-  ByteCount speculative;
-  ByteCount file_backed;
-  ByteCount purgeable;
+  ByteSize speculative;
+  ByteSize file_backed;
+  ByteSize purgeable;
 #endif  // BUILDFLAG(IS_APPLE)
 
   // Returns a cross-platform estimation of available physical memory.
   // This value is an approximation of the amount of physical memory that
   // can be used without the system needing to swap.
-  ByteCount GetAvailablePhysicalMemory() const;
+  ByteSize GetAvailablePhysicalMemory() const;
 };
 
 // On Linux/Android/Chrome OS, system-wide memory consumption data is parsed
diff --git a/base/process/process_metrics_apple.mm b/base/process/process_metrics_apple.mm
index 94ae15d..dcfb94a75 100644
--- a/base/process/process_metrics_apple.mm
+++ b/base/process/process_metrics_apple.mm
@@ -17,6 +17,7 @@
 #include "base/apple/mach_logging.h"
 #include "base/apple/scoped_mach_port.h"
 #include "base/byte_count.h"
+#include "base/byte_size.h"
 #include "base/containers/heap_array.h"
 #include "base/logging.h"
 #include "base/mac/mac_util.h"
@@ -254,7 +255,7 @@
 }
 
 bool GetSystemMemoryInfo(SystemMemoryInfo* meminfo) {
-  meminfo->total = SysInfo::AmountOfPhysicalMemory();
+  meminfo->total = ByteSize::FromByteCount(SysInfo::AmountOfPhysicalMemory());
 
   base::apple::ScopedMachSendRight host(mach_host_self());
   vm_statistics64_data_t vm_info;
@@ -299,8 +300,8 @@
 #endif  // !(defined(IS_IOS) && defined(ARCH_CPU_X86_FAMILY))
 
   if (vm_info.speculative_count <= vm_info.free_count) {
-    meminfo->free = ByteCount::FromUnsigned(
-        PAGE_SIZE * (vm_info.free_count - vm_info.speculative_count));
+    meminfo->free =
+        ByteSize(PAGE_SIZE * (vm_info.free_count - vm_info.speculative_count));
   } else {
     // Inside the `host_statistics64` call above, `speculative_count` is
     // computed later than `free_count`, so these values are snapshots of two
@@ -313,15 +314,12 @@
     // inexact, but even in the case where `speculative_count` is less than
     // `free_count`, the computed `meminfo->free` will only be an approximation
     // given that the two inputs come from different points in time.
-    meminfo->free = ByteCount(0);
+    meminfo->free = ByteSize(0);
   }
 
-  meminfo->speculative =
-      ByteCount::FromUnsigned(PAGE_SIZE * vm_info.speculative_count);
-  meminfo->file_backed =
-      ByteCount::FromUnsigned(PAGE_SIZE * vm_info.external_page_count);
-  meminfo->purgeable =
-      ByteCount::FromUnsigned(PAGE_SIZE * vm_info.purgeable_count);
+  meminfo->speculative = ByteSize(PAGE_SIZE * vm_info.speculative_count);
+  meminfo->file_backed = ByteSize(PAGE_SIZE * vm_info.external_page_count);
+  meminfo->purgeable = ByteSize(PAGE_SIZE * vm_info.purgeable_count);
 
   return true;
 }
@@ -413,7 +411,7 @@
   return checked_cast<int>(GetMaxFds());
 }
 
-ByteCount SystemMemoryInfo::GetAvailablePhysicalMemory() const {
+ByteSize SystemMemoryInfo::GetAvailablePhysicalMemory() const {
   // Available memory is free memory plus memory that can be reclaimed without
   // writing to disk, which on macOS is the file-backed cache. This corresponds
   // to (free_count - speculative_count + external_page_count) from
diff --git a/base/process/process_metrics_fuchsia.cc b/base/process/process_metrics_fuchsia.cc
index b4c8a52..7b098eb 100644
--- a/base/process/process_metrics_fuchsia.cc
+++ b/base/process/process_metrics_fuchsia.cc
@@ -74,12 +74,12 @@
   return false;
 }
 
-ByteCount SystemMemoryInfo::GetAvailablePhysicalMemory() const {
+ByteSize SystemMemoryInfo::GetAvailablePhysicalMemory() const {
   NOTIMPLEMENTED();
   // GetSystemMemoryInfo() is not implemented on Fuchsia, so this struct will
-  // contain default (zero) values. Return a zero ByteCount to satisfy the
+  // contain default (zero) values. Return a zero ByteSize to satisfy the
   // linker.
-  return ByteCount(0);
+  return ByteSize(0);
 }
 
 }  // namespace base
diff --git a/base/process/process_metrics_linux.cc b/base/process/process_metrics_linux.cc
index 53f465fb..d40b525 100644
--- a/base/process/process_metrics_linux.cc
+++ b/base/process/process_metrics_linux.cc
@@ -20,7 +20,7 @@
 #include <string_view>
 #include <utility>
 
-#include "base/byte_count.h"
+#include "base/byte_size.h"
 #include "base/compiler_specific.h"
 #include "base/containers/span.h"
 #include "base/cpu.h"
@@ -394,7 +394,7 @@
 
   // As a basic sanity check at the end, make sure the MemTotal value will be at
   // least non-zero. So start off with a zero total.
-  meminfo->total = ByteCount(0);
+  meminfo->total = ByteSize(0);
 
   for (std::string_view line : SplitStringPiece(
            meminfo_data, "\n", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY)) {
@@ -408,7 +408,7 @@
       continue;
     }
 
-    ByteCount* target = nullptr;
+    ByteSize* target = nullptr;
     if (tokens[0] == "MemTotal:") {
       target = &meminfo->total;
     } else if (tokens[0] == "MemFree:") {
@@ -446,15 +446,15 @@
     }
 #endif
     if (target) {
-      int64_t value;
-      if (StringToInt64(tokens[1], &value)) {
-        *target = KiB(value);
+      uint64_t value;
+      if (StringToUint64(tokens[1], &value)) {
+        *target = KiBU(value);
       }
     }
   }
 
   // Make sure the MemTotal is valid.
-  return meminfo->total > ByteCount(0);
+  return meminfo->total > ByteSize(0);
 }
 
 bool ParseProcVmstat(std::string_view vmstat_data, VmStatInfo* vmstat) {
@@ -1043,7 +1043,7 @@
 }
 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_AIX)
 
-ByteCount SystemMemoryInfo::GetAvailablePhysicalMemory() const {
+ByteSize SystemMemoryInfo::GetAvailablePhysicalMemory() const {
   // Use MemAvailable from /proc/meminfo if available (Linux 3.14+), otherwise
   // fall back to MemFree.
   return available.is_positive() ? available : free;
diff --git a/base/process/process_metrics_unittest.cc b/base/process/process_metrics_unittest.cc
index e71c0bf..a4b7b7a 100644
--- a/base/process/process_metrics_unittest.cc
+++ b/base/process/process_metrics_unittest.cc
@@ -20,7 +20,7 @@
 #include <utility>
 #include <vector>
 
-#include "base/byte_count.h"
+#include "base/byte_size.h"
 #include "base/command_line.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
@@ -445,7 +445,7 @@
   EXPECT_EQ(355725,
             base::SysInfo::AmountOfAvailablePhysicalMemory(meminfo).InKiB());
   // Simulate as if there is no MemAvailable.
-  meminfo.available = ByteCount(0);
+  meminfo.available = ByteSize(0);
   EXPECT_EQ(374448u,
             base::SysInfo::AmountOfAvailablePhysicalMemory(meminfo).InKiB());
   meminfo = {};
@@ -806,17 +806,17 @@
   EXPECT_TRUE(GetSystemMemoryInfo(&info));
 
   // Ensure each field received a value.
-  EXPECT_GT(info.total, ByteCount(0));
+  EXPECT_GT(info.total, ByteSize(0));
 #if BUILDFLAG(IS_WIN)
-  EXPECT_GT(info.avail_phys, ByteCount(0));
+  EXPECT_GT(info.avail_phys, ByteSize(0));
 #else
-  EXPECT_GT(info.free, ByteCount(0));
+  EXPECT_GT(info.free, ByteSize(0));
 #endif
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
-  EXPECT_GT(info.buffers, ByteCount(0));
-  EXPECT_GT(info.cached, ByteCount(0));
-  EXPECT_GT(info.active_anon + info.inactive_anon, ByteCount(0));
-  EXPECT_GT(info.active_file + info.inactive_file, ByteCount(0));
+  EXPECT_GT(info.buffers, ByteSize(0));
+  EXPECT_GT(info.cached, ByteSize(0));
+  EXPECT_GT(info.active_anon + info.inactive_anon, ByteSize(0));
+  EXPECT_GT(info.active_file + info.inactive_file, ByteSize(0));
 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) ||
         // BUILDFLAG(IS_ANDROID)
 
@@ -836,12 +836,12 @@
         // BUILDFLAG(IS_ANDROID)
 
 #if BUILDFLAG(IS_APPLE)
-  EXPECT_GT(info.file_backed, ByteCount(0));
+  EXPECT_GT(info.file_backed, ByteSize(0));
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS)
   // Chrome OS exposes shmem.
-  EXPECT_GT(info.shmem, ByteCount(0));
+  EXPECT_GT(info.shmem, ByteSize(0));
   EXPECT_LT(info.shmem, info.total);
 #endif
 }
diff --git a/base/process/process_metrics_win.cc b/base/process/process_metrics_win.cc
index 199f349..3a0400b7 100644
--- a/base/process/process_metrics_win.cc
+++ b/base/process/process_metrics_win.cc
@@ -13,7 +13,7 @@
 
 #include <algorithm>
 
-#include "base/byte_count.h"
+#include "base/byte_size.h"
 #include "base/check.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
@@ -261,10 +261,10 @@
     return false;
   }
 
-  meminfo->total = ByteCount::FromUnsigned(mem_status.ullTotalPhys);
-  meminfo->avail_phys = ByteCount::FromUnsigned(mem_status.ullAvailPhys);
-  meminfo->swap_total = ByteCount::FromUnsigned(mem_status.ullTotalPageFile);
-  meminfo->swap_free = ByteCount::FromUnsigned(mem_status.ullAvailPageFile);
+  meminfo->total = ByteSize(mem_status.ullTotalPhys);
+  meminfo->avail_phys = ByteSize(mem_status.ullAvailPhys);
+  meminfo->swap_total = ByteSize(mem_status.ullTotalPageFile);
+  meminfo->swap_free = ByteSize(mem_status.ullAvailPageFile);
 
   return true;
 }
@@ -315,7 +315,7 @@
   return true;
 }
 
-ByteCount SystemMemoryInfo::GetAvailablePhysicalMemory() const {
+ByteSize SystemMemoryInfo::GetAvailablePhysicalMemory() const {
   // Use ullAvailPhys from MEMORYSTATUSEX, which represents physical memory
   // available without paging.
   return avail_phys;
diff --git a/base/system/sys_info.h b/base/system/sys_info.h
index 20b12d91..e851a44 100644
--- a/base/system/sys_info.h
+++ b/base/system/sys_info.h
@@ -75,6 +75,7 @@
   // Return the number of bytes of physical memory on the current machine.
   // If low-end device mode is manually enabled via command line flag, this
   // will return the lesser of the actual physical memory, or 512MB.
+  // TODO(crbug.com/448661443): Switch to ByteSize as ByteCount is deprecated.
   static ByteCount AmountOfPhysicalMemory();
 
   // Return the number of bytes of current available physical memory on the
@@ -82,21 +83,23 @@
   // (The amount of memory that can be allocated without any significant
   // impact on the system. It can lead to freeing inactive file-backed
   // and/or speculative file-backed memory).
+  // TODO(crbug.com/448661443): Switch to ByteSize as ByteCount is deprecated.
   static ByteCount AmountOfAvailablePhysicalMemory();
 
   // Return the number of bytes of virtual memory of this process. A return
   // value of zero means that there is no limit on the available virtual
   // memory.
+  // TODO(crbug.com/448661443): Switch to ByteSize as ByteCount is deprecated.
   static ByteCount AmountOfVirtualMemory();
 
   // Return the available disk space in bytes on the volume containing |path|,
   // or nullopt on failure.
-  // TODO(crbug.com/429140103): Convert the return type to ByteCount.
+  // TODO(crbug.com/429140103): Convert the return type to ByteSize.
   static std::optional<int64_t> AmountOfFreeDiskSpace(const FilePath& path);
 
   // Return the total disk space in bytes on the volume containing |path|, or
   // nullopt on failure.
-  // TODO(crbug.com/429140103): Convert the return type to ByteCount.
+  // TODO(crbug.com/429140103): Convert the return type to ByteSize.
   static std::optional<int64_t> AmountOfTotalDiskSpace(const FilePath& path);
 
 #if BUILDFLAG(IS_FUCHSIA)
diff --git a/base/system/sys_info_ios.mm b/base/system/sys_info_ios.mm
index 22b3c91b..cf45b3b 100644
--- a/base/system/sys_info_ios.mm
+++ b/base/system/sys_info_ios.mm
@@ -12,6 +12,8 @@
 #include <sys/types.h>
 
 #include "base/apple/scoped_mach_port.h"
+#include "base/byte_count.h"
+#include "base/byte_size.h"
 #include "base/check_op.h"
 #include "base/no_destructor.h"
 #include "base/notreached.h"
@@ -113,7 +115,7 @@
   }
   // We should add inactive file-backed memory also but there is no such
   // information from iOS unfortunately.
-  return info.free + info.speculative;
+  return ByteCount::FromUnsigned((info.free + info.speculative).InBytes());
 }
 
 // static
diff --git a/base/system/sys_info_linux.cc b/base/system/sys_info_linux.cc
index a1c8d0f..9af1f60 100644
--- a/base/system/sys_info_linux.cc
+++ b/base/system/sys_info_linux.cc
@@ -12,12 +12,12 @@
 #include <stddef.h>
 #include <stdint.h>
 
-#include <algorithm>
 #include <limits>
 #include <sstream>
 #include <type_traits>
 
 #include "base/byte_count.h"
+#include "base/byte_size.h"
 #include "base/check.h"
 #include "base/files/file_util.h"
 #include "base/notreached.h"
@@ -73,11 +73,14 @@
   // https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=34e431b0ae398fc54ea69ff85ec700722c9da773
   // The fallback logic (when there is no MemAvailable) would be more precise
   // if we had info about zones watermarks (/proc/zoneinfo).
-  ByteCount res =
-      !info.available.is_zero()
-          ? std::max(info.available - info.active_file, ByteCount(0))
-          : info.free + info.reclaimable + info.inactive_file;
-  return res;
+  if (info.available.is_zero()) {
+    return ByteCount::FromUnsigned(
+        (info.free + info.reclaimable + info.inactive_file).InBytes());
+  } else if (info.available > info.active_file) {
+    return ByteCount((info.available - info.active_file).InBytes());
+  } else {
+    return ByteCount(0);
+  }
 }
 
 // static
diff --git a/base/system/sys_info_mac.mm b/base/system/sys_info_mac.mm
index cfa959e..d8ba1e9 100644
--- a/base/system/sys_info_mac.mm
+++ b/base/system/sys_info_mac.mm
@@ -16,6 +16,8 @@
 #include <string_view>
 
 #include "base/apple/scoped_mach_port.h"
+#include "base/byte_count.h"
+#include "base/byte_size.h"
 #include "base/check_op.h"
 #include "base/feature_list.h"
 #include "base/mac/mac_util.h"
@@ -106,7 +108,7 @@
   }
   // We should add inactive file-backed memory also but there is no such
   // information from Mac OS unfortunately.
-  return info.free + info.speculative;
+  return ByteCount::FromUnsigned((info.free + info.speculative).InBytes());
 }
 
 // static
diff --git a/base/system/sys_info_unittest.cc b/base/system/sys_info_unittest.cc
index 2125c63..9d1b489 100644
--- a/base/system/sys_info_unittest.cc
+++ b/base/system/sys_info_unittest.cc
@@ -11,6 +11,8 @@
 #include <utility>
 #include <vector>
 
+#include "base/byte_count.h"
+#include "base/byte_size.h"
 #include "base/environment.h"
 #include "base/files/file_util.h"
 #include "base/functional/bind.h"
@@ -53,7 +55,7 @@
 // Some Android (Cast) test devices have a large portion of physical memory
 // reserved. During investigation, around 115-150 MB were seen reserved, so we
 // track this here with a factory of safety of 2.
-static constexpr ByteCount kReservedPhysicalMemory = MiB(300);
+static constexpr ByteSize kReservedPhysicalMemory = MiBU(300);
 #endif  // BUILDFLAG(IS_ANDROID)
 
 using SysInfoTest = PlatformTest;
@@ -104,28 +106,31 @@
 TEST_F(SysInfoTest, MAYBE_AmountOfAvailablePhysicalMemory) {
   SystemMemoryInfo info;
   ASSERT_TRUE(GetSystemMemoryInfo(&info));
-  EXPECT_GT(info.free, ByteCount(0));
+  EXPECT_GT(info.free, ByteSize(0));
   if (!info.available.is_zero()) {
     // If there is MemAvailable from kernel.
     EXPECT_LT(info.available, info.total);
-    const ByteCount amount = SysInfo::AmountOfAvailablePhysicalMemory(info);
+    const ByteSize amount =
+        ByteSize::FromByteCount(SysInfo::AmountOfAvailablePhysicalMemory(info));
     // We aren't actually testing that it's correct, just that it's sane.
     // Available memory is |free - reserved + reclaimable (inactive, non-free)|.
     // On some android platforms, reserved is a substantial portion.
-    const ByteCount available =
+    const ByteSize available =
 #if BUILDFLAG(IS_ANDROID)
-        std::max(info.free - kReservedPhysicalMemory, ByteCount(0));
+        std::max(info.free - kReservedPhysicalMemory, ByteSizeDelta(0))
+            .AsByteSize();
 #else
         info.free;
 #endif  // BUILDFLAG(IS_ANDROID)
     EXPECT_GT(amount, available);
     EXPECT_LT(amount, info.available);
     // Simulate as if there is no MemAvailable.
-    info.available = ByteCount(0);
+    info.available = ByteSize(0);
   }
 
   // There is no MemAvailable. Check the fallback logic.
-  const ByteCount amount = SysInfo::AmountOfAvailablePhysicalMemory(info);
+  const ByteSize amount =
+      ByteSize::FromByteCount(SysInfo::AmountOfAvailablePhysicalMemory(info));
   // We aren't actually testing that it's correct, just that it's sane.
   EXPECT_GT(amount, info.free);
   EXPECT_LT(amount, info.total);
diff --git a/base/system/sys_info_win.cc b/base/system/sys_info_win.cc
index 6f318ce..28ae962a 100644
--- a/base/system/sys_info_win.cc
+++ b/base/system/sys_info_win.cc
@@ -20,6 +20,8 @@
 #include <type_traits>
 #include <vector>
 
+#include "base/byte_count.h"
+#include "base/byte_size.h"
 #include "base/check.h"
 #include "base/files/file_path.h"
 #include "base/notreached.h"
@@ -198,7 +200,7 @@
   if (!GetSystemMemoryInfo(&info)) {
     return ByteCount(0);
   }
-  return info.avail_phys;
+  return ByteCount::FromUnsigned(info.avail_phys.InBytes());
 }
 
 // static
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index 1a242d60..984ef75f 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -315,10 +315,12 @@
     # Where to write failed expectations for bots to read.
     expectations_failure_dir = "$root_build_dir/failed_expectations"
 
-    # Enables rewriting of certain method invocations with overloads that take an
-    # additional argument of type org.chromium.base.task.Location (see
-    # //build/android/location_rewriter)
-    enable_java_location_rewrite = false
+    # Enables rewriting of certain method invocations with overloads that take
+    # an additional argument of type org.chromium.base.task.Location (see
+    # //build/android/location_rewriter). Turned on for "default" and "canary"
+    # channel for tracing.
+    enable_java_location_rewrite =
+        android_channel == "default" || android_channel == "canary"
   }
 
   if (is_asan) {
diff --git a/build/config/win/BUILD.gn b/build/config/win/BUILD.gn
index 8704b0e..4e4ab17 100644
--- a/build/config/win/BUILD.gn
+++ b/build/config/win/BUILD.gn
@@ -444,6 +444,7 @@
     "/DELAYLOAD:uiautomationcore.dll",
     "/DELAYLOAD:urlmon.dll",
     "/DELAYLOAD:user32.dll",
+    "/DELAYLOAD:userenv.dll",
     "/DELAYLOAD:usp10.dll",
     "/DELAYLOAD:uxtheme.dll",
     "/DELAYLOAD:wer.dll",
@@ -476,7 +477,6 @@
   ldflags = [
     "/DELAYLOAD:crypt32.dll",
     "/DELAYLOAD:dwrite.dll",
-    "/DELAYLOAD:userenv.dll",
     "/DELAYLOAD:winmm.dll",
     "/DELAYLOAD:ws2_32.dll",
   ]
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 1e3de3e..16010ebd 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -11390,16 +11390,13 @@
 
 // Make sure LatencyInfo carried by LatencyInfoSwapPromise are passed
 // in viz::CompositorFrameMetadata.
-TEST_F(CommitToPendingTreeLayerTreeHostImplTest,
+TEST_P(CompositorFrameProducingLayerTreeHostImplTest,
        LatencyInfoPassedToCompositorFrameMetadata) {
   CreateHostImpl(DefaultSettings(), CreateLayerTreeFrameSink());
   SetupRootLayer<SolidColorLayerImpl>(host_impl_->active_tree(),
                                       gfx::Size(10, 10));
   UpdateDrawProperties(host_impl_->active_tree());
 
-  auto* fake_layer_tree_frame_sink =
-      static_cast<FakeLayerTreeFrameSink*>(host_impl_->layer_tree_frame_sink());
-
   ui::LatencyInfo latency_info;
   latency_info.set_trace_id(5);
   latency_info.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT);
@@ -11412,22 +11409,25 @@
                              /*skip_if_inside_draw=*/false);
   DrawFrame();
 
-  const auto& metadata_latency_after =
-      fake_layer_tree_frame_sink->last_sent_frame()->metadata.latency_info;
-  EXPECT_EQ(1u, metadata_latency_after.size());
-  EXPECT_TRUE(metadata_latency_after[0].FindLatency(
-      ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr));
+  auto* fake_layer_tree_frame_sink =
+      static_cast<FakeLayerTreeFrameSink*>(host_impl_->layer_tree_frame_sink());
+  const auto* frame = fake_layer_tree_frame_sink->last_sent_frame();
+  EXPECT_NE(frame, nullptr);
+  if (frame) {
+    const auto& metadata_latency_after = frame->metadata.latency_info;
+    EXPECT_EQ(1u, metadata_latency_after.size());
+    EXPECT_TRUE(metadata_latency_after[0].FindLatency(
+        ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, nullptr));
+  }
 }
 
-TEST_F(CommitToPendingTreeLayerTreeHostImplTest,
+TEST_P(CompositorFrameProducingLayerTreeHostImplTest,
        CompositorFrameMetadataFrameIntervalInputs) {
   CreateHostImpl(DefaultSettings(), CreateLayerTreeFrameSink());
   SetupRootLayer<SolidColorLayerImpl>(host_impl_->active_tree(),
                                       gfx::Size(10, 10));
   UpdateDrawProperties(host_impl_->active_tree());
 
-  auto* fake_layer_tree_frame_sink =
-      static_cast<FakeLayerTreeFrameSink*>(host_impl_->layer_tree_frame_sink());
   host_impl_->NotifyInputEvent(/*is_fling=*/false);
   host_impl_->SetFullViewportDamage();
   host_impl_->SetNeedsRedraw(/*animation_only=*/false,
@@ -11437,11 +11437,15 @@
       base::TimeTicks() + base::Milliseconds(1234));
   DrawFrameWithArgs(args);
 
-  const auto& frame_interval_inputs =
-      fake_layer_tree_frame_sink->last_sent_frame()
-          ->metadata.frame_interval_inputs;
-  EXPECT_TRUE(frame_interval_inputs.has_input);
-  EXPECT_EQ(args.frame_time, frame_interval_inputs.frame_time);
+  auto* fake_layer_tree_frame_sink =
+      static_cast<FakeLayerTreeFrameSink*>(host_impl_->layer_tree_frame_sink());
+  const auto* frame = fake_layer_tree_frame_sink->last_sent_frame();
+  EXPECT_NE(frame, nullptr);
+  if (frame) {
+    const auto& frame_interval_inputs = frame->metadata.frame_interval_inputs;
+    EXPECT_TRUE(frame_interval_inputs.has_input);
+    EXPECT_EQ(args.frame_time, frame_interval_inputs.frame_time);
+  }
 }
 
 #if BUILDFLAG(IS_ANDROID)
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsMessageService.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsMessageService.java
index e3e161d..671fd38 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsMessageService.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsMessageService.java
@@ -29,7 +29,6 @@
 import org.chromium.chrome.browser.app.tabmodel.ArchivedTabModelOrchestrator;
 import org.chromium.chrome.browser.back_press.BackPressManager;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.hub.PaneManager;
 import org.chromium.chrome.browser.layouts.LayoutStateProvider;
 import org.chromium.chrome.browser.layouts.LayoutStateProvider.LayoutStateObserver;
@@ -195,7 +194,6 @@
                     if (tabListCoordinator == null) return;
                     tabListCoordinator.addTabListItemSizeChangedObserver(
                             mTabListItemSizeChangedObserver);
-                    if (!ChromeFeatureList.sTabArchivalDragDropAndroid.isEnabled()) return;
 
                     tabListCoordinator.setOnDropOnArchivalMessageCardEventListener(
                             tabId -> {
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogView.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogView.java
index 7374f876..b41111cf 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogView.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogView.java
@@ -170,12 +170,20 @@
     @Override
     public boolean dispatchTouchEvent(MotionEvent event) {
         if (event.getAction() == MotionEvent.ACTION_DOWN) {
-            View v = findViewById(R.id.title);
-            if (v != null && v.isFocused()) {
-                Rect rect = new Rect();
-                v.getGlobalVisibleRect(rect);
-                if (!rect.contains((int) event.getRawX(), (int) event.getRawY())) {
-                    v.clearFocus();
+            View title = findViewById(R.id.title);
+
+            if (title != null && title.isFocused()) {
+                Rect viewRect = new Rect();
+                // 1. Get the text view's local bounds (0, 0, width, height)
+                title.getDrawingRect(viewRect);
+
+                // 2. Map those bounds to THIS toolbar's coordinate system
+                // This handles all nesting (LinearLayout inside FrameLayout) automatically.
+                offsetDescendantRectToMyCoords(title, viewRect);
+
+                // 3. Compare with event.getX()/getY() which are also relative to this toolbar
+                if (!viewRect.contains((int) event.getX(), (int) event.getY())) {
+                    title.clearFocus();
                 }
             }
         }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridItemTouchHelperCallback.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridItemTouchHelperCallback.java
index d6cfd0f4..4fa4302 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridItemTouchHelperCallback.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridItemTouchHelperCallback.java
@@ -632,8 +632,6 @@
     }
 
     private void handleHoverForArchiveMessage(RecyclerView recyclerView) {
-        if (!ChromeFeatureList.sTabArchivalDragDropAndroid.isEnabled()) return;
-
         SimpleRecyclerViewAdapter.ViewHolder hoveredViewHolder =
                 (SimpleRecyclerViewAdapter.ViewHolder)
                         recyclerView.findViewHolderForAdapterPosition(mHoveredTabIndex);
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListModel.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListModel.java
index 52fcfac..2e49537 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListModel.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListModel.java
@@ -21,7 +21,6 @@
 
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.ui.modelutil.MVCListAdapter;
@@ -449,13 +448,9 @@
 
         PropertyModel model = get(index).model;
 
-        boolean isArchiveMessageCard =
-                model.get(CARD_TYPE) == MESSAGE && model.get(MESSAGE_TYPE) == ARCHIVED_TABS_MESSAGE;
-        if (isArchiveMessageCard && !ChromeFeatureList.sTabArchivalDragDropAndroid.isEnabled()) {
-            return null;
-        }
-
-        assert model.get(CARD_TYPE) == TAB || isArchiveMessageCard;
+        assert model.get(CARD_TYPE) == TAB
+                || (model.get(CARD_TYPE) == MESSAGE
+                        && model.get(MESSAGE_TYPE) == ARCHIVED_TABS_MESSAGE);
         return model;
     }
 }
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsMessageServiceUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsMessageServiceUnitTest.java
index fb0909d0..f942977 100644
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsMessageServiceUnitTest.java
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/ArchivedTabsMessageServiceUnitTest.java
@@ -43,12 +43,9 @@
 import org.chromium.base.supplier.ObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.test.BaseRobolectricTestRunner;
-import org.chromium.base.test.util.Features.DisableFeatures;
-import org.chromium.base.test.util.Features.EnableFeatures;
 import org.chromium.chrome.browser.app.tabmodel.ArchivedTabModelOrchestrator;
 import org.chromium.chrome.browser.back_press.BackPressManager;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.hub.PaneManager;
 import org.chromium.chrome.browser.layouts.LayoutStateProvider;
 import org.chromium.chrome.browser.layouts.LayoutType;
@@ -79,7 +76,6 @@
 /** Tests for ArchivedTabsMessageService. */
 @RunWith(BaseRobolectricTestRunner.class)
 @Config(manifest = Config.NONE)
-@DisableFeatures(ChromeFeatureList.TAB_ARCHIVAL_DRAG_DROP_ANDROID)
 public class ArchivedTabsMessageServiceUnitTest {
     private static final int TIME_DELTA_DAYS = 10;
     private static final int INITIAL_TAB_COUNT = 0;
@@ -253,7 +249,6 @@
     }
 
     @Test
-    @EnableFeatures(ChromeFeatureList.TAB_ARCHIVAL_DRAG_DROP_ANDROID)
     public void testObserverInitialized() {
         createArchivedTabsMessageService();
         mTabListCoordinatorSupplier.set(null);
@@ -264,7 +259,6 @@
     }
 
     @Test
-    @EnableFeatures(ChromeFeatureList.TAB_ARCHIVAL_DRAG_DROP_ANDROID)
     public void testOnDropListener() {
         createArchivedTabsMessageService();
         mTabListCoordinatorSupplier.set(null);
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridItemTouchHelperCallbackUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridItemTouchHelperCallbackUnitTest.java
index d319560..3a5947b2 100644
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridItemTouchHelperCallbackUnitTest.java
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridItemTouchHelperCallbackUnitTest.java
@@ -53,10 +53,7 @@
 import org.chromium.base.Token;
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.test.BaseRobolectricTestRunner;
-import org.chromium.base.test.util.Features.DisableFeatures;
-import org.chromium.base.test.util.Features.EnableFeatures;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabGroupModelFilter;
@@ -86,7 +83,6 @@
         instrumentedPackages = {
             "androidx.recyclerview.widget.RecyclerView" // required to mock final
         })
-@DisableFeatures(ChromeFeatureList.TAB_ARCHIVAL_DRAG_DROP_ANDROID)
 public class TabGridItemTouchHelperCallbackUnitTest {
 
     private static final String TAB1_TITLE = "Tab1";
@@ -938,7 +934,6 @@
     }
 
     @Test
-    @EnableFeatures(ChromeFeatureList.TAB_ARCHIVAL_DRAG_DROP_ANDROID)
     public void onDropOverArchivalCard() {
         setupItemTouchHelperCallback(false);
         addArchivedMessageCard();
@@ -973,7 +968,6 @@
     }
 
     @Test
-    @EnableFeatures(ChromeFeatureList.TAB_ARCHIVAL_DRAG_DROP_ANDROID)
     public void onDropOverArchivalCard_withoutHovering() {
         setupItemTouchHelperCallback(false);
         addArchivedMessageCard();
@@ -998,7 +992,6 @@
     }
 
     @Test
-    @EnableFeatures(ChromeFeatureList.TAB_ARCHIVAL_DRAG_DROP_ANDROID)
     public void onHoverOverArchivalCard() {
         setupItemTouchHelperCallback(false);
         addArchivedMessageCard();
@@ -1037,45 +1030,6 @@
     }
 
     @Test
-    @DisableFeatures(ChromeFeatureList.TAB_ARCHIVAL_DRAG_DROP_ANDROID)
-    public void onHoverOverArchivalCard_archivalDropDisabled() {
-        setupItemTouchHelperCallback(false);
-        addArchivedMessageCard();
-
-        mItemTouchHelperCallback.setActionsOnAllRelatedTabsForTesting(true);
-
-        // Simulate the selection of card#1 in TabListModel.
-        mItemTouchHelperCallback.setSelectedTabIndexForTesting(POSITION1);
-
-        // Pretend a drag over the archived message card has started.
-        mItemTouchHelperCallback.onChildDraw(
-                mCanvas,
-                mRecyclerView,
-                mMockViewHolder1,
-                4,
-                8,
-                ItemTouchHelper.ACTION_STATE_DRAG,
-                true);
-        assertEquals(
-                AnimationStatus.CARD_RESTORE,
-                mModel.get(ARCHIVED_MSG_CARD_POSITION).model.get(CARD_ANIMATION_STATUS));
-
-        // Return to original position.
-        mItemTouchHelperCallback.onChildDraw(
-                mCanvas,
-                mRecyclerView,
-                mMockViewHolder1,
-                0,
-                0,
-                ItemTouchHelper.ACTION_STATE_DRAG,
-                true);
-        assertEquals(
-                AnimationStatus.CARD_RESTORE,
-                mModel.get(ARCHIVED_MSG_CARD_POSITION).model.get(CARD_ANIMATION_STATUS));
-    }
-
-    @Test
-    @EnableFeatures(ChromeFeatureList.TAB_ARCHIVAL_DRAG_DROP_ANDROID)
     public void onHoverAndDropPinnedTabOverArchivalCard() {
         setupItemTouchHelperCallback(false);
         addArchivedMessageCard();
@@ -1117,7 +1071,6 @@
     }
 
     @Test
-    @EnableFeatures(ChromeFeatureList.TAB_ARCHIVAL_DRAG_DROP_ANDROID)
     public void onHoverOverArchivalCard_sharedTabGroup() {
         when(mTabGroupColorViewProvider.hasCollaborationId()).thenReturn(true);
         when(mTab1.getTabGroupId()).thenReturn(Token.createRandom());
diff --git a/chrome/android/java/res/layout/tips_promo_detail_sheet.xml b/chrome/android/java/res/layout/tips_promo_detail_sheet.xml
index 50b3637..74c635c1 100644
--- a/chrome/android/java/res/layout/tips_promo_detail_sheet.xml
+++ b/chrome/android/java/res/layout/tips_promo_detail_sheet.xml
@@ -7,6 +7,7 @@
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
@@ -42,19 +43,34 @@
             style="@style/TextAppearance.Headline"/>
     </LinearLayout>
 
-    <LinearLayout
-        android:id="@+id/steps_container"
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent"
-        android:layout_marginBottom="@dimen/tips_notifications_bottom_sheet_step_vertical_padding"
-        android:orientation="vertical"
-        android:clickable="true"
-        android:focusable="true"/>
 
-    <org.chromium.ui.widget.ButtonCompat
-        android:id="@+id/tips_promo_details_settings_button" style="@style/FilledButton"
+    <ScrollView
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginHorizontal="@dimen/tips_notifications_bottom_sheet_horizontal_margin"
-        android:padding="@dimen/tips_notifications_bottom_sheet_button_padding"/>
+        android:scrollbars="none"
+        tools:ignore="UselessParent,MergeRootFrame">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <LinearLayout
+                android:id="@+id/steps_container"
+                android:layout_height="wrap_content"
+                android:layout_width="match_parent"
+                android:layout_marginBottom="@dimen/tips_notifications_bottom_sheet_step_vertical_padding"
+                android:orientation="vertical"
+                android:clickable="true"
+                android:focusable="true"/>
+
+            <org.chromium.ui.widget.ButtonCompat
+                android:id="@+id/tips_promo_details_settings_button" style="@style/FilledButton"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginHorizontal="@dimen/tips_notifications_bottom_sheet_horizontal_margin"
+                android:padding="@dimen/tips_notifications_bottom_sheet_button_padding"/>
+        </LinearLayout>
+
+    </ScrollView>
 </LinearLayout>
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/ArchivedTabModelOrchestrator.java b/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/ArchivedTabModelOrchestrator.java
index d2ecc84a..df164ac 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/ArchivedTabModelOrchestrator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/ArchivedTabModelOrchestrator.java
@@ -402,7 +402,7 @@
                 new TabbedModeTabPersistencePolicy(
                         TabMetadataFileManager.getMetadataFileName(
                                 ARCHIVED_TAB_SELECTOR_UNIQUE_TAG),
-                        /* otherMetadataFileName= */ null,
+                        /* otherWindowTag= */ null,
                         /* mergeTabsOnStartup= */ false,
                         /* tabMergingEnabled= */ false) {
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/CombinedTabRestorer.java b/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/CombinedTabRestorer.java
index 3c8850e3..34305109 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/CombinedTabRestorer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/CombinedTabRestorer.java
@@ -23,6 +23,8 @@
  */
 @NullMarked
 class CombinedTabRestorer {
+    private static final long INVALID_TIME = -1;
+
     /** Delegate for the {@link CombinedTabRestorer}. */
     public interface CombinedTabRestorerDelegate {
         /**
@@ -30,26 +32,26 @@
          *
          * @param loadedTabCount The number of tabs that were loaded.
          */
-        void onLoadFinished(int loadedTabCount);
+        default void onLoadFinished(int loadedTabCount) {}
 
         /** Called once both the regular and incognito tab restorer have been cancelled. */
-        void onCancelled();
+        default void onCancelled() {}
 
         /** Called once both the regular and incognito tab restorer have been finished. */
-        void onRestoreFinished();
+        default void onRestoreFinished() {}
 
         /**
          * Called when the details of a tab have been read {@see
          * TabPersistentStoreObserver#onDetailsRead}.
          */
-        void onDetailsRead(
+        default void onDetailsRead(
                 int index,
                 @TabId int tabId,
                 String url,
                 boolean isStandardActiveIndex,
                 boolean isIncognitoActiveIndex,
                 boolean isIncognito,
-                boolean fromMerge);
+                boolean fromMerge) {}
     }
 
     private final TabRestorerDelegate mDelegate;
@@ -120,9 +122,11 @@
             state.setLoadFinished();
 
             if (mRegularState.isLoadFinished() && mIncognitoState.isLoadFinished()) {
+                if (mLoadStartTime != INVALID_TIME) {
                 long duration = SystemClock.elapsedRealtime() - mLoadStartTime;
                 RecordHistogram.recordTimesHistogram(
                         "Tabs.TabStateStore.LoadAllTabsDuration", duration);
+                }
                 mOrchestratorDelegate.onLoadFinished(mRestoredTabCount);
             }
         }
@@ -196,11 +200,13 @@
      * @param restoreIncognitoTabs Whether to restore incognito tabs.
      * @param delegate The delegate to be notified of events from the tab restorers.
      * @param tabCreatorManager The tab creator manager to create the tabs.
+     * @param logRestoreDuration Whether to log the restore duration.
      */
     CombinedTabRestorer(
             boolean restoreIncognitoTabs,
             CombinedTabRestorerDelegate delegate,
-            TabCreatorManager tabCreatorManager) {
+            TabCreatorManager tabCreatorManager,
+            boolean logRestoreDuration) {
         mDelegate = new TabRestorerDelegateImpl(delegate, restoreIncognitoTabs);
         mRegularTabRestorer =
                 new TabRestorer(
@@ -214,7 +220,7 @@
                                 mDelegate,
                                 tabCreatorManager.getTabCreator(/* incognito= */ true))
                         : null;
-        mLoadStartTime = SystemClock.elapsedRealtime();
+        mLoadStartTime = logRestoreDuration ? SystemClock.elapsedRealtime() : INVALID_TIME;
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/TabStateStore.java b/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/TabStateStore.java
index b079821..b3506ef0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/TabStateStore.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/TabStateStore.java
@@ -6,6 +6,7 @@
 
 import static org.chromium.build.NullUtil.assumeNonNull;
 
+import org.chromium.base.Log;
 import org.chromium.base.ObserverList;
 import org.chromium.base.Token;
 import org.chromium.build.annotations.NullMarked;
@@ -33,6 +34,7 @@
 import org.chromium.chrome.browser.tabmodel.TabModelObserver;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabRegistrationObserver;
+import org.chromium.chrome.browser.tabmodel.TabPersistencePolicy;
 import org.chromium.chrome.browser.tabmodel.TabPersistentStore;
 import org.chromium.chrome.browser.tabwindow.TabWindowManager;
 import org.chromium.components.tab_groups.TabGroupColorId;
@@ -50,6 +52,7 @@
     private final TabCreatorManager mTabCreatorManager;
     private final TabModelSelector mTabModelSelector;
     private final String mWindowTag;
+    private final TabPersistencePolicy mTabPersistencePolicy;
     private final TabStateAttributes.Observer mAttributesObserver =
             this::onTabStateDirtinessChanged;
     private final ObserverList<TabPersistentStoreObserver> mObservers = new ObserverList<>();
@@ -87,6 +90,7 @@
 
     private @Nullable TabModelSelectorTabRegistrationObserver mTabRegistrationObserver;
     private @Nullable CombinedTabRestorer mCombinedTabRestorer;
+    private @Nullable CombinedTabRestorer mMergeCombinedTabRestorer;
     private @Nullable Runnable mInitRestoreOrchestratorForIncognito;
     private @Nullable StorageCollectionSynchronizer mIncognitoSynchronizer;
     private @Nullable StorageCollectionSynchronizer mRegularSynchronizer;
@@ -212,11 +216,13 @@
             TabStateStorageService tabStateStorageService,
             TabModelSelector tabModelSelector,
             String windowTag,
-            TabCreatorManager tabCreatorManager) {
+            TabCreatorManager tabCreatorManager,
+            TabPersistencePolicy tabPersistencePolicy) {
         mTabStateStorageService = tabStateStorageService;
         mTabModelSelector = tabModelSelector;
         mWindowTag = windowTag;
         mTabCreatorManager = tabCreatorManager;
+        mTabPersistencePolicy = tabPersistencePolicy;
 
         tabModelSelector.getModel(false).addObserver(mTabModelObserver);
         TabModel incognitoModel = tabModelSelector.getModel(true);
@@ -262,7 +268,10 @@
         assert mCombinedTabRestorer == null;
         mCombinedTabRestorer =
                 new CombinedTabRestorer(
-                        !ignoreIncognitoFiles, mCombinedTabRestorerDelegate, mTabCreatorManager);
+                        !ignoreIncognitoFiles,
+                        mCombinedTabRestorerDelegate,
+                        mTabCreatorManager,
+                        /* logRestoreDuration= */ true);
 
         boolean[] restoreOrder =
                 mTabModelSelector.isIncognitoSelected()
@@ -277,11 +286,57 @@
 
     @Override
     public void mergeState() {
-        // This is only invoked for SDK versions less than API 31. Currently this is not supported.
-        // TODO(https://crbug.com/463956290): Decide whether to support this behavior or limit the
-        // new system to API 31+. This could be accomplished with a separate queue of
-        // CombinedTabRestorers for merging.
-        assert false;
+        if (mCombinedTabRestorer != null) {
+            Log.e(TAG, "mergeState aborted as initial restore is in progress.");
+            return;
+        } else if (mMergeCombinedTabRestorer != null || mTabPersistencePolicy.isMergeInProgress()) {
+            Log.e(TAG, "mergeState aborted as merge restore is in progress.");
+            return;
+        }
+        mTabPersistencePolicy.setMergeInProgress(true);
+
+        String windowTagToMerge = mTabPersistencePolicy.getWindowTagToBeMerged();
+        assert windowTagToMerge != null : "Window tag must be non-null if merge is enabled.";
+
+        assert mMergeCombinedTabRestorer == null;
+        CombinedTabRestorerDelegate delegate =
+                new CombinedTabRestorerDelegate() {
+                    @Override
+                    public void onLoadFinished(int loadedTabCount) {
+                        mTabStateStorageService.clearWindow(windowTagToMerge);
+                    }
+
+                    @Override
+                    public void onRestoreFinished() {
+                        mTabPersistencePolicy.setMergeInProgress(false);
+                        mMergeCombinedTabRestorer = null;
+                    }
+                };
+
+        // TODO(crbug.com/463956290): Confirm the key for incognito tabs is valid.
+        mMergeCombinedTabRestorer =
+                new CombinedTabRestorer(
+                        /* restoreIncognitoTabs= */ true,
+                        delegate,
+                        mTabCreatorManager,
+                        /* logRestoreDuration= */ false);
+
+        for (boolean incognito : new boolean[] {false, true}) {
+            final boolean incognitoFinal = incognito;
+            mTabStateStorageService.loadAllData(
+                    windowTagToMerge,
+                    incognitoFinal,
+                    data -> {
+                        if (mIsDestroyed) {
+                            data.destroy();
+                            return;
+                        }
+                        assumeNonNull(mMergeCombinedTabRestorer);
+                        mMergeCombinedTabRestorer.onDataLoaded(data, incognitoFinal);
+                    });
+        }
+        mMergeCombinedTabRestorer.start(
+                mTabModelSelector.isIncognitoSelected(), /* restoreActiveTabImmediately= */ false);
     }
 
     @Override
@@ -333,6 +388,13 @@
             mCombinedTabRestorer = null;
         }
 
+        if (mMergeCombinedTabRestorer != null) {
+            mMergeCombinedTabRestorer.cancel();
+            mMergeCombinedTabRestorer = null;
+            // Reset if an ongoing merge gets cancelled.
+            mTabPersistencePolicy.setMergeInProgress(false);
+        }
+
         mTabModelSelector.getModel(false).removeObserver(mTabModelObserver);
         TabModel incognitoTabModel = mTabModelSelector.getModel(true);
         incognitoTabModel.removeObserver(mTabModelObserver);
@@ -456,10 +518,8 @@
             }
         }
 
-        // TODO(ckitagawa): Change back to assert if the `mIsDestroyed` check is sufficient.
-        if (mCombinedTabRestorer != null) {
-            mCombinedTabRestorer.onDataLoaded(data, incognito);
-        }
+        assumeNonNull(mCombinedTabRestorer);
+        mCombinedTabRestorer.onDataLoaded(data, incognito);
     }
 
     /** Called after both the regular and incognito data has been loaded. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/TabbedModeTabModelOrchestrator.java b/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/TabbedModeTabModelOrchestrator.java
index 3872a7d..2632a1c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/TabbedModeTabModelOrchestrator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/tabmodel/TabbedModeTabModelOrchestrator.java
@@ -310,7 +310,8 @@
                             TabStateStorageServiceFactory.getForProfile(profile),
                             mTabModelSelector,
                             mWindowTag,
-                            shadowTabCreatorManager);
+                            shadowTabCreatorManager,
+                            mTabPersistencePolicy);
 
             SupplierUtils.waitForAll(
                     this::onBothStateLoaded,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/ScrollDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/ScrollDelegate.java
index 0efeef82..42b1b69 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/ScrollDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/ScrollDelegate.java
@@ -12,7 +12,6 @@
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.browser.compositor.layouts.phone.stack.StackScroller;
 import org.chromium.chrome.browser.compositor.overlays.strip.reorder.TabStripDragHandler;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.ui.base.LocalizationUtils;
 
 /**
@@ -202,15 +201,7 @@
             if (view instanceof final StripLayoutTab tab) {
                 if (tab.isClosed()) continue;
 
-                // Need to use real width (which gets animated to effectively 0) to smoothly scroll
-                // when (collapsing) or (using updated animations) near the end of a full tab strip.
-                boolean useRealWidth =
-                        tab.isCollapsed()
-                                || ChromeFeatureList.sTabletTabStripAnimation.isEnabled()
-                                || tab.getIsPinned();
-                float tabWidth = useRealWidth ? tab.getWidth() : cachedTabWidth;
-
-                totalViewWidth += (tabWidth - tabOverlapWidth);
+                totalViewWidth += (tab.getWidth() - tabOverlapWidth);
             } else if (view instanceof StripLayoutGroupTitle groupTitle) {
                 totalViewWidth += (groupTitle.getWidth() - groupTitleOverlapWidth);
             }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
index 2a9203e..d06cf2e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
@@ -176,10 +176,9 @@
     private static final float SPINNER_DPMS = 0.33f;
     private static final int ANIM_TAB_CREATED_MS = 150;
     private static final int ANIM_TAB_CLOSED_MS = 150;
-    private static final int ANIM_TAB_RESIZE_MS = 250;
+    private static final int ANIM_TAB_RESIZE_MS = 200;
     private static final int ANIM_TAB_DRAW_X_MS = 250;
     private static final int ANIM_BUTTONS_FADE_MS = 150;
-    private static final int NEW_ANIM_TAB_RESIZE_MS = 200;
 
     // Visibility Constants
     private static final float NEW_TAB_BUTTON_BACKGROUND_Y_OFFSET_DP = 3.f;
@@ -576,7 +575,6 @@
     private final Context mContext;
 
     // Animation states. True while the relevant animations are running, and false otherwise.
-    private boolean mMultiStepTabCloseAnimRunning;
     private boolean mTabResizeAnimRunning;
 
     // TabModel info available before the tab state is actually initialized. Determined from frozen
@@ -1810,9 +1808,7 @@
         StripLayoutTab stripTab = findTabById(id);
         if (stripTab != null) {
             updateTabCollapsed(stripTab, collapsed, false);
-            if (!onStartup && !collapsed) {
-                runTabAddedAnimator(animationList, stripTab, /* fromTabCreation= */ true);
-            }
+            if (!onStartup && !collapsed) startAnimations(animationList);
         }
 
         // 4. If the new tab will be selected, scroll it to view. If the new tab will not be
@@ -1847,19 +1843,15 @@
         mUpdateHost.requestUpdate();
     }
 
-    private void runTabAddedAnimator(
-            List<Animator> animationList, StripLayoutTab tab, boolean fromTabCreation) {
-        if (!ChromeFeatureList.sTabletTabStripAnimation.isEnabled() || !fromTabCreation) {
-            animationList.add(
-                    CompositorAnimator.ofFloatProperty(
-                            mUpdateHost.getAnimationHandler(),
-                            tab,
-                            StripLayoutTab.Y_OFFSET,
-                            tab.getHeight(),
-                            0f,
-                            ANIM_TAB_CREATED_MS));
-        }
-
+    private void runTabAddedAnimator(List<Animator> animationList, StripLayoutTab tab) {
+        animationList.add(
+                CompositorAnimator.ofFloatProperty(
+                        mUpdateHost.getAnimationHandler(),
+                        tab,
+                        StripLayoutTab.Y_OFFSET,
+                        tab.getHeight(),
+                        0f,
+                        ANIM_TAB_CREATED_MS));
         startAnimations(animationList);
     }
 
@@ -2093,14 +2085,12 @@
             }
             boolean currContainerHidden = StripLayoutTabDelegate.isTabHidden(currTab);
 
-            boolean hideDividerForDyingTab =
-                    ChromeFeatureList.sTabletTabStripAnimation.isEnabled() && currTab.isDying();
             // 2. Set start divider visibility.
             if (i > 0 && viewsOnStrip[i - 1] instanceof StripLayoutTab prevTab) {
                 boolean prevContainerHidden = StripLayoutTabDelegate.isTabHidden(prevTab);
                 boolean prevTabHasMargin = prevTab.getTrailingMargin() > 0;
                 boolean startDividerVisible =
-                        !hideDividerForDyingTab
+                        !currTab.isDying()
                                 && currContainerHidden
                                 && (prevContainerHidden || prevTabHasMargin);
                 currTab.setStartDividerVisible(startDividerVisible);
@@ -2116,7 +2106,7 @@
                 boolean endDividerVisible =
                         (isLastTab || viewsOnStrip[i + 1] instanceof StripLayoutGroupTitle)
                                 && currContainerHidden
-                                && !hideDividerForDyingTab;
+                                && !currTab.isDying();
                 currTab.setEndDividerVisible(endDividerVisible);
             }
         }
@@ -2939,40 +2929,21 @@
      */
     @VisibleForTesting
     void handleCloseTab(StripLayoutTab tab, boolean allowUndo) {
-        mMultiStepTabCloseAnimRunning = false;
         finishAnimationsAndCloseDyingTabs(allowUndo);
 
-        // When a tab is closed #resizeStripOnTabClose will run animations for the new tab offset
-        // and tab x offsets. When there is only 1 tab remaining, we do not need to run those
-        // animations, so #computeAndUpdateTabWidth() is used instead.
-        boolean runImprovedTabAnimations = mStripTabs.length > 1;
-
         // 1. Set the dying state of the tab.
         tab.setIsDying(true);
 
         // 2. Start the tab closing animator with a listener to resize/move tabs after the closure.
-        // If closing the end-most tab, set an offset to prevent the tab from "jumping" to align
-        // with the new end-most tab. This will be cleared when the resize is animated.
-        if (!ChromeFeatureList.sTabletTabStripAnimation.isEnabled()
-                && isEndMostTab(tab.getTabId())) {
-            mNewTabButton.setOffsetX(
-                    MathUtils.flipSignIf(
-                            getEffectiveTabWidth(/* isPinned= */ false),
-                            LocalizationUtils.isLayoutRtl()));
-        }
         AnimatorListener listener =
                 new AnimatorListenerAdapter() {
                     @Override
                     public void onAnimationEnd(Animator animation) {
                         // Removes all dying tabs from TabModel.
                         finishAnimationsAndCloseDyingTabs(allowUndo);
-
-                        if (!ChromeFeatureList.sTabletTabStripAnimation.isEnabled()) {
-                            resizeStripOnTabClose(runImprovedTabAnimations);
-                        }
                     }
                 };
-        runTabRemovalAnimation(tab, listener);
+        startAnimations(getTabClosingAnimators(), listener);
 
         // 3. If we're closing the selected tab, attempt to select the next expanded tab now. If
         // none exists, we'll default to the normal auto-selection behavior (i.e. selecting the
@@ -2983,16 +2954,6 @@
         }
     }
 
-    private Animator getLegacyTabClosedAnimator(StripLayoutTab tab) {
-        return CompositorAnimator.ofFloatProperty(
-                mUpdateHost.getAnimationHandler(),
-                tab,
-                StripLayoutTab.Y_OFFSET,
-                tab.getOffsetY(),
-                tab.getHeight(),
-                ANIM_TAB_CLOSED_MS);
-    }
-
     private Animator getViewWidthAnimator(StripLayoutView view, float targetWidth, int duration) {
         return CompositorAnimator.ofFloatProperty(
                 mUpdateHost.getAnimationHandler(),
@@ -3003,36 +2964,11 @@
                 duration);
     }
 
-    private List<Animator> getTabClosingAnimators(Collection<StripLayoutTab> tabs) {
-        if (ChromeFeatureList.sTabletTabStripAnimation.isEnabled()) {
-            // computeAndUpdateTabWidth handles animating a tab closing.
-            List<Animator> tabClosingAnimators =
-                    computeAndUpdateTabWidth(/* animate= */ true, /* deferAnimations= */ true);
-            if (tabClosingAnimators != null) return tabClosingAnimators;
-            return new ArrayList<>();
-        } else {
-            mMultiStepTabCloseAnimRunning = true;
-            List<Animator> tabClosingAnimators = new ArrayList<>();
-            for (StripLayoutTab tab : tabs) {
-                tabClosingAnimators.add(getLegacyTabClosedAnimator(tab));
-            }
-            return tabClosingAnimators;
-        }
-    }
-
-    private void runTabRemovalAnimation(StripLayoutTab tab, AnimatorListener listener) {
-        startAnimations(getTabClosingAnimators(Collections.singletonList(tab)), listener);
-    }
-
-    private void resizeStripOnTabClose(boolean runImprovedTabAnimations) {
-        if (runImprovedTabAnimations) {
-            resizeStripOnTabClose();
-        } else {
-            mNewTabButton.setOffsetX(/* offsetX= */ 0.f);
-            mMultiStepTabCloseAnimRunning = false;
-            // Resize the tabs appropriately.
-            computeAndUpdateTabWidth(/* animate= */ true, /* deferAnimations= */ false);
-        }
+    private List<Animator> getTabClosingAnimators() {
+        // Dying tabs are animated to an effective width of 0 in the resize flow.
+        List<Animator> tabClosingAnimators =
+                computeAndUpdateTabWidth(/* animate= */ true, /* deferAnimations= */ true);
+        return tabClosingAnimators == null ? new ArrayList<>() : tabClosingAnimators;
     }
 
     private void resizeStripOnTabClose() {
@@ -3069,28 +3005,7 @@
                             ANIM_TAB_DRAW_X_MS);
             tabStripAnimators.add(drawXAnimator);
         }
-
-        // 4. Add new tab button offset animation if needed.
-        if (mNewTabButton.getOffsetX() != 0.f) {
-            tabStripAnimators.add(
-                    CompositorAnimator.ofFloatProperty(
-                            mUpdateHost.getAnimationHandler(),
-                            mNewTabButton,
-                            StripLayoutView.X_OFFSET,
-                            mNewTabButton.getOffsetX(),
-                            /* endValue= */ 0.f,
-                            ANIM_TAB_RESIZE_MS));
-        }
-
-        // 5. Add animation completion listener and start animations.
-        startAnimations(
-                tabStripAnimators,
-                new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        mMultiStepTabCloseAnimRunning = false;
-                    }
-                });
+        startAnimations(tabStripAnimators);
     }
 
     /**
@@ -3715,13 +3630,10 @@
         for (StripLayoutView view : mClosingGroupTitles) view.setIsDying(true);
 
         // Create animators.
-        List<Animator> animationList = getTabClosingAnimators(mClosingTabs);
-        if (ChromeFeatureList.sTabletTabStripAnimation.isEnabled()) {
-            for (StripLayoutGroupTitle groupTitle : mClosingGroupTitles) {
-                animationList.add(
-                        getViewWidthAnimator(
-                                groupTitle, mGroupTitleOverlapWidth, ANIM_TAB_CLOSED_MS));
-            }
+        List<Animator> animationList = getTabClosingAnimators();
+        for (StripLayoutGroupTitle groupTitle : mClosingGroupTitles) {
+            animationList.add(
+                    getViewWidthAnimator(groupTitle, mGroupTitleOverlapWidth, ANIM_TAB_CLOSED_MS));
         }
 
         // Queue the animations.
@@ -3730,11 +3642,7 @@
                 new AnimatorListenerAdapter() {
                     @Override
                     public void onAnimationEnd(Animator animation) {
-                        boolean runImprovedTabAnimations = mStripTabs.length > 1;
                         rebuildStripTabs(/* deferAnimations= */ false);
-                        if (!ChromeFeatureList.sTabletTabStripAnimation.isEnabled()) {
-                            resizeStripOnTabClose(runImprovedTabAnimations);
-                        }
                         clearStateOnCloseAnimationsEnd();
                     }
                 });
@@ -3884,7 +3792,7 @@
         rebuildStripViews();
 
         // If a tab close is animating, the resize may be handled elsewhere.
-        if (mMultiStepTabCloseAnimRunning || mPendingMouseTabClosure) return null;
+        if (mPendingMouseTabClosure) return null;
         recordPinnedOnlyTabStripUserAction();
 
         // Otherwise, animate the required width changes.
@@ -4491,24 +4399,21 @@
     }
 
     @Override
-    public void resizeTabStrip(
-            boolean animate, @Nullable StripLayoutTab tabToAnimate, boolean tabAddedAnimation) {
+    public void resizeTabStrip(@Nullable StripLayoutTab tabToAnimate, boolean tabAddedAnimation) {
         finishAnimationsAndCloseDyingTabs(/* allowUndo= */ true);
         if (tabToAnimate != null) {
-            assert animate;
             if (!tabAddedAnimation) {
-                mMultiStepTabCloseAnimRunning = true;
                 // Resize the tab strip accordingly.
                 resizeStripOnTabClose();
             } else {
                 List<Animator> animationList =
                         computeAndUpdateTabWidth(/* animate= */ true, /* deferAnimations= */ true);
                 if (animationList != null) {
-                    runTabAddedAnimator(animationList, tabToAnimate, /* fromTabCreation= */ false);
+                    runTabAddedAnimator(animationList, tabToAnimate);
                 }
             }
         } else {
-            computeAndUpdateTabWidth(animate, /* deferAnimations= */ animate);
+            computeAndUpdateTabWidth(/* animate= */ false, /* deferAnimations= */ false);
         }
 
         // Update the ideal view positions, since these are needed for reorder offset calculations.
@@ -4602,10 +4507,7 @@
     }
 
     private boolean isLiveTab(StripLayoutTab tab) {
-        return !tab.isClosed()
-                && !tab.isDraggedOffStrip()
-                && !tab.isCollapsed()
-                && !(tab.isDying() && ChromeFeatureList.sTabletTabStripAnimation.isEnabled());
+        return !tab.isClosed() && !tab.isDraggedOffStrip() && !tab.isCollapsed() && !tab.isDying();
     }
 
     /** Returns the total number of unpinned tabs that are live. */
@@ -4734,17 +4636,14 @@
         if (animate) resizeAnimationList = new ArrayList<>();
         for (int i = 0; i < mStripTabs.length; i++) {
             StripLayoutTab tab = mStripTabs[i];
-            if ((tab.isDying() && !ChromeFeatureList.sTabletTabStripAnimation.isEnabled())
-                    || tab.isCollapsed()) {
-                continue;
-            }
+            if (tab.isCollapsed()) continue;
+
             float cachedTabWidth = getCachedTabWidth(tab.getIsPinned());
             if (resizeAnimationList != null) {
                 // Handle animating a tab being closed for TabletTabStripAnimation.
                 if (tab.isDying()) {
                     resizeAnimationList.add(
-                            getViewWidthAnimator(
-                                    tab, TAB_OVERLAP_WIDTH_DP, NEW_ANIM_TAB_RESIZE_MS));
+                            getViewWidthAnimator(tab, TAB_OVERLAP_WIDTH_DP, ANIM_TAB_RESIZE_MS));
                     continue;
                 }
 
@@ -4753,11 +4652,8 @@
                     continue;
                 }
 
-                int duration =
-                        ChromeFeatureList.sTabletTabStripAnimation.isEnabled()
-                                ? NEW_ANIM_TAB_RESIZE_MS
-                                : ANIM_TAB_RESIZE_MS;
-                resizeAnimationList.add(getViewWidthAnimator(tab, cachedTabWidth, duration));
+                resizeAnimationList.add(
+                        getViewWidthAnimator(tab, cachedTabWidth, ANIM_TAB_RESIZE_MS));
             } else {
                 mStripTabs[i].setWidth(cachedTabWidth);
             }
@@ -4897,11 +4793,7 @@
                 // idealX represents where a tab should be placed in the tab strip.
                 setTabIdealX(tab, startX);
 
-                if (ChromeFeatureList.sTabletTabStripAnimation.isEnabled() || !tab.isDying()) {
-                    delta = (tab.getWidth() - TAB_OVERLAP_WIDTH_DP) * tab.getWidthWeight();
-                } else {
-                    delta = getEffectiveTabWidth(tab.getIsPinned());
-                }
+                delta = (tab.getWidth() - TAB_OVERLAP_WIDTH_DP) * tab.getWidthWeight();
             } else if (view instanceof StripLayoutGroupTitle groupTitle) {
                 // Offset to "undo" the tab overlap width as that doesn't apply to non-tab views.
                 // Also applies the desired overlap with the previous tab.
@@ -5502,10 +5394,6 @@
         mRunningAnimator = animator;
     }
 
-    protected boolean isMultiStepCloseAnimationsRunningForTesting() {
-        return mMultiStepTabCloseAnimRunning;
-    }
-
     protected float getLastReorderXForTesting() {
         return mReorderDelegate.getLastReorderXForTesting();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTabDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTabDelegate.java
index 017ec7c3..b944183 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTabDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTabDelegate.java
@@ -11,7 +11,6 @@
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.chrome.browser.compositor.layouts.LayoutUpdateHost;
 import org.chromium.chrome.browser.compositor.layouts.components.TintedCompositorButton;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.layouts.animation.CompositorAnimator;
 import org.chromium.ui.base.LocalizationUtils;
 
@@ -127,9 +126,7 @@
 
         // A dying tab that is not selected should not show its close button.
         // TODO(crbug.com/419843587): Await UX direction for close button appearance
-        if (ChromeFeatureList.sTabletTabStripAnimation.isEnabled()
-                && tab.isDying()
-                && !tab.getIsSelected()) {
+        if (tab.isDying() && !tab.getIsSelected()) {
             canShow = false;
             tab.setCanShowCloseButton(canShow, false);
         } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutUtils.java
index bd64e624..5cfbe8e0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutUtils.java
@@ -413,11 +413,6 @@
         view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
     }
 
-    public static boolean skipTabEdgePositionCalculation(StripLayoutTab tab) {
-        return (tab.isDying() && !ChromeFeatureList.sTabletTabStripAnimation.isEnabled())
-                || tab.isDraggedOffStrip();
-    }
-
     public static boolean shouldApplyMoreDensity() {
         return ChromeFeatureList.sTabStripDensityChangeAndroid.isEnabled()
                 && DeviceInfo.isDesktop();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripStacker.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripStacker.java
index 4387547..02efc54 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripStacker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripStacker.java
@@ -107,7 +107,7 @@
             float stripWidth) {
         float rightEdge = stripLeftMargin;
         for (StripLayoutTab tab : indexOrderedTabs) {
-            if (StripLayoutUtils.skipTabEdgePositionCalculation(tab)) continue;
+            if (tab.isDraggedOffStrip()) continue;
             float layoutWidth = (tab.getWidth() - tabOverlapWidth) * tab.getWidthWeight();
             rightEdge = Math.max(tab.getDrawX() + layoutWidth, rightEdge);
         }
@@ -124,7 +124,7 @@
             float newTabButtonWidth) {
         float leftEdge = stripWidth - stripRightMargin;
         for (StripLayoutTab tab : indexOrderedTabs) {
-            if (StripLayoutUtils.skipTabEdgePositionCalculation(tab)) continue;
+            if (tab.isDraggedOffStrip()) continue;
             leftEdge = Math.min(tab.getDrawX(), leftEdge);
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/reorder/ReorderDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/reorder/ReorderDelegate.java
index 6bdf43f..80665ce 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/reorder/ReorderDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/reorder/ReorderDelegate.java
@@ -84,13 +84,11 @@
         /**
          * Update strip - resize all views on tab strip.
          *
-         * @param animate Whether to animate the resize.
          * @param tabToAnimate Tab to additionally animate. Must be null if animate is false.
          * @param animateTabAdded Run tab added animation on tabToAnimate if true. Run tab closed
          *     animation if false.
          */
-        void resizeTabStrip(
-                boolean animate, @Nullable StripLayoutTab tabToAnimate, boolean animateTabAdded);
+        void resizeTabStrip(@Nullable StripLayoutTab tabToAnimate, boolean animateTabAdded);
 
         /**
          * Requests an update to strip (view properties etc) based on current state (eg: reorder,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/reorder/SourceViewDragDropReorderStrategy.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/reorder/SourceViewDragDropReorderStrategy.java
index 8627a78..82240b9c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/reorder/SourceViewDragDropReorderStrategy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/reorder/SourceViewDragDropReorderStrategy.java
@@ -360,7 +360,7 @@
             mAnimationHost.finishAnimationsAndPushTabUpdates();
             bringViewOntoStripAndOffset(draggedTab);
             mStripUpdateDelegate.resizeTabStrip(
-                    /* animate= */ false, /* tabToAnimate= */ null, /* animateTabAdded= */ false);
+                    /* tabToAnimate= */ null, /* animateTabAdded= */ false);
 
             // 3. Start to reorder within strip - delegate to the wrapped strategy.
             super.startReorderMode(
@@ -398,8 +398,7 @@
             // like a closed tab. Resize strip views accordingly.
             mAnimationHost.finishAnimationsAndPushTabUpdates();
             removeViewOutOfStrip(draggedTab);
-            mStripUpdateDelegate.resizeTabStrip(
-                    /* animate= */ true, draggedTab, /* animateTabAdded= */ false);
+            mStripUpdateDelegate.resizeTabStrip(draggedTab, /* animateTabAdded= */ false);
         }
 
         @Override
@@ -439,8 +438,7 @@
 
                 // Animate the tab translating back up onto the tab strip.
                 draggedTab.setWidth(0.f);
-                mStripUpdateDelegate.resizeTabStrip(
-                        /* animate= */ true, draggedTab, /* animateTabAdded= */ true);
+                mStripUpdateDelegate.resizeTabStrip(draggedTab, /* animateTabAdded= */ true);
             }
             super.onStopViewDragAction(stripViews, groupTitles);
         }
@@ -485,7 +483,7 @@
                 bringViewOntoStripAndOffset(view);
             }
             mStripUpdateDelegate.resizeTabStrip(
-                    /* animate= */ false, /* tabToAnimate= */ null, /* animateTabAdded= */ false);
+                    /* tabToAnimate= */ null, /* animateTabAdded= */ false);
 
             // 3. Re-select the previously selected dragged tab, if needed.
             reselectDraggedSelectedTab(mModel, mSelectedDraggedTab);
@@ -513,7 +511,7 @@
                 removeViewOutOfStrip(view);
             }
             mStripUpdateDelegate.resizeTabStrip(
-                    /* animate= */ false, /* tabToAnimate= */ null, /* animateTabAdded= */ false);
+                    /* tabToAnimate= */ null, /* animateTabAdded= */ false);
         }
 
         @Override
@@ -609,9 +607,7 @@
                     bringViewOntoStrip(view);
                 }
                 mStripUpdateDelegate.resizeTabStrip(
-                        /* animate= */ false,
-                        /* tabToAnimate= */ null,
-                        /* animateTabAdded= */ false);
+                        /* tabToAnimate= */ null, /* animateTabAdded= */ false);
                 // TODO(crbug.com/445152399) Re-select the dragged tab, if needed.
             }
             super.onStopViewDragAction(stripViews, groupTitles);
@@ -660,9 +656,7 @@
                     bringViewOntoStrip(view);
                 }
                 mStripUpdateDelegate.resizeTabStrip(
-                        /* animate= */ false,
-                        /* tabToAnimate= */ null,
-                        /* animateTabAdded= */ false);
+                        /* tabToAnimate= */ null, /* animateTabAdded= */ false);
                 // TODO(crbug.com/445152399) Re-select the dragged tab, if needed.
             }
             super.onStopViewDragAction(stripViews, groupTitles);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/AutoPictureInPicturePermissionController.java b/chrome/android/java/src/org/chromium/chrome/browser/media/AutoPictureInPicturePermissionController.java
index f37a0db..21bc09a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/AutoPictureInPicturePermissionController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/AutoPictureInPicturePermissionController.java
@@ -36,6 +36,7 @@
 
     private final WebContents mWebContents;
     private final GURL mUrl;
+    private final Runnable mClosePipCallback;
     private @Nullable AutoPipPermissionDialogView mView;
     private @Nullable AutoPictureInPicturePrivacyMaskView mMaskView;
 
@@ -44,8 +45,10 @@
      *
      * @param activity The activity to display the prompt in.
      * @param tab The tab that is entering auto picture-in-picture.
+     * @param closePipCallback A callback to run if the user selects 'Don't Allow' (BLOCK).
      */
-    public static void showPromptIfNeeded(Activity activity, @Nullable Tab tab) {
+    public static void showPromptIfNeeded(
+            Activity activity, @Nullable Tab tab, Runnable closePipCallback) {
         if (tab == null || tab.getWebContents() == null) {
             return;
         }
@@ -73,7 +76,7 @@
         // Create the controller and register it with the helper. This prevents "fire and forget"
         // by giving the controller a clear owner (the helper attached to the WebContents).
         AutoPictureInPicturePermissionController controller =
-                new AutoPictureInPicturePermissionController(webContents);
+                new AutoPictureInPicturePermissionController(webContents, closePipCallback);
         helper.setPermissionController(controller);
 
         controller.show(activity);
@@ -91,9 +94,11 @@
                 .isAutoPictureInPictureInUse(webContents);
     }
 
-    private AutoPictureInPicturePermissionController(WebContents webContents) {
+    private AutoPictureInPicturePermissionController(
+            WebContents webContents, Runnable closePipCallback) {
         mWebContents = webContents;
         mUrl = webContents.getLastCommittedUrl();
+        mClosePipCallback = closePipCallback;
     }
 
     private void show(Activity activity) {
@@ -168,7 +173,7 @@
             case AutoPipPermissionDialogView.UiResult.BLOCK:
                 AutoPictureInPicturePermissionControllerJni.get()
                         .setPermissionStatus(mWebContents, ContentSetting.BLOCK);
-                // TODO(crbug.com/459582604): close the document PiP window.
+                mClosePipCallback.run();
                 break;
             case AutoPipPermissionDialogView.UiResult.ALLOW_ONCE:
                 assertNonNull(AutoPictureInPictureTabHelper.fromWebContents(mWebContents))
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/DocumentPictureInPictureActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/media/DocumentPictureInPictureActivity.java
index 3737e10..7197702d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/DocumentPictureInPictureActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/DocumentPictureInPictureActivity.java
@@ -143,7 +143,7 @@
                         .post(
                                 () ->
                                         AutoPictureInPicturePermissionController.showPromptIfNeeded(
-                                                this, mInitiatorTab));
+                                                this, mInitiatorTab, this::finish));
             }
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31.java b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31.java
index 5479ae6e..d158944 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31.java
@@ -702,7 +702,7 @@
                             MultiInstancePersistentStore.readIncognitoTabCount(i),
                             MultiInstancePersistentStore.readIncognitoSelected(i),
                             lastAccessedTime,
-                            MultiInstancePersistentStore.readClosedByUser(i)));
+                            MultiInstancePersistentStore.readMarkedForDeletion(i)));
         }
         // Move the current instance always to the top of the list for favorable display on the UI.
         // It is possible that |currentItemPos| is invalid if this method is invoked early during
@@ -1373,7 +1373,8 @@
             }
             mTabModelOrchestratorSupplier.get().cleanupInstance(instanceId);
         } else {
-            MultiInstancePersistentStore.writeClosedByUser(instanceId, /* closedByUser= */ true);
+            MultiInstancePersistentStore.writeMarkedForDeletion(
+                    instanceId, /* markedForDeletion= */ true);
         }
         Activity activity = getActivityById(instanceId);
         if (activity != null) activity.finishAndRemoveTask();
@@ -1463,7 +1464,7 @@
         int count = 0;
         for (Integer id : persistedIds) {
             // Exclude instances closed by the user.
-            if (MultiInstancePersistentStore.readClosedByUser(id)) continue;
+            if (MultiInstancePersistentStore.readMarkedForDeletion(id)) continue;
             if (!isRestorableInstance(id)) continue;
             count++;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstancePersistentStore.java b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstancePersistentStore.java
index 7b50bc85..ed2fb79 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstancePersistentStore.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/multiwindow/MultiInstancePersistentStore.java
@@ -75,7 +75,7 @@
         removeIncognitoSelected(instanceId);
         removeLastAccessedTime(instanceId);
         removeProfileType(instanceId);
-        removeClosedByUser(instanceId);
+        removeMarkedForDeletion(instanceId);
     }
 
     static long readLastAccessedTime(int instanceId) {
@@ -169,12 +169,12 @@
         getManager().writeBoolean(incognitoSelectedKey(instanceId), incognitoSelected);
     }
 
-    static boolean readClosedByUser(int instanceId) {
-        return getManager().readBoolean(closedByUserKey(instanceId), false);
+    static boolean readMarkedForDeletion(int instanceId) {
+        return getManager().readBoolean(markedForDeletionKey(instanceId), false);
     }
 
-    static void writeClosedByUser(int instanceId, boolean closedByUser) {
-        getManager().writeBoolean(closedByUserKey(instanceId), closedByUser);
+    static void writeMarkedForDeletion(int instanceId, boolean markedForDeletion) {
+        getManager().writeBoolean(markedForDeletionKey(instanceId), markedForDeletion);
     }
 
     private static void removeLastAccessedTime(int instanceId) {
@@ -207,8 +207,8 @@
         getManager().removeKey(incognitoSelectedKey(instanceId));
     }
 
-    private static void removeClosedByUser(int instanceId) {
-        getManager().removeKey(closedByUserKey(instanceId));
+    private static void removeMarkedForDeletion(int instanceId) {
+        getManager().removeKey(markedForDeletionKey(instanceId));
     }
 
     private static String lastAccessedTimeKey(int instanceId) {
@@ -257,8 +257,8 @@
                 String.valueOf(instanceId));
     }
 
-    private static String closedByUserKey(int instanceId) {
-        return ChromePreferenceKeys.MULTI_INSTANCE_CLOSED_BY_USER.createKey(
+    private static String markedForDeletionKey(int instanceId) {
+        return ChromePreferenceKeys.MULTI_INSTANCE_MARKED_FOR_DELETION.createKey(
                 String.valueOf(instanceId));
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java
index 76682949df..f7698cd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java
@@ -786,6 +786,16 @@
         updatePreferences();
     }
 
+    @Override
+    public void onSignInAllowedChanged() {
+        updatePreferences();
+    }
+
+    @Override
+    public void onSignOutAllowedChanged() {
+        updatePreferences();
+    }
+
     // TemplateUrlService.LoadListener implementation.
     @Override
     public void onTemplateUrlServiceLoaded() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/search/SettingsSearchCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/settings/search/SettingsSearchCoordinator.java
index a6571f2..9c9ac03 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/settings/search/SettingsSearchCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/search/SettingsSearchCoordinator.java
@@ -246,7 +246,7 @@
     @EnsuresNonNull("mIndexData")
     private void initIndex() {
         if (mIndexData == null) {
-            mIndexData = new SettingsIndexData();
+            mIndexData = SettingsIndexData.createInstance();
         } else {
             if (!mIndexData.needsIndexing()) return;
         }
@@ -768,5 +768,8 @@
     public void destroy() {
         // Title supplier should be nulled out as we step out of Settings for cleanup.
         SearchResultsPreferenceFragment.reset();
+        if (mIndexData != null) {
+            SettingsIndexData.reset();
+        }
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistencePolicy.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistencePolicy.java
index 7a3b1c5..f38470a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistencePolicy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistencePolicy.java
@@ -40,6 +40,11 @@
     @Nullable
     String getMetadataFileNameToBeMerged();
 
+    /** Returns the window tag of the metadata file that is to be merged. */
+    default @Nullable String getWindowTagToBeMerged() {
+        return null;
+    }
+
     /**
      * Performs any necessary initialization required before accessing the tab information. This can
      * include cleanups or migrations that must occur before the tab state information can be read
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabbedModeTabPersistencePolicy.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabbedModeTabPersistencePolicy.java
index 78cf178..d4c1133 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabbedModeTabPersistencePolicy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabbedModeTabPersistencePolicy.java
@@ -84,7 +84,7 @@
     private static @Nullable AsyncTask<Void> sCleanupTask;
 
     private final String mMetadataFileName;
-    private final @Nullable String mOtherMetadataFileName;
+    private final @Nullable String mOtherWindowTag;
     private final boolean mMergeTabsOnStartup;
     private final int mMaxSelectors;
 
@@ -95,9 +95,9 @@
      * Constructs a persistence policy that handles the Tabbed mode specific logic.
      *
      * @param metadataFileName The state file name to pull and save state to.
-     * @param otherMetadataFileName The state file name to use for merging. Must be non-null if
-     *     either {@code mergeTabsOnStartup} or {@code tabMergingEnabled} are true and is ignored if
-     *     both are false.
+     * @param otherWindowTag The window tag to use for merging. Must be non-null if either {@code
+     *     mergeTabsOnStartup} or {@code tabMergingEnabled} are true and is ignored if both are
+     *     false.
      * @param mergeTabsOnStartup Whether this policy should handle merging tabs from all available
      *     tabbed mode files at startup.
      * @param tabMergingEnabled Whether tab merging operation should be done for multi-window/
@@ -105,16 +105,16 @@
      */
     public TabbedModeTabPersistencePolicy(
             String metadataFileName,
-            @Nullable String otherMetadataFileName,
+            @Nullable String otherWindowTag,
             boolean mergeTabsOnStartup,
             boolean tabMergingEnabled) {
         mMetadataFileName = metadataFileName;
         if (mergeTabsOnStartup || tabMergingEnabled) {
-            assert otherMetadataFileName != null
+            assert otherWindowTag != null
                     : "otherMetadataFileName must be non-null if tab merging is enabled.";
-            mOtherMetadataFileName = otherMetadataFileName;
+            mOtherWindowTag = otherWindowTag;
         } else {
-            mOtherMetadataFileName = null;
+            mOtherWindowTag = null;
         }
         mMergeTabsOnStartup = mergeTabsOnStartup;
         mMaxSelectors = TabWindowManager.MAX_SELECTORS;
@@ -134,7 +134,7 @@
             int selectorIndex, boolean mergeTabsOnStartup, boolean tabMergingEnabled) {
         this(
                 getMetadataFileNameForIndex(selectorIndex),
-                getMetadataFileNameForIndex(selectorIndex == 0 ? 1 : 0),
+                Integer.toString(selectorIndex == 0 ? 1 : 0),
                 mergeTabsOnStartup,
                 tabMergingEnabled);
     }
@@ -156,7 +156,13 @@
 
     @Override
     public @Nullable String getMetadataFileNameToBeMerged() {
-        return mOtherMetadataFileName;
+        if (mOtherWindowTag == null) return null;
+        return TabMetadataFileManager.getMetadataFileName(mOtherWindowTag);
+    }
+
+    @Override
+    public @Nullable String getWindowTagToBeMerged() {
+        return mOtherWindowTag;
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index 7e8f803..38652c0b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -1179,8 +1179,15 @@
                         progressBar,
                         mToolbarHairline,
                         mToolbarPositionSupplier,
+                        () ->
+                                mBookmarkBarHeightSupplier != null
+                                                && mBookmarkBarHeightSupplier.get() == 0
+                                        ? 0
+                                        : R.id.bookmark_bar,
                         topControlsStacker,
-                        bottomControlsStacker);
+                        bottomControlsStacker,
+                        ToolbarPositionController.isToolbarPositionCustomizationEnabled(
+                                mActivity, mIsCustomTab));
 
         HomeButtonDisplay homeButtonDisplay =
                 mIsNewTabPageCustomizationToolbarButtonEnabled
@@ -1856,6 +1863,7 @@
     private void initializeToolbarPositionController() {
         if (!ToolbarPositionController.isToolbarPositionCustomizationEnabled(
                 mActivity, mIsCustomTab)) {
+            mToolbarPositionSupplier.set(mBrowserControlsSizer.getControlsPosition());
             return;
         }
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java
index 8443751f..363ff9cb 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperTest.java
@@ -57,7 +57,6 @@
 import android.view.View;
 import android.view.ViewGroup.MarginLayoutParams;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.appcompat.content.res.AppCompatResources;
 import androidx.core.graphics.ColorUtils;
@@ -246,10 +245,9 @@
     private static final String IDENTIFIER_SELECTED = "Selected Tab";
     private static final String INCOGNITO_IDENTIFIER = "Incognito Tab";
     private static final String INCOGNITO_IDENTIFIER_SELECTED = "Selected Incognito Tab";
-    private static final float SCREEN_WIDTH = 800.f;
-    private static final float SCREEN_WIDTH_LANDSCAPE = 1200.f;
-    // TODO(wenyufu): This needs to be renamed to TAB_STRIP_HEIGHT.
-    private static final float SCREEN_HEIGHT = 40.f;
+    private static final float STRIP_WIDTH = 800.f;
+    private static final float STRIP_WIDTH_LANDSCAPE = 1200.f;
+    private static final float STRIP_HEIGHT = 40.f;
     private static final float TAB_WIDTH_1 = 140.f;
     private static final float TAB_WIDTH_SMALL = 108.f;
     private static final float TAB_WIDTH_MEDIUM = 156.f;
@@ -322,7 +320,7 @@
     public void testSimpleTabOrder() {
         initializeTest(false, false, 0);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
 
         assertTabStripAndOrder(getExpectedAccessibilityDescriptions(0));
@@ -339,7 +337,7 @@
     public void testTabOrderWithIndex() {
         initializeTest(false, false, 1);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
 
         // Tabs should be in left to right order regardless of index
@@ -356,7 +354,7 @@
     public void testTabOrderRtl() {
         initializeTest(true, false, 0);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
 
         // Tabs should be in linear order even in RTL.
@@ -374,7 +372,7 @@
     public void testIncognitoAccessibilityDescriptions() {
         initializeTest(false, true, 0);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
 
         assertTabStripAndOrder(getExpectedAccessibilityDescriptions(0));
@@ -559,14 +557,12 @@
     }
 
     @Test
-    // TODO(crbug.com/425740363): Rewrite the test to work with the animation enabled.
-    @DisableFeatures({ChromeFeatureList.TABLET_TAB_STRIP_ANIMATION})
     public void testResizeStripOnTabClose_DoNotAnimateIfNotMoving() {
         final int numTabs = 10;
         initializeTest(false, false, 0, numTabs);
         // Trigger a size change so the strip layout tab heights and widths get set.
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         // Set the initial scroll offset to trigger an update to draw X positions.
         mStripLayoutHelper.setScrollOffsetForTesting(0);
 
@@ -578,15 +574,9 @@
         stripLayoutHelperSpy.handleCloseButtonClick(
                 tabs[closeTabIndex], MotionEventUtils.MOTION_EVENT_BUTTON_NONE);
 
-        final Animator runningAnimator = stripLayoutHelperSpy.getRunningAnimatorForTesting();
-        // Initial animation is the tab removal animation, and after that ends the
-        // resizeStripOnTabClose animations begin.
-        runningAnimator.end();
-
         final ArgumentCaptor<List<Animator>> animationListCaptor =
                 ArgumentCaptor.forClass(List.class);
         final InOrder stripLayoutOrder = inOrder(stripLayoutHelperSpy);
-        stripLayoutOrder.verify(stripLayoutHelperSpy).startAnimations(any(), any());
         stripLayoutOrder
                 .verify(stripLayoutHelperSpy)
                 .startAnimations(animationListCaptor.capture(), any());
@@ -598,15 +588,13 @@
     }
 
     @Test
-    // TODO(crbug.com/425740363): Rewrite the test to work with the animation enabled.
-    @DisableFeatures({ChromeFeatureList.TABLET_TAB_STRIP_ANIMATION})
     public void
             testResizeStripOnTabClose_DoNotAnimateIfNotVisible_OutsideVisibleBounds_ToTheRight() {
         final int numTabs = 50;
         initializeTest(false, false, 0, numTabs);
         // Trigger a size change so the strip layout tab heights and widths get set.
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         // Simplify the visible bounds by removing the right fade.
         mStripLayoutHelper.setRightFadeWidth(0);
         // Set the initial scroll offset to trigger an update to draw X positions.
@@ -625,32 +613,24 @@
         stripLayoutHelperSpy.handleCloseButtonClick(
                 tabs[closeTabIndex], MotionEventUtils.MOTION_EVENT_BUTTON_NONE);
 
-        final Animator runningAnimator = stripLayoutHelperSpy.getRunningAnimatorForTesting();
-        // Initial animation is the tab removal animation, and after that ends the
-        // resizeStripOnTabClose animations begin.
-        runningAnimator.end();
-
         final ArgumentCaptor<List<Animator>> animationListCaptor =
                 ArgumentCaptor.forClass(List.class);
         final InOrder stripLayoutOrder = inOrder(stripLayoutHelperSpy);
-        stripLayoutOrder.verify(stripLayoutHelperSpy).startAnimations(any(), any());
         stripLayoutOrder
                 .verify(stripLayoutHelperSpy)
                 .startAnimations(animationListCaptor.capture(), any());
         final List<Animator> animationList = animationListCaptor.getValue();
-        assertEquals("There should not be an animation", 0, animationList.size());
+        assertEquals("There should 1 animation for the closing tab.", 1, animationList.size());
     }
 
     @Test
-    // TODO(crbug.com/425740363): Rewrite the test to work with the animation enabled.
-    @DisableFeatures({ChromeFeatureList.TABLET_TAB_STRIP_ANIMATION})
     public void
             testResizeStripOnTabClose_DoNotAnimateIfNotVisible_OutsideVisibleBounds_ToTheLeft() {
         final int numTabs = 50;
         initializeTest(false, false, 0, numTabs);
         // Trigger a size change so the strip layout tab heights and widths get set.
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         // Simplify the visible bounds by removing the left fade.
         mStripLayoutHelper.setLeftFadeWidth(0);
         // Set the initial scroll offset to trigger an update to draw X positions.
@@ -670,32 +650,23 @@
         stripLayoutHelperSpy.handleCloseButtonClick(
                 tabs[closeTabIndex], MotionEventUtils.MOTION_EVENT_BUTTON_NONE);
 
-        final Animator runningAnimator = stripLayoutHelperSpy.getRunningAnimatorForTesting();
-        // Initial animation is the tab removal animation, and after that ends the
-        // resizeStripOnTabClose animations begin.
-        runningAnimator.end();
-
         final ArgumentCaptor<List<Animator>> animationListCaptor =
                 ArgumentCaptor.forClass(List.class);
         final InOrder stripLayoutOrder = inOrder(stripLayoutHelperSpy);
-        stripLayoutOrder.verify(stripLayoutHelperSpy).startAnimations(any(), any());
         stripLayoutOrder
                 .verify(stripLayoutHelperSpy)
                 .startAnimations(animationListCaptor.capture(), any());
         final List<Animator> animationList = animationListCaptor.getValue();
-        assertEquals(
-                "There should be 11 animations for the visible tabs.", 11, animationList.size());
+        assertEquals("There should be 1 animations for the closing tab.", 1, animationList.size());
     }
 
     @Test
-    // TODO(crbug.com/425740363): Rewrite the test to work with the animation enabled.
-    @DisableFeatures({ChromeFeatureList.TABLET_TAB_STRIP_ANIMATION})
     public void testResizeStripOnTabClose_AnimateTab_MovingIntoVisibleBounds() {
         final int numTabs = 50;
         initializeTest(false, false, 0, numTabs);
         // Trigger a size change so the strip layout tab heights and widths get set.
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         // Set the initial scroll offset to trigger an update to draw X positions.
         mStripLayoutHelper.setScrollOffsetForTesting(0);
 
@@ -724,15 +695,9 @@
         stripLayoutHelperSpy.handleCloseButtonClick(
                 tabs[closeTabIndex], MotionEventUtils.MOTION_EVENT_BUTTON_NONE);
 
-        final Animator runningAnimator = stripLayoutHelperSpy.getRunningAnimatorForTesting();
-        // Initial animation is the tab removal animation, and after that ends the
-        // resizeStripOnTabClose animations begin.
-        runningAnimator.end();
-
         final ArgumentCaptor<List<Animator>> animationListCaptor =
                 ArgumentCaptor.forClass(List.class);
         final InOrder stripLayoutOrder = inOrder(stripLayoutHelperSpy);
-        stripLayoutOrder.verify(stripLayoutHelperSpy).startAnimations(any(), any());
         stripLayoutOrder
                 .verify(stripLayoutHelperSpy)
                 .startAnimations(animationListCaptor.capture(), any());
@@ -744,88 +709,13 @@
     }
 
     @Test
-    // TODO(crbug.com/425740363): Rewrite the test to work with the animation enabled.
-    @DisableFeatures({ChromeFeatureList.TABLET_TAB_STRIP_ANIMATION})
-    public void testResizeStripOnTabClose_AnimateNtb() {
-        int numTabs = 50;
-        initializeTest(false, false, 0, numTabs);
-        // Trigger a size change so the strip layout tab heights and widths get set.
-        mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
-        // Set the initial scroll offset to trigger an update to draw X positions.
-        mStripLayoutHelper.setScrollOffsetForTesting(0);
-
-        final StripLayoutHelper stripLayoutHelperSpy = spy(mStripLayoutHelper);
-        final StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabsForTesting();
-        stripLayoutHelperSpy.handleCloseButtonClick(
-                tabs[tabs.length - 1], MotionEventUtils.MOTION_EVENT_BUTTON_NONE);
-
-        // Verify the initial NTB offset.
-        assertEquals(
-                mStripLayoutHelper.getNewTabButton().getOffsetX(),
-                mStripLayoutHelper.getUnpinnedTabWidthForTesting() - TAB_OVERLAP_WIDTH_DP,
-                EPSILON);
-
-        final Animator runningAnimator = stripLayoutHelperSpy.getRunningAnimatorForTesting();
-        // Initial animation is the tab removal animation, and after that ends the
-        // resizeStripOnTabClose animations begin.
-        runningAnimator.end();
-
-        final ArgumentCaptor<List<Animator>> animationListCaptor =
-                ArgumentCaptor.forClass(List.class);
-        final InOrder stripLayoutOrder = inOrder(stripLayoutHelperSpy);
-        stripLayoutOrder.verify(stripLayoutHelperSpy).startAnimations(any(), any());
-        stripLayoutOrder
-                .verify(stripLayoutHelperSpy)
-                .startAnimations(animationListCaptor.capture(), any());
-        final List<Animator> animationList = animationListCaptor.getValue();
-        assertEquals(
-                "There should be one animation for the NTB sliding to its new position.",
-                1,
-                animationList.size());
-    }
-
-    @Test
-    @DisableFeatures({ChromeFeatureList.TABLET_TAB_STRIP_ANIMATION})
-    public void testResizeStripOnTabClose_AnimateNtb_OneTab() {
-        initializeTest(
-                /* rtl= */ false, /* incognito= */ false, /* tabIndex= */ 0, /* numTabs= */ 1);
-
-        final StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabsForTesting();
-        mStripLayoutHelper.handleCloseButtonClick(
-                tabs[0], MotionEventUtils.MOTION_EVENT_BUTTON_NONE);
-
-        // Verify the initial NTB offset.
-        assertEquals(
-                mStripLayoutHelper.getNewTabButton().getOffsetX(),
-                mStripLayoutHelper.getUnpinnedTabWidthForTesting() - TAB_OVERLAP_WIDTH_DP,
-                EPSILON);
-
-        final Animator runningAnimator = mStripLayoutHelper.getRunningAnimatorForTesting();
-        // Initial animation is the tab removal animation, and after that ends the
-        // resizeStripOnTabClose animations begin.
-        runningAnimator.end();
-
-        // Verify that the end offset is immediately set, since we skip the animations when closing
-        // the final tab.
-        float expectedOffsetX = 0.f;
-        assertEquals(
-                "The NTB offset should immediately be reset.",
-                expectedOffsetX,
-                mStripLayoutHelper.getNewTabButton().getOffsetX(),
-                EPSILON);
-    }
-
-    @Test
-    // TODO(crbug.com/425740363): Rewrite the test to work with the animation enabled.
-    @DisableFeatures({ChromeFeatureList.TABLET_TAB_STRIP_ANIMATION})
     public void testComputeAndUpdateTabWidth_DontAnimateIfSizeNotChanging() {
         // Create a high number of tabs to ensure they're already at the minimum size
         final int numTabs = 50;
         initializeTest(false, false, 0, numTabs);
         // Trigger a size change so the strip layout tab heights and widths get set.
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         // Set the initial scroll offset to trigger an update to draw X positions.
         mStripLayoutHelper.setScrollOffsetForTesting(0);
 
@@ -845,9 +735,8 @@
         verify(stripLayoutHelperSpy).startAnimations(animationListCaptor.capture(), any());
         final List<Animator> animationList = animationListCaptor.getValue();
         assertEquals(
-                "There should be one animation for the newly created tab width, "
-                        + "plus one more animation for the new tab y offset",
-                2,
+                "There should be one animation for the newly created tab width",
+                1,
                 animationList.size());
     }
 
@@ -1004,7 +893,7 @@
         initializeTest(false, true, 3);
         StripLayoutTab[] tabs = getMockedStripLayoutTabs(TAB_WIDTH_1);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.setStripLayoutTabsForTesting(tabs);
 
         // Non-last tab not overlapping strip fade:
@@ -1030,7 +919,7 @@
         initializeTest(false, true, 3);
         StripLayoutTab[] tabs = getMockedStripLayoutTabs(TAB_WIDTH_1);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.setStripLayoutTabsForTesting(tabs);
 
         // Non-last tab not overlapping strip fade:
@@ -1053,7 +942,7 @@
         initializeTest(false, true, 3);
         StripLayoutTab[] tabs = getMockedStripLayoutTabs(TAB_WIDTH_1);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.setStripLayoutTabsForTesting(tabs);
 
         // Non-last tab overlapping strip fade:
@@ -1076,7 +965,7 @@
         initializeTest(false, true, 4);
         StripLayoutTab[] tabs = getMockedStripLayoutTabs(TAB_WIDTH_1);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.getNewTabButton().setDrawX(NEW_TAB_BTN_X);
         mStripLayoutHelper.setStripLayoutTabsForTesting(tabs);
 
@@ -1100,7 +989,7 @@
         initializeTest(false, true, 4);
         StripLayoutTab[] tabs = getMockedStripLayoutTabs(TAB_WIDTH_1);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.getNewTabButton().setDrawX(NEW_TAB_BTN_X);
         mStripLayoutHelper.setStripLayoutTabsForTesting(tabs);
 
@@ -1124,7 +1013,7 @@
         initializeTest(false, false, 3);
         StripLayoutTab[] tabs = getMockedStripLayoutTabs(TAB_WIDTH_1);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.setStripLayoutTabsForTesting(tabs);
 
         // Non-last tab overlapping strip fade:
@@ -1148,7 +1037,7 @@
         initializeTest(false, false, 3);
         StripLayoutTab[] tabs = getMockedStripLayoutTabs(TAB_WIDTH_1);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.setStripLayoutTabsForTesting(tabs);
 
         // Non-last tab not overlapping strip fade:
@@ -1172,7 +1061,7 @@
         initializeTest(true, false, 4);
         StripLayoutTab[] tabs = getMockedStripLayoutTabs(TAB_WIDTH_1);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.getNewTabButton().setDrawX(NEW_TAB_BTN_X_RTL);
         mStripLayoutHelper.setStripLayoutTabsForTesting(tabs);
 
@@ -1196,7 +1085,7 @@
         initializeTest(true, false, 4);
         StripLayoutTab[] tabs = getMockedStripLayoutTabs(TAB_WIDTH_1);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.getNewTabButton().setDrawX(NEW_TAB_BTN_X_RTL);
         mStripLayoutHelper.setStripLayoutTabsForTesting(tabs);
 
@@ -1220,7 +1109,7 @@
         initializeTest(true, false, 3);
         StripLayoutTab[] tabs = getMockedStripLayoutTabs(TAB_WIDTH_1);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.setStripLayoutTabsForTesting(tabs);
 
         // Non-last tab overlapping strip fade:
@@ -1243,7 +1132,7 @@
         initializeTest(true, false, 3);
         StripLayoutTab[] tabs = getMockedStripLayoutTabs(TAB_WIDTH_1);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.getNewTabButton().setDrawX(NEW_TAB_BTN_X);
         mStripLayoutHelper.setStripLayoutTabsForTesting(tabs);
 
@@ -1341,7 +1230,7 @@
         int tabCount = 4;
         initializeTest(false, false, 3, tabCount);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
 
         // Set New tab button position.
         mStripLayoutHelper.updateLayout(TIMESTAMP);
@@ -1360,7 +1249,7 @@
         int tabCount = 1;
         initializeTest(false, false, 0, tabCount);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
 
         // Verify new tab button position.
@@ -1373,7 +1262,7 @@
         // rightBound(247) = tabWidth(237) + tabOverLapWidth(28) + offsetXLeft(10)
         assertEquals(
                 "TouchableRect does not match. Right size should match last tab's right edge.",
-                new RectF(PADDING_LEFT, 0, 275.f, SCREEN_HEIGHT),
+                new RectF(PADDING_LEFT, 0, 275.f, STRIP_HEIGHT),
                 mStripLayoutHelper.getTouchableRect());
     }
 
@@ -1383,7 +1272,7 @@
         int tabCount = 5;
         initializeTest(false, false, 0, tabCount);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
 
         // Verify new tab button position.
@@ -1395,7 +1284,7 @@
                 EPSILON);
         assertEquals(
                 "TouchableRect does not match. Strip is full, touch size should match the strip.",
-                new RectF(PADDING_LEFT, 0, SCREEN_WIDTH - PADDING_RIGHT, SCREEN_HEIGHT),
+                new RectF(PADDING_LEFT, 0, STRIP_WIDTH - PADDING_RIGHT, STRIP_HEIGHT),
                 mStripLayoutHelper.getTouchableRect());
     }
 
@@ -1404,7 +1293,7 @@
         int tabCount = 1;
         initializeTest(true, false, 0, tabCount);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
 
         // Verify new tab button position.
@@ -1419,7 +1308,7 @@
         // touchableLeftBound(515) = visualLeftBound(543) - TAB_OVERLAP_WIDTH_DP(28)
         assertEquals(
                 "TouchableRect does not match. Left side should be extended by tab overlap.",
-                new RectF(515.f, 0, SCREEN_WIDTH - PADDING_RIGHT, SCREEN_HEIGHT),
+                new RectF(515.f, 0, STRIP_WIDTH - PADDING_RIGHT, STRIP_HEIGHT),
                 mStripLayoutHelper.getTouchableRect());
     }
 
@@ -1429,7 +1318,7 @@
         int tabCount = 5;
         initializeTest(true, false, 0, tabCount);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
 
         // Verify new tab button position.
@@ -1441,7 +1330,7 @@
                 EPSILON);
         assertEquals(
                 "TouchableRect does not match. Strip is full, touch size should match the strip.",
-                new RectF(PADDING_LEFT, 0, SCREEN_WIDTH - PADDING_RIGHT, SCREEN_HEIGHT),
+                new RectF(PADDING_LEFT, 0, STRIP_WIDTH - PADDING_RIGHT, STRIP_HEIGHT),
                 mStripLayoutHelper.getTouchableRect());
     }
 
@@ -1450,7 +1339,7 @@
         int tabCount = 1;
         initializeTest(false, false, 0, tabCount);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
 
         assertEquals(
@@ -1468,7 +1357,7 @@
         // Setup
         initializeTest(false, false, 0, 1);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
 
         // Verify new tab button hover highlight resource id.
@@ -1534,7 +1423,7 @@
         // Setup
         initializeTest(false, false, 0, 1);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
 
         // Verify new tab button is hovered.
@@ -1726,7 +1615,7 @@
 
         // Set screen width to 800dp and scroll selected tab to view.
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
         mStripLayoutHelper.scrollTabToView(TIMESTAMP, false);
         // Complete animations
@@ -1738,7 +1627,7 @@
         // expectedOffset = scrollOffsetBefore + optimalEndDelta
         float expectedOffset =
                 scrollOffsetBefore
-                        + SCREEN_WIDTH
+                        + STRIP_WIDTH
                         - 60
                         - StripLayoutHelperManager.FADE_LONG_WIDTH_DP
                         - selectedTab.getIdealX()
@@ -1756,7 +1645,7 @@
 
         // Set screen width to 800dp and scroll selected tab to view.
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
         mStripLayoutHelper.scrollTabToView(TIMESTAMP, false);
         // Complete scroll to update offset.
@@ -1768,7 +1657,7 @@
         // expectedOffset = scrollOffsetBefore + optimalEndDelta
         float expectedOffset =
                 scrollOffsetBefore
-                        + SCREEN_WIDTH
+                        + STRIP_WIDTH
                         - 60
                         - StripLayoutHelperManager.FADE_MEDIUM_WIDTH_DP
                         - selectedTab.getIdealX()
@@ -1783,7 +1672,7 @@
 
         // Set screen width to 800dp and scroll selected tab to view.
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.scrollTabToView(TIMESTAMP, false);
 
         // optimalStart = leftFade(60) + leftPadding(10) - (index(0) * tabWidth(108-28))
@@ -1802,8 +1691,8 @@
 
         // Set screen width to 1200 to start.
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH_LANDSCAPE,
-                SCREEN_HEIGHT,
+                STRIP_WIDTH_LANDSCAPE,
+                STRIP_HEIGHT,
                 false,
                 TIMESTAMP,
                 PADDING_LEFT,
@@ -1819,13 +1708,13 @@
         when(tabs[9].getDrawX()).thenReturn(720.f);
         when(tabs[9].getIdealX()).thenReturn(720.f);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, true, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, true, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
 
         // Assert: finalX value after orientation change.
         // stripWidth(800) - rightPadding(60) - rightFade(72) - selectedTab.idealX -
         // mCachedTabWidth(108)
         float expectedFinalX =
-                SCREEN_WIDTH
+                STRIP_WIDTH
                         - 60
                         - StripLayoutHelperManager.FADE_MEDIUM_WIDTH_DP
                         - selectedTab.getIdealX()
@@ -1844,8 +1733,8 @@
 
         // Set screen width to 1200 to start
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH_LANDSCAPE,
-                SCREEN_HEIGHT,
+                STRIP_WIDTH_LANDSCAPE,
+                STRIP_HEIGHT,
                 false,
                 TIMESTAMP,
                 PADDING_LEFT,
@@ -1859,7 +1748,7 @@
         // Act: change orientation.
         when(tabs[9].getDrawX()).thenReturn(-1.f);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, true, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, true, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
 
         // Assert: finalX value remains the same on orientation change.
         assertEquals(initialFinalX, mStripLayoutHelper.getScrollerForTesting().getFinalX());
@@ -1904,7 +1793,7 @@
 
         // Set screen width to 800dp and scroll selected tab to view.
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         StripLayoutTab tabToFocus = mStripLayoutHelper.getStripLayoutTabsForTesting()[0];
 
         // Set keyboard focus state of the last tab, as if we focus looped around.
@@ -1940,9 +1829,9 @@
         StripLayoutTab[] tabs = getMockedStripLayoutTabs(TAB_WIDTH_MEDIUM);
         mStripLayoutHelper.setStripLayoutTabsForTesting(tabs);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         // Set initial scroller position to 1200.
-        mStripLayoutHelper.getScrollerForTesting().setFinalX((int) SCREEN_WIDTH_LANDSCAPE);
+        mStripLayoutHelper.getScrollerForTesting().setFinalX((int) STRIP_WIDTH_LANDSCAPE);
 
         // Act: Tab was restored after undoing a tab closure.
         boolean closureCancelled = true;
@@ -1968,9 +1857,9 @@
         StripLayoutTab[] tabs = getMockedStripLayoutTabs(TAB_WIDTH_MEDIUM);
         mStripLayoutHelper.setStripLayoutTabsForTesting(tabs);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         // Set initial scroller position to 1200.
-        mStripLayoutHelper.getScrollerForTesting().setFinalX((int) SCREEN_WIDTH_LANDSCAPE);
+        mStripLayoutHelper.getScrollerForTesting().setFinalX((int) STRIP_WIDTH_LANDSCAPE);
 
         // Act: Tab was not restored after undoing a tab closure.
         boolean closureCancelled = false;
@@ -1999,7 +1888,7 @@
         int selectedTabIndex = 1;
         initializeTest(isRtl, false, selectedTabIndex, 11);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
 
         // Set initial scroller position to -500 under ScrollDelegate's dynamic coordinate system
         // (not the static window coordinate system), which means:
@@ -2035,7 +1924,7 @@
             // The setup moved the selected tab beyond the window's right edge. To make the tab
             // visible, we should scroll the tab strip to the left, i.e., "scrollDelta" below should
             // be negative.
-            float expectedTabX = SCREEN_WIDTH - reservedWidthRight - selectedTab.getWidth();
+            float expectedTabX = STRIP_WIDTH - reservedWidthRight - selectedTab.getWidth();
             float scrollDelta = expectedTabX - selectedTab.getIdealX();
             expectedScrollOffset = scrollOffsetBefore + scrollDelta;
         } else {
@@ -2302,8 +2191,8 @@
         var tabs = initializeTest_ForTab();
         setupForIndividualTabContextMenu();
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH,
-                SCREEN_HEIGHT,
+                STRIP_WIDTH,
+                STRIP_HEIGHT,
                 false,
                 TIMESTAMP,
                 PADDING_LEFT,
@@ -2474,7 +2363,7 @@
         mStripLayoutHelper.setStripLayoutTabsForTesting(tabs);
         // NTB is after group indicator and tabs.
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.getNewTabButton().setDrawX(TAB_WIDTH_1 + tabs.length * TAB_WIDTH_1);
         setupForGroupContextMenu();
 
@@ -2660,14 +2549,14 @@
         // Initialize.
         initializeTest(false, false, 0);
         // Set internal state for height, width and paddings.
-        mStripLayoutHelper.onSizeChanged(SCREEN_WIDTH, SCREEN_HEIGHT, false, 0, 0, 0, 0);
+        mStripLayoutHelper.onSizeChanged(STRIP_WIDTH, STRIP_HEIGHT, false, 0, 0, 0, 0);
         StripLayoutTab[] tabs = getMockedStripLayoutTabs(150f);
         mStripLayoutHelper.setStripLayoutTabsForTesting(tabs);
         mStripLayoutHelper.setTabStripContextMenuCoordinatorForTesting(
                 mTabStripContextMenuCoordinator);
 
         // Long press past the last tab.
-        int x = (int) SCREEN_WIDTH - 10;
+        int x = (int) STRIP_WIDTH - 10;
         int y = 0;
         mStripLayoutHelper.setTabAtPositionForTesting(null);
         mStripLayoutHelper.onLongPress(x, y);
@@ -2693,14 +2582,14 @@
         // Initialize.
         initializeTest(false, false, 0);
         // Set internal state for height, width and paddings.
-        mStripLayoutHelper.onSizeChanged(SCREEN_WIDTH, SCREEN_HEIGHT, false, 0, 0, 0, 0);
+        mStripLayoutHelper.onSizeChanged(STRIP_WIDTH, STRIP_HEIGHT, false, 0, 0, 0, 0);
         StripLayoutTab[] tabs = getMockedStripLayoutTabs(150f);
         mStripLayoutHelper.setStripLayoutTabsForTesting(tabs);
         mStripLayoutHelper.setTabStripContextMenuCoordinatorForTesting(
                 mTabStripContextMenuCoordinator);
 
         // Right-click on the empty strip space.
-        int x = (int) SCREEN_WIDTH - 10;
+        int x = (int) STRIP_WIDTH - 10;
         int y = 0;
         mStripLayoutHelper.click(0, x, y, MotionEvent.BUTTON_SECONDARY, 0);
 
@@ -2765,8 +2654,6 @@
     }
 
     @Test
-    // TODO(crbug.com/425740363): Rewrite the test to work with the animation enabled.
-    @DisableFeatures(ChromeFeatureList.TABLET_TAB_STRIP_ANIMATION)
     public void testBottomIndicatorWidthAfterTabResize_UngroupedTabClosed() {
         // Arrange
         int tabCount = 6;
@@ -2781,7 +2668,7 @@
 
         // Update layout and set up animation.
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         setupForAnimations();
         mStripLayoutHelper.updateLayout(TIMESTAMP);
 
@@ -2799,23 +2686,10 @@
         mStripLayoutHelper.handleCloseButtonClick(
                 tabs[2], MotionEventUtils.MOTION_EVENT_BUTTON_NONE);
 
-        // Assert: Animations started.
-        assertTrue(
-                "MultiStepAnimations should have started.",
-                mStripLayoutHelper.isMultiStepCloseAnimationsRunningForTesting());
-
-        // Assert: Animations are still running.
-        assertTrue(
-                "MultiStepAnimations should still be running.",
-                mStripLayoutHelper.isMultiStepCloseAnimationsRunningForTesting());
-
-        // Act: End the animations to apply final values.
-        mStripLayoutHelper.finishAnimations();
-
         // Act: Fake the tab closure and end the animation, so the tab is removed from the model.
         Tab closingTab = mModel.getTabAt(2);
-        mStripLayoutHelper.tabClosed(closingTab);
         mStripLayoutHelper.finishAnimations();
+        mStripLayoutHelper.tabClosed(closingTab);
 
         // availableSize = width(800) - NTB(32) - endPadding(8) - offsetXLeft(10) - offsetXRight(20)
         // - groupTitleWidth(46) - titleOverlapWidth(4) = 680.
@@ -2830,9 +2704,6 @@
                     stripTab.getWidth(),
                     0.1f);
         }
-        assertFalse(
-                "MultiStepAnimations should have ended.",
-                mStripLayoutHelper.isMultiStepCloseAnimationsRunningForTesting());
 
         // Check bottom indicator end width.
         float expectedEndWidth =
@@ -2858,7 +2729,7 @@
         StripLayoutGroupTitle groupTitle = ((StripLayoutGroupTitle) views[0]);
 
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
 
         // Check initial bottom indicator width.
         float expectedStartWidth =
@@ -2905,7 +2776,7 @@
         // Mock 5 tabs, group first 3 tabs as group1 and group the rest as group2.
         initializeTest(false, false, 0, 5);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabsForTesting();
         groupTabs(0, 3, TAB_GROUP_ID_1);
         groupTabs(3, 5, TAB_GROUP_ID_2);
@@ -3440,7 +3311,7 @@
         // Mock 5 tabs. Group tab from start to endIndex.
         initializeTest(false, false, 0, 5);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         groupTabs(groupStartIndex, groupEndIndex, tabGroupId);
         mStripLayoutHelper.setTabModel(mModel, mTabCreator, false);
 
@@ -3693,7 +3564,7 @@
         initializeTest(false, false, 3, 5);
         verify(mDataSharingService).addObserver(mSharingObserverCaptor.capture());
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         if (multipleCollaborators) {
             mSharedGroupTestHelper.mockGetGroupData(
                     COLLABORATION_ID1, GROUP_MEMBER1, GROUP_MEMBER2);
@@ -3810,7 +3681,7 @@
         setupForAnimations();
         initializeTest(false, false, 0, tabCount);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
 
         // Remove tab from model and verify that the tab strip has not yet updated.
         int closedTabId = 1;
@@ -3882,8 +3753,8 @@
         initializeTest(/* rtl= */ false, /* incognito= */ false, selectedTabIndex, tabCount);
         StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabsForTesting();
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH,
-                SCREEN_HEIGHT,
+                STRIP_WIDTH,
+                STRIP_HEIGHT,
                 /* orientationChanged= */ false,
                 TIMESTAMP,
                 PADDING_LEFT,
@@ -3905,121 +3776,55 @@
     }
 
     @Test
-    @DisableFeatures({ChromeFeatureList.TABLET_TAB_STRIP_ANIMATION})
-    public void testTabClosing_NoTabResize() {
-        // Arrange
-        int tabCount = 15;
-        initializeTest(false, false, 14, tabCount);
-        StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabsForTesting();
-        mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
-        setupForAnimations();
-
-        mStripLayoutHelper.updateLayout(TIMESTAMP);
-
-        // Act: Call on close tab button handler.
-        mStripLayoutHelper.handleCloseButtonClick(
-                tabs[14], MotionEventUtils.MOTION_EVENT_BUTTON_NONE);
-
-        // Assert: Animations started.
-        assertTrue(
-                "MultiStepAnimations should have started.",
-                mStripLayoutHelper.isMultiStepCloseAnimationsRunningForTesting());
-
-        // Act: Only end the first animation, so the multi-step animations are still running.
-        Tab closingTab = mModel.getTabAt(14);
-        mStripLayoutHelper.getRunningAnimatorForTesting().end();
-        mStripLayoutHelper.tabClosed(closingTab);
-
-        // Assert: Tab is closed and animations are still running.
-        int expectedTabCount = 14;
-        assertEquals(
-                "Unexpected tabs count",
-                expectedTabCount,
-                mStripLayoutHelper.getStripLayoutTabsForTesting().length);
-        assertTrue(
-                "MultiStepAnimations should still be running.",
-                mStripLayoutHelper.isMultiStepCloseAnimationsRunningForTesting());
-
-        // Act: End next set of animations to apply final values.
-        mStripLayoutHelper.finishAnimations();
-
-        // Assert: Animations completed. The tab width is not resized and drawX does not change.
-        // stripRightBound = width(800) - offsetXRight(20) = 780;
-        // visibleTabRightBound = rightBound(780)- NTBWidth(32) - endPadding(8) = 740
-        // lastTabDrawX = visibleTabRightBound(740) - tabWidth(108) = 632
-        float expectedDrawX = 632.f;
-        StripLayoutTab[] updatedTabs = mStripLayoutHelper.getStripLayoutTabsForTesting();
-        for (int i = updatedTabs.length - 1; i >= 0; i--) {
-            StripLayoutTab stripTab = updatedTabs[i];
-            assertEquals("Unexpected tab width after resize.", 108.f, stripTab.getWidth(), 0);
-            assertEquals("Unexpected tab position.", expectedDrawX, stripTab.getDrawX(), 0);
-            expectedDrawX -= TAB_WIDTH_SMALL - TAB_OVERLAP_WIDTH_DP;
-        }
-        assertFalse(
-                "MultiStepAnimations should have stopped running.",
-                mStripLayoutHelper.isMultiStepCloseAnimationsRunningForTesting());
+    public void testTabClosing_UpdateDrawProperties_NoTabResize() {
+        float expectedDrawX = 10.f; // offsetXLeft(10)
+        doTestTabClosingUpdateDrawProperties(
+                /* tabCount= */ 15, /* closingIndex= */ 14, expectedDrawX, TAB_WIDTH_SMALL);
     }
 
     @Test
-    // TODO(crbug.com/425740363): Rewrite the test to work with the animation enabled.
-    @DisableFeatures({ChromeFeatureList.TABLET_TAB_STRIP_ANIMATION})
-    public void testTabClosing_NonLastTab_TabResize() {
+    public void testTabClosing_UpdateDrawProperties_TabResize() {
+        float expectedDrawX = 10.f; // offsetXLeft(10)
+        // availableSize = width(800) - NTB(32) - endPadding(8) - offsetXLeft(10) - offsetXRight(20)
+        // = 730
+        // expectedWidth = (availableSize(730) + 2 * overlap(28)) / 3  = 262
+        float expectedWidth = 262.f;
+        doTestTabClosingUpdateDrawProperties(
+                /* tabCount= */ 4, /* closingIndex= */ 2, expectedDrawX, expectedWidth);
+    }
+
+    private void doTestTabClosingUpdateDrawProperties(
+            int tabCount, int closingIndex, float expectedDrawX, float expectedWidth) {
         // Arrange
-        int tabCount = 4;
         initializeTest(false, false, 3, tabCount);
         StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabsForTesting();
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         setupForAnimations();
 
         mStripLayoutHelper.updateLayout(TIMESTAMP);
 
         // Act: Call on close tab button handler.
         mStripLayoutHelper.handleCloseButtonClick(
-                tabs[2], MotionEventUtils.MOTION_EVENT_BUTTON_NONE);
+                tabs[closingIndex], MotionEventUtils.MOTION_EVENT_BUTTON_NONE);
 
-        // Assert: Animations started.
-        assertTrue(
-                "MultiStepAnimations should have started.",
-                mStripLayoutHelper.isMultiStepCloseAnimationsRunningForTesting());
-
-        // Act: Only end the first animation, so the multi-step animations are still running.
-        Tab closingTab = mModel.getTabAt(2);
+        // Act: Finish the close animations.
+        Tab closingTab = mModel.getTabAt(closingIndex);
         mStripLayoutHelper.getRunningAnimatorForTesting().end();
         mStripLayoutHelper.tabClosed(closingTab);
 
-        // Assert: Tab is closed and animations are still running.
-        int expectedTabCount = 3;
+        // Assert: Tab is closed.
+        int expectedTabCount = tabCount - 1;
         assertEquals(expectedTabCount, mStripLayoutHelper.getStripLayoutTabsForTesting().length);
-        assertTrue(
-                "MultiStepAnimations should still be running.",
-                mStripLayoutHelper.isMultiStepCloseAnimationsRunningForTesting());
 
-        // Act: Finish the remaining animations.
-        mStripLayoutHelper.finishAnimations();
-
-        // Assert: Animations completed. The tab width is resized, tab.drawX is changed and
-        // newTabButton.drawX is also changed.
-        float expectedDrawX = 10.f; // offsetXLeft(10)
-        // availableSize = width(800) - NTB(32) - endPadding(8) - offsetXLeft(10) - offsetXRight(20)
-        // = 730
-        // ExpectedWidth = (availableSize(730) + 2 * overlap(28)) / 3  = 262
-        float expectedWidthAfterResize = 262.f;
+        // Assert: Animations completed. The tab width and drawX may have changed.
         StripLayoutTab[] updatedTabs = mStripLayoutHelper.getStripLayoutTabsForTesting();
         for (int i = 0; i < updatedTabs.length; i++) {
             StripLayoutTab stripTab = updatedTabs[i];
-            assertEquals(
-                    "Unexpected tab width after resize.",
-                    expectedWidthAfterResize,
-                    stripTab.getWidth(),
-                    0.1f);
-            assertEquals("Unexpected tab position.", expectedDrawX, stripTab.getDrawX(), 0.1f);
-            expectedDrawX += (expectedWidthAfterResize - TAB_OVERLAP_WIDTH_DP);
+            assertEquals("Unexpected tab width.", expectedWidth, stripTab.getWidth(), EPSILON);
+            assertEquals("Unexpected tab position.", expectedDrawX, stripTab.getDrawX(), EPSILON);
+            expectedDrawX += (expectedWidth - TAB_OVERLAP_WIDTH_DP);
         }
-        assertFalse(
-                "MultiStepAnimations should have ended.",
-                mStripLayoutHelper.isMultiStepCloseAnimationsRunningForTesting());
     }
 
     @Test
@@ -4079,12 +3884,11 @@
     public void testPendingMouseTabClosure_SuppressResize() {
         // Initialize and mark a pending a mouse tab closure.
         initializeTest(/* tabIndex= */ 0);
-        mStripLayoutHelper.onSizeChanged(SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, 0, 0, 0);
+        mStripLayoutHelper.onSizeChanged(STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, 0, 0, 0);
         mStripLayoutHelper.setPendingMouseTabClosureForTesting(true);
 
         // Attempt a resize.
-        mStripLayoutHelper.resizeTabStrip(
-                /* animate= */ true, /* tabToAnimate= */ null, /* tabAddedAnimation= */ false);
+        mStripLayoutHelper.resizeTabStrip(/* tabToAnimate= */ null, /* tabAddedAnimation= */ false);
 
         // Verify resize was suppressed.
         verifyPendingMouseTabClosure(/* expectedPendingMouseTabClosure= */ true);
@@ -4097,7 +3901,7 @@
     public void testPendingMouseTabClosure_ResizeOnHoverExit_InTabStrip() {
         // Initialize and mark a pending a mouse tab closure.
         initializeTest(/* tabIndex= */ 0);
-        mStripLayoutHelper.onSizeChanged(SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, 0, 0, 0);
+        mStripLayoutHelper.onSizeChanged(STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, 0, 0, 0);
         mStripLayoutHelper.setPendingMouseTabClosureForTesting(true);
 
         // Notify a hover exit event occurred in the tab strip.
@@ -4114,7 +3918,7 @@
     public void testPendingMouseTabClosure_ResizeOnHoverExit_NotInTabStrip() {
         // Initialize and mark a pending a mouse tab closure.
         initializeTest(/* tabIndex= */ 0);
-        mStripLayoutHelper.onSizeChanged(SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, 0, 0, 0);
+        mStripLayoutHelper.onSizeChanged(STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, 0, 0, 0);
         mStripLayoutHelper.setPendingMouseTabClosureForTesting(true);
 
         // Notify a hover exit event occurred outside the tab strip.
@@ -4217,7 +4021,7 @@
         initializeTest(false, false, 11, 12);
         // Disable the padding as changing the visible width change the existing expected fling
         // distance.
-        mStripLayoutHelper.onSizeChanged(SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, 0, 0, 0);
+        mStripLayoutHelper.onSizeChanged(STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, 0, 0, 0);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
         mStripLayoutHelper.setScrollOffsetForTesting(-150);
 
@@ -4247,7 +4051,7 @@
         initializeTest(false, false, 10, 11);
         // Disable the padding as changing the visible width change the existing expected fling
         // distance.
-        mStripLayoutHelper.onSizeChanged(SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, 0, 0, 0);
+        mStripLayoutHelper.onSizeChanged(STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, 0, 0, 0);
         // When updateLayout is called for the first time, bringSelectedTabToVisibleArea() method is
         // invoked. That also affects the scrollOffset value. So we call updateLayout before
         // performing a fling so that bringSelectedTabToVisible area isn't called after the fling.
@@ -4284,7 +4088,7 @@
         when(mTabGroupContextMenuCoordinator.isMenuShowing()).thenReturn(true);
         // Disable the padding as changing the visible width change the existing expected fling
         // distance.
-        mStripLayoutHelper.onSizeChanged(SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, 0, 0, 0);
+        mStripLayoutHelper.onSizeChanged(STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, 0, 0, 0);
         // When updateLayout is called for the first time, bringSelectedTabToVisibleArea() method is
         // invoked. That also affects the scrollOffset value. So we call updateLayout before
         // performing a fling so that bringSelectedTabToVisible area isn't called after the fling.
@@ -4315,7 +4119,7 @@
         // Arrange
         initializeTest(false, false, 13, 14);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         // When updateLayout is called for the first time, bringSelectedTabToVisibleArea() method is
         // invoked. That also affects the scrollOffset value. So we call updateLayout before
         // performing a fling so that bringSelectedTabToVisible area isn't called after the fling.
@@ -4549,7 +4353,7 @@
 
         // Set size.
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         assertNotEquals(
                 "Offset should have changed.", 0, mStripLayoutHelper.getScrollOffset(), EPSILON);
     }
@@ -4849,7 +4653,7 @@
         StripLayoutTab draggedTab = tabs[1];
         mStripLayoutHelper.startDragAndDropTabForTesting(draggedTab, DRAG_START_POINT);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
 
         // Drag tab out of strip.
         mStripLayoutHelper.setTabAtPositionForTesting(draggedTab);
@@ -4874,8 +4678,8 @@
         // Setup with 3 tabs.
         initializeTest(false, false, 1, 3);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH_LANDSCAPE,
-                SCREEN_HEIGHT,
+                STRIP_WIDTH_LANDSCAPE,
+                STRIP_HEIGHT,
                 false,
                 TIMESTAMP,
                 PADDING_LEFT,
@@ -4900,8 +4704,8 @@
         // Setup with 3 tabs.
         initializeTest(false, false, 1, 3);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH_LANDSCAPE,
-                SCREEN_HEIGHT,
+                STRIP_WIDTH_LANDSCAPE,
+                STRIP_HEIGHT,
                 false,
                 TIMESTAMP,
                 PADDING_LEFT,
@@ -4931,8 +4735,8 @@
         // Setup with 3 tabs.
         initializeTest(false, false, 1, 3);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH_LANDSCAPE,
-                SCREEN_HEIGHT,
+                STRIP_WIDTH_LANDSCAPE,
+                STRIP_HEIGHT,
                 false,
                 TIMESTAMP,
                 PADDING_LEFT,
@@ -4960,8 +4764,8 @@
         // Setup with 3 tabs.
         initializeTest(false, false, 1, 3);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH_LANDSCAPE,
-                SCREEN_HEIGHT,
+                STRIP_WIDTH_LANDSCAPE,
+                STRIP_HEIGHT,
                 false,
                 TIMESTAMP,
                 PADDING_LEFT,
@@ -4984,8 +4788,8 @@
         // Setup with 3 tabs.
         initializeTest(false, false, 1, 3);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH_LANDSCAPE,
-                SCREEN_HEIGHT,
+                STRIP_WIDTH_LANDSCAPE,
+                STRIP_HEIGHT,
                 false,
                 TIMESTAMP,
                 PADDING_LEFT,
@@ -5023,8 +4827,8 @@
         collapsedTab2.setWidth(TAB_OVERLAP_WIDTH_DP);
 
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH_LANDSCAPE,
-                SCREEN_HEIGHT,
+                STRIP_WIDTH_LANDSCAPE,
+                STRIP_HEIGHT,
                 false,
                 TIMESTAMP,
                 PADDING_LEFT,
@@ -5062,8 +4866,8 @@
         collapsedTab2.setWidth(TAB_OVERLAP_WIDTH_DP);
 
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH_LANDSCAPE,
-                SCREEN_HEIGHT,
+                STRIP_WIDTH_LANDSCAPE,
+                STRIP_HEIGHT,
                 false,
                 TIMESTAMP,
                 PADDING_LEFT,
@@ -5088,8 +4892,8 @@
         setupDragDropState();
         initializeTest(false, false, 1, 3);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH_LANDSCAPE,
-                SCREEN_HEIGHT,
+                STRIP_WIDTH_LANDSCAPE,
+                STRIP_HEIGHT,
                 false,
                 TIMESTAMP,
                 PADDING_LEFT,
@@ -5117,8 +4921,8 @@
         // Setup with 3 tabs.
         initializeTest(false, false, 1, 3);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH_LANDSCAPE,
-                SCREEN_HEIGHT,
+                STRIP_WIDTH_LANDSCAPE,
+                STRIP_HEIGHT,
                 false,
                 TIMESTAMP,
                 PADDING_LEFT,
@@ -5142,8 +4946,8 @@
         setupDragDropState();
         initializeTest(false, false, 1, 5);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH_LANDSCAPE,
-                SCREEN_HEIGHT,
+                STRIP_WIDTH_LANDSCAPE,
+                STRIP_HEIGHT,
                 false,
                 TIMESTAMP,
                 PADDING_LEFT,
@@ -5172,7 +4976,7 @@
 
         assertEquals(
                 "TouchableRect does not match. Touch size should match the strip during drag.",
-                new RectF(PADDING_LEFT, 0, SCREEN_WIDTH_LANDSCAPE - PADDING_RIGHT, SCREEN_HEIGHT),
+                new RectF(PADDING_LEFT, 0, STRIP_WIDTH_LANDSCAPE - PADDING_RIGHT, STRIP_HEIGHT),
                 mStripLayoutHelper.getTouchableRect());
     }
 
@@ -5182,7 +4986,7 @@
         boolean isIncognito = false;
         initializeTest(false, isIncognito, 1, 3);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
 
         // Prepare and verify no interaction.
         mStripLayoutHelper.handleDragEnter(0.f, 0.f, false, !isIncognito);
@@ -5212,7 +5016,7 @@
         // Initialize with 10 tabs. Group tabs 2 through 3. Group tabs 5 through 8.
         initializeTest(false, false, 0, 10);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         groupTabs(1, 3, TAB_GROUP_ID_1);
         groupTabs(4, 8, TAB_GROUP_ID_2);
 
@@ -5297,7 +5101,7 @@
                 HistogramWatcher.newSingleRecordWatcher("Android.TabStrip.TabGroupCollapsed", true);
         initializeTest(false, false, 3, 4);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         groupTabs(0, 3, TAB_GROUP_ID_1);
 
         // Fake a click on the group indicator.
@@ -5320,7 +5124,7 @@
                         "Android.TabStrip.TabGroupCollapsed", false);
         initializeTest(false, false, 3, 4);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         groupTabs(0, 3, TAB_GROUP_ID_1);
 
         // Mark the group as collapsed. Fake a click on the group indicator.
@@ -5343,7 +5147,7 @@
         initializeTest(false, false, 0, 4);
         // Update layout to set view draw properties
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
         // Group all tabs
         groupTabs(0, 3, TAB_GROUP_ID_1);
@@ -5392,7 +5196,7 @@
         // Initialize with 4 tabs. Group first three tabs.
         initializeTest(false, false, 3, 4);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         groupTabs(0, 3, TAB_GROUP_ID_1);
 
         // Verify initial dimensions.
@@ -5423,7 +5227,7 @@
         // Initialize with 4 tabs. Group first three tabs.
         initializeTest(false, false, 3, 4);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         groupTabs(0, 3, TAB_GROUP_ID_1);
 
         // Collapse the group.
@@ -5457,7 +5261,7 @@
         // Initialize with 5 tabs. Group last two tabs.
         initializeTest(false, false, 3, 5);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         groupTabs(3, 5, TAB_GROUP_ID_1);
 
         // Assert: the 4th tab is selected.
@@ -5481,7 +5285,7 @@
         // Initialize with 5 tabs. Group first three tabs.
         initializeTest(false, false, 1, 5);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         groupTabs(0, 3, TAB_GROUP_ID_1);
 
         // Assert: the 2nd tab is selected.
@@ -5505,7 +5309,7 @@
         // Initialize with 5 tabs. Group last two tabs.
         initializeTest(false, false, 3, 5);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         groupTabs(3, 5, TAB_GROUP_ID_1);
 
         // Assert: the 4th tab is selected.
@@ -5529,7 +5333,7 @@
         // Initialize with 5 tabs. Group all five tabs.
         initializeTest(false, false, 3, 5);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         groupTabs(0, 5, TAB_GROUP_ID_1);
 
         // Assert: the 4th tab is selected.
@@ -5751,7 +5555,7 @@
 
         // Change orientation.
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_HEIGHT, SCREEN_WIDTH, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_HEIGHT, STRIP_WIDTH, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
 
         // Verify iph text bubble is dismissed on screen size change.
         verify(mController, times(2)).dismissTextBubble();
@@ -5762,7 +5566,7 @@
         DeviceInfo.setIsXrForTesting(true);
         initializeTest(false, false, 0, 1);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
 
         // Create a new tab.
         mModel.addTab("new tab");
@@ -5797,7 +5601,7 @@
                         false,
                         hoveredTab.getDrawX(),
                         hoveredTab.getWidth(),
-                        SCREEN_HEIGHT,
+                        STRIP_HEIGHT,
                         0f);
         assertEquals(
                 "Tab container opacity is incorrect.",
@@ -5813,8 +5617,8 @@
 
         // Apply top padding to the strip.
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH,
-                SCREEN_HEIGHT,
+                STRIP_WIDTH,
+                STRIP_HEIGHT,
                 false,
                 TIMESTAMP,
                 PADDING_LEFT,
@@ -5831,7 +5635,7 @@
                         false,
                         hoveredTab.getDrawX(),
                         hoveredTab.getWidth(),
-                        SCREEN_HEIGHT,
+                        STRIP_HEIGHT,
                         PADDING_TOP);
         assertEquals(
                 "Tab container opacity is incorrect.",
@@ -5869,7 +5673,7 @@
                 mStripLayoutHelper.isViewCompletelyHidden(hoveredTab));
 
         // Set simulated hovered StripLayoutTab drawX to assume a position beyond the right fade.
-        hoveredTab.setDrawX(SCREEN_WIDTH - StripLayoutHelperManager.FADE_MEDIUM_WIDTH_DP + 1);
+        hoveredTab.setDrawX(STRIP_WIDTH - StripLayoutHelperManager.FADE_MEDIUM_WIDTH_DP + 1);
         assertTrue(
                 "Tab should be considered hidden for hover state.",
                 mStripLayoutHelper.isViewCompletelyHidden(hoveredTab));
@@ -5878,7 +5682,7 @@
     private void initializeTabHoverTest() {
         initializeTest(false, false, 0, 3);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.setTabHoverCardView(mTabHoverCardView);
         // For ease of dp/px calculation.
         mContext.getResources().getDisplayMetrics().density = 1f;
@@ -5998,13 +5802,13 @@
         // Setup some tabs and group some.
         initializeTest(false, false, 1, 5);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         groupTabs(1, 3, TAB_GROUP_ID_1);
 
         // Simulate top padding update.
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH,
-                SCREEN_HEIGHT,
+                STRIP_WIDTH,
+                STRIP_HEIGHT,
                 false,
                 TIMESTAMP,
                 PADDING_LEFT,
@@ -6025,7 +5829,7 @@
                     "Touch target bottom bound for view "
                             + stripViews[i].getAccessibilityDescription()
                             + " is incorrect.",
-                    PADDING_TOP + SCREEN_HEIGHT,
+                    PADDING_TOP + STRIP_HEIGHT,
                     stripViews[i].getTouchTargetBounds().bottom,
                     0f);
             if (stripViews[i] instanceof StripLayoutTab tab) {
@@ -6036,7 +5840,7 @@
                         0f);
                 assertEquals(
                         "Touch target bottom bound for tab's close button is incorrect.",
-                        PADDING_TOP + SCREEN_HEIGHT,
+                        PADDING_TOP + STRIP_HEIGHT,
                         tab.getCloseButton().getTouchTargetBounds().bottom,
                         0f);
             }
@@ -6176,7 +5980,6 @@
     }
 
     @Test
-    @EnableFeatures({ChromeFeatureList.TABLET_TAB_STRIP_ANIMATION})
     public void testTabCreated_HorizontalAnimation() {
         // Initialize with default amount of tabs. Clear any animations.
         initializeTest(false, false, 3);
@@ -6191,14 +5994,13 @@
     }
 
     @Test
-    @EnableFeatures({ChromeFeatureList.TABLET_TAB_STRIP_ANIMATION})
-    public void testTabClosing_NoTabResize_HorizontalAnimation() {
+    public void testTabClosing_HorizontalAnimation() {
         // Arrange
         int tabCount = 10;
         initializeTest(false, false, 9, tabCount);
         StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabsForTesting();
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         setupForAnimations();
 
         mStripLayoutHelper.updateLayout(TIMESTAMP);
@@ -6207,11 +6009,6 @@
         mStripLayoutHelper.handleCloseButtonClick(
                 tabs[9], MotionEventUtils.MOTION_EVENT_BUTTON_NONE);
 
-        // Assert: One set of animations started.
-        assertFalse(
-                "MultiStepAnimations should not have started.",
-                mStripLayoutHelper.isMultiStepCloseAnimationsRunningForTesting());
-
         // Act: Fake the tab closure and end the animation, so the tab is removed from the model.
         Tab closingTab = mModel.getTabAt(9);
         mStripLayoutHelper.finishAnimations();
@@ -6232,7 +6029,7 @@
     public void testWidthCalculated_withNullTabGroupModelFilter() {
         initializeTest(false, false, 0, 1, null);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         assertNotEquals(0, mStripLayoutHelper.getUnpinnedTabWidthForTesting(), EPSILON);
     }
 
@@ -6242,7 +6039,7 @@
         initializeTest(false, false, 0, 5);
         // Update layout to set view draw properties
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
         // Arrange
         StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabsForTesting();
@@ -6273,7 +6070,7 @@
         initializeTest(false, false, 0, 5);
         // Update layout to set view draw properties
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
         // Arrange
         StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabsForTesting();
@@ -6311,7 +6108,7 @@
         initializeTest(false, false, 1, 5); // Start with Tab 1 active (this is the anchor).
         // Update layout to set view draw properties
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
         // Arrange
         StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabsForTesting();
@@ -6347,7 +6144,7 @@
         initializeTest(false, false, 2, 5);
         // Update layout to set view draw properties
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
         // Arrange
         StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabsForTesting();
@@ -6395,7 +6192,7 @@
         initializeTest(false, false, 0, 5);
         // Update layout to set view draw properties
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
         // Arrange
         StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabsForTesting();
@@ -6437,7 +6234,7 @@
         initializeTest(false, false, 0, 5);
         // Update layout to set view draw properties
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
         // Arrange
         StripLayoutView[] stripViews = mStripLayoutHelper.getStripLayoutViewsForTesting();
@@ -6483,7 +6280,7 @@
         when(mTabGroupModelFilter.getTabGroupCollapsed(TAB_GROUP_ID_1)).thenReturn(true);
         // Update layout to set view draw properties
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
         StripLayoutView[] stripViews = mStripLayoutHelper.getStripLayoutViewsForTesting();
 
@@ -6505,7 +6302,7 @@
         initializeTest(false, false, 0, 5);
         // Update layout to set view draw properties
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
         StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabsForTesting();
         StripLayoutView[] stripViews = mStripLayoutHelper.getStripLayoutViewsForTesting();
@@ -6544,7 +6341,7 @@
     public void testMultiSelect_CtrlClick_ResetsAnchorTab() {
         initializeTest(false, false, 1, 5);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
 
         StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabsForTesting();
@@ -6585,7 +6382,7 @@
         // Setup
         initializeTest(false, false, 0, 5);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
         mStripLayoutHelper.setTabContextMenuCoordinatorForTesting(mTabContextMenuCoordinator);
         StripLayoutTab[] tabs = mStripLayoutHelper.getStripLayoutTabsForTesting();
@@ -6628,7 +6425,7 @@
         // Setup
         initializeTest(false, false, 0, 5);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
         StripLayoutView[] stripViews = mStripLayoutHelper.getStripLayoutViewsForTesting();
         StripLayoutTab tab = (StripLayoutTab) stripViews[4];
@@ -7019,7 +6816,7 @@
 
         // Trigger a size change so the strip layout tab heights and widths get set.
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
 
         // Set the initial scroll offset to trigger an update to draw X positions.
         mStripLayoutHelper.setScrollOffsetForTesting(0);
@@ -7110,7 +6907,7 @@
 
         // Trigger a size change so the strip layout tab heights and widths get set.
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_RIGHT, PADDING_LEFT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_RIGHT, PADDING_LEFT, 0f);
 
         // Set the initial scroll offset to trigger an update to draw X positions.
         mStripLayoutHelper.setScrollOffsetForTesting(0);
@@ -7132,7 +6929,7 @@
         mStripLayoutHelper.setTabModel(tabModel, mTabCreator, true);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
 
-        float expectedDrawXWithPinnedTab = SCREEN_WIDTH - PADDING_LEFT - TAB_OVERLAP_WIDTH_DP;
+        float expectedDrawXWithPinnedTab = STRIP_WIDTH - PADDING_LEFT - TAB_OVERLAP_WIDTH_DP;
 
         // 191.5(tabWidth) = (800(screenWidth) - 10(leftPadding) - 60(rightPadding) -
         // 48(pinnedTabWidth) + (28(overlapWidth) * 3) / 4(numTab).
@@ -7174,14 +6971,14 @@
         mStripLayoutHelper.setStripLayoutTabsForTesting(new StripLayoutTab[0]);
         mStripLayoutHelper.updateLayout(TIMESTAMP);
 
-        float expectedDrawXNoPinnedTab = SCREEN_WIDTH - PADDING_LEFT - TAB_OVERLAP_WIDTH_DP;
+        float expectedDrawXNoPinnedTab = STRIP_WIDTH - PADDING_LEFT - TAB_OVERLAP_WIDTH_DP;
         // 168.4(tabWidth) = (800(screenWidth) - 60(leftPadding) - 10(rightPadding) +
         // 28(overlapWidth) * 4) / 5(numTab).
         float expectedWidthNoPinnedTab = 168.4f;
 
         // Verify the tabs are resized and positioned correctly after unpinning.
         tabs = mStripLayoutHelper.getStripLayoutTabsForTesting();
-        expectedDrawXNoPinnedTab = SCREEN_WIDTH - PADDING_LEFT - TAB_OVERLAP_WIDTH_DP;
+        expectedDrawXNoPinnedTab = STRIP_WIDTH - PADDING_LEFT - TAB_OVERLAP_WIDTH_DP;
         for (StripLayoutTab tab : tabs) {
             assertEquals(
                     "The tab's width is incorrect", expectedWidthNoPinnedTab, tab.getWidth(), 0.1f);
@@ -7215,7 +7012,7 @@
             float expectedScrollDelta) {
         initializeTest(isRtl, false, 2, 22);
         mStripLayoutHelper.onSizeChanged(
-                SCREEN_WIDTH, SCREEN_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
+                STRIP_WIDTH, STRIP_HEIGHT, false, TIMESTAMP, PADDING_LEFT, PADDING_RIGHT, 0f);
 
         // Set initial scroll offset under ScrollDelegate's dynamic coordinate system
         // (not the static window coordinate system), which means:
@@ -7258,7 +7055,7 @@
 
         @Override
         public void closeTabs(
-                @NonNull TabClosureParams tabClosureParams,
+                TabClosureParams tabClosureParams,
                 boolean allowDialog,
                 @Nullable TabModelActionListener listener) {
             forceCloseTabs(tabClosureParams);
@@ -7266,23 +7063,23 @@
 
         @Override
         public void prepareCloseTabs(
-                @NonNull TabClosureParams tabClosureParams,
+                TabClosureParams tabClosureParams,
                 boolean allowDialog,
                 @Nullable TabModelActionListener listener,
-                @NonNull Callback<TabClosureParams> onPreparedCallback) {
+                Callback<TabClosureParams> onPreparedCallback) {
             onPreparedCallback.onResult(tabClosureParams);
             mLastParamsForPrepareCloseTabs = tabClosureParams;
         }
 
         @Override
-        public void forceCloseTabs(@NonNull TabClosureParams tabClosureParams) {
+        public void forceCloseTabs(TabClosureParams tabClosureParams) {
             mModel.closeTabs(tabClosureParams);
             mLastParamsForForceCloseTabs = tabClosureParams;
         }
 
         @Override
         public void removeTab(
-                @NonNull Tab tab, boolean allowDialog, @Nullable TabModelActionListener listener) {
+                Tab tab, boolean allowDialog, @Nullable TabModelActionListener listener) {
             throw new AssertionError("Not reached.");
         }
     }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabContextMenuCoordinatorUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabContextMenuCoordinatorUnitTest.java
index fdbfac8..041b6c1 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabContextMenuCoordinatorUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabContextMenuCoordinatorUnitTest.java
@@ -153,7 +153,7 @@
                     NUM_INCOGNITO_TABS,
                     /* isIncognitoSelected= */ false,
                     LAST_ACCESSED_TIME,
-                    /* closedByUser= */ false);
+                    /* markedForDeletion= */ false);
 
     private static final InstanceInfo INSTANCE_INFO_2 =
             new InstanceInfo(
@@ -167,7 +167,7 @@
                     NUM_INCOGNITO_TABS,
                     /* isIncognitoSelected= */ false,
                     LAST_ACCESSED_TIME,
-                    /* closedByUser= */ false);
+                    /* markedForDeletion= */ false);
 
     @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabGroupContextMenuCoordinatorUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabGroupContextMenuCoordinatorUnitTest.java
index 404fba9f..873d7f5 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabGroupContextMenuCoordinatorUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/TabGroupContextMenuCoordinatorUnitTest.java
@@ -149,7 +149,7 @@
                     NUM_INCOGNITO_TABS,
                     /* isIncognitoSelected= */ false,
                     LAST_ACCESSED_TIME,
-                    /* closedByUser= */ false);
+                    /* markedForDeletion= */ false);
 
     private static final InstanceInfo INSTANCE_INFO_2 =
             new InstanceInfo(
@@ -163,7 +163,7 @@
                     NUM_INCOGNITO_TABS,
                     /* isIncognitoSelected= */ false,
                     LAST_ACCESSED_TIME,
-                    /* closedByUser= */ false);
+                    /* markedForDeletion= */ false);
 
     // Other dependencies
     @Mock private Profile mProfile;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/reorder/SourceViewDragDropReorderStrategyTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/reorder/SourceViewDragDropReorderStrategyTest.java
index d7e085b..cd3e7f1a 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/reorder/SourceViewDragDropReorderStrategyTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/overlays/strip/reorder/SourceViewDragDropReorderStrategyTest.java
@@ -202,7 +202,7 @@
         // Verify
         verify(mStripUpdateDelegate).setCompositorButtonsVisible(false);
         verify(mAnimationHost).finishAnimationsAndPushTabUpdates();
-        verify(mStripUpdateDelegate).resizeTabStrip(false, null, false);
+        verify(mStripUpdateDelegate).resizeTabStrip(null, false);
         verify(mTabStrategy)
                 .startReorderMode(
                         eq(mStripViews),
@@ -229,7 +229,7 @@
         // Verify
         verify(mStripUpdateDelegate).setCompositorButtonsVisible(false);
         verify(mAnimationHost).finishAnimationsAndPushTabUpdates();
-        verify(mStripUpdateDelegate).resizeTabStrip(false, null, false);
+        verify(mStripUpdateDelegate).resizeTabStrip(null, false);
         verify(mMultiTabStrategy)
                 .startReorderMode(
                         eq(mStripViews),
@@ -345,7 +345,7 @@
         verify(mStripUpdateDelegate).setCompositorButtonsVisible(true);
         verify(mMultiTabStrategy).stopReorderMode(mStripViews, mGroupTitles);
         verify(mAnimationHost, times(2)).finishAnimationsAndPushTabUpdates();
-        verify(mStripUpdateDelegate, times(2)).resizeTabStrip(false, null, false);
+        verify(mStripUpdateDelegate, times(2)).resizeTabStrip(null, false);
         verifyNoMoreInteractions(mMultiTabStrategy);
     }
 
@@ -382,7 +382,7 @@
         verify(mStripUpdateDelegate).setCompositorButtonsVisible(true);
         verify(mTabStrategy).stopReorderMode(mStripViews, mGroupTitles);
         verify(mAnimationHost, times(2)).finishAnimationsAndPushTabUpdates();
-        verify(mStripUpdateDelegate).resizeTabStrip(true, mInteractingTab, false);
+        verify(mStripUpdateDelegate).resizeTabStrip(mInteractingTab, false);
         verifyNoMoreInteractions(mTabStrategy);
     }
 
@@ -503,7 +503,7 @@
 
         // Verify restore.
         verify(mAnimationHost, times(2)).finishAnimationsAndPushTabUpdates();
-        verify(mStripUpdateDelegate).resizeTabStrip(true, mInteractingTab, true);
+        verify(mStripUpdateDelegate).resizeTabStrip(mInteractingTab, true);
         assertFalse("DraggedOffStrip should be false", mInteractingTab.isDraggedOffStrip());
         assertEquals("Width should be 0", 0f, mInteractingTab.getWidth(), EPSILON);
     }
@@ -536,7 +536,7 @@
 
         // Verify restore.
         verify(mAnimationHost, times(2)).finishAnimationsAndPushTabUpdates();
-        verify(mStripUpdateDelegate, times(2)).resizeTabStrip(false, null, false);
+        verify(mStripUpdateDelegate, times(2)).resizeTabStrip(null, false);
         assertFalse("DraggedOffStrip should be false", mInteractingGroupTitle.isDraggedOffStrip());
         assertEquals("offsetY should be 0", 0f, mInteractingGroupTitle.getOffsetY(), EPSILON);
     }
@@ -571,7 +571,7 @@
 
         // Verify restore.
         verify(mAnimationHost, times(2)).finishAnimationsAndPushTabUpdates();
-        verify(mStripUpdateDelegate, times(2)).resizeTabStrip(false, null, false);
+        verify(mStripUpdateDelegate, times(2)).resizeTabStrip(null, false);
         assertFalse("DraggedOffStrip should be false", mInteractingTab.isDraggedOffStrip());
         assertFalse("DraggedOffStrip should be false", mOtherSelectedTab.isDraggedOffStrip());
         assertEquals("offsetY should be 0", 0f, mInteractingTab.getOffsetY(), EPSILON);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/media/AutoPictureInPicturePermissionControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/media/AutoPictureInPicturePermissionControllerTest.java
index a3ed7d2..297e8b7 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/media/AutoPictureInPicturePermissionControllerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/media/AutoPictureInPicturePermissionControllerTest.java
@@ -52,6 +52,8 @@
     @Mock private UrlFormatter.Natives mUrlFormatterJniMock;
     @Mock private Tab mTab;
 
+    private static final Runnable NO_OP_CALLBACK = () -> {};
+
     private ActivityController<Activity> mActivityController;
     private Activity mActivity;
     private WebContents mWebContents;
@@ -93,10 +95,11 @@
     }
 
     @Test
-    public void testShowPrompt_Ask() {
+    public void testShowPrompt_WhenPermissionIsAsk_DisplaysPrompt() {
         when(mNativeMock.getPermissionStatus(mWebContents)).thenReturn(ContentSetting.ASK);
 
-        AutoPictureInPicturePermissionController.showPromptIfNeeded(mActivity, mTab);
+        AutoPictureInPicturePermissionController.showPromptIfNeeded(
+                mActivity, mTab, NO_OP_CALLBACK);
 
         // Verify the prompt is added to the root view.
         ViewGroup rootView = mActivity.findViewById(android.R.id.content);
@@ -110,30 +113,33 @@
     }
 
     @Test
-    public void testShowPrompt_Allow() {
+    public void testShowPrompt_WhenPermissionIsAllow_DoesNotDisplayPrompt() {
         when(mNativeMock.getPermissionStatus(mWebContents)).thenReturn(ContentSetting.ALLOW);
 
-        AutoPictureInPicturePermissionController.showPromptIfNeeded(mActivity, mTab);
+        AutoPictureInPicturePermissionController.showPromptIfNeeded(
+                mActivity, mTab, NO_OP_CALLBACK);
 
         ViewGroup rootView = mActivity.findViewById(android.R.id.content);
         Assert.assertEquals(0, rootView.getChildCount());
     }
 
     @Test
-    public void testShowPrompt_Block() {
+    public void testShowPrompt_WhenPermissionIsBlock_DoesNotDisplayPrompt() {
         when(mNativeMock.getPermissionStatus(mWebContents)).thenReturn(ContentSetting.BLOCK);
 
-        AutoPictureInPicturePermissionController.showPromptIfNeeded(mActivity, mTab);
+        AutoPictureInPicturePermissionController.showPromptIfNeeded(
+                mActivity, mTab, NO_OP_CALLBACK);
 
         ViewGroup rootView = mActivity.findViewById(android.R.id.content);
         Assert.assertEquals(0, rootView.getChildCount());
     }
 
     @Test
-    public void testShowPrompt_AlreadyAllowedOnce() {
+    public void testShowPrompt_AllowOnce_PreventsSubsequentPrompt() {
         // Show prompt and simulate "Allow Once" click.
         when(mNativeMock.getPermissionStatus(mWebContents)).thenReturn(ContentSetting.ASK);
-        AutoPictureInPicturePermissionController.showPromptIfNeeded(mActivity, mTab);
+        AutoPictureInPicturePermissionController.showPromptIfNeeded(
+                mActivity, mTab, NO_OP_CALLBACK);
 
         ViewGroup rootView = mActivity.findViewById(android.R.id.content);
         AutoPipPermissionDialogView view = (AutoPipPermissionDialogView) rootView.getChildAt(1);
@@ -148,14 +154,16 @@
         Assert.assertEquals(0, rootView.getChildCount());
 
         // Should not show prompt.
-        AutoPictureInPicturePermissionController.showPromptIfNeeded(mActivity, mTab);
+        AutoPictureInPicturePermissionController.showPromptIfNeeded(
+                mActivity, mTab, NO_OP_CALLBACK);
         Assert.assertEquals(0, rootView.getChildCount());
     }
 
     @Test
-    public void testShowPrompt_AllowEveryVisit() {
+    public void testShowPrompt_AllowEveryVisit_SetsPermissionToAllow() {
         when(mNativeMock.getPermissionStatus(mWebContents)).thenReturn(ContentSetting.ASK);
-        AutoPictureInPicturePermissionController.showPromptIfNeeded(mActivity, mTab);
+        AutoPictureInPicturePermissionController.showPromptIfNeeded(
+                mActivity, mTab, NO_OP_CALLBACK);
 
         ViewGroup rootView = mActivity.findViewById(android.R.id.content);
         AutoPipPermissionDialogView view = (AutoPipPermissionDialogView) rootView.getChildAt(1);
@@ -170,9 +178,11 @@
     }
 
     @Test
-    public void testShowPrompt_BlockClick() {
+    public void testShowPrompt_BlockClick_SetsPermissionToBlockAndClosesPip() {
         when(mNativeMock.getPermissionStatus(mWebContents)).thenReturn(ContentSetting.ASK);
-        AutoPictureInPicturePermissionController.showPromptIfNeeded(mActivity, mTab);
+        Runnable closePipCallback = mock(Runnable.class);
+        AutoPictureInPicturePermissionController.showPromptIfNeeded(
+                mActivity, mTab, closePipCallback);
 
         ViewGroup rootView = mActivity.findViewById(android.R.id.content);
         AutoPipPermissionDialogView view = (AutoPipPermissionDialogView) rootView.getChildAt(1);
@@ -183,13 +193,15 @@
         blockButton.performClick();
 
         verify(mNativeMock).setPermissionStatus(eq(mWebContents), eq(ContentSetting.BLOCK));
+        verify(closePipCallback).run();
         Assert.assertEquals(0, rootView.getChildCount());
     }
 
     @Test
-    public void testDismiss_CleansUpState() {
+    public void testDismiss_CleansUpUIAndHelperState() {
         when(mNativeMock.getPermissionStatus(mWebContents)).thenReturn(ContentSetting.ASK);
-        AutoPictureInPicturePermissionController.showPromptIfNeeded(mActivity, mTab);
+        AutoPictureInPicturePermissionController.showPromptIfNeeded(
+                mActivity, mTab, NO_OP_CALLBACK);
 
         // Capture the controller instance
         AutoPictureInPicturePermissionController controller = mTabHelper.getPermissionController();
@@ -209,7 +221,7 @@
     }
 
     @Test
-    public void testIsAutoPictureInPictureInUse() {
+    public void testIsAutoPictureInPictureInUse_ReflectsNativeState() {
         when(mNativeMock.isAutoPictureInPictureInUse(mWebContents)).thenReturn(true);
         Assert.assertTrue(
                 AutoPictureInPicturePermissionController.isAutoPictureInPictureInUse(mWebContents));
@@ -220,7 +232,7 @@
     }
 
     @Test
-    public void testPrimaryPageChanged_ClearsAllowOnce() {
+    public void testPrimaryPageChanged_ClearsAllowOnceState() {
         mTabHelper.setHasAllowOnce(true);
 
         // Capture the observer registered by the helper
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31UnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31UnitTest.java
index 10b0822..7dfcaaea 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31UnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/multiwindow/MultiInstanceManagerApi31UnitTest.java
@@ -309,7 +309,7 @@
                                 /* incognitoTabCount= */ 0,
                                 /* isIncognitoSelected= */ false,
                                 MultiInstancePersistentStore.readLastAccessedTime(instanceId),
-                                /* closedByUser= */ false));
+                                /* markedForDeletion= */ false));
             }
         }
 
@@ -839,7 +839,7 @@
         for (InstanceInfo instanceInfo :
                 mMultiInstanceManager.getInstanceInfo(PersistedInstanceType.ANY)) {
             if (instanceInfo.instanceId == 1) {
-                assertTrue(instanceInfo.closedByUser);
+                assertTrue(instanceInfo.markedForDeletion);
                 break;
             }
         }
@@ -1288,7 +1288,7 @@
         MultiInstancePersistentStore.writeLastAccessedTime(index);
         MultiInstancePersistentStore.writeProfileType(
                 index, /* profileType= */ SupportedProfileType.MIXED);
-        MultiInstancePersistentStore.writeClosedByUser(index, /* closedByUser= */ true);
+        MultiInstancePersistentStore.writeMarkedForDeletion(index, /* markedForDeletion= */ true);
 
         var histogramWatcher =
                 HistogramWatcher.newBuilder()
@@ -1333,7 +1333,7 @@
                 MultiInstancePersistentStore.readProfileType(index));
         assertFalse(
                 "Persistent store should be updated.",
-                MultiInstancePersistentStore.readClosedByUser(index));
+                MultiInstancePersistentStore.readMarkedForDeletion(index));
     }
 
     private void triggerSelectTab(TabModelObserver tabModelObserver, Tab tab) {
@@ -1823,7 +1823,7 @@
                         /* incognitoTabCount= */ 0,
                         /* isIncognitoSelected= */ false,
                         /* lastAccessedTime= */ 0,
-                        /* closedByUser= */ false);
+                        /* markedForDeletion= */ false);
         mMultiInstanceManager.moveTabsToWindow(
                 info,
                 Collections.singletonList(mTab1),
@@ -1864,7 +1864,7 @@
                         /* incognitoTabCount= */ 0,
                         /* isIncognitoSelected= */ false,
                         /* lastAccessedTime= */ 0,
-                        /* closedByUser= */ false);
+                        /* markedForDeletion= */ false);
         mMultiInstanceManager.moveTabsToWindow(
                 info, tabs, /* tabAtIndex= */ 0, NewWindowAppSource.OTHER);
 
@@ -1898,7 +1898,7 @@
                         /* incognitoTabCount= */ 0,
                         /* isIncognitoSelected= */ false,
                         /* lastAccessedTime= */ 0,
-                        /* closedByUser= */ false);
+                        /* markedForDeletion= */ false);
         mMultiInstanceManager.moveTabGroupToWindow(
                 info, mTabGroupMetadata, /* startIndex= */ 0, NewWindowAppSource.OTHER);
 
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 63168c0a0..7694b4bd 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2064,7 +2064,7 @@
     "//chrome/browser/ui/webui/bluetooth_internals:mojo_bindings",
     "//chrome/browser/ui/webui/internal_debug_pages_disabled",
     "//chrome/browser/ui/zoom",
-    "//chrome/browser/updater",
+    "//chrome/browser/updater:scheduler",
     "//chrome/browser/updates/announcement_notification",
     "//chrome/browser/updates/announcement_notification:impl",
     "//chrome/browser/vr",
@@ -6320,6 +6320,7 @@
     deps += [
       "//chrome/browser/ui/pdf/infobar",
       "//chrome/browser/ui/startup/default_browser_prompt/pin_infobar:impl",
+      "//chrome/browser/updater:browser_updater_client",
       "//chrome/common/notifications",
       "//chrome/updater:browser_sources",
     ]
@@ -6661,6 +6662,7 @@
       "//chrome/browser/apps/app_shim",
       "//chrome/browser/enterprise/connectors/device_trust/key_management/core/mac",
       "//chrome/browser/renderer_host:history_swiper",
+      "//chrome/browser/updater:browser_updater_client",
       "//chrome/browser/web_applications/os_integration/mac:web_app_shortcut_copier_lib",
       "//chrome/browser/webshare:storage",
       "//chrome/services/mac_notifications",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 4540a0015..86883f1 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -8119,11 +8119,6 @@
      flag_descriptions::kTabSwitcherDragDropDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(chrome::android::kTabSwitcherDragDropAndroid)},
 
-    {"tab-archival-drag-drop-android",
-     flag_descriptions::kTabArchivalDragDropAndroidName,
-     flag_descriptions::kTabArchivalDragDropAndroidDescription, kOsAndroid,
-     FEATURE_VALUE_TYPE(chrome::android::kTabArchivalDragDropAndroid)},
-
     {"most-visited-tiles-customization",
      flag_descriptions::kMostVisitedTilesCustomizationName,
      flag_descriptions::kMostVisitedTilesCustomizationDescription, kOsAndroid,
@@ -12445,13 +12440,6 @@
      FEATURE_VALUE_TYPE(features::kPreinstalledWebAppAlwaysMigrateCalculator)},
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
-#if BUILDFLAG(IS_ANDROID)
-    {"tablet-tab-strip-animation",
-     flag_descriptions::kTabletTabStripAnimationName,
-     flag_descriptions::kTabletTabStripAnimationDescription, kOsAndroid,
-     FEATURE_VALUE_TYPE(chrome::android::kTabletTabStripAnimation)},
-#endif  // BUILDFLAG(IS_ANDROID)
-
     {"enable-secure-payment-confirmation-ux-refresh",
      flag_descriptions::kSecurePaymentConfirmationUxRefreshName,
      flag_descriptions::kSecurePaymentConfirmationUxRefreshDescription,
diff --git a/chrome/browser/apps/app_service/app_icon/chrome_apps_icon_unittest.cc b/chrome/browser/apps/app_service/app_icon/chrome_apps_icon_unittest.cc
index 9e85415..a12ddda 100644
--- a/chrome/browser/apps/app_service/app_icon/chrome_apps_icon_unittest.cc
+++ b/chrome/browser/apps/app_service/app_icon/chrome_apps_icon_unittest.cc
@@ -200,6 +200,12 @@
     OverrideAppServiceProxyInnerIconLoader(fake_icon_loader_.get());
   }
 
+  void TearDown() override {
+    fake_icon_loader_.reset();
+    proxy_ = nullptr;
+    ChromeAppsIconFactoryTest::TearDown();
+  }
+
   void OverrideAppServiceProxyInnerIconLoader(apps::IconLoader* icon_loader) {
     app_service_proxy().OverrideInnerIconLoaderForTesting(icon_loader);
   }
@@ -246,7 +252,7 @@
   AppServiceProxy& app_service_proxy() { return *proxy_; }
 
  private:
-  raw_ptr<AppServiceProxy> proxy_;
+  raw_ptr<AppServiceProxy> proxy_ = nullptr;
   std::unique_ptr<apps::FakeIconLoader> fake_icon_loader_;
   data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
 };
diff --git a/chrome/browser/ash/app_list/app_service/app_service_promise_app_model_builder_unittest.cc b/chrome/browser/ash/app_list/app_service/app_service_promise_app_model_builder_unittest.cc
index a4ef78de..8ae958b 100644
--- a/chrome/browser/ash/app_list/app_service/app_service_promise_app_model_builder_unittest.cc
+++ b/chrome/browser/ash/app_list/app_service/app_service_promise_app_model_builder_unittest.cc
@@ -37,6 +37,7 @@
 
  protected:
   void ResetBuilder() {
+    cache_ = nullptr;
     scoped_callback_.reset();
     builder_.reset();
     controller_.reset();
@@ -111,8 +112,7 @@
   std::unique_ptr<test::TestAppListControllerDelegate> controller_;
   std::unique_ptr<FakeAppListModelUpdater> model_updater_;
   display::test::TestScreen test_screen_;
-  std::unique_ptr<Profile> profile_;
-  raw_ptr<apps::PromiseAppRegistryCache> cache_;
+  raw_ptr<apps::PromiseAppRegistryCache> cache_ = nullptr;
   syncer::StringOrdinal last_position_;
   base::WeakPtrFactory<AppServicePromiseAppModelBuilderTest> weak_ptr_factory_{
       this};
diff --git a/chrome/browser/ash/app_list/search/app_search_provider_test_base.cc b/chrome/browser/ash/app_list/search/app_search_provider_test_base.cc
index bd688fd..115e4af0 100644
--- a/chrome/browser/ash/app_list/search/app_search_provider_test_base.cc
+++ b/chrome/browser/ash/app_list/search/app_search_provider_test_base.cc
@@ -49,6 +49,14 @@
   ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
 }
 
+void AppSearchProviderTestBase::TearDown() {
+  controller_.reset();
+  app_search_ = nullptr;
+  data_source_.reset();
+  search_controller_.reset();
+  AppListTestBase::TearDown();
+}
+
 void AppSearchProviderTestBase::InitializeSearchProvider() {
   search_controller_ = std::make_unique<TestSearchController>();
   data_source_ =
diff --git a/chrome/browser/ash/app_list/search/app_search_provider_test_base.h b/chrome/browser/ash/app_list/search/app_search_provider_test_base.h
index 154695ce..60e6a1d 100644
--- a/chrome/browser/ash/app_list/search/app_search_provider_test_base.h
+++ b/chrome/browser/ash/app_list/search/app_search_provider_test_base.h
@@ -39,6 +39,7 @@
 
   // AppListTestBase overrides:
   void SetUp() override;
+  void TearDown() override;
 
   //  Sets up app search provider to be used in the test.
   void InitializeSearchProvider();
diff --git a/chrome/browser/ash/app_list/search/arc/arc_playstore_search_provider_unittest.cc b/chrome/browser/ash/app_list/search/arc/arc_playstore_search_provider_unittest.cc
index 10123628..54b6f883 100644
--- a/chrome/browser/ash/app_list/search/arc/arc_playstore_search_provider_unittest.cc
+++ b/chrome/browser/ash/app_list/search/arc/arc_playstore_search_provider_unittest.cc
@@ -46,6 +46,8 @@
   }
 
   void TearDown() override {
+    provider_ = nullptr;
+    search_controller_.reset();
     controller_.reset();
     arc_app_test_.PreProfileTearDown();
     AppListTestBase::TearDown();
@@ -81,10 +83,10 @@
   }
 
  private:
+  ArcAppTest arc_app_test_;
   std::unique_ptr<::test::TestAppListControllerDelegate> controller_;
   std::unique_ptr<TestSearchController> search_controller_;
   raw_ptr<ArcPlayStoreSearchProvider> provider_ = nullptr;
-  ArcAppTest arc_app_test_;
 };
 
 TEST_F(ArcPlayStoreSearchProviderTest, Basic) {
diff --git a/chrome/browser/ash/app_list/search/help_app_provider_unittest.cc b/chrome/browser/ash/app_list/search/help_app_provider_unittest.cc
index 0188de24..ba0096e 100644
--- a/chrome/browser/ash/app_list/search/help_app_provider_unittest.cc
+++ b/chrome/browser/ash/app_list/search/help_app_provider_unittest.cc
@@ -99,17 +99,26 @@
     auto provider = std::make_unique<HelpAppProvider>(profile());
     provider->MaybeInitialize(&mock_handler_);
     provider_ = provider.get();
-    search_controller_.AddProvider(std::move(provider));
+    search_controller_ = std::make_unique<TestSearchController>();
+    search_controller_->AddProvider(std::move(provider));
+  }
+
+  void TearDown() override {
+    provider_ = nullptr;
+    search_controller_.reset();
+
+    proxy_ = nullptr;
+    AppListTestBase::TearDown();
   }
 
   // Starts a search and waits for the query to be sent.
   void StartSearch(const std::u16string& query) {
-    search_controller_.StartSearch(query);
+    search_controller_->StartSearch(query);
     task_environment()->RunUntilIdle();
   }
 
   const app_list::Results& GetLatestResults() {
-    return search_controller_.last_results();
+    return search_controller_->last_results();
   }
 
   MockSearchHandler* mock_handler() { return &mock_handler_; }
@@ -117,12 +126,12 @@
  private:
   session_manager::SessionManager session_manager_{
       std::make_unique<session_manager::FakeSessionManagerDelegate>()};
-  TestSearchController search_controller_;
   std::unique_ptr<ash::local_search_service::LocalSearchServiceProxy>
       local_search_service_proxy_;
   ash::help_app::SearchTagRegistry search_tag_registry_;
+  raw_ptr<apps::AppServiceProxy> proxy_ = nullptr;
   raw_ptr<HelpAppProvider> provider_ = nullptr;
-  raw_ptr<apps::AppServiceProxy> proxy_;
+  std::unique_ptr<TestSearchController> search_controller_;
   MockSearchHandler mock_handler_;
 };
 
diff --git a/chrome/browser/ash/app_list/search/help_app_zero_state_provider_unittest.cc b/chrome/browser/ash/app_list/search/help_app_zero_state_provider_unittest.cc
index f5c092e6..95f71e2 100644
--- a/chrome/browser/ash/app_list/search/help_app_zero_state_provider_unittest.cc
+++ b/chrome/browser/ash/app_list/search/help_app_zero_state_provider_unittest.cc
@@ -52,15 +52,23 @@
     auto provider = std::make_unique<HelpAppZeroStateProvider>(
         profile(), app_list_notifier_.get());
     provider_ = provider.get();
-    search_controller_.AddProvider(std::move(provider));
+    search_controller_ = std::make_unique<TestSearchController>();
+    search_controller_->AddProvider(std::move(provider));
+  }
+
+  void TearDown() override {
+    provider_ = nullptr;
+    search_controller_.reset();
+    app_list_notifier_.reset();
+    AppListTestBase::TearDown();
   }
 
   void StartZeroStateSearch() {
-    search_controller_.StartZeroState(base::DoNothing(), base::TimeDelta());
+    search_controller_->StartZeroState(base::DoNothing(), base::TimeDelta());
   }
 
   const app_list::Results& GetLatestResults() {
-    return search_controller_.last_results();
+    return search_controller_->last_results();
   }
 
   ::test::TestAppListController* app_list_controller() {
@@ -72,8 +80,8 @@
  private:
   ::test::TestAppListController app_list_controller_;
   std::unique_ptr<ash::AppListNotifier> app_list_notifier_;
-  TestSearchController search_controller_;
   raw_ptr<HelpAppZeroStateProvider> provider_ = nullptr;
+  std::unique_ptr<TestSearchController> search_controller_;
 };
 
 // Test for empty query.
diff --git a/chrome/browser/ash/app_list/test/app_list_syncable_service_test_base.cc b/chrome/browser/ash/app_list/test/app_list_syncable_service_test_base.cc
index ba060a2..70f8216 100644
--- a/chrome/browser/ash/app_list/test/app_list_syncable_service_test_base.cc
+++ b/chrome/browser/ash/app_list/test/app_list_syncable_service_test_base.cc
@@ -32,6 +32,11 @@
   content::RunAllTasksUntilIdle();
 }
 
+void AppListSyncableServiceTestBase::TearDown() {
+  app_list_syncable_service_.reset();
+  AppListTestBase::TearDown();
+}
+
 void AppListSyncableServiceTestBase::RestartSyncableService() {
   app_list_syncable_service_ =
       std::make_unique<app_list::AppListSyncableService>(profile());
diff --git a/chrome/browser/ash/app_list/test/app_list_syncable_service_test_base.h b/chrome/browser/ash/app_list/test/app_list_syncable_service_test_base.h
index 775bcf41..0eec0716 100644
--- a/chrome/browser/ash/app_list/test/app_list_syncable_service_test_base.h
+++ b/chrome/browser/ash/app_list/test/app_list_syncable_service_test_base.h
@@ -26,6 +26,7 @@
 
   // AppListTestBase:
   void SetUp() override;
+  void TearDown() override;
 
  protected:
   void RestartSyncableService();
diff --git a/chrome/browser/ash/crosapi/DEPS b/chrome/browser/ash/crosapi/DEPS
index 768ce18..c5a7671 100644
--- a/chrome/browser/ash/crosapi/DEPS
+++ b/chrome/browser/ash/crosapi/DEPS
@@ -28,6 +28,7 @@
   "+chrome/browser/browser_process.h",
   "+chrome/browser/browser_process_platform_part.h",
   "+chrome/browser/chromeos/extensions/file_system_provider",
+  "+chrome/browser/chromeos/extensions/vpn_provider",
   "+chrome/browser/chromeos/platform_keys",
   "+chrome/browser/extensions/extension_apitest.h",
   "+chrome/browser/file_system_access/cloud_identifier",
diff --git a/chrome/browser/ash/crosapi/vpn_service_ash.cc b/chrome/browser/ash/crosapi/vpn_service_ash.cc
index cda9f31..dd1fff8 100644
--- a/chrome/browser/ash/crosapi/vpn_service_ash.cc
+++ b/chrome/browser/ash/crosapi/vpn_service_ash.cc
@@ -16,6 +16,7 @@
 #include "base/uuid.h"
 #include "base/values.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
+#include "chrome/browser/chromeos/extensions/vpn_provider/vpn_service.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chromeos/ash/components/dbus/shill/shill_third_party_vpn_driver_client.h"
 #include "chromeos/ash/components/dbus/shill/shill_third_party_vpn_observer.h"
@@ -124,8 +125,9 @@
 }
 
 VpnServiceForExtensionAsh::VpnServiceForExtensionAsh(
-    const std::string& extension_id)
-    : extension_id_(extension_id) {
+    const std::string& extension_id,
+    chromeos::VpnService* controller)
+    : extension_id_(extension_id), controller_(controller) {
   network_configuration_observer_.Observe(
       ash::NetworkHandler::Get()->network_configuration_handler());
 }
@@ -149,7 +151,7 @@
   }
 
   const std::string key = GetKey(extension_id(), configuration_name);
-  if (base::Contains(key_to_configuration_map_, key)) {
+  if (base::Contains(controller_->key_to_configuration_map_, key)) {
     RunFailureCallback(std::move(callback), /*error_name=*/{},
                        "Name not unique.");
     return;
@@ -201,7 +203,7 @@
   const std::string key = GetKey(extension_id(), configuration_name);
 
   VpnConfiguration* configuration =
-      base::FindPtrOrNull(key_to_configuration_map_, key);
+      base::FindPtrOrNull(controller_->key_to_configuration_map_, key);
   if (!configuration) {
     RunFailureCallback(std::move(callback), /*error_name=*/{},
                        "Unauthorized access.");
@@ -270,7 +272,8 @@
 
 void VpnServiceForExtensionAsh::DestroyAllConfigurations() {
   std::vector<std::string> to_be_destroyed;
-  for (const auto& [key, configuration] : key_to_configuration_map_) {
+  for (const auto& [key, configuration] :
+       controller_->key_to_configuration_map_) {
     to_be_destroyed.push_back(configuration->configuration_name());
   }
   for (const auto& configuration_name : to_be_destroyed) {
@@ -329,7 +332,7 @@
   auto configuration =
       std::make_unique<VpnConfigurationImpl>(configuration_name, key, this);
   auto* ptr = configuration.get();
-  key_to_configuration_map_.emplace(key, std::move(configuration));
+  controller_->key_to_configuration_map_.emplace(key, std::move(configuration));
   return ptr;
 }
 
@@ -338,8 +341,8 @@
   // |owned_configuration| ensures that |configuration| stays valid until the
   // end of the scope.
   auto owned_configuration =
-      std::move(key_to_configuration_map_[configuration->key()]);
-  key_to_configuration_map_.erase(configuration->key());
+      std::move(controller_->key_to_configuration_map_[configuration->key()]);
+  controller_->key_to_configuration_map_.erase(configuration->key());
   if (active_configuration_ == configuration) {
     SetActiveConfiguration(nullptr);
   }
@@ -498,9 +501,15 @@
     const std::string& extension_id) {
   auto& service = extension_id_to_service_[extension_id];
   if (!service) {
-    service = std::make_unique<VpnServiceForExtensionAsh>(extension_id);
+    service =
+        std::make_unique<VpnServiceForExtensionAsh>(extension_id, controller_);
   }
   return service.get();
 }
 
+void VpnServiceAsh::Reset() {
+  controller_ = nullptr;
+  extension_id_to_service_.clear();
+}
+
 }  // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/vpn_service_ash.h b/chrome/browser/ash/crosapi/vpn_service_ash.h
index a381689..14b06df 100644
--- a/chrome/browser/ash/crosapi/vpn_service_ash.h
+++ b/chrome/browser/ash/crosapi/vpn_service_ash.h
@@ -38,6 +38,8 @@
 
 namespace chromeos {
 
+class VpnService;
+
 // Fwd for friend declaration in VpnServiceAsh.
 class VpnProviderApiTest;
 
@@ -63,7 +65,8 @@
   class VpnConfiguration;
 
  public:
-  explicit VpnServiceForExtensionAsh(const std::string& extension_id);
+  explicit VpnServiceForExtensionAsh(const std::string& extension_id,
+                                     chromeos::VpnService* controller);
   ~VpnServiceForExtensionAsh() override;
 
   VpnServiceForExtensionAsh(const VpnServiceForExtensionAsh&) = delete;
@@ -103,8 +106,6 @@
   friend class chromeos::VpnProviderApiTest;
   friend class TestShillControllerAsh;
 
-  using StringToOwnedConfigurationMap =
-      std::map<std::string, std::unique_ptr<VpnConfiguration>>;
   using StringToConfigurationMap =
       std::map<std::string, raw_ptr<VpnConfiguration, CtnExperimental>>;
 
@@ -146,10 +147,8 @@
   void SetActiveConfiguration(VpnConfiguration*);
 
   const extensions::ExtensionId extension_id_;
+  raw_ptr<chromeos::VpnService> controller_;
 
-  // Owns all configurations. Key is a hash of |extension_id| and
-  // |configuration_name|.
-  StringToOwnedConfigurationMap key_to_configuration_map_;
   // Maps shill service path to unowned configuration.
   StringToConfigurationMap service_path_to_configuration_map_;
 
@@ -200,6 +199,12 @@
   VpnServiceForExtensionAsh* GetVpnServiceForExtension(
       const std::string& extension_id);
 
+  void SetController(chromeos::VpnService* controller) {
+    controller_ = controller;
+  }
+
+  void Reset();
+
  private:
   friend class chromeos::VpnProviderApiTest;
   friend class VpnServiceForExtensionAsh;
@@ -231,6 +236,7 @@
 
   std::unique_ptr<ash::VpnProvidersObserver> vpn_providers_observer_;
 
+  raw_ptr<chromeos::VpnService> controller_ = nullptr;
   base::WeakPtrFactory<VpnServiceAsh> weak_factory_{this};
 };
 
diff --git a/chrome/browser/chrome_browser_interface_binders_webui.cc b/chrome/browser/chrome_browser_interface_binders_webui.cc
index e3df1eed..cd7be2175 100644
--- a/chrome/browser/chrome_browser_interface_binders_webui.cc
+++ b/chrome/browser/chrome_browser_interface_binders_webui.cc
@@ -150,16 +150,24 @@
   // this function longer.
 }
 
-void PopulateChromeWebUIFrameInterfaceBrokers(
+void PopulateTrustedChromeWebUIFrameInterfaceBrokers(
     content::WebUIBrowserInterfaceBrokerRegistry& registry) {
   // This function is broken up into sections based on WebUI types.
 
-  // --- Section 1: chrome:// WebUIs:
 #if BUILDFLAG(IS_CHROMEOS)
   PopulateChromeWebUIFrameInterfaceBrokersTrustedPartsCros(registry);
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
-  // --- Section 2: chrome-untrusted:// WebUIs:
+#if !BUILDFLAG(IS_ANDROID)
+  PopulateChromeWebUIFrameInterfaceBrokersTrustedPartsDesktop(registry);
+#endif  // !BUILDFLAG(IS_ANDROID)
+
+  // When possible, please use one of the Parts functions above and avoid making
+  // this function longer.
+}
+
+void PopulateUntrustedChromeWebUIFrameInterfaceBrokers(
+    content::WebUIBrowserInterfaceBrokerRegistry& registry) {
   PopulateChromeWebUIFrameInterfaceBrokersUntrustedPartsFeatures(registry);
 
 #if BUILDFLAG(IS_CHROMEOS)
@@ -167,11 +175,10 @@
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
 #if !BUILDFLAG(IS_ANDROID)
-  PopulateChromeWebUIFrameInterfaceBrokersTrustedPartsDesktop(registry);
   PopulateChromeWebUIFrameInterfaceBrokersUntrustedPartsDesktop(registry);
 #endif  // !BUILDFLAG(IS_ANDROID)
 
-  // When possible, please one one of the Parts functions above and avoid making
+  // When possible, please use one of the Parts functions above and avoid making
   // this function longer.
 }
 
diff --git a/chrome/browser/chrome_browser_interface_binders_webui.h b/chrome/browser/chrome_browser_interface_binders_webui.h
index 7c43c31..e2ee0622 100644
--- a/chrome/browser/chrome_browser_interface_binders_webui.h
+++ b/chrome/browser/chrome_browser_interface_binders_webui.h
@@ -24,10 +24,16 @@
     mojo::BinderMapWithContext<content::RenderFrameHost*>* map,
     content::RenderFrameHost* render_frame_host);
 
-// PopulateChromeWebUIFrameInterfaceBrokers() registers BrowserInterfaceBrokers
-// for each WebUI, these brokers are used to handle that WebUI's JavaScript
-// Mojo.bindInterface calls.
-void PopulateChromeWebUIFrameInterfaceBrokers(
+// PopulateTrustedChromeWebUIFrameInterfaceBrokers() registers
+// BrowserInterfaceBrokers for each trusted WebUI, these brokers are used to
+// handle that WebUI's JavaScript Mojo.bindInterface calls.
+void PopulateTrustedChromeWebUIFrameInterfaceBrokers(
+    content::WebUIBrowserInterfaceBrokerRegistry& registry);
+
+// PopulateUntrustedChromeWebUIFrameInterfaceBrokers() registers
+// BrowserInterfaceBrokers for each untrusted WebUI, these brokers are used to
+// handle that WebUI's JavaScript Mojo.bindInterface calls.
+void PopulateUntrustedChromeWebUIFrameInterfaceBrokers(
     content::WebUIBrowserInterfaceBrokerRegistry& registry);
 
 } // namespace chrome::internal
diff --git a/chrome/browser/chrome_browser_interface_binders_webui_parts_desktop.cc b/chrome/browser/chrome_browser_interface_binders_webui_parts_desktop.cc
index 315433ebd..deb0f86a 100644
--- a/chrome/browser/chrome_browser_interface_binders_webui_parts_desktop.cc
+++ b/chrome/browser/chrome_browser_interface_binders_webui_parts_desktop.cc
@@ -611,6 +611,16 @@
                CustomizeColorSchemeModeHandlerFactory>()
       .Add<help_bubble::mojom::HelpBubbleHandlerFactory>();
 
+  if (webui_browser::IsWebUIBrowserEnabled()) {
+    registry.ForWebUI<WebUIBrowserUI>()
+        .Add<webui_browser::mojom::PageHandlerFactory>()
+        .Add<bookmark_bar::mojom::PageHandlerFactory>()
+        .Add<extensions_bar::mojom::PageHandlerFactory>()
+        .Add<searchbox::mojom::PageHandler>()
+        .Add<tabs_api::mojom::TabStripService>()
+        .Add<tracked_element::mojom::TrackedElementHandler>();
+  }
+
   // TODO(crbug.com/452983498): Migrate all remaining
   // RegisterWebUIControllerInterfaceBinder calls to registry.ForWebUI().Add()
   // calls.
@@ -618,6 +628,9 @@
 
 void PopulateChromeWebUIFrameInterfaceBrokersUntrustedPartsDesktop(
     content::WebUIBrowserInterfaceBrokerRegistry& registry) {
+  registry.AddGlobal<color_change_listener::mojom::PageHandler>(
+      base::BindRepeating(&BindColorChangeListener));
+
   if (lens::features::IsLensOverlayEnabled()) {
     registry.ForWebUI<lens::LensSidePanelUntrustedUI>()
         .Add<lens::mojom::LensSidePanelPageHandlerFactory>()
@@ -644,16 +657,6 @@
       .Add<new_tab_page::mojom::
                MicrosoftAuthUntrustedDocumentInterfacesFactory>();
 
-  if (webui_browser::IsWebUIBrowserEnabled()) {
-    registry.ForWebUI<WebUIBrowserUI>()
-        .Add<webui_browser::mojom::PageHandlerFactory>()
-        .Add<bookmark_bar::mojom::PageHandlerFactory>()
-        .Add<extensions_bar::mojom::PageHandlerFactory>()
-        .Add<searchbox::mojom::PageHandler>()
-        .Add<tabs_api::mojom::TabStripService>()
-        .Add<tracked_element::mojom::TrackedElementHandler>();
-  }
-
   if (features::IsWebUIReloadButtonEnabled()) {
     registry.ForWebUI<ReloadButtonUI>()
         .Add<reload_button::mojom::PageHandlerFactory>();
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index b522748..d347c428 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -75,7 +75,6 @@
 #include "chrome/browser/ui/webui/chrome_untrusted_web_ui_configs.h"
 #include "chrome/browser/ui/webui/chrome_web_ui_configs.h"
 #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
-#include "chrome/browser/updater/updater.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_result_codes.h"
@@ -220,7 +219,6 @@
 #include <Security/Security.h>
 
 #include "chrome/browser/mac/chrome_browser_main_extra_parts_mac.h"
-#include "chrome/browser/ui/cocoa/keystone_infobar_delegate.h"
 #include "chrome/browser/ui/ui_features.h"
 
 #if defined(ARCH_CPU_X86_64)
@@ -300,6 +298,10 @@
 #include "components/rlz/rlz_tracker.h"  // nogncheck crbug.com/1125897
 #endif
 
+#if BUILDFLAG(ENABLE_UPDATER)
+#include "chrome/browser/updater/scheduler.h"
+#endif
+
 #if defined(TOOLKIT_VIEWS)
 #include "chrome/browser/ui/views/chrome_browser_main_extra_parts_views.h"
 #endif
@@ -994,13 +996,9 @@
   for (auto& chrome_extra_part : chrome_extra_parts_)
     chrome_extra_part->PreCreateMainMessageLoop();
 
-  updater::SchedulePeriodicTasks(
-#if BUILDFLAG(IS_MAC) && BUILDFLAG(ENABLE_UPDATER)
-      base::BindRepeating(&ShowUpdaterPromotionInfoBar)
-#else
-      base::DoNothing()
+#if BUILDFLAG(ENABLE_UPDATER)
+  updater::SchedulePeriodicTasks();
 #endif
-  );
 }
 
 void ChromeBrowserMainParts::PostCreateMainMessageLoop() {
diff --git a/chrome/browser/chrome_browser_main_mac.mm b/chrome/browser/chrome_browser_main_mac.mm
index 91ee1fc0..e26e3625 100644
--- a/chrome/browser/chrome_browser_main_mac.mm
+++ b/chrome/browser/chrome_browser_main_mac.mm
@@ -32,7 +32,7 @@
 #include "chrome/browser/mac/metrics.h"
 #include "chrome/browser/ui/cocoa/main_menu_builder.h"
 #include "chrome/browser/ui/cocoa/renderer_context_menu/chrome_swizzle_services_menu_updater.h"
-#include "chrome/browser/updater/updater.h"
+#include "chrome/browser/updater/browser_updater_client_util.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index b4987a0..f13df8a1 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -610,7 +610,9 @@
   void RegisterBrowserInterfaceBindersForFrame(
       content::RenderFrameHost* render_frame_host,
       mojo::BinderMapWithContext<content::RenderFrameHost*>* map) override;
-  void RegisterWebUIInterfaceBrokers(
+  void RegisterTrustedWebUIInterfaceBrokers(
+      content::WebUIBrowserInterfaceBrokerRegistry& registry) override;
+  void RegisterUntrustedWebUIInterfaceBrokers(
       content::WebUIBrowserInterfaceBrokerRegistry& registry) override;
   void RegisterMojoBinderPoliciesForSameOriginPrerendering(
       content::MojoBinderPolicyMap& policy_map) override;
diff --git a/chrome/browser/chrome_content_browser_client_receiver_bindings.cc b/chrome/browser/chrome_content_browser_client_receiver_bindings.cc
index a3f1a89..cf8ed19c 100644
--- a/chrome/browser/chrome_content_browser_client_receiver_bindings.cc
+++ b/chrome/browser/chrome_content_browser_client_receiver_bindings.cc
@@ -353,9 +353,14 @@
 #endif
 }
 
-void ChromeContentBrowserClient::RegisterWebUIInterfaceBrokers(
+void ChromeContentBrowserClient::RegisterTrustedWebUIInterfaceBrokers(
     content::WebUIBrowserInterfaceBrokerRegistry& registry) {
-  chrome::internal::PopulateChromeWebUIFrameInterfaceBrokers(registry);
+  chrome::internal::PopulateTrustedChromeWebUIFrameInterfaceBrokers(registry);
+}
+
+void ChromeContentBrowserClient::RegisterUntrustedWebUIInterfaceBrokers(
+    content::WebUIBrowserInterfaceBrokerRegistry& registry) {
+  chrome::internal::PopulateUntrustedChromeWebUIFrameInterfaceBrokers(registry);
 }
 
 void ChromeContentBrowserClient::
diff --git a/chrome/browser/chromeos/extensions/vpn_provider/vpn_service.cc b/chrome/browser/chromeos/extensions/vpn_provider/vpn_service.cc
index 459f426..8a4af930 100644
--- a/chrome/browser/chromeos/extensions/vpn_provider/vpn_service.cc
+++ b/chrome/browser/chromeos/extensions/vpn_provider/vpn_service.cc
@@ -134,6 +134,8 @@
 
 VpnService::VpnService(content::BrowserContext* browser_context)
     : browser_context_(browser_context) {
+  GetVpnService()->SetController(this);
+
   auto* registry = extensions::ExtensionRegistry::Get(browser_context);
   extension_registry_observer_.Observe(registry);
 
@@ -143,7 +145,10 @@
   }
 }
 
-VpnService::~VpnService() = default;
+VpnService::~VpnService() {
+  key_to_configuration_map_.clear();
+  GetVpnService()->Reset();
+}
 
 void VpnService::SendShowAddDialogToExtension(const std::string& extension_id) {
   SendToExtension(
diff --git a/chrome/browser/chromeos/extensions/vpn_provider/vpn_service.h b/chrome/browser/chromeos/extensions/vpn_provider/vpn_service.h
index a6acdcfb..c565407 100644
--- a/chrome/browser/chromeos/extensions/vpn_provider/vpn_service.h
+++ b/chrome/browser/chromeos/extensions/vpn_provider/vpn_service.h
@@ -15,6 +15,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observation.h"
 #include "base/values.h"
+#include "chrome/browser/ash/crosapi/vpn_service_ash.h"
 #include "chrome/browser/chromeos/extensions/vpn_provider/vpn_service_interface.h"
 #include "chromeos/crosapi/mojom/vpn_service.mojom.h"
 #include "extensions/browser/event_router.h"
@@ -124,6 +125,14 @@
   // EventRouter::Observer:
   void OnListenerAdded(const extensions::EventListenerInfo&) override;
 
+  // Owns all configurations. Key is a hash of |extension_id| and
+  // |configuration_name|. This is public temporarily while we are dismantling
+  // the crosapi VpnService (crbug.com/365902693).
+  using StringToOwnedConfigurationMap = std::map<
+      std::string,
+      std::unique_ptr<crosapi::VpnServiceForExtensionAsh::VpnConfiguration>>;
+  StringToOwnedConfigurationMap key_to_configuration_map_;
+
  private:
   friend class VpnProviderApiTest;
   friend class VpnServiceForExtension;
diff --git a/chrome/browser/contextual_tasks/contextual_tasks_side_panel_coordinator.cc b/chrome/browser/contextual_tasks/contextual_tasks_side_panel_coordinator.cc
index c9672c92..3b58ff9 100644
--- a/chrome/browser/contextual_tasks/contextual_tasks_side_panel_coordinator.cc
+++ b/chrome/browser/contextual_tasks/contextual_tasks_side_panel_coordinator.cc
@@ -279,7 +279,7 @@
 }
 
 content::WebContents*
-ContextualTasksSidePanelCoordinator::GetActiveWebContentsForTesting() {
+ContextualTasksSidePanelCoordinator::GetActiveWebContents() {
   return web_view_ ? web_view_->web_contents() : nullptr;
 }
 
diff --git a/chrome/browser/contextual_tasks/contextual_tasks_side_panel_coordinator.h b/chrome/browser/contextual_tasks/contextual_tasks_side_panel_coordinator.h
index 1ce8274..38299b0 100644
--- a/chrome/browser/contextual_tasks/contextual_tasks_side_panel_coordinator.h
+++ b/chrome/browser/contextual_tasks/contextual_tasks_side_panel_coordinator.h
@@ -90,7 +90,7 @@
   void PrimaryPageChanged(content::Page& page) override;
   void TitleWasSet(content::NavigationEntry* entry) override;
 
-  content::WebContents* GetActiveWebContentsForTesting();
+  content::WebContents* GetActiveWebContents();
 
   // Detaches the WebContents for the given task and returns it.
   std::unique_ptr<content::WebContents> DetachWebContentsForTask(
diff --git a/chrome/browser/contextual_tasks/contextual_tasks_side_panel_coordinator_interactive_uitest.cc b/chrome/browser/contextual_tasks/contextual_tasks_side_panel_coordinator_interactive_uitest.cc
index e0cda3a..04bf3bc1 100644
--- a/chrome/browser/contextual_tasks/contextual_tasks_side_panel_coordinator_interactive_uitest.cc
+++ b/chrome/browser/contextual_tasks/contextual_tasks_side_panel_coordinator_interactive_uitest.cc
@@ -121,8 +121,7 @@
   ContextualTasksUI* GetContextualTasksUI() {
     ContextualTasksSidePanelCoordinator* coordinator =
         ContextualTasksSidePanelCoordinator::From(browser());
-    content::WebContents* web_contents =
-        coordinator->GetActiveWebContentsForTesting();
+    content::WebContents* web_contents = coordinator->GetActiveWebContents();
     if (!web_contents) {
       return nullptr;
     }
@@ -161,14 +160,14 @@
       WaitForShow(kContextualTasksSidePanelWebViewElementId), Do([&]() {
         // Verify the first side panel WebContents is created for the first tab.
         content::WebContents* side_panel_web_contents1 =
-            coordinator->GetActiveWebContentsForTesting();
+            coordinator->GetActiveWebContents();
         ASSERT_NE(nullptr, side_panel_web_contents1);
 
         // Activate the second tab, verify the second side panel WebContents is
         // created for the second tab.
         browser()->tab_strip_model()->ActivateTabAt(1);
         content::WebContents* side_panel_web_contents2 =
-            coordinator->GetActiveWebContentsForTesting();
+            coordinator->GetActiveWebContents();
         ASSERT_NE(nullptr, side_panel_web_contents2);
         ASSERT_NE(side_panel_web_contents1, side_panel_web_contents2);
 
@@ -176,7 +175,7 @@
         // swapped back.
         browser()->tab_strip_model()->ActivateTabAt(0);
         ASSERT_EQ(side_panel_web_contents1,
-                  coordinator->GetActiveWebContentsForTesting());
+                  coordinator->GetActiveWebContents());
       }));
 }
 
@@ -344,7 +343,7 @@
       }),
       WaitForShow(kContextualTasksSidePanelWebViewElementId), Do([&]() {
         // Verify the side panel can still open.
-        ASSERT_NE(nullptr, coordinator->GetActiveWebContentsForTesting());
+        ASSERT_NE(nullptr, coordinator->GetActiveWebContents());
       }));
 }
 
@@ -401,8 +400,7 @@
         EXPECT_EQ(5, tab_strip_model->count());
 
         // Verify the tab web contents is transferred into the side panel.
-        EXPECT_EQ(tab_web_contents,
-                  coordinator->GetActiveWebContentsForTesting());
+        EXPECT_EQ(tab_web_contents, coordinator->GetActiveWebContents());
 
         // Verify the tab web contents is still associated with task3.
         EXPECT_TRUE(contextual_tasks_controller->GetContextualTaskForTab(
@@ -474,8 +472,7 @@
         EXPECT_EQ(5, tab_strip_model->count());
 
         // Verify the tab web contents is transferred into the side panel.
-        EXPECT_EQ(tab_web_contents,
-                  coordinator->GetActiveWebContentsForTesting());
+        EXPECT_EQ(tab_web_contents, coordinator->GetActiveWebContents());
 
         // Moving the WebContents to the side panel should also clear the back
         // stack.
@@ -495,7 +492,7 @@
       }),
       WaitForShow(kContextualTasksSidePanelWebViewElementId), Do([&]() {
         content::WebContents* web_contents1 =
-            coordinator->GetActiveWebContentsForTesting();
+            coordinator->GetActiveWebContents();
         // Change current task from task1 to a new task.
         ContextualTasksContextController* contextual_tasks_controller =
             ContextualTasksContextControllerFactory::GetForProfile(
@@ -510,12 +507,12 @@
 
         // Activate tab1, it associates with the task2 WebContents.
         browser()->tab_strip_model()->ActivateTabAt(1);
-        EXPECT_NE(web_contents1, coordinator->GetActiveWebContentsForTesting());
+        EXPECT_NE(web_contents1, coordinator->GetActiveWebContents());
         EXPECT_TRUE(coordinator->IsSidePanelOpen());
 
         // Activate tab0, it associates with the new WebContents.
         browser()->tab_strip_model()->ActivateTabAt(0);
-        EXPECT_EQ(web_contents1, coordinator->GetActiveWebContentsForTesting());
+        EXPECT_EQ(web_contents1, coordinator->GetActiveWebContents());
         EXPECT_TRUE(coordinator->IsSidePanelOpen());
       }));
 }
@@ -532,7 +529,7 @@
       }),
       WaitForShow(kContextualTasksSidePanelWebViewElementId), Do([&]() {
         content::WebContents* web_contents1 =
-            coordinator->GetActiveWebContentsForTesting();
+            coordinator->GetActiveWebContents();
         // Change current task from task1 to task2.
         ContextualTasksContextController* contextual_tasks_controller =
             ContextualTasksContextControllerFactory::GetForProfile(
@@ -546,12 +543,12 @@
 
         // Activate tab1, now it associates with the current WebContents.
         browser()->tab_strip_model()->ActivateTabAt(1);
-        EXPECT_EQ(web_contents1, coordinator->GetActiveWebContentsForTesting());
+        EXPECT_EQ(web_contents1, coordinator->GetActiveWebContents());
         EXPECT_TRUE(coordinator->IsSidePanelOpen());
 
         // Activate tab0, it still associates with the current WebContents.
         browser()->tab_strip_model()->ActivateTabAt(0);
-        EXPECT_EQ(web_contents1, coordinator->GetActiveWebContentsForTesting());
+        EXPECT_EQ(web_contents1, coordinator->GetActiveWebContents());
         EXPECT_TRUE(coordinator->IsSidePanelOpen());
       }));
 }
@@ -636,7 +633,7 @@
       }),
       WaitForShow(kContextualTasksSidePanelWebViewElementId), Do([&]() {
         content::WebContents* web_contents1 =
-            coordinator->GetActiveWebContentsForTesting();
+            coordinator->GetActiveWebContents();
         ContextualTasksContextController* contextual_tasks_controller =
             ContextualTasksContextControllerFactory::GetForProfile(
                 browser()->profile());
@@ -656,7 +653,7 @@
 
         // Activate tab1, verify the side panel cache is still present.
         browser()->tab_strip_model()->ActivateTabAt(1);
-        EXPECT_EQ(web_contents1, coordinator->GetActiveWebContentsForTesting());
+        EXPECT_EQ(web_contents1, coordinator->GetActiveWebContents());
 
         SessionID tab_id1 = sessions::SessionTabHelper::IdForTab(
             browser()->tab_strip_model()->GetWebContentsAt(1));
@@ -672,7 +669,7 @@
             std::nullopt,
             contextual_tasks_controller->GetContextualTaskForTab(tab_id1));
 
-        EXPECT_EQ(nullptr, coordinator->GetActiveWebContentsForTesting());
+        EXPECT_EQ(nullptr, coordinator->GetActiveWebContents());
       }));
 }
 
@@ -758,7 +755,7 @@
       WaitForShow(kContextualTasksSidePanelWebViewElementId), Do([&]() {
         // Verify the first side panel WebContents is created for the first tab.
         content::WebContents* side_panel_web_contents1 =
-            coordinator->GetActiveWebContentsForTesting();
+            coordinator->GetActiveWebContents();
         ASSERT_NE(nullptr, side_panel_web_contents1);
         EXPECT_EQ(true, coordinator->IsSidePanelOpenForContextualTask());
 
@@ -766,7 +763,7 @@
         // created for the second tab.
         browser()->tab_strip_model()->ActivateTabAt(1);
         content::WebContents* side_panel_web_contents2 =
-            coordinator->GetActiveWebContentsForTesting();
+            coordinator->GetActiveWebContents();
         ASSERT_NE(nullptr, side_panel_web_contents2);
         ASSERT_NE(side_panel_web_contents1, side_panel_web_contents2);
         EXPECT_EQ(true, coordinator->IsSidePanelOpenForContextualTask());
@@ -775,7 +772,7 @@
         // swapped back.
         browser()->tab_strip_model()->ActivateTabAt(2);
         ASSERT_EQ(side_panel_web_contents1,
-                  coordinator->GetActiveWebContentsForTesting());
+                  coordinator->GetActiveWebContents());
         EXPECT_EQ(true, coordinator->IsSidePanelOpenForContextualTask());
 
         // Close the side panel for the third tab.
diff --git a/chrome/browser/contextual_tasks/contextual_tasks_ui_service.cc b/chrome/browser/contextual_tasks/contextual_tasks_ui_service.cc
index 389fdd6..6a4cd705 100644
--- a/chrome/browser/contextual_tasks/contextual_tasks_ui_service.cc
+++ b/chrome/browser/contextual_tasks/contextual_tasks_ui_service.cc
@@ -550,17 +550,45 @@
 void ContextualTasksUiService::StartTaskUiInSidePanel(
     BrowserWindowInterface* browser_window_interface,
     tabs::TabInterface* tab_interface,
-    const GURL& url) {
+    const GURL& url,
+    std::unique_ptr<contextual_search::ContextualSearchSessionHandle>
+        session_handle) {
   CHECK(context_controller_);
 
-  // Create a task for the URL that was just intercepted.
-  ContextualTask task = context_controller_->CreateTaskFromUrl(url);
-  task_id_to_creation_url_[task.GetTaskId()] = url;
+  // Get the coordinator for the current window.
+  auto* coordinator =
+      ContextualTasksSidePanelCoordinator::From(browser_window_interface);
+  auto* panel_contents = coordinator->GetActiveWebContents();
 
-  // Associate the task with the active tab.
-  AssociateWebContentsToTask(tab_interface->GetContents(), task.GetTaskId());
+  // Create a task for the URL if the side panel wasn't already showing a task.
+  if (!panel_contents || !coordinator->IsSidePanelOpenForContextualTask()) {
+    ContextualTask task = context_controller_->CreateTaskFromUrl(url);
+    task_id_to_creation_url_[task.GetTaskId()] = url;
+    AssociateWebContentsToTask(tab_interface->GetContents(), task.GetTaskId());
+    coordinator->Show();
 
-  ContextualTasksSidePanelCoordinator::From(browser_window_interface)->Show();
+    // Associate the web contents with the task and set the session handle if
+    // provided.
+    content::WebContents* web_contents = coordinator->GetActiveWebContents();
+    AssociateWebContentsToTask(panel_contents, task.GetTaskId());
+    if (session_handle) {
+      ContextualSearchWebContentsHelper::GetOrCreateForWebContents(web_contents)
+          ->set_session_handle(std::move(session_handle));
+    }
+    return;
+  }
+
+  // If the side panel contents already exist, get the WebUI controller to
+  // load the URL into the already loaded contextual tasks UI.
+  ContextualTasksUI* webui_controller = nullptr;
+  if (panel_contents->GetWebUI()) {
+    webui_controller =
+        panel_contents->GetWebUI()->GetController()->GetAs<ContextualTasksUI>();
+    content::OpenURLParams url_params(
+        url, content::Referrer(), WindowOpenDisposition::CURRENT_TAB,
+        ui::PAGE_TRANSITION_LINK, /*is_renderer_initiated=*/false);
+    webui_controller->TransferNavigationToEmbeddedPage(url_params);
+  }
 }
 
 bool ContextualTasksUiService::IsAiUrl(const GURL& url) {
diff --git a/chrome/browser/contextual_tasks/contextual_tasks_ui_service.h b/chrome/browser/contextual_tasks/contextual_tasks_ui_service.h
index 16fc7a4..93bc575 100644
--- a/chrome/browser/contextual_tasks/contextual_tasks_ui_service.h
+++ b/chrome/browser/contextual_tasks/contextual_tasks_ui_service.h
@@ -10,6 +10,7 @@
 #include "base/functional/callback.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/contextual_tasks/contextual_tasks.mojom.h"
+#include "components/contextual_search/contextual_search_session_handle.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "content/public/browser/frame_tree_node_id.h"
 #include "url/gurl.h"
@@ -123,7 +124,9 @@
   virtual void StartTaskUiInSidePanel(
       BrowserWindowInterface* browser_window_interface,
       tabs::TabInterface* tab_interface,
-      const GURL& url);
+      const GURL& url,
+      std::unique_ptr<contextual_search::ContextualSearchSessionHandle>
+          session_handle);
 
   // Returns whether the provided URL is to an AI page.
   bool IsAiUrl(const GURL& url);
diff --git a/chrome/browser/contextual_tasks/contextual_tasks_ui_service_interactive_uitest.cc b/chrome/browser/contextual_tasks/contextual_tasks_ui_service_interactive_uitest.cc
index fc26e31..8b940670 100644
--- a/chrome/browser/contextual_tasks/contextual_tasks_ui_service_interactive_uitest.cc
+++ b/chrome/browser/contextual_tasks/contextual_tasks_ui_service_interactive_uitest.cc
@@ -114,7 +114,7 @@
                               task1.GetTaskId().AsLowercaseString());
         content::NavigationController::LoadURLParams load_params(source_url);
         content::WebContents* panel_contents =
-            coordinator->GetActiveWebContentsForTesting();
+            coordinator->GetActiveWebContents();
         panel_contents->GetController().LoadURLWithParams(load_params);
         content::WaitForLoadStop(panel_contents);
 
@@ -236,21 +236,73 @@
           browser()->profile());
   ASSERT_TRUE(service);
 
+  const GURL search_url("https://google.com/search");
+
   // Call StartTaskUiInSidePanel and verify that the side panel is shown and the
   // task is associated with the active tab.
+  RunTestSequence(
+      Do([&]() {
+        service->StartTaskUiInSidePanel(
+            browser(), browser()->GetActiveTabInterface(), search_url, nullptr);
+      }),
+      WaitForShow(kContextualTasksSidePanelWebViewElementId), Do([&]() {
+        ContextualTasksSidePanelCoordinator* coordinator =
+            ContextualTasksSidePanelCoordinator::From(browser());
+        EXPECT_TRUE(coordinator->IsSidePanelOpenForContextualTask());
+
+        SessionID tab_id = sessions::SessionTabHelper::IdForTab(
+            browser()->tab_strip_model()->GetActiveWebContents());
+        std::optional<ContextualTask> task =
+            contextual_tasks_controller->GetContextualTaskForTab(tab_id);
+        EXPECT_TRUE(task.has_value());
+        EXPECT_EQ(service->GetInitialUrlForTask(task->GetTaskId()), search_url);
+      }));
+}
+
+IN_PROC_BROWSER_TEST_F(ContextualTasksUiServiceInteractiveUiTest,
+                       StartTaskUiInSidePanel_WhenSidePanelIsOpen) {
+  // Add a new tab.
+  chrome::AddTabAt(browser(), GURL(chrome::kChromeUISettingsURL), -1, false);
+
+  ContextualTasksContextController* contextual_tasks_controller =
+      ContextualTasksContextControllerFactory::GetForProfile(
+          browser()->profile());
+  ContextualTasksUiService* service =
+      ContextualTasksUiServiceFactory::GetForBrowserContext(
+          browser()->profile());
+  ASSERT_TRUE(service);
+
   const GURL search_url("https://google.com/search");
-  service->StartTaskUiInSidePanel(browser(), browser()->GetActiveTabInterface(),
-                                  search_url);
+  RunTestSequence(
+      Do([&]() {
+        service->StartTaskUiInSidePanel(
+            browser(), browser()->GetActiveTabInterface(), search_url, nullptr);
+      }),
+      WaitForShow(kContextualTasksSidePanelWebViewElementId), Do([&]() {
+        ContextualTasksSidePanelCoordinator* coordinator =
+            ContextualTasksSidePanelCoordinator::From(browser());
+        EXPECT_TRUE(coordinator->IsSidePanelOpenForContextualTask());
 
-  ContextualTasksSidePanelCoordinator* coordinator =
-      ContextualTasksSidePanelCoordinator::From(browser());
-  EXPECT_TRUE(coordinator->IsSidePanelOpenForContextualTask());
+        SessionID tab_id = sessions::SessionTabHelper::IdForTab(
+            browser()->tab_strip_model()->GetActiveWebContents());
+        std::optional<ContextualTask> task =
+            contextual_tasks_controller->GetContextualTaskForTab(tab_id);
+        EXPECT_TRUE(task.has_value());
+        base::Uuid initial_task_id = task->GetTaskId();
 
-  SessionID tab_id = sessions::SessionTabHelper::IdForTab(
-      browser()->tab_strip_model()->GetActiveWebContents());
-  std::optional<ContextualTask> task =
-      contextual_tasks_controller->GetContextualTaskForTab(tab_id);
-  EXPECT_TRUE(task.has_value());
+        // Call StartTaskUiInSidePanel again.
+        const GURL search_url2("https://google.com/search?q=foo");
+        service->StartTaskUiInSidePanel(browser(),
+                                        browser()->GetActiveTabInterface(),
+                                        search_url2, nullptr);
+
+        // Verify that the task ID is still the same.
+        std::optional<ContextualTask> task2 =
+            contextual_tasks_controller->GetContextualTaskForTab(tab_id);
+        EXPECT_TRUE(task2.has_value());
+        EXPECT_EQ(task2->GetTaskId(), initial_task_id);
+        EXPECT_TRUE(coordinator->IsSidePanelOpenForContextualTask());
+      }));
 }
 
 IN_PROC_BROWSER_TEST_F(ContextualTasksUiServiceInteractiveUiTest,
@@ -273,7 +325,7 @@
       }),
       WaitForShow(kContextualTasksSidePanelWebViewElementId), Do([&]() {
         content::WebContents* web_contents =
-            coordinator->GetActiveWebContentsForTesting();
+            coordinator->GetActiveWebContents();
         ContextualTasksUI* ui = static_cast<ContextualTasksUI*>(
             web_contents->GetWebUI()->GetController());
 
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc
index e110a74d..0afa228 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -54,11 +54,30 @@
 #endif
 
 #if !BUILDFLAG(IS_ANDROID)
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/types/expected_macros.h"
 #include "chrome/browser/platform_util.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/browser/ui/browser_navigator_params.h"
+#include "chrome/browser/ui/browser_window/public/create_browser_window.h"
+#include "chrome/browser/ui/tabs/tab_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/web_applications/app_browser_controller.h"
+#include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
+#include "chrome/browser/ui/window_sizer/window_sizer.h"
+#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h"
+#include "chrome/browser/web_applications/web_app_filter.h"
+#include "chrome/browser/web_applications/web_app_helpers.h"
+#include "chrome/browser/web_applications/web_app_provider.h"
+#include "chrome/browser/web_applications/web_app_registrar.h"
+#include "components/webapps/isolated_web_apps/scheme.h"
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS)
+#include "ash/constants/ash_features.h"
+#include "ash/wm/window_pin_util.h"
 #include "chrome/browser/ash/boca/on_task/locked_quiz_session_manager_factory.h"
 #include "chrome/browser/ui/browser.h"
 #endif  // BUILDFLAG(IS_CHROMEOS)
@@ -80,6 +99,72 @@
 
 namespace {
 
+#if BUILDFLAG(IS_CHROMEOS)
+constexpr char kWindowCreateLockedFullscreenUrlCountMismatchError[] =
+    "When creating a new window in locked fullscreen mode, exactly one URL "
+    "should be supplied.";
+#endif  // BUILDFLAG(IS_CHROMEOS)
+
+#if !BUILDFLAG(IS_ANDROID)
+
+constexpr char kInvalidWindowTypeError[] = "Invalid value for type";
+constexpr char kWindowCreateSupportsOnlySingleIwaUrlError[] =
+    "When creating a window for a URL with the 'isolated-app:' scheme, only "
+    "one tab can be added to the window.";
+constexpr char kWindowCreateCannotParseIwaUrlError[] =
+    "Unable to parse 'isolated-app:' URL: %s";
+constexpr char kWindowCreateCannotUseTabIdWithIwaError[] =
+    "Creating a new window for an Isolated Web App does not support adding a "
+    "tab by its ID.";
+constexpr char kWindowCreateCannotMoveIwaTabError[] =
+    "The tab of an Isolated Web App cannot be moved to a new window.";
+
+bool IsValidStateForWindowsCreateFunction(
+    const windows::Create::Params::CreateData* create_data) {
+  if (!create_data) {
+    return true;
+  }
+
+  bool has_bound = create_data->left || create_data->top ||
+                   create_data->width || create_data->height;
+
+  switch (create_data->state) {
+    case windows::WindowState::kMinimized:
+      // If minimised, default focused state should be unfocused.
+      return !(create_data->focused && *create_data->focused) && !has_bound;
+    case windows::WindowState::kMaximized:
+    case windows::WindowState::kFullscreen:
+    case windows::WindowState::kLockedFullscreen:
+      // If maximised/fullscreen, default focused state should be focused.
+      return !(create_data->focused && !*create_data->focused) && !has_bound;
+    case windows::WindowState::kNormal:
+    case windows::WindowState::kNone:
+      return true;
+  }
+  NOTREACHED();
+}
+
+class ScopedPinBrowserAtFront {
+ public:
+  explicit ScopedPinBrowserAtFront(BrowserWindowInterface* bwi)
+      : bwi_(bwi->GetWeakPtr()) {
+    old_z_order_level_ = bwi->GetWindow()->GetZOrderLevel();
+    bwi->GetWindow()->SetZOrderLevel(ui::ZOrderLevel::kFloatingWindow);
+  }
+
+  ~ScopedPinBrowserAtFront() {
+    if (bwi_) {
+      bwi_->GetWindow()->SetZOrderLevel(old_z_order_level_);
+    }
+  }
+
+ private:
+  base::WeakPtr<BrowserWindowInterface> bwi_;
+  ui::ZOrderLevel old_z_order_level_;
+};
+
+#endif  // !BUILDFLAG(IS_ANDROID)
+
 // Returns true if either |boolean| is disengaged, or if |boolean| and
 // |value| are equal. This function is used to check if a tab's parameters match
 // those of the browser.
@@ -500,6 +585,502 @@
   return RespondNow(WithArguments(std::move(window_list)));
 }
 
+ExtensionFunction::ResponseAction WindowsCreateFunction::Run() {
+  std::optional<windows::Create::Params> params =
+      windows::Create::Params::Create(args());
+  EXTENSION_FUNCTION_VALIDATE(params);
+// TODO(https://crbug.com/431004500): Port this to desktop android.
+#if BUILDFLAG(IS_ANDROID)
+  return RespondNow(Error("chrome.windows not implemented"));
+#else
+  std::vector<GURL> urls;
+  int tab_index = -1;
+
+  DCHECK(extension() || source_context_type() == mojom::ContextType::kWebUi ||
+         source_context_type() == mojom::ContextType::kUntrustedWebUi);
+  std::optional<windows::Create::Params::CreateData>& create_data =
+      params->create_data;
+
+  std::optional<web_app::IsolatedWebAppUrlInfo> isolated_web_app_url_info;
+
+  // Look for optional url.
+  if (create_data && create_data->url) {
+    std::vector<std::string> url_strings;
+    // First, get all the URLs the client wants to open.
+    if (create_data->url->as_string) {
+      url_strings.push_back(std::move(*create_data->url->as_string));
+    } else if (create_data->url->as_strings) {
+      url_strings = std::move(*create_data->url->as_strings);
+    }
+
+    // Second, resolve, validate and convert them to GURLs.
+    for (auto& url_string : url_strings) {
+      auto url = ExtensionTabUtil::PrepareURLForNavigation(
+          url_string, extension(), browser_context());
+      if (!url.has_value()) {
+        return RespondNow(Error(std::move(url.error())));
+      }
+      if (url->SchemeIs(webapps::kIsolatedAppScheme)) {
+        if (url_strings.size() > 1) {
+          return RespondNow(Error(kWindowCreateSupportsOnlySingleIwaUrlError));
+        }
+
+        base::expected<web_app::IsolatedWebAppUrlInfo, std::string>
+            maybe_url_info = web_app::IsolatedWebAppUrlInfo::Create(*url);
+        if (!maybe_url_info.has_value()) {
+          return RespondNow(
+              Error(base::StringPrintf(kWindowCreateCannotParseIwaUrlError,
+                                       maybe_url_info.error().c_str())));
+        }
+        isolated_web_app_url_info = *maybe_url_info;
+      }
+      urls.push_back(*url);
+    }
+  }
+
+  // Decide whether we are opening a normal window or an incognito window.
+  std::string error;
+  Profile* calling_profile = Profile::FromBrowserContext(browser_context());
+  windows_util::IncognitoResult incognito_result =
+      windows_util::ShouldOpenIncognitoWindow(
+          calling_profile,
+          create_data && create_data->incognito
+              ? std::optional<bool>(*create_data->incognito)
+              : std::nullopt,
+          &urls, &error);
+  if (incognito_result == windows_util::IncognitoResult::kError) {
+    return RespondNow(Error(std::move(error)));
+  }
+
+  Profile* window_profile =
+      incognito_result == windows_util::IncognitoResult::kIncognito
+          ? calling_profile->GetPrimaryOTRProfile(/*create_if_needed=*/true)
+          : calling_profile;
+
+  if (!IsValidStateForWindowsCreateFunction(base::OptionalToPtr(create_data))) {
+    return RespondNow(Error(tabs_constants::kInvalidWindowStateError));
+  }
+
+  // Look for optional tab id.
+  bool is_locked_fullscreen =
+      create_data &&
+      create_data->state == windows::WindowState::kLockedFullscreen;
+  WindowController* source_window = nullptr;
+  if (create_data && create_data->tab_id) {
+    if (isolated_web_app_url_info.has_value()) {
+      return RespondNow(Error(kWindowCreateCannotUseTabIdWithIwaError));
+    }
+
+    // Find the tab. `tab_index` will later be used to move the tab into the
+    // created window.
+    content::WebContents* web_contents = nullptr;
+    if (!tabs_internal::GetTabById(*create_data->tab_id, calling_profile,
+                                   include_incognito_information(),
+                                   &source_window, &web_contents, &tab_index,
+                                   &error)) {
+      return RespondNow(Error(std::move(error)));
+    }
+
+    // Validate the tab information. Return an error if it's not valid.
+    std::string tab_error =
+        ValidateTab(source_window, window_profile, calling_profile,
+                    web_contents, is_locked_fullscreen, urls);
+    if (!tab_error.empty()) {
+      return RespondNow(Error(std::move(tab_error)));
+    }
+  }
+
+  if (is_locked_fullscreen) {
+    if (!tabs_internal::ExtensionHasLockedFullscreenPermission(extension())) {
+      return RespondNow(
+          Error(tabs_internal::kMissingLockWindowFullscreenPrivatePermission));
+    }
+
+#if BUILDFLAG(IS_CHROMEOS)
+    // Set up and launch the OnTask system web app if applicable. The legacy
+    // setup leverages a regular browser instance today.
+    if (ash::features::IsBocaOnTaskLockedQuizMigrationEnabled()) {
+      if (urls.size() != 1) {
+        return RespondNow(
+            Error(kWindowCreateLockedFullscreenUrlCountMismatchError));
+      }
+      ash::boca::LockedQuizSessionManagerFactory::GetInstance()
+          ->GetForBrowserContext(calling_profile)
+          ->OpenLockedQuiz(
+              urls.front(),
+              base::BindOnce(
+                  &WindowsCreateFunction::OnWindowCreatedAsynchronously, this));
+      return RespondLater();
+    }
+#endif  // BUILDFLAG(IS_CHROMEOS)
+  }
+
+  Browser::Type window_type = Browser::TYPE_NORMAL;
+
+  gfx::Rect window_bounds;
+  bool focused = true;
+  std::string extension_id;
+
+  if (create_data) {
+    // Figure out window type before figuring out bounds so that default
+    // bounds can be set according to the window type.
+    switch (create_data->type) {
+      // TODO(stevenjb): Remove 'panel' from windows.json.
+      case windows::CreateType::kPanel:
+      case windows::CreateType::kPopup:
+        window_type = Browser::TYPE_POPUP;
+        if (isolated_web_app_url_info.has_value()) {
+          return RespondNow(Error(kInvalidWindowTypeError));
+        }
+        if (extension()) {
+          extension_id = extension()->id();
+        }
+        break;
+      case windows::CreateType::kNone:
+      case windows::CreateType::kNormal:
+        break;
+      default:
+        return RespondNow(Error(kInvalidWindowTypeError));
+    }
+
+    // Initialize default window bounds according to window type.
+    ui::mojom::WindowShowState ignored_show_state =
+        ui::mojom::WindowShowState::kDefault;
+    WindowSizer::GetBrowserWindowBoundsAndShowState(
+        gfx::Rect(), nullptr, &window_bounds, &ignored_show_state);
+
+    // Update the window bounds based on the create parameters.
+    std::string bounds_error = SetWindowBounds(*create_data, window_bounds);
+    if (!bounds_error.empty()) {
+      return RespondNow(Error(std::move(bounds_error)));
+    }
+
+    if (create_data->focused) {
+      focused = *create_data->focused;
+    }
+
+    // Record the window height and width to determine if we
+    // can set a mininimum value for them (crbug.com/1369103).
+    UMA_HISTOGRAM_COUNTS_1000("Extensions.CreateWindowWidth",
+                              window_bounds.width());
+    UMA_HISTOGRAM_COUNTS_1000("Extensions.CreateWindowHeight",
+                              window_bounds.height());
+  }
+
+  // Create a new BrowserWindow if possible.
+  if (GetBrowserWindowCreationStatusForProfile(*window_profile) !=
+      BrowserWindowInterface::CreationStatus::kOk) {
+    return RespondNow(Error(ExtensionTabUtil::kBrowserWindowNotAllowed));
+  }
+  BrowserWindowCreateParams create_params(window_type, *window_profile,
+                                          user_gesture());
+
+  if (isolated_web_app_url_info.has_value()) {
+    create_params.type = BrowserWindowInterface::TYPE_APP;
+    create_params.app_name = web_app::GenerateApplicationNameFromAppId(
+        isolated_web_app_url_info->app_id());
+    // For Isolated Web Apps, the actual navigating-to URL will be the app's
+    // start_url to prevent deep-linking attacks, while the original URL will be
+    // accessible via window.launchQueue; for this reason the browser is marked
+    // trusted.
+    create_params.is_trusted_source = true;
+  } else if (!extension_id.empty()) {
+    // extension_id is only set for CREATE_TYPE_POPUP.
+    create_params.type = BrowserWindowInterface::TYPE_APP_POPUP;
+    create_params.app_name =
+        web_app::GenerateApplicationNameFromAppId(extension_id);
+    create_params.is_trusted_source = false;
+  }
+  create_params.initial_bounds = window_bounds;
+  create_params.initial_show_state = ui::mojom::WindowShowState::kNormal;
+
+  if (create_data && create_data->state != windows::WindowState::kNone) {
+    create_params.initial_show_state =
+        tabs_internal::ConvertToWindowShowState(create_data->state);
+  }
+
+  BrowserWindowInterface* new_window =
+      CreateBrowserWindow(std::move(create_params));
+  if (!new_window) {
+    return RespondNow(Error(ExtensionTabUtil::kBrowserWindowNotAllowed));
+  }
+  // NOTE: Even though `new_window` was returned, it may not be fully
+  // initialized on non-desktop platforms. See documentation on
+  // CreateBrowserWindow().
+
+  auto create_nav_params =
+      [&](const GURL& url) -> base::expected<NavigateParams, std::string> {
+    NavigateParams navigate_params(new_window, url, ui::PAGE_TRANSITION_LINK);
+    navigate_params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
+    // Ensure that these navigations will not get 'captured' into PWA windows,
+    // as this means that `new_window` could be ignored. It may be
+    // useful/desired in the future to allow this behavior, but this may require
+    // an API change, or at least a re-write of how these navigations are called
+    // to be compatible with the navigation capturing behavior.
+    navigate_params.pwa_navigation_capturing_force_off = true;
+
+    // Depending on the |setSelfAsOpener| option, we need to put the new
+    // contents in the same BrowsingInstance as their opener.  See also
+    // https://crbug.com/713888.
+    bool set_self_as_opener = create_data->set_self_as_opener &&  // present?
+                              *create_data->set_self_as_opener;  // set to true?
+    if (set_self_as_opener) {
+      if (is_from_service_worker()) {
+        // TODO(crbug.com/40636155): Add test for this.
+        return base::unexpected(
+            "Cannot specify setSelfAsOpener Service Worker extension.");
+      }
+      if (isolated_web_app_url_info) {
+        return base::unexpected(
+            "Cannot specify setSelfAsOpener for isolated-app:// URLs.");
+      }
+      // TODO(crbug.com/40636155): Add tests for checking opener SiteInstance
+      // behavior from a SW based extension's extension frame (e.g. from popup).
+      // See ExtensionApiTest.WindowsCreate* tests for details.
+      navigate_params.initiator_origin =
+          extension() ? extension()->origin()
+                      : render_frame_host()->GetLastCommittedOrigin();
+      navigate_params.opener = render_frame_host();
+      navigate_params.source_site_instance =
+          render_frame_host()->GetSiteInstance();
+    }
+
+    return navigate_params;
+  };
+
+  if (!isolated_web_app_url_info) {
+    for (const GURL& url : urls) {
+      ASSIGN_OR_RETURN(
+          NavigateParams navigate_params, create_nav_params(url),
+          [&](const std::string& error) { return RespondNow(Error(error)); });
+      Navigate(&navigate_params);
+    }
+  } else {
+    CHECK_EQ(urls.size(), 1U);
+    const GURL& original_url = urls[0];
+
+    const webapps::AppId& iwa_id = isolated_web_app_url_info->app_id();
+    web_app::WebAppRegistrar& registrar =
+        web_app::WebAppProvider::GetForWebApps(window_profile)
+            ->registrar_unsafe();
+
+    // TODO(crbug.com/424128443): create an dummy tab in the browser so that the
+    // returned window's tab count is always equal to 1 -- this will limit the
+    // extension's ability to figure out which IWAs are installed without the
+    // `tabs` permission.
+    if (registrar.AppMatches(iwa_id, web_app::WebAppFilter::IsIsolatedApp())) {
+      ASSIGN_OR_RETURN(
+          NavigateParams navigate_params,
+          create_nav_params(registrar.GetAppStartUrl(iwa_id)),
+          [&](const std::string& error) { return RespondNow(Error(error)); });
+      base::WeakPtr<content::NavigationHandle> handle =
+          Navigate(&navigate_params);
+      CHECK(handle);
+      web_app::EnqueueLaunchParams(
+          handle->GetWebContents(), iwa_id, original_url,
+          /*wait_for_navigation_to_complete=*/true, handle->NavigationStart());
+    }
+  }
+
+  const ::tabs::TabModel* tab = nullptr;
+  // Move the tab into the created window only if it's an empty popup or it's
+  // a tabbed window.
+  if (window_type == Browser::TYPE_NORMAL || urls.empty()) {
+    if (source_window && source_window->GetBrowser()) {
+      TabStripModel* source_tab_strip =
+          source_window->GetBrowser()->tab_strip_model();
+      CHECK(!isolated_web_app_url_info.has_value());
+      std::unique_ptr<::tabs::TabModel> detached_tab =
+          source_tab_strip->DetachTabAtForInsertion(tab_index);
+      tab = detached_tab.get();
+      TabStripModel* target_tab_strip =
+          ExtensionTabUtil::GetEditableTabStripModel(
+              new_window->GetBrowserForMigrationOnly());
+      if (!target_tab_strip) {
+        return RespondNow(Error(ExtensionTabUtil::kTabStripNotEditableError));
+      }
+      target_tab_strip->InsertDetachedTabAt(
+          urls.size(), std::move(detached_tab), AddTabTypes::ADD_NONE);
+    }
+  }
+  // Create a new tab if the created window is still empty. Don't create a new
+  // tab when it is intended to create an empty popup.
+  if (!tab && urls.empty() && window_type == Browser::TYPE_NORMAL) {
+    // TODO(crbug.com/452431839) Make a new NewTabTypes value for
+    // when new tabs are made because of an empty window.
+    chrome::NewTab(new_window->GetBrowserForMigrationOnly(),
+                   NewTabTypes::kNewTabCommand);
+  }
+  chrome::SelectNumberedTab(
+      new_window->GetBrowserForMigrationOnly(), 0,
+      TabStripUserGestureDetails(
+          TabStripUserGestureDetails::GestureType::kNone));
+
+  if (focused) {
+    new_window->GetWindow()->Show();
+  } else {
+    // Show an unfocused new window.
+    BrowserWindowInterface* const last_active_bwi =
+        GetLastActiveBrowserWindowInterfaceWithAnyProfile();
+
+    // On some OSes the new unfocused window is shown on top by default.
+    // ScopedPinBrowserAtFront prevents the new browser from being shown above
+    // the old active browser.
+    if (last_active_bwi && last_active_bwi->IsActive()) {
+      ScopedPinBrowserAtFront scoper(last_active_bwi);
+      new_window->GetWindow()->ShowInactive();
+    } else {
+      new_window->GetWindow()->ShowInactive();
+    }
+  }
+
+// Despite creating the window with initial_show_state() ==
+// ui::mojom::WindowShowState::kMinimized above, on Linux the window is not
+// created as minimized.
+// TODO(crbug.com/40254339): Remove this workaround when linux is fixed.
+// TODO(crbug.com/40254339): Find a fix for wayland as well.
+#if BUILDFLAG(IS_LINUX) && BUILDFLAG(IS_OZONE_X11)
+  if (new_window->GetBrowserForMigrationOnly()->initial_show_state() ==
+      ui::mojom::WindowShowState::kMinimized) {
+    new_window->GetWindow()->Minimize();
+  }
+#endif  // BUILDFLAG(IS_LINUX) && BUILDFLAG(IS_OZONE_X11)
+
+  // Lock the window fullscreen only after the new tab has been created
+  // (otherwise the tabstrip is empty), and window()->show() has been called
+  // (otherwise that resets the locked mode for devices in tablet mode).
+  // TODO(crbug.com/438540029) - Remove once the migration is complete.
+  if (create_data &&
+      create_data->state == windows::WindowState::kLockedFullscreen) {
+#if BUILDFLAG(IS_CHROMEOS)
+    ash::boca::LockedQuizSessionManagerFactory::GetInstance()
+        ->GetForBrowserContext(calling_profile)
+        ->SetLockedFullscreenState(new_window->GetBrowserForMigrationOnly(),
+                                   /*pinned=*/true);
+#endif  // BUILDFLAG(IS_CHROMEOS)
+  }
+
+  if (new_window->GetProfile()->IsOffTheRecord() &&
+      !browser_context()->IsOffTheRecord() &&
+      !include_incognito_information()) {
+    // Don't expose incognito windows if extension itself works in non-incognito
+    // profile and CanCrossIncognito isn't allowed.
+    return RespondNow(WithArguments(base::Value()));
+  }
+
+  return RespondNow(
+      WithArguments(ExtensionTabUtil::CreateWindowValueForExtension(
+          *new_window, extension(), WindowController::kPopulateTabs,
+          source_context_type())));
+#endif  // !BUILDFLAG(IS_ANDROID)
+}
+
+// static
+#if !BUILDFLAG(IS_ANDROID)
+std::string WindowsCreateFunction::ValidateTab(
+    WindowController* source_window,
+    Profile* window_profile,
+    Profile* calling_profile,
+    content::WebContents* web_contents,
+    bool is_locked_fullscreen,
+    const std::vector<GURL>& urls) {
+  if (!source_window) {
+    // The source window can be null for prerender tabs.
+    return tabs_constants::kInvalidWindowStateError;
+  }
+
+  Browser* source_browser = source_window->GetBrowser();
+  if (!source_browser) {
+    return ExtensionTabUtil::kCanOnlyMoveTabsWithinNormalWindowsError;
+  }
+
+  if (web_app::AppBrowserController* controller =
+          source_browser->app_controller();
+      controller && controller->IsIsolatedWebApp()) {
+    return kWindowCreateCannotMoveIwaTabError;
+  }
+
+  if (!ExtensionTabUtil::IsTabStripEditable()) {
+    return ExtensionTabUtil::kTabStripNotEditableError;
+  }
+
+  if (source_window->profile() != window_profile) {
+    return ExtensionTabUtil::kCanOnlyMoveTabsWithinSameProfileError;
+  }
+
+  if (DevToolsWindow::IsDevToolsWindow(web_contents)) {
+    return tabs_constants::kNotAllowedForDevToolsError;
+  }
+
+#if BUILDFLAG(IS_CHROMEOS)
+  // Tabs cannot be moved to the OnTask system web app. Only relevant for
+  // locked fullscreen on ChromeOS.
+  if (is_locked_fullscreen &&
+      ash::features::IsBocaOnTaskLockedQuizMigrationEnabled()) {
+    return ExtensionTabUtil::kCanOnlyMoveTabsWithinNormalWindowsError;
+  }
+#endif  // BUILDFLAG(IS_CHROMEOS)
+
+  return std::string();  // No error.
+}
+
+// static
+std::string WindowsCreateFunction::SetWindowBounds(
+    const api::windows::Create::Params::CreateData& create_data,
+    gfx::Rect& window_bounds) {
+  bool set_window_position = false;
+  bool set_window_size = false;
+  if (create_data.left) {
+    window_bounds.set_x(*create_data.left);
+    set_window_position = true;
+  }
+  if (create_data.top) {
+    window_bounds.set_y(*create_data.top);
+    set_window_position = true;
+  }
+  if (create_data.width) {
+    window_bounds.set_width(*create_data.width);
+    set_window_size = true;
+  }
+  if (create_data.height) {
+    window_bounds.set_height(*create_data.height);
+    set_window_size = true;
+  }
+
+  // If the extension specified the window size but no position, adjust the
+  // window to fit in the display.
+  if (!set_window_position && set_window_size) {
+    const display::Display& display =
+        display::Screen::Get()->GetDisplayMatching(window_bounds);
+    window_bounds.AdjustToFit(display.bounds());
+  }
+
+  // Immediately fail if the window bounds don't intersect the displays.
+  if ((set_window_position || set_window_size) &&
+      !tabs_internal::WindowBoundsIntersectDisplays(window_bounds)) {
+    return tabs_constants::kInvalidWindowBoundsError;
+  }
+
+  return std::string();  // No error.
+}
+
+#if BUILDFLAG(IS_CHROMEOS)
+void WindowsCreateFunction::OnWindowCreatedAsynchronously(
+    const SessionID& session_id) {
+  BrowserWindowInterface* const browser =
+      BrowserWindowInterface::FromSessionID(session_id);
+  if (!browser) {
+    RespondWithError(ExtensionTabUtil::kBrowserWindowNotAllowed);
+    return;
+  }
+  Respond(WithArguments(ExtensionTabUtil::CreateWindowValueForExtension(
+      *browser, extension(), WindowController::kPopulateTabs,
+      source_context_type())));
+}
+#endif  // BUILDFLAG(IS_CHROMEOS)
+
+#endif  // !BUILDFLAG(IS_ANDROID)
+
 ExtensionFunction::ResponseAction WindowsUpdateFunction::Run() {
   std::optional<windows::Update::Params> params =
       windows::Update::Params::Create(args());
diff --git a/chrome/browser/extensions/api/tabs/tabs_api_android.cc b/chrome/browser/extensions/api/tabs/tabs_api_android.cc
index 20bd1df5..589ee3d 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api_android.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api_android.cc
@@ -27,7 +27,6 @@
 constexpr char kNoActiveTab[] = "No active tab";
 constexpr char kInvalidArguments[] = "Invalid arguments";
 constexpr char kTabsNotImplemented[] = "chrome.tabs not implemented";
-constexpr char kWindowsNotImplemented[] = "chrome.windows not implemented";
 
 content::WebContents* GetActiveWebContents() {
   for (TabModel* tab_model : TabModelList::models()) {
@@ -54,15 +53,6 @@
                                            extension);
 }
 
-// Windows ---------------------------------------------------------------------
-
-ExtensionFunction::ResponseAction WindowsCreateFunction::Run() {
-  std::optional<windows::Create::Params> params =
-      windows::Create::Params::Create(args());
-  EXTENSION_FUNCTION_VALIDATE(params);
-  return RespondNow(Error(kWindowsNotImplemented));
-}
-
 // Tabs ------------------------------------------------------------------------
 
 ExtensionFunction::ResponseAction TabsCreateFunction::Run() {
diff --git a/chrome/browser/extensions/api/tabs/tabs_api_non_android.cc b/chrome/browser/extensions/api/tabs/tabs_api_non_android.cc
index 52d3245..ff252da 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api_non_android.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api_non_android.cc
@@ -158,563 +158,12 @@
 constexpr char kTabIndexNotFoundError[] = "No tab at index: *.";
 constexpr char kCannotFindTabToDiscard[] = "Cannot find a tab to discard.";
 constexpr char kNoHighlightedTabError[] = "No highlighted tab";
-constexpr char kInvalidWindowTypeError[] = "Invalid value for type";
 constexpr char kCannotUpdateMuteCaptured[] =
     "Cannot update mute state for tab *, tab has audio or video currently "
     "being captured";
-constexpr char kWindowCreateSupportsOnlySingleIwaUrlError[] =
-    "When creating a window for a URL with the 'isolated-app:' scheme, only "
-    "one tab can be added to the window.";
-constexpr char kWindowCreateCannotParseIwaUrlError[] =
-    "Unable to parse 'isolated-app:' URL: %s";
-constexpr char kWindowCreateCannotUseTabIdWithIwaError[] =
-    "Creating a new window for an Isolated Web App does not support adding a "
-    "tab by its ID.";
-constexpr char kWindowCreateCannotMoveIwaTabError[] =
-    "The tab of an Isolated Web App cannot be moved to a new window.";
-
-#if BUILDFLAG(IS_CHROMEOS)
-constexpr char kWindowCreateLockedFullscreenUrlCountMismatchError[] =
-    "When creating a new window in locked fullscreen mode, exactly one URL "
-    "should be supplied.";
-#endif  // BUILDFLAG(IS_CHROMEOS)
-
-bool IsValidStateForWindowsCreateFunction(
-    const windows::Create::Params::CreateData* create_data) {
-  if (!create_data) {
-    return true;
-  }
-
-  bool has_bound = create_data->left || create_data->top ||
-                   create_data->width || create_data->height;
-
-  switch (create_data->state) {
-    case windows::WindowState::kMinimized:
-      // If minimised, default focused state should be unfocused.
-      return !(create_data->focused && *create_data->focused) && !has_bound;
-    case windows::WindowState::kMaximized:
-    case windows::WindowState::kFullscreen:
-    case windows::WindowState::kLockedFullscreen:
-      // If maximised/fullscreen, default focused state should be focused.
-      return !(create_data->focused && !*create_data->focused) && !has_bound;
-    case windows::WindowState::kNormal:
-    case windows::WindowState::kNone:
-      return true;
-  }
-  NOTREACHED();
-}
-
-class ScopedPinBrowserAtFront {
- public:
-  explicit ScopedPinBrowserAtFront(BrowserWindowInterface* bwi)
-      : bwi_(bwi->GetWeakPtr()) {
-    old_z_order_level_ = bwi->GetWindow()->GetZOrderLevel();
-    bwi->GetWindow()->SetZOrderLevel(ui::ZOrderLevel::kFloatingWindow);
-  }
-
-  ~ScopedPinBrowserAtFront() {
-    if (bwi_) {
-      bwi_->GetWindow()->SetZOrderLevel(old_z_order_level_);
-    }
-  }
-
- private:
-  base::WeakPtr<BrowserWindowInterface> bwi_;
-  ui::ZOrderLevel old_z_order_level_;
-};
 
 }  // namespace
 
-// Windows ---------------------------------------------------------------------
-
-ExtensionFunction::ResponseAction WindowsCreateFunction::Run() {
-  std::optional<windows::Create::Params> params =
-      windows::Create::Params::Create(args());
-  EXTENSION_FUNCTION_VALIDATE(params);
-  std::vector<GURL> urls;
-  int tab_index = -1;
-
-  DCHECK(extension() || source_context_type() == mojom::ContextType::kWebUi ||
-         source_context_type() == mojom::ContextType::kUntrustedWebUi);
-  std::optional<windows::Create::Params::CreateData>& create_data =
-      params->create_data;
-
-  std::optional<web_app::IsolatedWebAppUrlInfo> isolated_web_app_url_info;
-
-  // Look for optional url.
-  if (create_data && create_data->url) {
-    std::vector<std::string> url_strings;
-    // First, get all the URLs the client wants to open.
-    if (create_data->url->as_string) {
-      url_strings.push_back(std::move(*create_data->url->as_string));
-    } else if (create_data->url->as_strings) {
-      url_strings = std::move(*create_data->url->as_strings);
-    }
-
-    // Second, resolve, validate and convert them to GURLs.
-    for (auto& url_string : url_strings) {
-      auto url = ExtensionTabUtil::PrepareURLForNavigation(
-          url_string, extension(), browser_context());
-      if (!url.has_value()) {
-        return RespondNow(Error(std::move(url.error())));
-      }
-      if (url->SchemeIs(webapps::kIsolatedAppScheme)) {
-        if (url_strings.size() > 1) {
-          return RespondNow(Error(kWindowCreateSupportsOnlySingleIwaUrlError));
-        }
-
-        base::expected<web_app::IsolatedWebAppUrlInfo, std::string>
-            maybe_url_info = web_app::IsolatedWebAppUrlInfo::Create(*url);
-        if (!maybe_url_info.has_value()) {
-          return RespondNow(
-              Error(base::StringPrintf(kWindowCreateCannotParseIwaUrlError,
-                                       maybe_url_info.error().c_str())));
-        }
-        isolated_web_app_url_info = *maybe_url_info;
-      }
-      urls.push_back(*url);
-    }
-  }
-
-  // Decide whether we are opening a normal window or an incognito window.
-  std::string error;
-  Profile* calling_profile = Profile::FromBrowserContext(browser_context());
-  windows_util::IncognitoResult incognito_result =
-      windows_util::ShouldOpenIncognitoWindow(
-          calling_profile,
-          create_data && create_data->incognito
-              ? std::optional<bool>(*create_data->incognito)
-              : std::nullopt,
-          &urls, &error);
-  if (incognito_result == windows_util::IncognitoResult::kError) {
-    return RespondNow(Error(std::move(error)));
-  }
-
-  Profile* window_profile =
-      incognito_result == windows_util::IncognitoResult::kIncognito
-          ? calling_profile->GetPrimaryOTRProfile(/*create_if_needed=*/true)
-          : calling_profile;
-
-  if (!IsValidStateForWindowsCreateFunction(base::OptionalToPtr(create_data))) {
-    return RespondNow(Error(tabs_constants::kInvalidWindowStateError));
-  }
-
-  // Look for optional tab id.
-  bool is_locked_fullscreen =
-      create_data &&
-      create_data->state == windows::WindowState::kLockedFullscreen;
-  WindowController* source_window = nullptr;
-  if (create_data && create_data->tab_id) {
-    if (isolated_web_app_url_info.has_value()) {
-      return RespondNow(Error(kWindowCreateCannotUseTabIdWithIwaError));
-    }
-
-    // Find the tab. `tab_index` will later be used to move the tab into the
-    // created window.
-    content::WebContents* web_contents = nullptr;
-    if (!tabs_internal::GetTabById(*create_data->tab_id, calling_profile,
-                                   include_incognito_information(),
-                                   &source_window, &web_contents, &tab_index,
-                                   &error)) {
-      return RespondNow(Error(std::move(error)));
-    }
-
-    // Validate the tab information. Return an error if it's not valid.
-    std::string tab_error =
-        ValidateTab(source_window, window_profile, calling_profile,
-                    web_contents, is_locked_fullscreen, urls);
-    if (!tab_error.empty()) {
-      return RespondNow(Error(std::move(tab_error)));
-    }
-  }
-
-  if (is_locked_fullscreen) {
-    if (!tabs_internal::ExtensionHasLockedFullscreenPermission(extension())) {
-      return RespondNow(
-          Error(tabs_internal::kMissingLockWindowFullscreenPrivatePermission));
-    }
-
-#if BUILDFLAG(IS_CHROMEOS)
-    // Set up and launch the OnTask system web app if applicable. The legacy
-    // setup leverages a regular browser instance today.
-    if (ash::features::IsBocaOnTaskLockedQuizMigrationEnabled()) {
-      if (urls.size() != 1) {
-        return RespondNow(
-            Error(kWindowCreateLockedFullscreenUrlCountMismatchError));
-      }
-      ash::boca::LockedQuizSessionManagerFactory::GetInstance()
-          ->GetForBrowserContext(calling_profile)
-          ->OpenLockedQuiz(
-              urls.front(),
-              base::BindOnce(
-                  &WindowsCreateFunction::OnWindowCreatedAsynchronously, this));
-      return RespondLater();
-    }
-#endif  // BUILDFLAG(IS_CHROMEOS)
-  }
-
-  Browser::Type window_type = Browser::TYPE_NORMAL;
-
-  gfx::Rect window_bounds;
-  bool focused = true;
-  std::string extension_id;
-
-  if (create_data) {
-    // Figure out window type before figuring out bounds so that default
-    // bounds can be set according to the window type.
-    switch (create_data->type) {
-      // TODO(stevenjb): Remove 'panel' from windows.json.
-      case windows::CreateType::kPanel:
-      case windows::CreateType::kPopup:
-        window_type = Browser::TYPE_POPUP;
-        if (isolated_web_app_url_info.has_value()) {
-          return RespondNow(Error(kInvalidWindowTypeError));
-        }
-        if (extension()) {
-          extension_id = extension()->id();
-        }
-        break;
-      case windows::CreateType::kNone:
-      case windows::CreateType::kNormal:
-        break;
-      default:
-        return RespondNow(Error(kInvalidWindowTypeError));
-    }
-
-    // Initialize default window bounds according to window type.
-    ui::mojom::WindowShowState ignored_show_state =
-        ui::mojom::WindowShowState::kDefault;
-    WindowSizer::GetBrowserWindowBoundsAndShowState(
-        gfx::Rect(), nullptr, &window_bounds, &ignored_show_state);
-
-    // Update the window bounds based on the create parameters.
-    std::string bounds_error = SetWindowBounds(*create_data, window_bounds);
-    if (!bounds_error.empty()) {
-      return RespondNow(Error(std::move(bounds_error)));
-    }
-
-    if (create_data->focused) {
-      focused = *create_data->focused;
-    }
-
-    // Record the window height and width to determine if we
-    // can set a mininimum value for them (crbug.com/1369103).
-    UMA_HISTOGRAM_COUNTS_1000("Extensions.CreateWindowWidth",
-                              window_bounds.width());
-    UMA_HISTOGRAM_COUNTS_1000("Extensions.CreateWindowHeight",
-                              window_bounds.height());
-  }
-
-  // Create a new BrowserWindow if possible.
-  if (GetBrowserWindowCreationStatusForProfile(*window_profile) !=
-      BrowserWindowInterface::CreationStatus::kOk) {
-    return RespondNow(Error(ExtensionTabUtil::kBrowserWindowNotAllowed));
-  }
-  BrowserWindowCreateParams create_params(window_type, *window_profile,
-                                          user_gesture());
-
-  if (isolated_web_app_url_info.has_value()) {
-    create_params.type = BrowserWindowInterface::TYPE_APP;
-    create_params.app_name = web_app::GenerateApplicationNameFromAppId(
-        isolated_web_app_url_info->app_id());
-    // For Isolated Web Apps, the actual navigating-to URL will be the app's
-    // start_url to prevent deep-linking attacks, while the original URL will be
-    // accessible via window.launchQueue; for this reason the browser is marked
-    // trusted.
-    create_params.is_trusted_source = true;
-  } else if (!extension_id.empty()) {
-    // extension_id is only set for CREATE_TYPE_POPUP.
-    create_params.type = BrowserWindowInterface::TYPE_APP_POPUP;
-    create_params.app_name =
-        web_app::GenerateApplicationNameFromAppId(extension_id);
-    create_params.is_trusted_source = false;
-  }
-  create_params.initial_bounds = window_bounds;
-  create_params.initial_show_state = ui::mojom::WindowShowState::kNormal;
-
-  if (create_data && create_data->state != windows::WindowState::kNone) {
-    create_params.initial_show_state =
-        tabs_internal::ConvertToWindowShowState(create_data->state);
-  }
-
-  BrowserWindowInterface* new_window =
-      CreateBrowserWindow(std::move(create_params));
-  if (!new_window) {
-    return RespondNow(Error(ExtensionTabUtil::kBrowserWindowNotAllowed));
-  }
-  // NOTE: Even though `new_window` was returned, it may not be fully
-  // initialized on non-desktop platforms. See documentation on
-  // CreateBrowserWindow().
-
-  auto create_nav_params =
-      [&](const GURL& url) -> base::expected<NavigateParams, std::string> {
-    NavigateParams navigate_params(new_window, url, ui::PAGE_TRANSITION_LINK);
-    navigate_params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
-    // Ensure that these navigations will not get 'captured' into PWA windows,
-    // as this means that `new_window` could be ignored. It may be
-    // useful/desired in the future to allow this behavior, but this may require
-    // an API change, or at least a re-write of how these navigations are called
-    // to be compatible with the navigation capturing behavior.
-    navigate_params.pwa_navigation_capturing_force_off = true;
-
-    // Depending on the |setSelfAsOpener| option, we need to put the new
-    // contents in the same BrowsingInstance as their opener.  See also
-    // https://crbug.com/713888.
-    bool set_self_as_opener = create_data->set_self_as_opener &&  // present?
-                              *create_data->set_self_as_opener;  // set to true?
-    if (set_self_as_opener) {
-      if (is_from_service_worker()) {
-        // TODO(crbug.com/40636155): Add test for this.
-        return base::unexpected(
-            "Cannot specify setSelfAsOpener Service Worker extension.");
-      }
-      if (isolated_web_app_url_info) {
-        return base::unexpected(
-            "Cannot specify setSelfAsOpener for isolated-app:// URLs.");
-      }
-      // TODO(crbug.com/40636155): Add tests for checking opener SiteInstance
-      // behavior from a SW based extension's extension frame (e.g. from popup).
-      // See ExtensionApiTest.WindowsCreate* tests for details.
-      navigate_params.initiator_origin =
-          extension() ? extension()->origin()
-                      : render_frame_host()->GetLastCommittedOrigin();
-      navigate_params.opener = render_frame_host();
-      navigate_params.source_site_instance =
-          render_frame_host()->GetSiteInstance();
-    }
-
-    return navigate_params;
-  };
-
-  if (!isolated_web_app_url_info) {
-    for (const GURL& url : urls) {
-      ASSIGN_OR_RETURN(
-          NavigateParams navigate_params, create_nav_params(url),
-          [&](const std::string& error) { return RespondNow(Error(error)); });
-      Navigate(&navigate_params);
-    }
-  } else {
-    CHECK_EQ(urls.size(), 1U);
-    const GURL& original_url = urls[0];
-
-    const webapps::AppId& iwa_id = isolated_web_app_url_info->app_id();
-    web_app::WebAppRegistrar& registrar =
-        web_app::WebAppProvider::GetForWebApps(window_profile)
-            ->registrar_unsafe();
-
-    // TODO(crbug.com/424128443): create an dummy tab in the browser so that the
-    // returned window's tab count is always equal to 1 -- this will limit the
-    // extension's ability to figure out which IWAs are installed without the
-    // `tabs` permission.
-    if (registrar.AppMatches(iwa_id, web_app::WebAppFilter::IsIsolatedApp())) {
-      ASSIGN_OR_RETURN(
-          NavigateParams navigate_params,
-          create_nav_params(registrar.GetAppStartUrl(iwa_id)),
-          [&](const std::string& error) { return RespondNow(Error(error)); });
-      base::WeakPtr<content::NavigationHandle> handle =
-          Navigate(&navigate_params);
-      CHECK(handle);
-      web_app::EnqueueLaunchParams(
-          handle->GetWebContents(), iwa_id, original_url,
-          /*wait_for_navigation_to_complete=*/true, handle->NavigationStart());
-    }
-  }
-
-  const TabModel* tab = nullptr;
-  // Move the tab into the created window only if it's an empty popup or it's
-  // a tabbed window.
-  if (window_type == Browser::TYPE_NORMAL || urls.empty()) {
-    if (source_window && source_window->GetBrowser()) {
-      TabStripModel* source_tab_strip =
-          source_window->GetBrowser()->tab_strip_model();
-      CHECK(!isolated_web_app_url_info.has_value());
-      std::unique_ptr<TabModel> detached_tab =
-          source_tab_strip->DetachTabAtForInsertion(tab_index);
-      tab = detached_tab.get();
-      TabStripModel* target_tab_strip =
-          ExtensionTabUtil::GetEditableTabStripModel(
-              new_window->GetBrowserForMigrationOnly());
-      if (!target_tab_strip) {
-        return RespondNow(Error(ExtensionTabUtil::kTabStripNotEditableError));
-      }
-      target_tab_strip->InsertDetachedTabAt(
-          urls.size(), std::move(detached_tab), AddTabTypes::ADD_NONE);
-    }
-  }
-  // Create a new tab if the created window is still empty. Don't create a new
-  // tab when it is intended to create an empty popup.
-  if (!tab && urls.empty() && window_type == Browser::TYPE_NORMAL) {
-    // TODO(crbug.com/452431839) Make a new NewTabTypes value for
-    // when new tabs are made because of an empty window.
-    chrome::NewTab(new_window->GetBrowserForMigrationOnly(),
-                   NewTabTypes::kNewTabCommand);
-  }
-  chrome::SelectNumberedTab(
-      new_window->GetBrowserForMigrationOnly(), 0,
-      TabStripUserGestureDetails(
-          TabStripUserGestureDetails::GestureType::kNone));
-
-  if (focused) {
-    new_window->GetWindow()->Show();
-  } else {
-    // Show an unfocused new window.
-    BrowserWindowInterface* const last_active_bwi =
-        GetLastActiveBrowserWindowInterfaceWithAnyProfile();
-
-    // On some OSes the new unfocused window is shown on top by default.
-    // ScopedPinBrowserAtFront prevents the new browser from being shown above
-    // the old active browser.
-    if (last_active_bwi && last_active_bwi->IsActive()) {
-      ScopedPinBrowserAtFront scoper(last_active_bwi);
-      new_window->GetWindow()->ShowInactive();
-    } else {
-      new_window->GetWindow()->ShowInactive();
-    }
-  }
-
-// Despite creating the window with initial_show_state() ==
-// ui::mojom::WindowShowState::kMinimized above, on Linux the window is not
-// created as minimized.
-// TODO(crbug.com/40254339): Remove this workaround when linux is fixed.
-// TODO(crbug.com/40254339): Find a fix for wayland as well.
-#if BUILDFLAG(IS_LINUX) && BUILDFLAG(IS_OZONE_X11)
-  if (new_window->GetBrowserForMigrationOnly()->initial_show_state() ==
-      ui::mojom::WindowShowState::kMinimized) {
-    new_window->GetWindow()->Minimize();
-  }
-#endif  // BUILDFLAG(IS_LINUX) && BUILDFLAG(IS_OZONE_X11)
-
-  // Lock the window fullscreen only after the new tab has been created
-  // (otherwise the tabstrip is empty), and window()->show() has been called
-  // (otherwise that resets the locked mode for devices in tablet mode).
-  // TODO(crbug.com/438540029) - Remove once the migration is complete.
-  if (create_data &&
-      create_data->state == windows::WindowState::kLockedFullscreen) {
-#if BUILDFLAG(IS_CHROMEOS)
-    ash::boca::LockedQuizSessionManagerFactory::GetInstance()
-        ->GetForBrowserContext(calling_profile)
-        ->SetLockedFullscreenState(new_window->GetBrowserForMigrationOnly(),
-                                   /*pinned=*/true);
-#endif  // BUILDFLAG(IS_CHROMEOS)
-  }
-
-  if (new_window->GetProfile()->IsOffTheRecord() &&
-      !browser_context()->IsOffTheRecord() &&
-      !include_incognito_information()) {
-    // Don't expose incognito windows if extension itself works in non-incognito
-    // profile and CanCrossIncognito isn't allowed.
-    return RespondNow(WithArguments(base::Value()));
-  }
-
-  return RespondNow(
-      WithArguments(ExtensionTabUtil::CreateWindowValueForExtension(
-          *new_window, extension(), WindowController::kPopulateTabs,
-          source_context_type())));
-}
-
-// static
-std::string WindowsCreateFunction::ValidateTab(
-    WindowController* source_window,
-    Profile* window_profile,
-    Profile* calling_profile,
-    content::WebContents* web_contents,
-    bool is_locked_fullscreen,
-    const std::vector<GURL>& urls) {
-  if (!source_window) {
-    // The source window can be null for prerender tabs.
-    return tabs_constants::kInvalidWindowStateError;
-  }
-
-  Browser* source_browser = source_window->GetBrowser();
-  if (!source_browser) {
-    return ExtensionTabUtil::kCanOnlyMoveTabsWithinNormalWindowsError;
-  }
-
-  if (web_app::AppBrowserController* controller =
-          source_browser->app_controller();
-      controller && controller->IsIsolatedWebApp()) {
-    return kWindowCreateCannotMoveIwaTabError;
-  }
-
-  if (!ExtensionTabUtil::IsTabStripEditable()) {
-    return ExtensionTabUtil::kTabStripNotEditableError;
-  }
-
-  if (source_window->profile() != window_profile) {
-    return ExtensionTabUtil::kCanOnlyMoveTabsWithinSameProfileError;
-  }
-
-  if (DevToolsWindow::IsDevToolsWindow(web_contents)) {
-    return tabs_constants::kNotAllowedForDevToolsError;
-  }
-
-#if BUILDFLAG(IS_CHROMEOS)
-  // Tabs cannot be moved to the OnTask system web app. Only relevant for
-  // locked fullscreen on ChromeOS.
-  if (is_locked_fullscreen &&
-      ash::features::IsBocaOnTaskLockedQuizMigrationEnabled()) {
-    return ExtensionTabUtil::kCanOnlyMoveTabsWithinNormalWindowsError;
-  }
-#endif  // BUILDFLAG(IS_CHROMEOS)
-
-  return std::string();  // No error.
-}
-
-// static
-std::string WindowsCreateFunction::SetWindowBounds(
-    const api::windows::Create::Params::CreateData& create_data,
-    gfx::Rect& window_bounds) {
-  bool set_window_position = false;
-  bool set_window_size = false;
-  if (create_data.left) {
-    window_bounds.set_x(*create_data.left);
-    set_window_position = true;
-  }
-  if (create_data.top) {
-    window_bounds.set_y(*create_data.top);
-    set_window_position = true;
-  }
-  if (create_data.width) {
-    window_bounds.set_width(*create_data.width);
-    set_window_size = true;
-  }
-  if (create_data.height) {
-    window_bounds.set_height(*create_data.height);
-    set_window_size = true;
-  }
-
-  // If the extension specified the window size but no position, adjust the
-  // window to fit in the display.
-  if (!set_window_position && set_window_size) {
-    const display::Display& display =
-        display::Screen::Get()->GetDisplayMatching(window_bounds);
-    window_bounds.AdjustToFit(display.bounds());
-  }
-
-  // Immediately fail if the window bounds don't intersect the displays.
-  if ((set_window_position || set_window_size) &&
-      !tabs_internal::WindowBoundsIntersectDisplays(window_bounds)) {
-    return tabs_constants::kInvalidWindowBoundsError;
-  }
-
-  return std::string();  // No error.
-}
-
-#if BUILDFLAG(IS_CHROMEOS)
-void WindowsCreateFunction::OnWindowCreatedAsynchronously(
-    const SessionID& session_id) {
-  BrowserWindowInterface* const browser =
-      BrowserWindowInterface::FromSessionID(session_id);
-  if (!browser) {
-    RespondWithError(ExtensionTabUtil::kBrowserWindowNotAllowed);
-    return;
-  }
-  Respond(WithArguments(ExtensionTabUtil::CreateWindowValueForExtension(
-      *browser, extension(), WindowController::kPopulateTabs,
-      source_context_type())));
-}
-#endif  // BUILDFLAG(IS_CHROMEOS)
-
 // Tabs ------------------------------------------------------------------------
 
 ExtensionFunction::ResponseAction TabsCreateFunction::Run() {
diff --git a/chrome/browser/extensions/api/vpn_provider/vpn_provider_apitest.cc b/chrome/browser/extensions/api/vpn_provider/vpn_provider_apitest.cc
index 358144d..eb2eba9a 100644
--- a/chrome/browser/extensions/api/vpn_provider/vpn_provider_apitest.cc
+++ b/chrome/browser/extensions/api/vpn_provider/vpn_provider_apitest.cc
@@ -207,12 +207,8 @@
                                                       configuration_name);
   }
 
-  bool DoesConfigExist(const std::string& configuration_name) const {
-    const auto& mapping = GetVpnServiceAsh()->extension_id_to_service_;
-    if (!base::Contains(mapping, extension_id())) {
-      return false;
-    }
-    return base::Contains(mapping.at(extension_id())->key_to_configuration_map_,
+  bool DoesConfigExist(const std::string& configuration_name) {
+    return base::Contains(service()->key_to_configuration_map_,
                           GetKey(configuration_name));
   }
 
diff --git a/chrome/browser/extensions/autoplay_browsertest.cc b/chrome/browser/extensions/autoplay_browsertest.cc
index f9946182..2721f10d 100644
--- a/chrome/browser/extensions/autoplay_browsertest.cc
+++ b/chrome/browser/extensions/autoplay_browsertest.cc
@@ -16,6 +16,10 @@
 #include "extensions/test/test_extension_dir.h"
 #include "media/base/media_switches.h"
 
+// TODO(crbug.com/467442812): Port these tests to desktop Android. This isn't
+// straightforward, as some of the tests rely on manifest V2 behavior, but
+// Android only supports manifest V3. Likewise, Android does not support hosted
+// apps.
 class AutoplayExtensionBrowserTest : public extensions::ExtensionApiTest {
  public:
   void SetUpCommandLine(base::CommandLine* command_line) override {
diff --git a/chrome/browser/extensions/extension_override_apitest.cc b/chrome/browser/extensions/extension_override_apitest.cc
index 6f63d15f..6fc9d769 100644
--- a/chrome/browser/extensions/extension_override_apitest.cc
+++ b/chrome/browser/extensions/extension_override_apitest.cc
@@ -11,6 +11,7 @@
 #include "base/values.h"
 #include "build/build_config.h"
 #include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/extensions/extension_web_ui.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/url_constants.h"
@@ -22,6 +23,7 @@
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "extensions/browser/extension_creator.h"
+#include "extensions/browser/test_extension_registry_observer.h"
 #include "extensions/buildflags/buildflags.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/manifest_handlers/chrome_url_overrides_handler.h"
@@ -73,27 +75,64 @@
   testing::AssertionResult ExtensionControlsPage(
       content::WebContents* web_contents,
       const std::string& extension_id) {
-    if (!web_contents->GetController().GetLastCommittedEntry())
+    if (!web_contents->GetController().GetLastCommittedEntry()) {
       return testing::AssertionFailure() << "No last committed entry.";
+    }
     // We can't just use WebContents::GetLastCommittedURL() here because
-    // trickiness makes it think that it committed chrome://newtab.
+    // trickiness makes the WebContents think that it committed chrome://newtab
+    // when dealing with the new tab page.
     GURL gurl = web_contents->GetController().GetLastCommittedEntry()->GetURL();
-    if (!gurl.SchemeIs(kExtensionScheme))
+    if (!gurl.SchemeIs(kExtensionScheme)) {
       return testing::AssertionFailure() << gurl;
+    }
     if (gurl.host() != extension_id) {
       return testing::AssertionFailure() << gurl;
     }
     return testing::AssertionSuccess();
   }
 
+  // Returns AssertionSuccess() if the given |web_contents| is not being
+  // actively controlled by any extension.
+  testing::AssertionResult ExtensionDoesNotControlPage(
+      content::WebContents* web_contents) {
+    if (!web_contents->GetController().GetLastCommittedEntry()) {
+      return testing::AssertionFailure() << "No last committed entry.";
+    }
+    // We can't just use WebContents::GetLastCommittedURL() here because
+    // trickiness makes the WebContents think that it committed chrome://newtab
+    // when dealing with the new tab page.
+    GURL gurl = web_contents->GetController().GetLastCommittedEntry()->GetURL();
+    if (gurl.SchemeIs(kExtensionScheme)) {
+      return testing::AssertionFailure() << gurl;
+    }
+    return testing::AssertionSuccess();
+  }
+
   base::FilePath data_dir() {
     return test_data_dir_.AppendASCII("override");
   }
+
+  // Enables the extension with the given ID in incognito, waits for it to
+  // reload and returns it.
+  scoped_refptr<const Extension> EnableExtensionInIncognito(
+      const ExtensionId& extension_id) {
+    // Allowing in incognito requires a reload of the extension, so we have to
+    // wait for it.
+    TestExtensionRegistryObserver observer(ExtensionRegistry::Get(profile()),
+                                           extension_id);
+    util::SetIsIncognitoEnabled(extension_id, profile(), true);
+    scoped_refptr<const Extension> extension =
+        observer.WaitForExtensionLoaded();
+    EXPECT_TRUE(extension);
+    return extension;
+  }
 };
 
-// Basic test for overriding the NTP.
+// Test for overriding the new tab page with an extension with "incognito":
+// "spanning" (default if the "incognito" manifest key is unspecified).
 IN_PROC_BROWSER_TEST_F(ExtensionOverrideTest, OverrideNewTab) {
-  const Extension* extension = LoadExtension(data_dir().AppendASCII("newtab"));
+  scoped_refptr<const Extension> extension =
+      LoadExtension(data_dir().AppendASCII("newtab"));
   {
     // Navigate to the new tab page.  The overridden new tab page
     // will call chrome.test.sendMessage('controlled by first').
@@ -104,6 +143,136 @@
     EXPECT_TRUE(listener.WaitUntilSatisfied());
     EXPECT_EQ("controlled by first", listener.message());
   }
+  {
+    // Navigate an incognito tab to the new tab page, first without enabling the
+    // extension in incognito. We should get the default new tab page.
+    auto* incognito_web_contents =
+        PlatformOpenURLOffTheRecord(profile(), GURL("chrome://newtab/"));
+    EXPECT_TRUE(ExtensionDoesNotControlPage(incognito_web_contents));
+
+    // Now enable the extension in incognito mode.
+    extension = EnableExtensionInIncognito(extension->id());
+
+    // Even after enabling in incognito, the extension still shouldn't override
+    // the new tab page, as only "incognito": "split" extensions can override
+    // incognito chrome pages.
+    // TODO(crbug.com/460732314): Extensions should never be able to override
+    // the new tab page, even with "incognito": "split".
+    ASSERT_TRUE(
+        NavigateToURL(incognito_web_contents, GURL("chrome://newtab/")));
+    EXPECT_TRUE(ExtensionDoesNotControlPage(incognito_web_contents));
+  }
+}
+
+// Test for overriding the new tab page with an "incognito": "split" extension.
+IN_PROC_BROWSER_TEST_F(ExtensionOverrideTest, OverrideNewTabSplitMode) {
+  scoped_refptr<const Extension> extension =
+      LoadExtension(data_dir().AppendASCII("newtab_split_mode"));
+  {
+    // Navigate to the new tab page.  The overridden new tab page
+    // will call chrome.test.notifyPass().
+    ResultCatcher catcher;
+    auto* web_contents = GetActiveWebContents();
+    ASSERT_TRUE(NavigateToURL(web_contents, GURL("chrome://newtab/")));
+    EXPECT_TRUE(ExtensionControlsPage(web_contents, extension->id()));
+    ASSERT_TRUE(catcher.GetNextResult());
+  }
+  {
+    // Navigate an incognito tab to the new tab page, first without enabling the
+    // extension in incognito. We should get the default new tab page.
+    auto* incognito_web_contents =
+        PlatformOpenURLOffTheRecord(profile(), GURL("chrome://newtab/"));
+    EXPECT_TRUE(ExtensionDoesNotControlPage(incognito_web_contents));
+
+    // Now enable the extension in incognito mode.
+    extension = EnableExtensionInIncognito(extension->id());
+
+    // After enabling in incognito the extension will be able to override the
+    // new tab page. The overridden page will call chrome.test.notifyPass().
+    // TODO(crbug.com/460732314): Extensions should never be able to override
+    // the new tab page, even with "incognito": "split".
+    ResultCatcher catcher;
+    ASSERT_TRUE(
+        NavigateToURL(incognito_web_contents, GURL("chrome://newtab/")));
+    EXPECT_TRUE(ExtensionControlsPage(incognito_web_contents, extension->id()));
+    ASSERT_TRUE(catcher.GetNextResult());
+  }
+}
+
+// Test for overriding the bookmarks page with an extension with "incognito":
+// "spanning" (default if "incognito" is unspecified).
+IN_PROC_BROWSER_TEST_F(ExtensionOverrideTest, OverrideBookmarks) {
+  scoped_refptr<const Extension> extension =
+      LoadExtension(data_dir().AppendASCII("bookmarks"));
+  {
+    // Navigate to the bookmarks page. The overridden page will call
+    // chrome.test.notifyPass().
+    ResultCatcher catcher;
+    auto* web_contents = GetActiveWebContents();
+    ASSERT_TRUE(NavigateToURL(web_contents, GURL("chrome://bookmarks/")));
+    EXPECT_TRUE(ExtensionControlsPage(web_contents, extension->id()));
+    ASSERT_TRUE(catcher.GetNextResult());
+  }
+  {
+    // Navigate an incognito tab to the bookmarks, first without enabling the
+    // extension in incognito. We should get the default bookmarks page.
+    auto* incognito_web_contents =
+        PlatformOpenURLOffTheRecord(profile(), GURL("chrome://bookmarks/"));
+    EXPECT_TRUE(ExtensionDoesNotControlPage(incognito_web_contents));
+
+    // Now enable the extension in incognito mode.
+    extension = EnableExtensionInIncognito(extension->id());
+
+    // Even after enabling in incognito, the extension still shouldn't override
+    // the bookmarks page, as only "incognito": "split" extensions can override
+    // incognito chrome pages.
+#if BUILDFLAG(IS_ANDROID)
+    // This is a bit strange, but we actually expect this NavigateToURL call to
+    // fail on Android for the bookmarks page if it is not being overridden by
+    // an extension. Instead it is swapped out with a Android NativePage, so the
+    // web contents doesn't finish the navigation like NavigateToUrl expects.
+    ASSERT_FALSE(
+        NavigateToURL(incognito_web_contents, GURL("chrome://bookmarks/")));
+#else
+    ASSERT_TRUE(
+        NavigateToURL(incognito_web_contents, GURL("chrome://bookmarks/")));
+#endif  // BUILDFLAG(IS_ANDROID)
+    EXPECT_TRUE(ExtensionDoesNotControlPage(incognito_web_contents));
+  }
+}
+
+// Test for overriding the Bookmarks page with an "incognito": "split"
+// extension.
+IN_PROC_BROWSER_TEST_F(ExtensionOverrideTest, OverrideBookmarksSplitMode) {
+  scoped_refptr<const Extension> extension =
+      LoadExtension(data_dir().AppendASCII("bookmarks_split_mode"));
+  {
+    // Navigate to the bookmarks page. The overridden page will call
+    // chrome.test.notifyPass().
+    ResultCatcher catcher;
+    auto* web_contents = GetActiveWebContents();
+    ASSERT_TRUE(NavigateToURL(web_contents, GURL("chrome://bookmarks/")));
+    EXPECT_TRUE(ExtensionControlsPage(web_contents, extension->id()));
+    ASSERT_TRUE(catcher.GetNextResult());
+  }
+  {
+    // Navigate an incognito tab to the bookmarks page, first without enabling
+    // the extension in incognito. We should get the default bookmarks page.
+    auto* incognito_web_contents =
+        PlatformOpenURLOffTheRecord(profile(), GURL("chrome://bookmarks/"));
+    EXPECT_TRUE(ExtensionDoesNotControlPage(incognito_web_contents));
+
+    // Now enable the extension in incognito mode.
+    extension = EnableExtensionInIncognito(extension->id());
+
+    // After enabling in incognito the extension will be able to override the
+    // bookmarks page. The overridden page will call chrome.test.notifyPass().
+    ResultCatcher catcher;
+    ASSERT_TRUE(
+        NavigateToURL(incognito_web_contents, GURL("chrome://bookmarks/")));
+    EXPECT_TRUE(ExtensionControlsPage(incognito_web_contents, extension->id()));
+    ASSERT_TRUE(catcher.GetNextResult());
+  }
 }
 
 // Check having multiple extensions with the same override.
@@ -230,18 +399,6 @@
   EXPECT_FALSE(ExtensionControlsPage(web_contents, extension1_id));
 }
 
-IN_PROC_BROWSER_TEST_F(ExtensionOverrideTest, OverrideNewTabIncognito) {
-  LoadExtension(data_dir().AppendASCII("newtab"));
-
-  // Navigate an incognito tab to the new tab page.  We should get the actual
-  // new tab page because we can't load chrome-extension URLs in incognito.
-  WebContents* tab =
-      PlatformOpenURLOffTheRecord(profile(), GURL("chrome://newtab/"));
-  ASSERT_TRUE(tab->GetController().GetVisibleEntry());
-  EXPECT_FALSE(tab->GetController().GetVisibleEntry()->GetURL().
-               SchemeIs(kExtensionScheme));
-}
-
 // Check that when an overridden new tab page has focus, a subframe navigation
 // on that page does not steal the focus away by focusing the omnibox.
 // See https://crbug.com/700124.
diff --git a/chrome/browser/extensions/manifest_v3_browsertest.cc b/chrome/browser/extensions/manifest_v3_browsertest.cc
index 0f535b70..dd74d54c 100644
--- a/chrome/browser/extensions/manifest_v3_browsertest.cc
+++ b/chrome/browser/extensions/manifest_v3_browsertest.cc
@@ -6,14 +6,12 @@
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/extensions/extension_action_test_helper.h"
-#include "chrome/test/base/ui_test_utils.h"
 #include "components/version_info/channel.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test.h"
 #include "extensions/browser/extension_action.h"
 #include "extensions/browser/extension_action_manager.h"
+#include "extensions/buildflags/buildflags.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/features/feature_channel.h"
 #include "extensions/test/extension_test_message_listener.h"
@@ -22,6 +20,13 @@
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/extensions/extension_action_test_helper.h"
+#endif
+
+static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE));
+
 namespace extensions {
 
 class ManifestV3BrowserTest : public ExtensionBrowserTest {
@@ -45,6 +50,9 @@
   ScopedCurrentChannel channel_override_{version_info::Channel::UNKNOWN};
 };
 
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+// TODO(crbug.com/371432155): Port to desktop Android when chrome.tabs works
+// better there (specifically, for onUpdated events).
 IN_PROC_BROWSER_TEST_F(ManifestV3BrowserTest, ProgrammaticScriptInjection) {
   constexpr char kManifest[] =
       R"({
@@ -99,13 +107,14 @@
   ASSERT_TRUE(listener.WaitUntilSatisfied());
 
   ResultCatcher catcher;
-  ASSERT_TRUE(ui_test_utils::NavigateToURL(
-      browser(),
+  ASSERT_TRUE(NavigateToURL(
+      GetActiveWebContents(),
       embedded_test_server()->GetURL("example.com", "/simple.html")));
   ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
 
   EXPECT_EQ(u"My New Title", GetActiveWebContents()->GetTitle());
 }
+#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
 
 // A simple end-to-end test exercising the new action API in Manifest V3.
 // More robust tests for the action API are in extension_action_apitest.cc.
@@ -139,21 +148,29 @@
   ASSERT_TRUE(extension);
   ASSERT_TRUE(listener.WaitUntilSatisfied());
 
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+  // TODO(crbug.com/393179880): Desktop Android does not yet support
+  // ExtensionActionTestHelper.
   std::unique_ptr<ExtensionActionTestHelper> action_test_util =
       ExtensionActionTestHelper::Create(browser());
   ASSERT_EQ(1, action_test_util->NumberOfBrowserActions());
   EXPECT_TRUE(action_test_util->HasAction(extension->id()));
+#endif
 
   ExtensionAction* const action =
       ExtensionActionManager::Get(profile())->GetExtensionAction(*extension);
   ASSERT_TRUE(action);
   EXPECT_FALSE(action->HasIcon(ExtensionAction::kDefaultTabId));
 
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+  // TODO(crbug.com/393179880): Desktop Android does not yet support
+  // ExtensionActionTestHelper.
   ResultCatcher catcher;
   action_test_util->Press(extension->id());
   ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
 
   EXPECT_TRUE(action->HasIcon(ExtensionAction::kDefaultTabId));
+#endif
 }
 
 IN_PROC_BROWSER_TEST_F(ManifestV3BrowserTest, SynthesizedAction) {
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStreamViewResizer.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStreamViewResizer.java
index 890b744..59ad9fa3 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStreamViewResizer.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStreamViewResizer.java
@@ -9,7 +9,6 @@
 import android.content.res.Resources;
 import android.graphics.Rect;
 import android.view.View;
-import android.view.ViewGroup;
 
 import org.chromium.base.FeatureList;
 import org.chromium.build.annotations.NullMarked;
@@ -32,6 +31,7 @@
 
     private final View mView;
     private final Activity mActivity;
+    private final int mToolbarHeightPx;
 
     /**
      * @param activity The activity displays the view.
@@ -39,7 +39,7 @@
      * @param config The UiConfig object to subscribe to.
      * @param defaultPaddingPixels Padding to use in {@link HorizontalDisplayStyle#REGULAR}.
      * @param minWidePaddingPixels Minimum lateral padding to use in {@link
-     *         HorizontalDisplayStyle#WIDE}.
+     *     HorizontalDisplayStyle#WIDE}.
      */
     public FeedStreamViewResizer(
             Activity activity,
@@ -50,6 +50,9 @@
         super(view, config, defaultPaddingPixels, minWidePaddingPixels);
         mView = view;
         mActivity = activity;
+
+        mToolbarHeightPx =
+                mActivity.getResources().getDimensionPixelSize(R.dimen.default_action_bar_height);
     }
 
     /**
@@ -106,7 +109,7 @@
         float dpToPx = resources.getDisplayMetrics().density;
         float screenWidth = getScreenWidth();
         float screenHeight = resources.getConfiguration().screenHeightDp * dpToPx;
-        float useableHeight = screenHeight - statusBarHeight() - toolbarHeight();
+        float useableHeight = screenHeight - statusBarHeight() - mToolbarHeightPx;
         int customPadding =
                 (int) ((screenWidth - useableHeight * FEED_IMAGE_OR_VIDEO_ASPECT_RATIO) / 2);
         return Math.max(customPadding, padding);
@@ -145,18 +148,6 @@
         return screenWidth;
     }
 
-    private int toolbarHeight() {
-        ViewGroup contentContainer = mActivity.findViewById(android.R.id.content);
-        if (contentContainer == null) {
-            return 0;
-        }
-        View toolbarView = contentContainer.findViewById(R.id.toolbar_container);
-        if (toolbarView == null) {
-            return 0;
-        }
-        return toolbarView.getHeight();
-    }
-
     private int statusBarHeight() {
         Rect visibleContentRect = new Rect();
         mActivity.getWindow().getDecorView().getWindowVisibleDisplayFrame(visibleContentRect);
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStreamViewResizerTest.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStreamViewResizerTest.java
index 1ebbc66..70d10ea 100644
--- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStreamViewResizerTest.java
+++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/FeedStreamViewResizerTest.java
@@ -93,8 +93,9 @@
     public void computePaddingPhoneLandscape() {
         mUiConfig.setDisplayStyleForTesting(
                 new DisplayStyle(HorizontalDisplayStyle.REGULAR, VerticalDisplayStyle.REGULAR));
-        // expectedPadding = ((width - usableHeight * 1.778) / 2) = (820 - (390*1.778))/2 = 63;
-        int expectedPadding = 63;
+        // expectedPadding = ((width - (usableHeight - toolbarHeight) * 1.778) / 2)
+        //                 = (820 - ((390 - 56)*1.778))/2 = 113;
+        int expectedPadding = 113;
         assertPaddingEquals(expectedPadding);
     }
 
diff --git a/chrome/browser/feedback/BUILD.gn b/chrome/browser/feedback/BUILD.gn
index 58f32a78..93f4cc5 100644
--- a/chrome/browser/feedback/BUILD.gn
+++ b/chrome/browser/feedback/BUILD.gn
@@ -113,7 +113,6 @@
       "//chrome/browser/ui:ui_features",
       "//chrome/browser/ui/browser_window",
       "//chrome/browser/ui/tabs:tab_strip",
-      "//chrome/browser/updater",
       "//chrome/common",
       "//components/device_event_log",
       "//components/feedback",
@@ -152,6 +151,9 @@
       "//chromeos/version",
     ]
   }
+  if (is_win || is_mac) {
+    deps += [ "//chrome/browser/updater:browser_updater_client" ]
+  }
   if (is_linux) {
     sources += [
       "system_logs/log_sources/ozone_platform_state_dump_source.cc",
diff --git a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
index 6d31fbd..7997d15 100644
--- a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
+++ b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
@@ -75,7 +75,7 @@
 
 #if BUILDFLAG(IS_MAC)
 #include "base/mac/mac_util.h"
-#include "chrome/browser/updater/updater.h"
+#include "chrome/browser/updater/browser_updater_client.h"
 #endif
 
 #if !BUILDFLAG(IS_CHROMEOS)
@@ -690,8 +690,8 @@
 #if BUILDFLAG(IS_MAC)
 void ChromeInternalLogSource::PopulateLastUpdateState(
     SystemLogsResponse* response) {
-  const std::optional<updater::mojom::UpdateState> update_state =
-      updater::GetLastOnDemandUpdateState();
+  const std::optional<updater::UpdateService::UpdateState> update_state =
+      BrowserUpdaterClient::GetLastOnDemandUpdateState();
   if (!update_state) {
     return;  // There is nothing to include if no update check has completed.
   }
diff --git a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source_unittest.cc b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source_unittest.cc
index 41c655ad..21e9cbf 100644
--- a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source_unittest.cc
+++ b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source_unittest.cc
@@ -7,12 +7,10 @@
 #include <memory>
 #include <vector>
 
-#include "base/functional/callback_helpers.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
-#include "chrome/browser/buildflags.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "content/public/browser/gpu_data_manager.h"
@@ -26,8 +24,8 @@
 #if BUILDFLAG(IS_MAC)
 #include "base/mac/mac_util.h"
 #include "chrome/browser/metrics/chrome_metrics_service_client.h"
+#include "chrome/browser/updater/browser_updater_client.h"
 #include "chrome/browser/updater/browser_updater_client_testutils.h"
-#include "chrome/browser/updater/updater.h"
 #include "chrome/updater/constants.h"       // nogncheck
 #include "chrome/updater/update_service.h"  // nogncheck
 #include "chrome/updater/updater_scope.h"   // nogncheck
@@ -212,21 +210,23 @@
 }
 #endif  // BUILDFLAG(IS_CHROMEOS)
 
-#if BUILDFLAG(IS_MAC) && BUILDFLAG(ENABLE_UPDATER)
+#if BUILDFLAG(IS_MAC)
 TEST_F(ChromeInternalLogSourceTest, UpdaterDataPresent) {
-  base::ScopedClosureRunner service_override =
-      updater::OverrideService(updater::UpdateService::Result::kSuccess, {});
   base::RunLoop loop;
-  updater::CheckForUpdate(
-      base::BindRepeating([](const updater::UpdateService::UpdateState&) {
-      }).Then(loop.QuitWhenIdleClosure()));
+  BrowserUpdaterClient::Create(
+      updater::MakeFakeService(updater::UpdateService::Result::kSuccess, {}),
+      updater::UpdaterScope::kUser)
+      ->CheckForUpdate(base::BindLambdaForTesting(
+          [&](const updater::UpdateService::UpdateState& status) {
+            loop.QuitWhenIdle();
+          }));
   loop.Run();
 
   std::unique_ptr<SystemLogsResponse> response = GetChromeInternalLogs();
   EXPECT_EQ(response->at("update_error_code"), "0/0");
   EXPECT_EQ(response->at("update_hresult"), "0");
 }
-#endif  // BUILDFLAG(IS_MAC) && BUILDFLAG(ENABLE_UPDATER)
+#endif  // BUILDFLAG(IS_MAC)
 
 }  // namespace
 }  // namespace system_logs
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 4090345..03b540f5 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2674,11 +2674,6 @@
     "expiry_milestone": 145
   },
   {
-    "name": "draw-key-native-edge-to-edge",
-    "owners": ["wenyufu@chromium.org", "clhager@google.com", "edge-to-edge@chromium.org"],
-    "expiry_milestone": 145
-  },
-  {
     "name": "drive-fs-mirroring",
     "owners": [ "wenbojie@chromium.org", "fdegros@chromium.org", "simmonsjosh@google.com"],
     "expiry_milestone": 150
@@ -2704,16 +2699,6 @@
     "expiry_milestone": 90
   },
   {
-    "name": "dynamic-safe-area-insets",
-    "owners": [ "wenyufu@chromium.org", "clhager@google.com","twellington@chromium.org" ],
-    "expiry_milestone": 145
-  },
-  {
-    "name": "dynamic-safe-area-insets-on-scroll",
-    "owners": [ "wenyufu@chromium.org", "clhager@google.com", "twellington@chromium.org" ],
-    "expiry_milestone": 145
-  },
-  {
     "name": "dynamic-search-update-animation",
     "owners": ["yulunwu@chromium.org"],
     "expiry_milestone": 103
@@ -2784,11 +2769,6 @@
     "expiry_milestone": 145
   },
   {
-    "name": "edge-to-edge-web-opt-in",
-    "owners": ["clhager@google.com", "wenyufu@chromium.org","twellington@chromium.org", "edge-to-edge@chromium.org"],
-    "expiry_milestone": 145
-  },
-  {
     "name": "elastic-overscroll",
     "owners": [ "arakeri@microsoft.com", "flackr@chromium.org" ],
     "expiry_milestone": 150
@@ -9347,11 +9327,6 @@
     "expiry_milestone": 135
   },
   {
-    "name": "set-up-list-shortened-duration",
-    "owners": [ "hiramahmood@google.com", "bling-pandamonium@google.com" ],
-    "expiry_milestone": 135
-  },
-  {
     "name": "set-up-list-without-sign-in-item",
     "owners": [ "hiramahmood@google.com", "bling-pandamonium@google.com" ],
     "expiry_milestone": 135
@@ -9784,11 +9759,6 @@
     "expiry_milestone": 130
   },
   {
-    "name": "tab-archival-drag-drop-android",
-    "owners": ["mfiaz@google.com", "clank-tab-dev@google.com"],
-    "expiry_milestone": 143
-  },
-  {
     "name": "tab-capture-infobar-links",
     "owners": [ "tovep@chromium.org", "eladalon@chromium.org" ],
     "expiry_milestone": 150
@@ -9935,11 +9905,6 @@
     "expiry_milestone": 150
   },
   {
-    "name": "tablet-tab-strip-animation",
-    "owners": [ "jtanaristy@google.org", "wenyufu@chromium.org" ],
-    "expiry_milestone": 150
-  },
-  {
     "name": "tabsearch-toolbar-button",
     "owners": [ "estalin@chromium.org", "top-chrome-desktop-ui@google.com" ],
     "expiry_milestone": 150
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 85dde76..b1a4a22 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -4121,11 +4121,6 @@
     "keyboard shortcuts and have the events routed directly to the website "
     "when in fullscreen mode.";
 
-inline constexpr char kTabArchivalDragDropAndroidName[] =
-    "Drag and Drop to Archive Tabs";
-inline constexpr char kTabArchivalDragDropAndroidDescription[] =
-    "Enables drag-and-drop tabs in the tab switcher to archive tabs.";
-
 inline constexpr char kTabFreezingUsesDiscardName[] =
     "Tab Freezing Uses Discard";
 inline constexpr char kTabFreezingUsesDiscardDescription[] =
@@ -4167,11 +4162,6 @@
 inline constexpr char kChromeNativeUrlOverridingDescription[] =
     "Allows for URL overriding for chrome-native:// pages";
 
-inline constexpr char kTabletTabStripAnimationName[] =
-    "Tablet Tab Strip Animation";
-inline constexpr char kTabletTabStripAnimationDescription[] =
-    "Enables new tablet tab strip animations.";
-
 inline constexpr char kDataSharingDebugLogsName[] =
     "Enable data sharing debug logs";
 inline constexpr char kDataSharingDebugLogsDescription[] =
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index 9b65350..f312646d 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -420,7 +420,6 @@
     &kSubmenusInAppMenu,
     &kSubmenusTabContextMenuLffTabStrip,
     &kSuppressToolbarCapturesAtGestureEnd,
-    &kTabArchivalDragDropAndroid,
     &kTabClosureMethodRefactor,
     &kTabFreezingUsesDiscard,
     &kTabGroupAndroidVisualDataCleanup,
@@ -433,7 +432,6 @@
     &kTabSwitcherGroupSuggestionsAndroid,
     &kTabSwitcherGroupSuggestionsTestModeAndroid,
     &kTabWindowManagerReportIndicesMismatch,
-    &kTabletTabStripAnimation,
     &kTestDefaultDisabled,
     &kTestDefaultEnabled,
     &kThirdPartyDisableChromeAutofillSettingsScreen,
@@ -652,7 +650,7 @@
 // Android with androidx.biometric.
 BASE_FEATURE(kDeviceAuthenticatorAndroidx, base::FEATURE_ENABLED_BY_DEFAULT);
 BASE_FEATURE(kDisableInstanceLimit, base::FEATURE_ENABLED_BY_DEFAULT);
-BASE_FEATURE(kDiscardPageWithCrashedSubframePolicy, base::FEATURE_DISABLED_BY_DEFAULT);
+BASE_FEATURE(kDiscardPageWithCrashedSubframePolicy, base::FEATURE_ENABLED_BY_DEFAULT);
 BASE_FEATURE(kDontAutoHideBrowserControls, base::FEATURE_DISABLED_BY_DEFAULT);
 BASE_FEATURE(kDrawChromePagesEdgeToEdge, base::FEATURE_ENABLED_BY_DEFAULT);
 BASE_FEATURE(kEdgeToEdgeBottomChin, base::FEATURE_ENABLED_BY_DEFAULT);
@@ -764,7 +762,6 @@
 BASE_FEATURE(kSubmenusInAppMenu, base::FEATURE_DISABLED_BY_DEFAULT);
 BASE_FEATURE(kSubmenusTabContextMenuLffTabStrip, base::FEATURE_DISABLED_BY_DEFAULT);
 BASE_FEATURE(kSuppressToolbarCapturesAtGestureEnd, base::FEATURE_ENABLED_BY_DEFAULT);
-BASE_FEATURE(kTabArchivalDragDropAndroid, base::FEATURE_ENABLED_BY_DEFAULT);
 BASE_FEATURE(kTabClosureMethodRefactor, base::FEATURE_DISABLED_BY_DEFAULT);
 BASE_FEATURE(kTabFreezingUsesDiscard, base::FEATURE_DISABLED_BY_DEFAULT);
 BASE_FEATURE(kTabGroupAndroidVisualDataCleanup, base::FEATURE_ENABLED_BY_DEFAULT);
@@ -777,7 +774,6 @@
 BASE_FEATURE(kTabSwitcherGroupSuggestionsAndroid, base::FEATURE_DISABLED_BY_DEFAULT);
 BASE_FEATURE(kTabSwitcherGroupSuggestionsTestModeAndroid, base::FEATURE_DISABLED_BY_DEFAULT);
 BASE_FEATURE(kTabWindowManagerReportIndicesMismatch, base::FEATURE_ENABLED_BY_DEFAULT);
-BASE_FEATURE(kTabletTabStripAnimation, base::FEATURE_ENABLED_BY_DEFAULT);
 BASE_FEATURE(kTestDefaultDisabled, base::FEATURE_DISABLED_BY_DEFAULT);
 BASE_FEATURE(kTestDefaultEnabled, base::FEATURE_ENABLED_BY_DEFAULT);
 // If the user configured Chrome to use 3P autofill and this feature is enabled,
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index 4fa21ba..db01143f 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -255,7 +255,6 @@
 BASE_DECLARE_FEATURE(kSubmenusInAppMenu);
 BASE_DECLARE_FEATURE(kSubmenusTabContextMenuLffTabStrip);
 BASE_DECLARE_FEATURE(kSuppressToolbarCapturesAtGestureEnd);
-BASE_DECLARE_FEATURE(kTabArchivalDragDropAndroid);
 BASE_DECLARE_FEATURE(kTabClosureMethodRefactor);
 BASE_DECLARE_FEATURE(kTabFreezingUsesDiscard);
 BASE_DECLARE_FEATURE(kTabGroupAndroidVisualDataCleanup);
@@ -268,7 +267,6 @@
 BASE_DECLARE_FEATURE(kTabSwitcherGroupSuggestionsAndroid);
 BASE_DECLARE_FEATURE(kTabSwitcherGroupSuggestionsTestModeAndroid);
 BASE_DECLARE_FEATURE(kTabWindowManagerReportIndicesMismatch);
-BASE_DECLARE_FEATURE(kTabletTabStripAnimation);
 BASE_DECLARE_FEATURE(kTestDefaultDisabled);
 BASE_DECLARE_FEATURE(kTestDefaultEnabled);
 BASE_DECLARE_FEATURE(kThirdPartyDisableChromeAutofillSettingsScreen);
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index bbe88aa..ff15f07 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -642,8 +642,6 @@
     public static final String SYNC_ENABLE_NEW_SYNC_DASHBOARD_URL = "SyncEnableNewSyncDashboardUrl";
     public static final String SYNC_ENABLE_PASSWORDS_SYNC_ERROR_MESSAGE_ALTERNATIVE =
             "SyncEnablePasswordsSyncErrorMessageAlternative";
-    public static final String TABLET_TAB_STRIP_ANIMATION = "TabletTabStripAnimation";
-    public static final String TAB_ARCHIVAL_DRAG_DROP_ANDROID = "TabArchivalDragDropAndroid";
     public static final String TAB_CLOSURE_METHOD_REFACTOR = "TabClosureMethodRefactor";
     public static final String TAB_FREEZING_USES_DISCARD = "TabFreezingUsesDiscard";
     public static final String TAB_GROUP_ANDROID_VISUAL_DATA_CLEANUP =
@@ -1048,8 +1046,6 @@
             newCachedFlag(TAB_STRIP_INCOGNITO_MIGRATION, BuildConfig.IS_DESKTOP_ANDROID, true);
     public static final CachedFlag sTabWindowManagerReportIndicesMismatch =
             newCachedFlag(TAB_WINDOW_MANAGER_REPORT_INDICES_MISMATCH, true);
-    public static final CachedFlag sTabletTabStripAnimation =
-            newCachedFlag(TABLET_TAB_STRIP_ANIMATION, true);
     public static final CachedFlag sTestDefaultDisabled =
             newCachedFlag(TEST_DEFAULT_DISABLED, false);
     public static final CachedFlag sTestDefaultEnabled = newCachedFlag(TEST_DEFAULT_ENABLED, true);
@@ -1244,7 +1240,6 @@
                     sTabStripDensityChangeAndroid,
                     sTabStripIncognitoMigration,
                     sTabWindowManagerReportIndicesMismatch,
-                    sTabletTabStripAnimation,
                     sToolbarPhoneAnimationRefactor,
                     sToolbarSnapshotRefactor,
                     sToolbarStaleCaptureBugFix,
@@ -1348,8 +1343,6 @@
             newMutableFlagWithSafeDefault(SHOW_TAB_LIST_ANIMATIONS, false);
     public static final MutableFlagWithSafeDefault sSuppressToolbarCapturesAtGestureEnd =
             newMutableFlagWithSafeDefault(SUPPRESS_TOOLBAR_CAPTURES_AT_GESTURE_END, false);
-    public static final MutableFlagWithSafeDefault sTabArchivalDragDropAndroid =
-            newMutableFlagWithSafeDefault(TAB_ARCHIVAL_DRAG_DROP_ANDROID, true);
     public static final MutableFlagWithSafeDefault sTabFreezingUsesDiscard =
             newMutableFlagWithSafeDefault(TAB_FREEZING_USES_DISCARD, false);
     public static final MutableFlagWithSafeDefault sTabSwitcherGroupSuggestionsAndroid =
diff --git a/chrome/browser/glic/media/BUILD.gn b/chrome/browser/glic/media/BUILD.gn
index 1cae56b..bdaf64b 100644
--- a/chrome/browser/glic/media/BUILD.gn
+++ b/chrome/browser/glic/media/BUILD.gn
@@ -23,6 +23,7 @@
     "//base",
     "//chrome/browser/glic:mojo_bindings",
     "//chrome/browser/media/webrtc",
+    "//chrome/browser/picture_in_picture",
     "//chrome/browser/profiles:profile",
     "//components/live_caption",
     "//components/live_caption:constants",
diff --git a/chrome/browser/glic/media/glic_media_context.cc b/chrome/browser/glic/media/glic_media_context.cc
index 5b82ab7..65ef7ca 100644
--- a/chrome/browser/glic/media/glic_media_context.cc
+++ b/chrome/browser/glic/media/glic_media_context.cc
@@ -42,11 +42,14 @@
 }
 
 bool GlicMediaContext::OnResult(const media::SpeechRecognitionResult& result) {
+  // Do not turn off transcription here, since there's no way to re-enable it
+  // later when IsExcludedFromTranscript() changes.
+  if (IsExcludedFromTranscript()) {
+    return true;
+  }
+
   Transcript* transcript = GetOrCreateTranscript();
   if (!transcript) {
-    // Do not turn off transcription here, since there's no way to re-enable it
-    // later.  For example, if `IsExcludedByTranscript()` changes, then we'd be
-    // stuck without transcription.
     return true;
   }
 
diff --git a/chrome/browser/glic/media/glic_media_context.h b/chrome/browser/glic/media/glic_media_context.h
index 1919719..599de8c 100644
--- a/chrome/browser/glic/media/glic_media_context.h
+++ b/chrome/browser/glic/media/glic_media_context.h
@@ -36,6 +36,8 @@
 
   void OnPeerConnectionAdded();
   void OnPeerConnectionRemoved();
+  void OnPipPeerConnectionAdded();
+  void OnPipPeerConnectionRemoved();
 
   bool is_excluded_from_transcript_for_testing() {
     return IsExcludedFromTranscript();
diff --git a/chrome/browser/glic/media/glic_media_integration.cc b/chrome/browser/glic/media/glic_media_integration.cc
index 81767025..e3733939 100644
--- a/chrome/browser/glic/media/glic_media_integration.cc
+++ b/chrome/browser/glic/media/glic_media_integration.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/glic/media/glic_media_context.h"
 #include "chrome/browser/glic/media/glic_media_page_cache.h"
 #include "chrome/browser/glic/media/media_transcript_provider_impl.h"
+#include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/live_caption/caption_controller_base.h"
 #include "components/live_caption/caption_util.h"
@@ -52,6 +53,20 @@
         context->OnPeerConnectionAdded();
       }
     });
+
+    // Also attribute this to its opener WebContents if this is a document PiP
+    // window.
+    if (auto* pip_window_manager =
+            PictureInPictureWindowManager::GetInstance()) {
+      auto* opener_wc = pip_window_manager->GetWebContents();
+      if (opener_wc) {
+        if (auto* context =
+                glic::GlicMediaContext::GetOrCreateForCurrentDocument(
+                    opener_wc->GetPrimaryMainFrame())) {
+          context->OnPeerConnectionAdded();
+        }
+      }
+    }
   }
 
   void OnPeerConnectionRemoved(
@@ -74,6 +89,20 @@
         context->OnPeerConnectionRemoved();
       }
     });
+
+    // Also attribute this to its opener WebContents if this is a document PiP
+    // window.
+    if (auto* pip_window_manager =
+            PictureInPictureWindowManager::GetInstance()) {
+      auto* opener_wc = pip_window_manager->GetWebContents();
+      if (opener_wc) {
+        if (auto* context =
+                glic::GlicMediaContext::GetOrCreateForCurrentDocument(
+                    opener_wc->GetPrimaryMainFrame())) {
+          context->OnPeerConnectionRemoved();
+        }
+      }
+    }
   }
 };
 
diff --git a/chrome/browser/glic/media/glic_media_integration_unittest.cc b/chrome/browser/glic/media/glic_media_integration_unittest.cc
index b92c3ed..1e8d365e 100644
--- a/chrome/browser/glic/media/glic_media_integration_unittest.cc
+++ b/chrome/browser/glic/media/glic_media_integration_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/accessibility/live_caption/live_caption_controller_factory.h"
 #include "chrome/browser/glic/media/glic_media_context.h"
+#include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h"
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "components/live_caption/live_caption_controller.h"
@@ -286,6 +287,30 @@
   EXPECT_FALSE(subframe_context->is_excluded_from_transcript_for_testing());
 }
 
+TEST_F(GlicMediaIntegrationTest,
+       PeerConnectionInDocumentPiPPreventsTranscription) {
+  auto* integration = GetIntegration();
+  auto* main_context = GlicMediaContext::GetOrCreateForCurrentDocument(rfh());
+
+  // Create a document pip window.
+  std::unique_ptr<content::WebContents> pip_web_contents =
+      content::WebContentsTester::CreateTestWebContents(
+          web_contents()->GetBrowserContext(), nullptr);
+  auto* pip_window_manager = PictureInPictureWindowManager::GetInstance();
+  pip_window_manager->EnterDocumentPictureInPicture(web_contents(),
+                                                    pip_web_contents.get());
+
+  // Add a peer connection to the pip window.
+  integration->OnPeerConnectionAddedForTesting(
+      pip_web_contents->GetPrimaryMainFrame());
+  EXPECT_TRUE(main_context->is_excluded_from_transcript_for_testing());
+
+  // Remove the peer connection.
+  integration->OnPeerConnectionRemovedForTesting(
+      pip_web_contents->GetPrimaryMainFrame());
+  EXPECT_FALSE(main_context->is_excluded_from_transcript_for_testing());
+}
+
 TEST_F(GlicMediaIntegrationTest, ExcludedOriginsStopTranscription) {
   // Sending a transcript to an excluded origin should request that
   // transcription stops.
diff --git a/chrome/browser/language/android/java/res/xml/languages_detailed_preferences.xml b/chrome/browser/language/android/java/res/xml/languages_detailed_preferences.xml
index d744b3e..5760f32b 100644
--- a/chrome/browser/language/android/java/res/xml/languages_detailed_preferences.xml
+++ b/chrome/browser/language/android/java/res/xml/languages_detailed_preferences.xml
@@ -48,8 +48,7 @@
 
         <org.chromium.components.browser_ui.settings.ChromeSwitchPreference
             android:key="translate_switch"
-            android:summaryOn="@string/languages_send_translate_switch"
-            android:summaryOff="@string/languages_send_translate_switch"
+            android:title="@string/languages_send_translate_switch"
             app:allowDividerAbove="false"
             app:allowDividerBelow="true"/>
 
diff --git a/chrome/browser/language/android/java/res/xml/languages_preferences.xml b/chrome/browser/language/android/java/res/xml/languages_preferences.xml
index b23241a0..901f42f1 100644
--- a/chrome/browser/language/android/java/res/xml/languages_preferences.xml
+++ b/chrome/browser/language/android/java/res/xml/languages_preferences.xml
@@ -20,7 +20,6 @@
 
     <org.chromium.components.browser_ui.settings.ChromeSwitchPreference
         android:key="translate_switch"
-        android:summaryOn="@string/languages_offer_translate_switch"
-        android:summaryOff="@string/languages_offer_translate_switch" />
+        android:title="@string/languages_offer_translate_switch" />
 
 </PreferenceScreen>
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageSettings.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageSettings.java
index e8741758..37bf3e0 100644
--- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageSettings.java
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageSettings.java
@@ -7,6 +7,7 @@
 import static org.chromium.build.NullUtil.assumeNonNull;
 
 import android.app.Activity;
+import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.text.TextUtils;
@@ -28,6 +29,7 @@
 import org.chromium.chrome.browser.language.R;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.preferences.PrefServiceUtil;
+import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.settings.ChromeBaseSettingsFragment;
 import org.chromium.chrome.browser.settings.ChromeManagedPreferenceDelegate;
 import org.chromium.chrome.browser.settings.SettingsNavigationFactory;
@@ -35,6 +37,7 @@
 import org.chromium.chrome.browser.translate.TranslateBridge;
 import org.chromium.components.browser_ui.settings.ChromeSwitchPreference;
 import org.chromium.components.browser_ui.settings.SettingsUtils;
+import org.chromium.components.browser_ui.settings.search.SettingsIndexData;
 import org.chromium.components.prefs.PrefChangeRegistrar;
 import org.chromium.components.prefs.PrefService;
 import org.chromium.components.user_prefs.UserPrefs;
@@ -249,6 +252,7 @@
                     public boolean onPreferenceChange(Preference preference, Object newValue) {
                         boolean enabled = (boolean) newValue;
                         getPrefService().setBoolean(Pref.OFFER_TRANSLATE_ENABLED, enabled);
+                        updateTranslateAdvancedSectionIndex(enabled);
                         contentLanguagesPreference.notifyPrefChanged();
                         translationAdvancedSection.setVisible(enabled);
                         LanguagesManager.recordAction(
@@ -456,12 +460,44 @@
         return "languages";
     }
 
-    // TODO(crbug.com/444470792): Verify if these are the prefs to be removed and if dynamic ones
-    // need to be handled.
     public static final ChromeBaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
             new ChromeBaseSearchIndexProvider(
                     LanguageSettings.class.getName(),
                     shouldShowDetailedPreferences()
-                            ? R.xml.languages_preferences
-                            : R.xml.languages_detailed_preferences);
+                            ? R.xml.languages_detailed_preferences
+                            : R.xml.languages_preferences) {
+
+                @Override
+                public void updateDynamicPreferences(
+                        Context context, SettingsIndexData indexData, Profile profile) {
+                    if (shouldShowDetailedPreferences()) {
+                        indexData.updateEntryForKey(
+                                LanguageSettings.class.getName(),
+                                APP_LANGUAGE_PREFERENCE_KEY,
+                                R.string.default_lang_subtitle);
+                        if (!UserPrefs.get(profile).getBoolean(Pref.OFFER_TRANSLATE_ENABLED)) {
+                            updateTranslateAdvancedSectionIndex(false);
+                        }
+                    }
+                }
+            };
+
+    private static void updateTranslateAdvancedSectionIndex(boolean enabled) {
+        var indexData = SettingsIndexData.getInstance();
+        if (indexData == null) return;
+
+        String prefFrag = LanguageSettings.class.getName();
+        if (enabled) {
+            indexData.addEntryForKey(
+                    prefFrag, TARGET_LANGUAGE_KEY, R.string.languages_settings_target);
+            indexData.addEntryForKey(
+                    prefFrag, ALWAYS_LANGUAGES_KEY, R.string.languages_settings_automatic);
+            indexData.addEntryForKey(
+                    prefFrag, NEVER_LANGUAGES_KEY, R.string.languages_settings_dont_offer_langs);
+        } else {
+            indexData.removeEntryForKey(prefFrag, TARGET_LANGUAGE_KEY);
+            indexData.removeEntryForKey(prefFrag, ALWAYS_LANGUAGES_KEY);
+            indexData.removeEntryForKey(prefFrag, NEVER_LANGUAGES_KEY);
+        }
+    }
 }
diff --git a/chrome/browser/metrics/google_update_metrics_provider_mac.cc b/chrome/browser/metrics/google_update_metrics_provider_mac.cc
index 327eb5b7..f2480e7c 100644
--- a/chrome/browser/metrics/google_update_metrics_provider_mac.cc
+++ b/chrome/browser/metrics/google_update_metrics_provider_mac.cc
@@ -10,7 +10,7 @@
 #include "base/hash/hash.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/metrics_hashes.h"
-#include "chrome/browser/updater/updater.h"
+#include "chrome/browser/updater/browser_updater_client.h"
 #include "chrome/updater/update_service.h"
 #include "third_party/metrics_proto/system_profile.pb.h"
 
@@ -23,7 +23,7 @@
       system_profile_proto->mutable_google_update();
 
   std::optional<updater::UpdateService::AppState> browser_state =
-      updater::GetLastKnownBrowserRegistration();
+      BrowserUpdaterClient::GetLastKnownBrowserRegistration();
   if (browser_state) {
     const std::string browser_state_cohort = browser_state->cohort.value_or("");
     base::UmaHistogramSparse("GoogleUpdate.InstallDetails.UpdateCohortId",
@@ -33,7 +33,7 @@
   }
 
   std::optional<updater::UpdateService::AppState> updater_state =
-      updater::GetLastKnownUpdaterRegistration();
+      BrowserUpdaterClient::GetLastKnownUpdaterRegistration();
   if (updater_state) {
     google_update->mutable_google_update_status()->set_version(
         updater_state->version);
diff --git a/chrome/browser/metrics/google_update_metrics_provider_mac_unittest.cc b/chrome/browser/metrics/google_update_metrics_provider_mac_unittest.cc
index fd3a7a7..67a0c1c 100644
--- a/chrome/browser/metrics/google_update_metrics_provider_mac_unittest.cc
+++ b/chrome/browser/metrics/google_update_metrics_provider_mac_unittest.cc
@@ -4,13 +4,10 @@
 
 #include "chrome/browser/metrics/google_update_metrics_provider_mac.h"
 
-#include "base/functional/callback_helpers.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
 #include "base/test/task_environment.h"
 #include "base/version.h"
-#include "build/build_config.h"
-#include "chrome/browser/buildflags.h"
 #include "chrome/browser/updater/browser_updater_client.h"
 #include "chrome/browser/updater/browser_updater_client_testutils.h"
 #include "chrome/updater/branded_constants.h"
@@ -18,25 +15,31 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/metrics_proto/system_profile.pb.h"
 
-#if BUILDFLAG(ENABLE_UPDATER)
 TEST(GoogleUpdateMetricsProviderMacTest, SetsVersions) {
   base::test::SingleThreadTaskEnvironment task_environment;
   updater::UpdateService::AppState app1;
   app1.app_id = updater::kUpdaterAppId;
   app1.version = "1.2.3.4";
   updater::UpdateService::AppState app2;
-  app2.app_id = updater::GetAppId();
-  app2.ecp = updater::GetExpectedEcp();
+  app2.app_id = BrowserUpdaterClient::GetAppId();
+  app2.ecp = BrowserUpdaterClient::GetExpectedEcp();
   app2.version = "5.6.7.8";
-  base::ScopedClosureRunner scoped_override = updater::OverrideService(
-      updater::UpdateService::Result::kSuccess, {
-                                                    app1,
-                                                    app2,
-                                                });
-  updater::LoadAppStates();
+  {
+    base::RunLoop loop;
+    BrowserUpdaterClient::Create(
+        updater::MakeFakeService(updater::UpdateService::Result::kSuccess,
+                                 {
+                                     app1,
+                                     app2,
+                                 }),
+        updater::UpdaterScope::kUser)
+        ->IsBrowserRegistered(base::BindLambdaForTesting(
+            [&](bool registered) { loop.QuitWhenIdle(); }));
+    loop.Run();
+  }
+
   metrics::SystemProfileProto proto;
   GoogleUpdateMetricsProviderMac().ProvideSystemProfileMetrics(&proto);
   EXPECT_EQ(proto.google_update().client_status().version(), "5.6.7.8");
   EXPECT_EQ(proto.google_update().google_update_status().version(), "1.2.3.4");
 }
-#endif
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter.cc b/chrome/browser/metrics/process_memory_metrics_emitter.cc
index 3128d90..5f2bed7 100644
--- a/chrome/browser/metrics/process_memory_metrics_emitter.cc
+++ b/chrome/browser/metrics/process_memory_metrics_emitter.cc
@@ -11,6 +11,7 @@
 #include <utility>
 
 #include "base/allocator/buildflags.h"
+#include "base/byte_size.h"
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
 #include "base/containers/flat_set.h"
@@ -1662,11 +1663,12 @@
 #if BUILDFLAG(IS_CHROMEOS)
     base::SystemMemoryInfo system_meminfo;
     if (base::GetSystemMemoryInfo(&system_meminfo)) {
-      int64_t mem_used_mb =
-          (system_meminfo.total - system_meminfo.available).InMiB();
+      const base::ByteSizeDelta mem_used =
+          system_meminfo.total - system_meminfo.available;
       UMA_HISTOGRAM_LARGE_MEMORY_MB("Memory.System.MemAvailableMB",
                                     system_meminfo.available.InMiB());
-      UMA_HISTOGRAM_LARGE_MEMORY_MB("Memory.System.MemUsedMB", mem_used_mb);
+      UMA_HISTOGRAM_LARGE_MEMORY_MB("Memory.System.MemUsedMB",
+                                    mem_used.InMiB());
     }
 #endif
   }
diff --git a/chrome/browser/performance_manager/metrics/metrics_provider_common.cc b/chrome/browser/performance_manager/metrics/metrics_provider_common.cc
index 3b34d55..538d23d4 100644
--- a/chrome/browser/performance_manager/metrics/metrics_provider_common.cc
+++ b/chrome/browser/performance_manager/metrics/metrics_provider_common.cc
@@ -4,12 +4,14 @@
 
 #include "chrome/browser/performance_manager/metrics/metrics_provider_common.h"
 
+#include "base/byte_count.h"
+#include "base/byte_size.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/process/process_metrics.h"
+#include "base/system/sys_info.h"
 #include "content/public/browser/browser_accessibility_state.h"
 #include "ui/accessibility/ax_mode.h"
-#include "base/system/sys_info.h"
-#include "base/process/process_metrics.h"
 
 namespace performance_manager {
 
@@ -65,8 +67,10 @@
 MetricsProviderCommon::~MetricsProviderCommon() = default;
 
 void MetricsProviderCommon::RecordAvailableMemoryMetrics() {
-  auto available_bytes = base::SysInfo::AmountOfAvailablePhysicalMemory();
-  auto total_bytes = base::SysInfo::AmountOfPhysicalMemory();
+  auto available_bytes = base::ByteSize::FromByteCount(
+      base::SysInfo::AmountOfAvailablePhysicalMemory());
+  auto total_bytes =
+      base::ByteSize::FromByteCount(base::SysInfo::AmountOfPhysicalMemory());
 
   base::UmaHistogramMemoryLargeMB("Memory.Experimental.AvailableMemoryMB",
                                   available_bytes.InMiB());
diff --git a/chrome/browser/performance_manager/policies/sustained_memory_pressure_evaluator.cc b/chrome/browser/performance_manager/policies/sustained_memory_pressure_evaluator.cc
index 6f565c7..5b32e130 100644
--- a/chrome/browser/performance_manager/policies/sustained_memory_pressure_evaluator.cc
+++ b/chrome/browser/performance_manager/policies/sustained_memory_pressure_evaluator.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/performance_manager/policies/sustained_memory_pressure_evaluator.h"
 
-#include "base/byte_count.h"
+#include "base/byte_size.h"
 #include "base/process/process_metrics.h"
 #include "build/build_config.h"
 #include "chrome/browser/performance_manager/policies/policy_features.h"
@@ -21,8 +21,8 @@
     return false;
   }
 
-  base::ByteCount total = info.total;
-  base::ByteCount avail = info.avail_phys;
+  base::ByteSize total = info.total;
+  base::ByteSize avail = info.avail_phys;
 
   // This is unexpected, do nothing.
   if (!total.is_positive()) {
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
index f1efb6f..dd93459d 100644
--- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
+++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
@@ -521,8 +521,8 @@
     public static final KeyPrefix MULTI_INSTANCE_LAST_ACCESSED_TIME =
             new KeyPrefix("Chrome.MultiInstance.LastAccessedTime.*");
     public static final KeyPrefix MULTI_INSTANCE_URL = new KeyPrefix("Chrome.MultiInstance.Url.*");
-    public static final KeyPrefix MULTI_INSTANCE_CLOSED_BY_USER =
-            new KeyPrefix("Chrome.MultiInstance.ClosedByUser.*");
+    public static final KeyPrefix MULTI_INSTANCE_MARKED_FOR_DELETION =
+            new KeyPrefix("Chrome.MultiInstance.MarkedForDeletion.*");
 
     // Start timestamp of 1-day period for measuring the duration of disjoint time spent in various
     // windowing modes.
@@ -1219,7 +1219,7 @@
                 MULTI_INSTANCE_TITLE.pattern(),
                 MULTI_INSTANCE_CUSTOM_TITLE.pattern(),
                 MULTI_INSTANCE_URL.pattern(),
-                MULTI_INSTANCE_CLOSED_BY_USER.pattern(),
+                MULTI_INSTANCE_MARKED_FOR_DELETION.pattern(),
                 MULTI_WINDOW_MODE_ACTIVITY_COUNT.pattern(),
                 MULTI_WINDOW_MODE_CYCLE_START_TIME,
                 MULTI_WINDOW_MODE_DURATION_MS.pattern(),
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java
index 42ca30ec..b4eed138 100644
--- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java
+++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java
@@ -44,6 +44,7 @@
                 "Chrome.Flags.SafeString.*",
                 "Chrome.Flags.SafeValuesVersion",
                 "Chrome.IsolatedSplits.VersionCode",
+                "Chrome.MultiInstance.ClosedByUser.*",
                 "Chrome.NtpCustomization.BackgroundImageLandscapeMatrix",
                 "Chrome.NtpCustomization.BackgroundImagePortraitMatrix",
                 "Chrome.OfflineMeasurements.HttpProbeResultsList",
diff --git a/chrome/browser/resources/downloads/manager.ts b/chrome/browser/resources/downloads/manager.ts
index 7892adc..56562af 100644
--- a/chrome/browser/resources/downloads/manager.ts
+++ b/chrome/browser/resources/downloads/manager.ts
@@ -319,6 +319,16 @@
         this.inSearchMode_ ? 'noSearchResults' : 'noDownloads');
   }
 
+  /**
+   * @return Whether the undo command can be handled by accelerator.
+   */
+  private canHandleUndoByAccelerator_(): boolean {
+    // If the toolbar's search field is in a focused state, we should not
+    // handle the undo command by accelerator, as it conflicts with the
+    // text undo accelerator key of the search field.
+    return !this.$.toolbar.isSearchFocused();
+  }
+
   private onKeyDown_(e: KeyboardEvent) {
     let clearAllKey = 'c';
     // <if expr="is_macosx">
@@ -337,7 +347,7 @@
       // <if expr="is_macosx">
       hasTriggerModifier = !e.ctrlKey && e.metaKey;
       // </if>
-      if (hasTriggerModifier) {
+      if (hasTriggerModifier && this.canHandleUndoByAccelerator_()) {
         this.onUndoCommand_();
         e.preventDefault();
       }
diff --git a/chrome/browser/resources/updater/event_list/filter_bar.html.ts b/chrome/browser/resources/updater/event_list/filter_bar.html.ts
index b0942d3..1e54a98 100644
--- a/chrome/browser/resources/updater/event_list/filter_bar.html.ts
+++ b/chrome/browser/resources/updater/event_list/filter_bar.html.ts
@@ -4,6 +4,7 @@
 
 import '/strings.m.js';
 
+import {assertNotReached} from '//resources/js/assert.js';
 import {loadTimeData} from '//resources/js/load_time_data.js';
 import type {TemplateResult} from '//resources/lit/v3_0/lit.rollup.js';
 import {html, nothing} from '//resources/lit/v3_0/lit.rollup.js';
@@ -269,6 +270,8 @@
         return renderOutcomeFilterDialogContents(element);
       case 'date':
         return renderDateFilterDialogContents(element);
+      default:
+        assertNotReached();
     }
   })();
 
diff --git a/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/settings/SearchEngineAdapter.java b/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/settings/SearchEngineAdapter.java
index d2bd0fa6..0cda3cb 100644
--- a/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/settings/SearchEngineAdapter.java
+++ b/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/settings/SearchEngineAdapter.java
@@ -507,11 +507,12 @@
 
             View containerView = view.findViewById(R.id.container);
 
-            ContainerStyle style =
-                    mContainmentItemController.createBuilderWithDefaultStyle(
-                            isTop, isBottom, /* isSingleLine= */ true);
-            ContainmentViewStyler.applyBackgroundStyle(containerView, style);
-            ContainmentViewStyler.applyMargins(containerView, style);
+            ContainerStyle containerStyle =
+                    mContainmentItemController
+                            .createStandardBuilder(isTop, isBottom, /* isSingleLine= */ true)
+                            .build();
+            ContainmentViewStyler.applyBackgroundStyle(containerView, containerStyle);
+            ContainmentViewStyler.applyMargins(containerView, containerStyle);
         }
 
         view.setOnClickListener(this);
diff --git a/chrome/browser/tabwindow/internal/android/java/src/org/chromium/chrome/browser/tabwindow/TabWindowManagerImplUnitTest.java b/chrome/browser/tabwindow/internal/android/java/src/org/chromium/chrome/browser/tabwindow/TabWindowManagerImplUnitTest.java
index 8d6e226..390d2f32 100644
--- a/chrome/browser/tabwindow/internal/android/java/src/org/chromium/chrome/browser/tabwindow/TabWindowManagerImplUnitTest.java
+++ b/chrome/browser/tabwindow/internal/android/java/src/org/chromium/chrome/browser/tabwindow/TabWindowManagerImplUnitTest.java
@@ -1089,7 +1089,7 @@
                         /* incognitoTabCount= */ 0,
                         /* isIncognitoSelected= */ false,
                         /* lastAccessedTime= */ 0,
-                        /* closedByUser= */ false));
+                        /* markedForDeletion= */ false));
         instanceInfoList.add(
                 new InstanceInfo(
                         /* instanceId= */ 1,
@@ -1102,7 +1102,7 @@
                         /* incognitoTabCount= */ 0,
                         /* isIncognitoSelected= */ false,
                         /* lastAccessedTime= */ 0,
-                        /* closedByUser= */ false));
+                        /* markedForDeletion= */ false));
         instanceInfoList.add(
                 new InstanceInfo(
                         /* instanceId= */ 2,
@@ -1115,7 +1115,7 @@
                         /* incognitoTabCount= */ 0,
                         /* isIncognitoSelected= */ false,
                         /* lastAccessedTime= */ 0,
-                        /* closedByUser= */ false));
+                        /* markedForDeletion= */ false));
         when(mMultiInstanceManager.getInstanceInfo(PersistedInstanceType.ANY))
                 .thenReturn(instanceInfoList);
 
@@ -1175,7 +1175,7 @@
                         /* incognitoTabCount= */ 0,
                         /* isIncognitoSelected= */ false,
                         /* lastAccessedTime= */ 0,
-                        /* closedByUser= */ false));
+                        /* markedForDeletion= */ false));
         when(mMultiInstanceManager.getInstanceInfo(PersistedInstanceType.ANY))
                 .thenReturn(instanceInfoList);
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index a250a7c..17301c8 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -3235,7 +3235,7 @@
     deps += [
       "//chrome/browser/apps/app_shim",
       "//chrome/browser/enterprise/connectors/device_trust/key_management/core/mac",
-      "//chrome/browser/updater",
+      "//chrome/browser/updater:browser_updater_client",
       "//chrome/browser/web_applications/extensions",
       "//chrome/updater:browser_sources",
       "//components/remote_cocoa/app_shim",
diff --git a/chrome/browser/ui/android/extensions/java/res/layout/extension_toolbar_container.xml b/chrome/browser/ui/android/extensions/java/res/layout/extension_toolbar_container.xml
index 8bf471d..774ca61 100644
--- a/chrome/browser/ui/android/extensions/java/res/layout/extension_toolbar_container.xml
+++ b/chrome/browser/ui/android/extensions/java/res/layout/extension_toolbar_container.xml
@@ -20,6 +20,7 @@
 
     <org.chromium.ui.listmenu.ListMenuButton
         android:id="@+id/extensions_menu_button"
+        android:visibility="gone"
         style="@style/ToolbarHoverableButton"
         android:src="@drawable/chrome_extension"
         app:menuVerticalOverlapAnchor="false"
@@ -29,6 +30,7 @@
     <com.google.android.material.divider.MaterialDivider
         android:id="@+id/extensions_divider"
         android:layout_width="@dimen/toolbar_divider_width"
-        android:layout_height="@dimen/toolbar_divider_height"/>
+        android:layout_height="@dimen/toolbar_divider_height"
+        android:visibility="gone"/>
 
 </LinearLayout>
diff --git a/chrome/browser/ui/android/extensions/windowing/internal/java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridgeImpl.java b/chrome/browser/ui/android/extensions/windowing/internal/java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridgeImpl.java
index c37eb33..9a87d56 100644
--- a/chrome/browser/ui/android/extensions/windowing/internal/java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridgeImpl.java
+++ b/chrome/browser/ui/android/extensions/windowing/internal/java/src/org/chromium/chrome/browser/ui/extensions/windowing/ExtensionWindowControllerBridgeImpl.java
@@ -54,29 +54,6 @@
                 });
     }
 
-    /**
-     * Deprecated. Use {@link #initializeWindowControllerListObserverForTesting()} instead.
-     *
-     * <p>TODO(crbug.com/466457024): delete this method.
-     */
-    @Deprecated
-    static void addWindowControllerListObserverForTesting() {
-        ExtensionWindowControllerBridgeImplJni.get()
-                .addWindowControllerListObserverForTesting(); // IN-TEST
-    }
-
-    /**
-     * Deprecated. Use {@link #initializeWindowControllerListObserverForTesting()} instead.
-     *
-     * <p>TODO(crbug.com/466457024): delete this method.
-     */
-    @Deprecated
-    static void removeWindowControllerListObserverForTesting() {
-        ExtensionWindowControllerBridgeImplJni.get()
-                .removeWindowControllerListObserverForTesting(); // IN-TEST
-        sExtensionInternalEventsForTesting.clear();
-    }
-
     static Map<Integer, List<@ExtensionInternalWindowEventForTesting Integer>>
             getExtensionInternalEventsForTesting() {
         return sExtensionInternalEventsForTesting;
diff --git a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceInfo.java b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceInfo.java
index a8f599b..e57fc9d1 100644
--- a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceInfo.java
+++ b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceInfo.java
@@ -65,10 +65,10 @@
     public final long lastAccessedTime;
 
     /**
-     * Whether this instance was closed by an explicit user request. This is relevant only for a
+     * Whether this instance is marked for permanent deletion. This is relevant only for a
      * non-active instance.
      */
-    public final boolean closedByUser;
+    public final boolean markedForDeletion;
 
     public InstanceInfo(
             int instanceId,
@@ -81,7 +81,7 @@
             int incognitoTabCount,
             boolean isIncognitoSelected,
             long lastAccessedTime,
-            boolean closedByUser) {
+            boolean markedForDeletion) {
         this.instanceId = instanceId;
         this.taskId = taskId;
         this.type = type;
@@ -92,7 +92,7 @@
         this.incognitoTabCount = incognitoTabCount;
         this.isIncognitoSelected = isIncognitoSelected;
         this.lastAccessedTime = lastAccessedTime;
-        this.closedByUser = closedByUser;
+        this.markedForDeletion = markedForDeletion;
     }
 
     @Override
diff --git a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinator.java b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinator.java
index 7bfea65..0718b5c 100644
--- a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinator.java
+++ b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinator.java
@@ -331,7 +331,7 @@
         for (int i = 0; i < items.size(); ++i) {
             InstanceInfo instanceInfo = items.get(i);
             // Do not show instances that are closed by user.
-            if (instanceInfo.closedByUser) continue;
+            if (instanceInfo.markedForDeletion) continue;
             // An active instance should have an associated live task.
             boolean isActiveInstance = instanceInfo.taskId != INVALID_TASK_ID;
             PropertyModel itemModel = generateListItem(items.get(i));
diff --git a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinatorTest.java b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinatorTest.java
index 1729cac..b99e68d 100644
--- a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinatorTest.java
+++ b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/InstanceSwitcherCoordinatorTest.java
@@ -906,7 +906,7 @@
                             /* incognitoTabCount= */ 0,
                             /* isIncognitoSelected= */ false,
                             /* lastAccessedTime= */ 0,
-                            /* closedByUser= */ false),
+                            /* markedForDeletion= */ false),
                     new InstanceInfo(
                             /* instanceId= */ 1,
                             /* taskId= */ 58,
@@ -918,7 +918,7 @@
                             /* incognitoTabCount= */ 0,
                             /* isIncognitoSelected= */ false,
                             /* lastAccessedTime= */ 0,
-                            /* closedByUser= */ false),
+                            /* markedForDeletion= */ false),
                     new InstanceInfo(
                             /* instanceId= */ 2,
                             /* taskId= */ 59,
@@ -930,7 +930,7 @@
                             /* incognitoTabCount= */ 0,
                             /* isIncognitoSelected= */ false,
                             /* lastAccessedTime= */ 0,
-                            /* closedByUser= */ false)
+                            /* markedForDeletion= */ false)
                 };
         final CallbackHelper closeCallbackHelper = new CallbackHelper();
         Callback<InstanceInfo> closeCallback = (item) -> closeCallbackHelper.notifyCalled();
@@ -1503,7 +1503,7 @@
                         /* incognitoTabCount= */ 1,
                         /* isIncognitoSelected= */ false,
                         /* lastAccessedTime= */ 0,
-                        /* closedByUser= */ false);
+                        /* markedForDeletion= */ false);
 
         // Create other active instances.
         for (int i = 1; i < numActiveInstances; i++) {
@@ -1519,7 +1519,7 @@
                             /* incognitoTabCount= */ 0,
                             /* isIncognitoSelected= */ false,
                             /* lastAccessedTime= */ getDaysAgoMillis(i),
-                            /* closedByUser= */ false);
+                            /* markedForDeletion= */ false);
         }
 
         // Create inactive instances.
@@ -1536,7 +1536,7 @@
                             /* incognitoTabCount= */ 0,
                             /* isIncognitoSelected= */ false,
                             /* lastAccessedTime= */ 0,
-                            /* closedByUser= */ false);
+                            /* markedForDeletion= */ false);
         }
 
         return instances;
diff --git a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/TargetSelectorCoordinatorTest.java b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/TargetSelectorCoordinatorTest.java
index d962d43b..a3a367f 100644
--- a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/TargetSelectorCoordinatorTest.java
+++ b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/TargetSelectorCoordinatorTest.java
@@ -95,7 +95,7 @@
                             /* incognitoTabCount= */ 0,
                             /* isIncognitoSelected= */ false,
                             /* lastAccessedTime= */ 0,
-                            /* closedByUser= */ false),
+                            /* markedForDeletion= */ false),
                     new InstanceInfo(
                             /* instanceId= */ 1,
                             /* taskId= */ 58,
@@ -107,7 +107,7 @@
                             /* incognitoTabCount= */ 0,
                             /* isIncognitoSelected= */ false,
                             /* lastAccessedTime= */ 0,
-                            /* closedByUser= */ false),
+                            /* markedForDeletion= */ false),
                     new InstanceInfo(
                             /* instanceId= */ 2,
                             /* taskId= */ 59,
@@ -119,7 +119,7 @@
                             /* incognitoTabCount= */ 1,
                             /* isIncognitoSelected= */ false,
                             /* lastAccessedTime= */ 0,
-                            /* closedByUser= */ false)
+                            /* markedForDeletion= */ false)
                 };
         final CallbackHelper itemClickCallbackHelper = new CallbackHelper();
         final int itemClickCount = itemClickCallbackHelper.getCallCount();
@@ -165,7 +165,7 @@
                             /* incognitoTabCount= */ 0,
                             /* isIncognitoSelected= */ false,
                             /* lastAccessedTime= */ 0,
-                            /* closedByUser= */ false),
+                            /* markedForDeletion= */ false),
                     new InstanceInfo(
                             /* instanceId= */ 1,
                             /* taskId= */ 58,
@@ -177,7 +177,7 @@
                             /* incognitoTabCount= */ 0,
                             /* isIncognitoSelected= */ false,
                             /* lastAccessedTime= */ 0,
-                            /* closedByUser= */ false),
+                            /* markedForDeletion= */ false),
                     new InstanceInfo(
                             /* instanceId= */ 2,
                             /* taskId= */ 59,
@@ -189,7 +189,7 @@
                             /* incognitoTabCount= */ 1,
                             /* isIncognitoSelected= */ false,
                             /* lastAccessedTime= */ 0,
-                            /* closedByUser= */ false)
+                            /* markedForDeletion= */ false)
                 };
         final CallbackHelper itemClickCallbackHelper = new CallbackHelper();
         final int itemClickCount = itemClickCallbackHelper.getCallCount();
diff --git a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/UiUtilsUnitTest.java b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/UiUtilsUnitTest.java
index 9c77694..269750ee 100644
--- a/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/UiUtilsUnitTest.java
+++ b/chrome/browser/ui/android/multiwindow/java/src/org/chromium/chrome/browser/multiwindow/UiUtilsUnitTest.java
@@ -625,7 +625,7 @@
                 incognitoTabCount,
                 isIncognito,
                 /* lastAccessedTime= */ 0,
-                /* closedByUser= */ false);
+                /* markedForDeletion= */ false);
     }
 
     private InstanceInfo mockInstance(
@@ -645,7 +645,7 @@
                 incognitoTabCount,
                 isIncognito,
                 /* lastAccessedTime= */ 0,
-                /* closedByUser= */ false);
+                /* markedForDeletion= */ false);
     }
 
     private InstanceInfo mockInstance(int type) {
@@ -660,7 +660,7 @@
                 /* incognitoTabCount= */ 1,
                 /* isIncognitoSelected= */ true,
                 /* lastAccessedTime= */ 0,
-                /* closedByUser= */ false);
+                /* markedForDeletion= */ false);
     }
 
     private InstanceInfo mockInstanceBeforeLoadingTab(int type) {
@@ -675,6 +675,6 @@
                 /* incognitoTabCount= */ 0,
                 /* isIncognitoSelected= */ false,
                 /* lastAccessedTime= */ 0,
-                /* closedByUser= */ false);
+                /* markedForDeletion= */ false);
     }
 }
diff --git a/chrome/browser/ui/android/toolbar/BUILD.gn b/chrome/browser/ui/android/toolbar/BUILD.gn
index af275eb..08a3f92 100644
--- a/chrome/browser/ui/android/toolbar/BUILD.gn
+++ b/chrome/browser/ui/android/toolbar/BUILD.gn
@@ -404,6 +404,7 @@
     "java/src/org/chromium/chrome/browser/toolbar/MiniOriginBarControllerTest.java",
     "java/src/org/chromium/chrome/browser/toolbar/ToolbarLongPressMenuHandlerUnitTest.java",
     "java/src/org/chromium/chrome/browser/toolbar/ToolbarPositionControllerTest.java",
+    "java/src/org/chromium/chrome/browser/toolbar/ToolbarProgressBarLayerTest.java",
     "java/src/org/chromium/chrome/browser/toolbar/ToolbarProgressBarTest.java",
     "java/src/org/chromium/chrome/browser/toolbar/VoiceToolbarButtonControllerUnitTest.java",
     "java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveButtonActionMenuCoordinatorTest.java",
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarProgressBarLayer.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarProgressBarLayer.java
index 774ef21..2696447 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarProgressBarLayer.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarProgressBarLayer.java
@@ -4,7 +4,11 @@
 
 package org.chromium.chrome.browser.toolbar;
 
+import android.os.Handler;
 import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
 
 import org.chromium.base.MathUtils;
 import org.chromium.build.annotations.NullMarked;
@@ -32,8 +36,11 @@
     private final ToolbarProgressBar mProgressBarView;
     private final View mToolbarHairline;
     private final Supplier<@ControlsPosition Integer> mControlsPositionSupplier;
+    private final Supplier<Integer> mBookmarkBarIdSupplier;
     private final TopControlsStacker mTopControlsStacker;
     private final BottomControlsStacker mBottomControlsStacker;
+    private final boolean mIsToolbarPositionCustomizationEnabled;
+    private final Handler mHandler = new Handler();
 
     /**
      * Construct the browser control layer that represents the toolbar progress bar.
@@ -43,8 +50,10 @@
      * @param toolbarProgressBar The ToolbarProgressBar view instance.
      * @param hairlineView The view for toolbar hairline.
      * @param controlsPositionSupplier The supplier for the current ControlsPosition.
+     * @param bookmarkBarIdSupplier The supplier for the bookmark bar Id.
      * @param topControlStacker The TopControlStacker instance.
      * @param bottomControlsStacker The BottomControlsStacker instance.
+     * @param isToolbarPositionCustomizationEnabled Whether the toolbar position is customizable.
      */
     public ToolbarProgressBarLayer(
             ControlContainer controlContainer,
@@ -52,18 +61,22 @@
             ToolbarProgressBar toolbarProgressBar,
             View hairlineView,
             Supplier<@ControlsPosition Integer> controlsPositionSupplier,
+            Supplier<Integer> bookmarkBarIdSupplier,
             TopControlsStacker topControlStacker,
-            BottomControlsStacker bottomControlsStacker) {
+            BottomControlsStacker bottomControlsStacker,
+            boolean isToolbarPositionCustomizationEnabled) {
         mControlContainer = controlContainer;
         mProgressBarContainer = progressBarContainer;
         mProgressBarView = toolbarProgressBar;
         mToolbarHairline = hairlineView;
         mControlsPositionSupplier = controlsPositionSupplier;
-
+        mBookmarkBarIdSupplier = bookmarkBarIdSupplier;
         mTopControlsStacker = topControlStacker;
         mBottomControlsStacker = bottomControlsStacker;
+        mIsToolbarPositionCustomizationEnabled = isToolbarPositionCustomizationEnabled;
 
         mTopControlsStacker.addControl(this);
+        updateTopAnchorView();
     }
 
     public void destroy() {
@@ -87,7 +100,7 @@
     @Override
     public int getTopControlVisibility() {
         // TODO(crbug.com/417238089): Possibly add way to notify stacker of visibility changes.
-        return mProgressBarView.getVisibility() == View.VISIBLE
+        return mProgressBarView.isStarted()
                         && mControlsPositionSupplier.get() == ControlsPosition.TOP
                 ? TopControlVisibility.VISIBLE
                 : TopControlVisibility.HIDDEN;
@@ -99,6 +112,11 @@
         return false;
     }
 
+    @Override
+    public void onTopControlLayerHeightChanged(int topControlsHeight, int topControlsMinHeight) {
+        updateTopAnchorView();
+    }
+
     /**
      * Progress the progress bar info based on the current browser control positioning.
      *
@@ -109,7 +127,9 @@
 
         // Control container / progress bar container can have a non-zero translation
         // when sitting at the bottom / during animation.
-        // TODO(crbug.com/419846301): Coordinate the yOffset based on browser controls.
+        // TODO(crbug.com/466162772): This calculation is based on the fact that the progress bar
+        // lives with toolbar in the scene layer. As a result, the yOffset for the progress bar
+        // needs to be based on the control container's position.
         final float controlContainerY = mControlContainer.getView().getY();
         final float progressBarContainerY = mProgressBarContainer.getY();
         int yOffset =
@@ -145,4 +165,34 @@
         drawingInfo.progressBarRect.offset(0, yOffset);
         drawingInfo.progressBarBackgroundRect.offset(0, yOffset);
     }
+
+    // Progress bar should anchor at the bottom of the top controls.
+    private void updateTopAnchorView() {
+        // When mIsToolbarPositionCustomizationEnabled, this is handled in
+        // ToolbarPositionController. Avoid doing duplicate work.
+        if (mIsToolbarPositionCustomizationEnabled) return;
+
+        Runnable progressBarChangeRunnable =
+                () -> {
+                    if (mControlsPositionSupplier.get() != ControlsPosition.TOP) return;
+                    CoordinatorLayout.LayoutParams lp =
+                            (CoordinatorLayout.LayoutParams)
+                                    mProgressBarContainer.getLayoutParams();
+                    if (mTopControlsStacker.isLayerAtBottom(TopControlType.BOOKMARK_BAR)
+                            && mBookmarkBarIdSupplier.get() != 0) {
+                        int bookmarkBarId = mBookmarkBarIdSupplier.get();
+                        lp.setAnchorId(bookmarkBarId);
+                    } else {
+                        lp.setAnchorId(mControlContainer.getView().getId());
+                    }
+                    mProgressBarContainer.setLayoutParams(lp);
+                };
+
+        // Anchor ID cannot be changed during a layout pass. Post the runnable instead.
+        if (((ViewGroup) mProgressBarContainer.getParent()).isInLayout()) {
+            mHandler.post(progressBarChangeRunnable);
+        } else {
+            progressBarChangeRunnable.run();
+        }
+    }
 }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarProgressBarLayerTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarProgressBarLayerTest.java
new file mode 100644
index 0000000..af59302
--- /dev/null
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/ToolbarProgressBarLayerTest.java
@@ -0,0 +1,130 @@
+// 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.toolbar;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
+import org.robolectric.shadows.ShadowLooper;
+
+import org.chromium.base.supplier.ObservableSuppliers;
+import org.chromium.base.supplier.SettableObservableSupplier;
+import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.chrome.browser.browser_controls.BottomControlsStacker;
+import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider.ControlsPosition;
+import org.chromium.chrome.browser.browser_controls.TopControlsStacker;
+import org.chromium.chrome.browser.browser_controls.TopControlsStacker.TopControlVisibility;
+import org.chromium.ui.base.TestActivity;
+
+/** Unit tests for {@link ToolbarProgressBarLayer}. */
+@RunWith(BaseRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+@LooperMode(LooperMode.Mode.PAUSED)
+public class ToolbarProgressBarLayerTest {
+    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+    @Rule
+    public ActivityScenarioRule<TestActivity> mActivityScenarioRule =
+            new ActivityScenarioRule<>(TestActivity.class);
+
+    @Mock private ControlContainer mControlContainer;
+    @Mock private ToolbarProgressBar mProgressBarView;
+    @Mock private TopControlsStacker mTopControlsStacker;
+    @Mock private BottomControlsStacker mBottomControlsStacker;
+    @Mock private CoordinatorLayout mContentView;
+
+    private Activity mActivity;
+    private View mProgressBarContainer;
+    private View mToolbarHairline;
+
+    private ToolbarProgressBarLayer mLayer;
+    private @ControlsPosition int mTestControlPosition = ControlsPosition.NONE;
+    private SettableObservableSupplier<Integer> mBookmarkBarIdSupplier;
+
+    @Before
+    public void setUp() {
+        mActivityScenarioRule.getScenario().onActivity(activity -> mActivity = activity);
+        mProgressBarContainer = spy(new View(mActivity));
+        doReturn(mContentView).when(mProgressBarContainer).getParent();
+        mToolbarHairline = new View(mActivity);
+
+        mBookmarkBarIdSupplier = ObservableSuppliers.createMonotonic(0);
+
+        mLayer =
+                new ToolbarProgressBarLayer(
+                        mControlContainer,
+                        mProgressBarContainer,
+                        mProgressBarView,
+                        mToolbarHairline,
+                        () -> mTestControlPosition,
+                        mBookmarkBarIdSupplier,
+                        mTopControlsStacker,
+                        mBottomControlsStacker,
+                        false);
+    }
+
+    @Test
+    public void testTopControlVisibility() {
+        when(mProgressBarView.isStarted()).thenReturn(true);
+        mTestControlPosition = ControlsPosition.TOP;
+        assertEquals(TopControlVisibility.VISIBLE, mLayer.getTopControlVisibility());
+
+        mTestControlPosition = ControlsPosition.BOTTOM;
+        assertEquals(TopControlVisibility.HIDDEN, mLayer.getTopControlVisibility());
+
+        when(mProgressBarView.isStarted()).thenReturn(false);
+        mTestControlPosition = ControlsPosition.TOP;
+        assertEquals(TopControlVisibility.HIDDEN, mLayer.getTopControlVisibility());
+    }
+
+    @Test
+    public void testUpdateTopAnchorView() {
+        mTestControlPosition = ControlsPosition.TOP;
+        View controlContainerView = new View(mActivity);
+        controlContainerView.setId(123);
+        when(mControlContainer.getView()).thenReturn(controlContainerView);
+        mProgressBarContainer.setLayoutParams(
+                new CoordinatorLayout.LayoutParams(
+                        ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+
+        // Bookmark bar is not visible.
+        mBookmarkBarIdSupplier.set(0);
+        mLayer.onTopControlLayerHeightChanged(0, 0);
+        ShadowLooper.idleMainLooper();
+        assertEquals(
+                controlContainerView.getId(),
+                ((CoordinatorLayout.LayoutParams) mProgressBarContainer.getLayoutParams())
+                        .getAnchorId());
+
+        // Bookmark bar is visible.
+        mBookmarkBarIdSupplier.set(456);
+        ShadowLooper.idleMainLooper();
+        when(mTopControlsStacker.isLayerAtBottom(TopControlsStacker.TopControlType.BOOKMARK_BAR))
+                .thenReturn(true);
+        mLayer.onTopControlLayerHeightChanged(0, 0);
+        assertEquals(
+                456,
+                ((CoordinatorLayout.LayoutParams) mProgressBarContainer.getLayoutParams())
+                        .getAnchorId());
+    }
+}
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarCoordinator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarCoordinator.java
index b2155e8..f1804a3 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarCoordinator.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarCoordinator.java
@@ -20,7 +20,6 @@
 import org.chromium.chrome.browser.tabmodel.TabCreator;
 import org.chromium.chrome.browser.theme.ThemeColorProvider;
 import org.chromium.chrome.browser.ui.browser_window.ChromeAndroidTask;
-import org.chromium.chrome.browser.ui.extensions.ExtensionUi;
 import org.chromium.ui.base.WindowAndroid;
 
 /**
@@ -48,11 +47,6 @@
             NullableObservableSupplier<Tab> currentTabSupplier,
             TabCreator tabCreator,
             ThemeColorProvider themeColorProvider) {
-        // Check if the extension UI is enabled first.
-        if (ExtensionUi.isEnabled(task.getProfile())) {
-            return null;
-        }
-
         ExtensionToolbarCoordinator coordinator =
                 ServiceLoaderUtil.maybeCreate(ExtensionToolbarCoordinator.class);
         if (coordinator == null) {
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarCoordinatorImpl.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarCoordinatorImpl.java
index de9f56d..f41a971 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarCoordinatorImpl.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionToolbarCoordinatorImpl.java
@@ -9,6 +9,7 @@
 import android.view.ViewStub;
 import android.widget.LinearLayout;
 
+import org.chromium.base.Callback;
 import org.chromium.base.lifetime.LifetimeAssert;
 import org.chromium.base.supplier.NullableObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplier;
@@ -29,11 +30,15 @@
 @ServiceImpl(ExtensionToolbarCoordinator.class)
 public class ExtensionToolbarCoordinatorImpl implements ExtensionToolbarCoordinator {
     private final @Nullable LifetimeAssert mLifetimeAssert = LifetimeAssert.create(this);
+    private final Callback<@Nullable Profile> mProfileUpdatedCallback =
+            (profile) -> mCurrentProfile = profile;
 
     private ObservableSupplier<@Nullable Profile> mProfileSupplier;
     private ExtensionActionListCoordinator mExtensionActionListCoordinator;
     private ExtensionsMenuCoordinator mExtensionsMenuCoordinator;
 
+    private @Nullable Profile mCurrentProfile;
+
     @Override
     public void initializeWithNative(
             Context context,
@@ -45,6 +50,7 @@
             TabCreator tabCreator,
             ThemeColorProvider themeColorProvider) {
         mProfileSupplier = profileSupplier;
+        mProfileSupplier.addObserver(mProfileUpdatedCallback);
 
         extensionToolbarStub.setLayoutResource(R.layout.extension_toolbar_container);
         LinearLayout container = (LinearLayout) extensionToolbarStub.inflate();
@@ -60,6 +66,7 @@
                 new ExtensionsMenuCoordinator(
                         context,
                         container.findViewById(R.id.extensions_menu_button),
+                        container.findViewById(R.id.extensions_divider),
                         themeColorProvider,
                         task,
                         profileSupplier,
@@ -71,6 +78,7 @@
     public void destroy() {
         mExtensionsMenuCoordinator.destroy();
         mExtensionActionListCoordinator.destroy();
+        mProfileSupplier.removeObserver(mProfileUpdatedCallback);
         LifetimeAssert.setSafeToGc(mLifetimeAssert, true);
     }
 
@@ -81,12 +89,11 @@
             return false;
         }
 
-        Profile profile = mProfileSupplier.get();
-        if (profile == null) {
+        if (mCurrentProfile == null) {
             return false;
         }
 
-        ExtensionActionsBridge bridge = ExtensionActionsBridge.get(profile);
+        ExtensionActionsBridge bridge = ExtensionActionsBridge.get(mCurrentProfile);
         if (bridge == null) {
             return false;
         }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuCoordinator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuCoordinator.java
index b402dfe..e05771c 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuCoordinator.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuCoordinator.java
@@ -14,6 +14,8 @@
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 
+import com.google.android.material.divider.MaterialDivider;
+
 import org.chromium.base.lifetime.Destroyable;
 import org.chromium.base.supplier.NullableObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplier;
@@ -49,6 +51,7 @@
 public class ExtensionsMenuCoordinator implements Destroyable {
     private final Context mContext;
     private final ListMenuButton mExtensionsMenuButton;
+    private final MaterialDivider mExtensionsMenuTabSwitcherDivider;
     private final ThemeColorProvider mThemeColorProvider;
     private final NullableObservableSupplier<Tab> mCurrentTabSupplier;
     private final TabCreator mTabCreator;
@@ -67,6 +70,8 @@
      *
      * @param context The context for this component.
      * @param extensionsMenuButton The puzzle icon in the toolbar.
+     * @param extensionsMenuTabSwitcherDivider The divider between the extensions menu and the tab
+     *     switcher.
      * @param themeColorProvider The provider for theme colors.
      * @param taskSupplier Supplies the {@link ChromeAndroidTask}.
      * @param profileSupplier Supplies the current {@link Profile}.
@@ -76,6 +81,7 @@
     public ExtensionsMenuCoordinator(
             Context context,
             ListMenuButton extensionsMenuButton,
+            MaterialDivider extensionsMenuTabSwitcherDivider,
             ThemeColorProvider themeColorProvider,
             ChromeAndroidTask task,
             ObservableSupplier<@Nullable Profile> profileSupplier,
@@ -90,6 +96,8 @@
         mExtensionsMenuButton.setMenuMaxWidth(
                 context.getResources().getDimensionPixelSize(R.dimen.extension_menu_max_width));
 
+        mExtensionsMenuTabSwitcherDivider = extensionsMenuTabSwitcherDivider;
+
         mThemeColorProvider = themeColorProvider;
         mThemeColorProvider.addTintObserver(mTintObserver);
 
@@ -152,6 +160,11 @@
                                 mShouldShowMenuOnInit = false;
                             }
                         },
+                        (extensionsSupported) -> {
+                            int visibility = extensionsSupported ? View.VISIBLE : View.GONE;
+                            mExtensionsMenuButton.setVisibility(visibility);
+                            mExtensionsMenuTabSwitcherDivider.setVisibility(visibility);
+                        },
                         mExtensionsMenuButton.getRootView());
     }
 
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuCoordinatorTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuCoordinatorTest.java
index 71a01e53..7609ad9 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuCoordinatorTest.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuCoordinatorTest.java
@@ -13,6 +13,8 @@
 
 import androidx.appcompat.app.AppCompatActivity;
 
+import com.google.android.material.divider.MaterialDivider;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -56,6 +58,7 @@
     private final ObservableSupplierImpl<@Nullable Tab> mCurrentTabSupplier =
             new ObservableSupplierImpl<>();
     private ListMenuButton mExtensionsMenuButton;
+    private MaterialDivider mExtensionsMenuTabSwitcherDivider;
     @Mock private TabCreator mTabCreator;
     @Mock private ChromeAndroidTask mTask;
     @Mock private Profile mProfile;
@@ -79,6 +82,7 @@
         mContext = activity;
 
         mExtensionsMenuButton = new ListMenuButton(activity, null);
+        mExtensionsMenuTabSwitcherDivider = new MaterialDivider(activity);
         activity.setContentView(mExtensionsMenuButton);
 
         mProfileModel = mBridge.getOrCreateProfileModel(mProfile);
@@ -93,6 +97,7 @@
                 new ExtensionsMenuCoordinator(
                         mContext,
                         mExtensionsMenuButton,
+                        mExtensionsMenuTabSwitcherDivider,
                         mThemeColorProvider,
                         mTask,
                         mProfileSupplier,
@@ -114,6 +119,7 @@
                 new ExtensionsMenuCoordinator(
                         mContext,
                         mExtensionsMenuButton,
+                        mExtensionsMenuTabSwitcherDivider,
                         mThemeColorProvider,
                         mTask,
                         mProfileSupplier,
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuMediator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuMediator.java
index 6095740..812620d 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuMediator.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuMediator.java
@@ -9,6 +9,7 @@
 import android.graphics.Rect;
 import android.view.View;
 
+import org.chromium.base.Callback;
 import org.chromium.base.lifetime.Destroyable;
 import org.chromium.base.supplier.NullableObservableSupplier;
 import org.chromium.base.supplier.ObservableSupplier;
@@ -37,8 +38,11 @@
     private final ActionsUpdateDelegate mActionsUpdateDelegate = new ActionsUpdateDelegate();
     private final Context mContext;
     private final ChromeAndroidTask mTask;
+    private final ObservableSupplier<@Nullable Profile> mProfileSupplier;
     private final Runnable mOnUpdateFinishedRunnable;
+    private final Callback<Boolean> mOnExtensionsAvailableCallback;
     private final ExtensionActionsUpdateHelper mExtensionActionsUpdateHelper;
+    private final Callback<@Nullable Profile> mProfileUpdatedCallback = this::onProfileUpdated;
     private final View mRootView;
 
     public ExtensionsMenuMediator(
@@ -48,10 +52,14 @@
             NullableObservableSupplier<Tab> currentTabSupplier,
             ModelList extensionModels,
             Runnable onUpdateFinishedRunnable,
+            Callback<Boolean> onExtensionsAvailableCallback,
             View rootView) {
         mTask = task;
+        mProfileSupplier = profileSupplier;
+        mProfileSupplier.addObserver(mProfileUpdatedCallback);
 
         mOnUpdateFinishedRunnable = onUpdateFinishedRunnable;
+        mOnExtensionsAvailableCallback = onExtensionsAvailableCallback;
         mContext = context;
         mRootView = rootView;
 
@@ -92,6 +100,13 @@
         }
     }
 
+    private void onProfileUpdated(@Nullable Profile profile) {
+        // TODO(crbug.com/422307625): Remove this check once extensions are ready for dogfooding.
+        boolean extensionsSupported =
+                profile != null ? ExtensionActionsBridge.extensionsEnabled(profile) : false;
+        mOnExtensionsAvailableCallback.onResult(extensionsSupported);
+    }
+
     private void onPrimaryClick(ListMenuButton buttonView, String actionId) {
         Tab currentTab = mExtensionActionsUpdateHelper.getCurrentTab();
         if (currentTab == null) {
@@ -118,6 +133,7 @@
     @Override
     public void destroy() {
         mExtensionActionsUpdateHelper.destroy();
+        mProfileSupplier.removeObserver(mProfileUpdatedCallback);
     }
 
     private class ActionsUpdateDelegate
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuMediatorTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuMediatorTest.java
index 96714b2a..3652e09 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuMediatorTest.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuMediatorTest.java
@@ -33,10 +33,12 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.robolectric.annotation.LooperMode;
 
+import org.chromium.base.Callback;
 import org.chromium.base.supplier.ObservableSupplierImpl;
 import org.chromium.base.supplier.ObservableSuppliers;
 import org.chromium.base.supplier.SettableNullableObservableSupplier;
@@ -86,6 +88,7 @@
     @Mock private ChromeAndroidTask mTask;
     @Mock private Profile mProfile;
     @Mock private Runnable mDataReadyCallback;
+    @Mock private Callback<Boolean> mOnExtensionsSupportedCallback;
     @Mock private WebContents mWebContents;
     @Mock private ExtensionActionContextMenuBridge.Native mActionContextMenuBridgeJniMock;
     @Mock private MenuModelBridge mMenuModelBridge;
@@ -144,6 +147,7 @@
                         mCurrentTabSupplier,
                         mModels,
                         mDataReadyCallback,
+                        mOnExtensionsSupportedCallback,
                         null);
 
         // Wait for the main thread to settle.
@@ -156,6 +160,23 @@
     }
 
     @Test
+    public void testExtensionsSupportedCallback() {
+        Mockito.clearInvocations(mOnExtensionsSupportedCallback);
+        mProfileSupplier.set(mProfile);
+        shadowOf(Looper.getMainLooper()).idle();
+        verify(mOnExtensionsSupportedCallback).onResult(true);
+
+        mProfileSupplier.set(null);
+        shadowOf(Looper.getMainLooper()).idle();
+        verify(mOnExtensionsSupportedCallback).onResult(false);
+
+        mUiBackendRule.setEnabled(false);
+        mProfileSupplier.set(mProfile);
+        shadowOf(Looper.getMainLooper()).idle();
+        verify(mOnExtensionsSupportedCallback).onResult(false);
+    }
+
+    @Test
     public void testUpdateModels() {
         // Set the profile and the tab.
         mProfileSupplier.set(mProfile);
diff --git a/chrome/browser/ui/cocoa/keystone_infobar_delegate.cc b/chrome/browser/ui/cocoa/keystone_infobar_delegate.cc
index 55cf1d2c..4d3348f 100644
--- a/chrome/browser/ui/cocoa/keystone_infobar_delegate.cc
+++ b/chrome/browser/ui/cocoa/keystone_infobar_delegate.cc
@@ -13,7 +13,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/updater/updater.h"
+#include "chrome/browser/updater/browser_updater_client_util.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/branded_strings.h"
@@ -104,7 +104,7 @@
 }
 
 bool KeystonePromotionInfoBarDelegate::Accept() {
-  updater::SetUpSystemUpdater();
+  SetupSystemUpdater();
   return true;
 }
 
diff --git a/chrome/browser/ui/extensions/BUILD.gn b/chrome/browser/ui/extensions/BUILD.gn
index ca7d3dc..644c6a0 100644
--- a/chrome/browser/ui/extensions/BUILD.gn
+++ b/chrome/browser/ui/extensions/BUILD.gn
@@ -28,7 +28,7 @@
       "extensions_dialogs.h",
       "extensions_menu_view_model.h",
       "extensions_menu_view_platform_delegate.h",
-      "extensions_toolbar_container_view_model.h",
+      "extensions_toolbar_view_model.h",
       "reload_page_dialog_controller.h",
       "settings_overridden_dialog.h",
     ]
@@ -118,7 +118,7 @@
       "extension_multiple_uninstall_dialog.cc",
       "extension_uninstall_dialog_impl.cc",
       "extensions_menu_view_model.cc",
-      "extensions_toolbar_container_view_model.cc",
+      "extensions_toolbar_view_model.cc",
       "reload_page_dialog_controller.cc",
       "settings_overridden_dialog.cc",
     ]
diff --git a/chrome/browser/ui/extensions/extensions_toolbar_container_view_model.cc b/chrome/browser/ui/extensions/extensions_toolbar_container_view_model.cc
deleted file mode 100644
index 17fec6c2..0000000
--- a/chrome/browser/ui/extensions/extensions_toolbar_container_view_model.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// 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/extensions/extensions_toolbar_container_view_model.h"
-
-ExtensionsToolbarContainerViewModel::ExtensionsToolbarContainerViewModel() =
-    default;
-
-ExtensionsToolbarContainerViewModel::~ExtensionsToolbarContainerViewModel() =
-    default;
-
-void ExtensionsToolbarContainerViewModel::AddAction(
-    const ToolbarActionsModel::ActionId& action_id,
-    BrowserWindowInterface* browser,
-    std::unique_ptr<ExtensionActionPlatformDelegate> platform_delegate) {
-  actions_.push_back(ExtensionActionViewModel::Create(
-      action_id, browser, std::move(platform_delegate)));
-}
-
-std::unique_ptr<ToolbarActionViewModel>
-ExtensionsToolbarContainerViewModel::RemoveAction(
-    const ToolbarActionsModel::ActionId& action_id) {
-  auto iter =
-      std::ranges::find(actions_, action_id, &ToolbarActionViewModel::GetId);
-  CHECK(iter != actions_.end());
-  std::unique_ptr<ToolbarActionViewModel> model = std::move(*iter);
-  actions_.erase(iter);
-  return model;
-}
diff --git a/chrome/browser/ui/extensions/extensions_toolbar_container_view_model.h b/chrome/browser/ui/extensions/extensions_toolbar_container_view_model.h
deleted file mode 100644
index 2693042..0000000
--- a/chrome/browser/ui/extensions/extensions_toolbar_container_view_model.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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_EXTENSIONS_EXTENSIONS_TOOLBAR_CONTAINER_VIEW_MODEL_H_
-#define CHROME_BROWSER_UI_EXTENSIONS_EXTENSIONS_TOOLBAR_CONTAINER_VIEW_MODEL_H_
-
-#include "chrome/browser/ui/extensions/extension_action_platform_delegate.h"
-#include "chrome/browser/ui/extensions/extension_action_view_model.h"
-#include "chrome/browser/ui/toolbar/toolbar_action_view_model.h"
-#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
-
-// ViewModel for the ExtensionsToolbarContainer. This class manages the business
-// logic for the order and state of extension actions in the toolbar. It serves
-// as the single source of truth for the ordering of the list of actions.
-class ExtensionsToolbarContainerViewModel {
- public:
-  ExtensionsToolbarContainerViewModel();
-  ExtensionsToolbarContainerViewModel(
-      const ExtensionsToolbarContainerViewModel&) = delete;
-  ExtensionsToolbarContainerViewModel& operator=(
-      ExtensionsToolbarContainerViewModel&) = delete;
-  ~ExtensionsToolbarContainerViewModel();
-
-  // TODO(crbug.com/461981075): This is temporary for the refactor. We should
-  // only expose attributes that are necessary.
-  const std::vector<std::unique_ptr<ToolbarActionViewModel>>& GetActions() {
-    return actions_;
-  }
-
-  // Adds the action view model corresponding to `action_id` to the list of
-  // actions.
-  void AddAction(
-      const ToolbarActionsModel::ActionId& action_id,
-      BrowserWindowInterface* browser,
-      std::unique_ptr<ExtensionActionPlatformDelegate> platform_delegate);
-
-  // Removes the action view model corresponding to `action_id` from list of
-  // actions. The returning pointer can be used to ensure that the action
-  // outlives the UI element for cleanup.
-  std::unique_ptr<ToolbarActionViewModel> RemoveAction(
-      const ToolbarActionsModel::ActionId& action_id);
-
- private:
-  // TODO(crbug.com/461981075): Use the order of this vector as the
-  // source of truth for action view order.
-  // Actions for all extensions.
-  std::vector<std::unique_ptr<ToolbarActionViewModel>> actions_;
-};
-
-#endif  // CHROME_BROWSER_UI_EXTENSIONS_EXTENSIONS_TOOLBAR_CONTAINER_VIEW_MODEL_H_
diff --git a/chrome/browser/ui/extensions/extensions_toolbar_view_model.cc b/chrome/browser/ui/extensions/extensions_toolbar_view_model.cc
new file mode 100644
index 0000000..608778f7
--- /dev/null
+++ b/chrome/browser/ui/extensions/extensions_toolbar_view_model.cc
@@ -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.
+
+#include "chrome/browser/ui/extensions/extensions_toolbar_view_model.h"
+
+ExtensionsToolbarViewModel::ExtensionsToolbarViewModel() = default;
+
+ExtensionsToolbarViewModel::~ExtensionsToolbarViewModel() = default;
+
+void ExtensionsToolbarViewModel::AddAction(
+    const ToolbarActionsModel::ActionId& action_id,
+    BrowserWindowInterface* browser,
+    std::unique_ptr<ExtensionActionPlatformDelegate> platform_delegate) {
+  actions_.push_back(ExtensionActionViewModel::Create(
+      action_id, browser, std::move(platform_delegate)));
+}
+
+std::unique_ptr<ToolbarActionViewModel>
+ExtensionsToolbarViewModel::RemoveAction(
+    const ToolbarActionsModel::ActionId& action_id) {
+  auto iter =
+      std::ranges::find(actions_, action_id, &ToolbarActionViewModel::GetId);
+  CHECK(iter != actions_.end());
+  std::unique_ptr<ToolbarActionViewModel> model = std::move(*iter);
+  actions_.erase(iter);
+  return model;
+}
diff --git a/chrome/browser/ui/extensions/extensions_toolbar_view_model.h b/chrome/browser/ui/extensions/extensions_toolbar_view_model.h
new file mode 100644
index 0000000..35fbb06
--- /dev/null
+++ b/chrome/browser/ui/extensions/extensions_toolbar_view_model.h
@@ -0,0 +1,49 @@
+// 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_EXTENSIONS_EXTENSIONS_TOOLBAR_VIEW_MODEL_H_
+#define CHROME_BROWSER_UI_EXTENSIONS_EXTENSIONS_TOOLBAR_VIEW_MODEL_H_
+
+#include "chrome/browser/ui/extensions/extension_action_platform_delegate.h"
+#include "chrome/browser/ui/extensions/extension_action_view_model.h"
+#include "chrome/browser/ui/toolbar/toolbar_action_view_model.h"
+#include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
+
+// ViewModel for the ExtensionsToolbarContainer. This class manages the business
+// logic for the order and state of extension actions in the toolbar. It serves
+// as the single source of truth for the ordering of the list of actions.
+class ExtensionsToolbarViewModel {
+ public:
+  ExtensionsToolbarViewModel();
+  ExtensionsToolbarViewModel(const ExtensionsToolbarViewModel&) = delete;
+  ExtensionsToolbarViewModel& operator=(ExtensionsToolbarViewModel&) = delete;
+  ~ExtensionsToolbarViewModel();
+
+  // TODO(crbug.com/461981075): This is temporary for the refactor. We should
+  // only expose attributes that are necessary.
+  const std::vector<std::unique_ptr<ToolbarActionViewModel>>& GetActions() {
+    return actions_;
+  }
+
+  // Adds the action view model corresponding to `action_id` to the list of
+  // actions.
+  void AddAction(
+      const ToolbarActionsModel::ActionId& action_id,
+      BrowserWindowInterface* browser,
+      std::unique_ptr<ExtensionActionPlatformDelegate> platform_delegate);
+
+  // Removes the action view model corresponding to `action_id` from list of
+  // actions. The returning pointer can be used to ensure that the action
+  // outlives the UI element for cleanup.
+  std::unique_ptr<ToolbarActionViewModel> RemoveAction(
+      const ToolbarActionsModel::ActionId& action_id);
+
+ private:
+  // TODO(crbug.com/461981075): Use the order of this vector as the
+  // source of truth for action view order.
+  // Actions for all extensions.
+  std::vector<std::unique_ptr<ToolbarActionViewModel>> actions_;
+};
+
+#endif  // CHROME_BROWSER_UI_EXTENSIONS_EXTENSIONS_TOOLBAR_VIEW_MODEL_H_
diff --git a/chrome/browser/ui/layout_constants.cc b/chrome/browser/ui/layout_constants.cc
index ae5091f..579dfca 100644
--- a/chrome/browser/ui/layout_constants.cc
+++ b/chrome/browser/ui/layout_constants.cc
@@ -131,6 +131,7 @@
       return 20;
     case MAIN_BACKGROUND_REGION_CORNER_RADIUS:
     case TOOLBAR_CORNER_RADIUS:
+    case VERTICAL_TAB_CORNER_RADIUS:
       return 8;
     case VERTICAL_TAB_HEIGHT:
       return 30;
@@ -138,6 +139,8 @@
       return 12;
     case VERTICAL_TAB_STRIP_BOTTOM_BUTTON_PADDING:
       return 4;
+    case VERTICAL_TAB_PINNED_BORDER_THICKNESS:
+      return 1;
     default:
       break;
   }
diff --git a/chrome/browser/ui/layout_constants.h b/chrome/browser/ui/layout_constants.h
index 16081262..a9b6fb4 100644
--- a/chrome/browser/ui/layout_constants.h
+++ b/chrome/browser/ui/layout_constants.h
@@ -182,9 +182,16 @@
   // height side panel.
   TOOLBAR_HEIGHT_SIDE_PANEL_INSET,
 
+  // The corner radius used for borders, fill, and hover targets with vertical
+  // tabs.
+  VERTICAL_TAB_CORNER_RADIUS,
+
   // The height of a vertical tab.
   VERTICAL_TAB_HEIGHT,
 
+  // The width of the border stroke around pinned tabs in a vertical tab strip.
+  VERTICAL_TAB_PINNED_BORDER_THICKNESS,
+
   // The horizontal padding between the sides of the vertical tab strip and its
   // content.
   VERTICAL_TAB_STRIP_HORIZONTAL_PADDING,
diff --git a/chrome/browser/ui/lens/lens_query_flow_router.cc b/chrome/browser/ui/lens/lens_query_flow_router.cc
index 56d8095d..3e17cdf 100644
--- a/chrome/browser/ui/lens/lens_query_flow_router.cc
+++ b/chrome/browser/ui/lens/lens_query_flow_router.cc
@@ -4,21 +4,26 @@
 
 #include "chrome/browser/ui/lens/lens_query_flow_router.h"
 
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/contextual_search/contextual_search_service_factory.h"
 #include "chrome/browser/contextual_search/contextual_search_web_contents_helper.h"
 #include "chrome/browser/contextual_tasks/contextual_tasks_side_panel_coordinator.h"
 #include "chrome/browser/contextual_tasks/contextual_tasks_ui_service.h"
 #include "chrome/browser/contextual_tasks/contextual_tasks_ui_service_factory.h"
 #include "chrome/browser/lens/core/mojom/lens.mojom.h"
+#include "chrome/browser/ui/lens/lens_overlay_controller.h"
 #include "chrome/browser/ui/lens/lens_overlay_image_helper.h"
 #include "chrome/browser/ui/lens/lens_search_contextualization_controller.h"
 #include "chrome/browser/ui/webui/new_tab_page/composebox/variations/composebox_fieldtrial.h"
 #include "components/contextual_search/contextual_search_context_controller.h"
 #include "components/contextual_search/contextual_search_service.h"
 #include "components/contextual_tasks/public/features.h"
+#include "components/lens/lens_features.h"
 #include "components/lens/lens_overlay_mime_type.h"
+#include "components/lens/lens_url_utils.h"
 #include "components/lens/ref_counted_lens_overlay_client_logs.h"
 #include "components/sessions/content/session_tab_helper.h"
+#include "net/base/url_util.h"
 
 namespace {
 std::vector<lens::ContextualInput> ConvertPageContentToContextualInput(
@@ -42,23 +47,9 @@
 
 LensQueryFlowRouter::~LensQueryFlowRouter() = default;
 
-std::unique_ptr<contextual_search::ContextualSearchSessionHandle>
-LensQueryFlowRouter::CreateContextualSearchSessionHandle() {
-  auto* contextual_search_service =
-      ContextualSearchServiceFactory::GetForProfile(profile());
-  // TODO(crbug.com/463400248): Use contextual tasks config params for Lens
-  // requests.
-  return contextual_search_service->CreateSession(
-      ntp_composebox::CreateQueryControllerConfigParams(),
-      contextual_search::ContextualSearchSource::kLens);
-}
-
 bool LensQueryFlowRouter::IsOff() const {
   if (contextual_tasks::GetEnableLensInContextualTasks()) {
-    // TODO(crbug.com/461909986): If the pending session handle is not present, then
-    // the session handle can possibly already be bound to the contextual tasks
-    // UI.
-    return !pending_session_handle_;
+    return !GetContextualSearchSessionHandle();
   }
   return lens_overlay_query_controller()->IsOff();
 }
@@ -140,9 +131,7 @@
     lens::LensOverlaySelectionType lens_selection_type,
     std::map<std::string, std::string> additional_search_query_params) {
   if (contextual_tasks::GetEnableLensInContextualTasks()) {
-    SendInteractionToContextualTasks(CreateSearchUrlRequestInfoFromInteraction(
-        /*region=*/nullptr, /*region_bytes=*/std::nullopt, query_text,
-        lens_selection_type, additional_search_query_params, query_start_time));
+    LoadQueryInContextualTasks(query_text);
     return;
   }
 
@@ -170,18 +159,37 @@
       additional_search_query_params, region_bytes);
 }
 
+std::unique_ptr<contextual_search::ContextualSearchSessionHandle>
+LensQueryFlowRouter::CreateContextualSearchSessionHandle() {
+  auto* contextual_search_service =
+      ContextualSearchServiceFactory::GetForProfile(profile());
+  // TODO(crbug.com/463400248): Use contextual tasks config params for Lens
+  // requests.
+  auto session_handle = contextual_search_service->CreateSession(
+      ntp_composebox::CreateQueryControllerConfigParams(),
+      contextual_search::ContextualSearchSource::kLens);
+  return session_handle;
+}
+
+const SkBitmap& LensQueryFlowRouter::GetViewportScreenshot() const {
+  return lens_search_controller_->lens_overlay_controller()
+      ->initial_screenshot();
+}
+
+void LensQueryFlowRouter::LoadQueryInContextualTasks(
+    const std::string& query_text) {
+  auto* ui_service =
+      contextual_tasks::ContextualTasksUiServiceFactory::GetForBrowserContext(
+          web_contents()->GetBrowserContext());
+  GURL ai_url = ui_service->GetDefaultAiPageUrl();
+  ai_url = net::AppendQueryParameter(ai_url, "q", query_text);
+  OpenContextualTasksPanel(ai_url);
+}
+
 void LensQueryFlowRouter::SendInteractionToContextualTasks(
     std::unique_ptr<CreateSearchUrlRequestInfo> request_info) {
-  // TODO(crbug.com/461911257): Currently, follow up visual selections that are
-  // made once the contextual tasks panel is already open / session handle has
-  // been moved will do nothing. In the future, they should grab the current
-  // open session handle and use that to send the interaction request.
-  if (!pending_session_handle_) {
-    return;
-  }
-
-  auto search_url =
-      pending_session_handle_->CreateSearchUrl(std::move(request_info));
+  auto* session_handle = GetOrCreateContextualSearchSessionHandle();
+  auto search_url = session_handle->CreateSearchUrl(std::move(request_info));
   OpenContextualTasksPanel(search_url);
 }
 
@@ -190,8 +198,8 @@
   // active tab.
   contextual_tasks::ContextualTasksUiServiceFactory::GetForBrowserContext(
       web_contents()->GetBrowserContext())
-      ->StartTaskUiInSidePanel(browser_window_interface(), tab_interface(),
-                               url);
+      ->StartTaskUiInSidePanel(browser_window_interface(), tab_interface(), url,
+                               std::move(pending_session_handle_));
 }
 
 void LensQueryFlowRouter::UploadContextualInputData(
@@ -271,8 +279,8 @@
     auto client_logs =
         base::MakeRefCounted<lens::RefCountedLensOverlayClientLogs>();
     auto image_crop_and_bitmap = lens::DownscaleAndEncodeBitmapRegionIfNeeded(
-        lens_search_contextualization_controller()->viewport_screenshot(),
-        region->Clone(), region_bytes, client_logs);
+        GetViewportScreenshot(), region->Clone(), region_bytes,
+        std::move(client_logs));
     if (image_crop_and_bitmap) {
       request_info->image_crop = std::move(image_crop_and_bitmap->image_crop);
     }
@@ -280,4 +288,42 @@
   return request_info;
 }
 
+contextual_search::ContextualSearchSessionHandle*
+LensQueryFlowRouter::GetOrCreateContextualSearchSessionHandle() {
+  auto* session_handle = GetContextualSearchSessionHandle();
+  if (session_handle) {
+    return session_handle;
+  }
+
+  pending_session_handle_ = CreateContextualSearchSessionHandle();
+  pending_session_handle_->NotifySessionStarted();
+  return pending_session_handle_.get();
+}
+
+contextual_search::ContextualSearchSessionHandle*
+LensQueryFlowRouter::GetContextualSearchSessionHandle() const {
+  if (pending_session_handle_) {
+    return pending_session_handle_.get();
+  }
+
+  auto* coordinator =
+      contextual_tasks::ContextualTasksSidePanelCoordinator::From(
+          browser_window_interface());
+  if (!coordinator) {
+    return nullptr;
+  }
+
+  auto* web_contents = coordinator->GetActiveWebContents();
+  if (!web_contents || !coordinator->IsSidePanelOpenForContextualTask()) {
+    return nullptr;
+  }
+
+  auto* helper = ContextualSearchWebContentsHelper::FromWebContents(
+      coordinator->GetActiveWebContents());
+  if (helper && helper->session_handle()) {
+    return helper->session_handle();
+  }
+  return nullptr;
+}
+
 }  // namespace lens
diff --git a/chrome/browser/ui/lens/lens_query_flow_router.h b/chrome/browser/ui/lens/lens_query_flow_router.h
index 2aa2bec..2d7c820 100644
--- a/chrome/browser/ui/lens/lens_query_flow_router.h
+++ b/chrome/browser/ui/lens/lens_query_flow_router.h
@@ -85,18 +85,14 @@
       std::map<std::string, std::string> additional_search_query_params,
       std::optional<SkBitmap> region_bytes);
 
-  // TODO(crbug.com/): This is a temporary workaround to allow tests to set a
-  // session handle. In the future, this should be removed once the query
-  // router fetches a session handle for the currently active panel.
-  void create_session_handle_for_testing() {
-    pending_session_handle_ = CreateContextualSearchSessionHandle();
-  }
-
  protected:
   // Creates a contextual search session handle. Virtual for testing.
   virtual std::unique_ptr<contextual_search::ContextualSearchSessionHandle>
   CreateContextualSearchSessionHandle();
 
+  // Returns the viewport screenshot. Virtual for testing.
+  virtual const SkBitmap& GetViewportScreenshot() const;
+
  private:
   LensOverlayQueryController* lens_overlay_query_controller() const {
     return lens_search_controller_->lens_overlay_query_controller();
@@ -123,6 +119,9 @@
     return Profile::FromBrowserContext(web_contents()->GetBrowserContext());
   }
 
+  // Loads the provided query text in the contextual tasks panel.
+  void LoadQueryInContextualTasks(const std::string& query_text);
+
   // Sends the provided request info to the contextual tasks panel to create a
   // search URL which is then loaded into the contextual tasks panel.
   void SendInteractionToContextualTasks(
@@ -166,6 +165,16 @@
       std::map<std::string, std::string> additional_search_query_params,
       base::Time query_start_time);
 
+  // Returns the contextual search session handle for the query router. If the
+  // handle does not exist, it will create one.
+  contextual_search::ContextualSearchSessionHandle*
+  GetOrCreateContextualSearchSessionHandle();
+
+  // Returns the contextual search session handle for the query router if it
+  // exists.
+  contextual_search::ContextualSearchSessionHandle*
+  GetContextualSearchSessionHandle() const;
+
   // The contextual search session handle that is used to make requests to the
   // contextual search service. This is only stored by this query router in
   // cases where the overlay has been opened but a results panel is not present.
diff --git a/chrome/browser/ui/lens/lens_query_flow_router_unittest.cc b/chrome/browser/ui/lens/lens_query_flow_router_unittest.cc
index 61f3381..35314a4 100644
--- a/chrome/browser/ui/lens/lens_query_flow_router_unittest.cc
+++ b/chrome/browser/ui/lens/lens_query_flow_router_unittest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/lens/lens_query_flow_router.h"
 
 #include "base/test/scoped_feature_list.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/contextual_tasks/contextual_tasks_ui_service.h"
 #include "chrome/browser/contextual_tasks/contextual_tasks_ui_service_factory.h"
 #include "chrome/browser/ui/browser_window/test/mock_browser_window_interface.h"
@@ -18,6 +19,7 @@
 #include "components/contextual_tasks/public/features.h"
 #include "components/lens/contextual_input.h"
 #include "components/lens/lens_features.h"
+#include "components/lens/lens_url_utils.h"
 #include "components/tabs/public/mock_tab_interface.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_renderer_host.h"
@@ -102,28 +104,28 @@
     // immediately.
     pending_mock_session_handle_ = std::make_unique<
         contextual_search::MockContextualSearchSessionHandle>();
+    viewport_screenshot_.allocN32Pixels(10, 10);
   }
   ~TestLensQueryFlowRouter() override = default;
 
   std::unique_ptr<contextual_search::ContextualSearchSessionHandle>
   CreateContextualSearchSessionHandle() override {
     CHECK(pending_mock_session_handle_);
-    mock_session_handle_ = pending_mock_session_handle_.get();
     return std::move(pending_mock_session_handle_);
   }
 
+  const SkBitmap& GetViewportScreenshot() const override {
+    return viewport_screenshot_;
+  }
+
   contextual_search::MockContextualSearchSessionHandle* mock_session_handle() {
-    if (mock_session_handle_) {
-      return mock_session_handle_;
-    }
     return pending_mock_session_handle_.get();
   }
 
  private:
+  SkBitmap viewport_screenshot_;
   std::unique_ptr<contextual_search::MockContextualSearchSessionHandle>
       pending_mock_session_handle_;
-  raw_ptr<contextual_search::MockContextualSearchSessionHandle>
-      mock_session_handle_ = nullptr;
 };
 
 class MockContextualTasksUiService
@@ -137,8 +139,12 @@
               StartTaskUiInSidePanel,
               (BrowserWindowInterface * browser_window_interface,
                tabs::TabInterface* tab_interface,
-               const GURL& url),
+               const GURL& url,
+               std::unique_ptr<contextual_search::ContextualSearchSessionHandle>
+                   session_handle),
               (override));
+
+  MOCK_METHOD(GURL, GetDefaultAiPageUrl, (), (override));
 };
 
 std::unique_ptr<KeyedService> CreateMockContextualTasksUiService(
@@ -377,13 +383,6 @@
       .WillOnce(Return(contextualization_controller_.get()));
   TestLensQueryFlowRouter router(mock_lens_search_controller_.get());
 
-  // Arrange: Set up the start query flow parameters and set a dummy viewport
-  // screenshot on the contextualization controller.
-  SkBitmap screenshot;
-  screenshot.allocN32Pixels(10, 10);
-  contextualization_controller_->set_viewport_screenshot_for_testing(
-      screenshot);
-
   GURL example_url("https://example.com");
   std::string page_title = "Title";
   lens::MimeType primary_content_type = lens::MimeType::kAnnotatedPageContent;
@@ -395,7 +394,7 @@
   expected_input_data.page_url = example_url;
   expected_input_data.page_title = page_title;
   expected_input_data.primary_content_type = primary_content_type;
-  expected_input_data.viewport_screenshot = screenshot;
+  expected_input_data.viewport_screenshot = router.GetViewportScreenshot();
   expected_input_data.pdf_current_page = std::nullopt;
   expected_input_data.is_page_context_eligible = true;
 
@@ -419,26 +418,15 @@
                   ImageEncodingOptionsMatches(expected_image_options)));
 
   // Act: Start query flow.
-  router.StartQueryFlow(screenshot, example_url, page_title, {}, {},
-                        primary_content_type, std::nullopt, ui_scale_factor,
-                        invocation_time);
+  router.StartQueryFlow(router.GetViewportScreenshot(), example_url, page_title,
+                        {}, {}, primary_content_type, std::nullopt,
+                        ui_scale_factor, invocation_time);
 }
 
 TEST_F(LensQueryFlowRouterContextualTaskEnabledTest,
        SendRegionSearch_RoutesToContextualTasks) {
   // Arrange: Set up and create the router.
-  EXPECT_CALL(*mock_lens_search_controller_,
-              lens_search_contextualization_controller())
-      .WillRepeatedly(Return(contextualization_controller_.get()));
   TestLensQueryFlowRouter router(mock_lens_search_controller_.get());
-  router.create_session_handle_for_testing();
-
-  // Arrange: Set a dummy viewport screenshot on the contextualization
-  // controller. This is needed for creating the image crop.
-  SkBitmap screenshot;
-  screenshot.allocN32Pixels(10, 10);
-  contextualization_controller_->set_viewport_screenshot_for_testing(
-      screenshot);
 
   // Arrange: Set up the parameters.
   base::Time query_start_time = base::Time::Now();
@@ -460,6 +448,7 @@
 
   // Assert: Create expectation to call CreateSearchUrl. We also expect a call
   // to open the side panel, but that is harder to mock, so we omit it for now.
+  EXPECT_CALL(*router.mock_session_handle(), NotifySessionStarted());
   EXPECT_CALL(*router.mock_session_handle(),
               CreateSearchUrl(CreateSearchUrlRequestInfoMatches(
                   expected_request_info.get())))
@@ -470,7 +459,8 @@
   EXPECT_CALL(*service,
               StartTaskUiInSidePanel(
                   mock_browser_window_interface_.get(), &mock_tab_interface_,
-                  GURL("https://www.google.com/search?q=test")))
+                  GURL("https://www.google.com/search?q=test"),
+                  testing::Pointer(router.mock_session_handle())))
       .Times(1);
 
   // Act: Call the method.
@@ -485,7 +475,6 @@
               lens_search_contextualization_controller())
       .WillRepeatedly(Return(contextualization_controller_.get()));
   TestLensQueryFlowRouter router(mock_lens_search_controller_.get());
-  router.create_session_handle_for_testing();
 
   // Arrange: Set up the parameters.
   base::Time query_start_time = base::Time::Now();
@@ -505,6 +494,7 @@
   expected_request_info->image_crop = std::nullopt;
 
   // Assert: Create expectation to call CreateSearchUrl.
+  EXPECT_CALL(*router.mock_session_handle(), NotifySessionStarted());
   EXPECT_CALL(*router.mock_session_handle(),
               CreateSearchUrl(CreateSearchUrlRequestInfoMatches(
                   expected_request_info.get())))
@@ -515,7 +505,8 @@
   EXPECT_CALL(*service,
               StartTaskUiInSidePanel(
                   mock_browser_window_interface_.get(), &mock_tab_interface_,
-                  GURL("https://www.google.com/search?q=test")))
+                  GURL("https://www.google.com/search?q=test"),
+                  testing::Pointer(router.mock_session_handle())))
       .Times(1);
 
   // Act: Call the method.
@@ -526,11 +517,7 @@
 TEST_F(LensQueryFlowRouterContextualTaskEnabledTest,
        SendContextualTextQuery_RoutesToContextualTasks) {
   // Arrange: Set up and create the router.
-  EXPECT_CALL(*mock_lens_search_controller_,
-              lens_search_contextualization_controller())
-      .WillRepeatedly(Return(contextualization_controller_.get()));
   TestLensQueryFlowRouter router(mock_lens_search_controller_.get());
-  router.create_session_handle_for_testing();
 
   // Arrange: Set up the parameters.
   base::Time query_start_time = base::Time::Now();
@@ -539,28 +526,16 @@
       lens::LensOverlaySelectionType::MULTIMODAL_SUGGEST_TYPEAHEAD;
   std::map<std::string, std::string> additional_params;
 
-  // Arrange: Create expected request info.
-  auto expected_request_info = std::make_unique<CreateSearchUrlRequestInfo>();
-  expected_request_info->search_url_type = contextual_search::
-      ContextualSearchContextController::SearchUrlType::kStandard;
-  expected_request_info->query_text = query_text;
-  expected_request_info->query_start_time = query_start_time;
-  expected_request_info->lens_overlay_selection_type = selection_type;
-  expected_request_info->additional_params = additional_params;
-  expected_request_info->image_crop = std::nullopt;
-
-  // Assert: Create expectation to call CreateSearchUrl.
-  EXPECT_CALL(*router.mock_session_handle(),
-              CreateSearchUrl(CreateSearchUrlRequestInfoMatches(
-                  expected_request_info.get())))
-      .WillOnce(Return(GURL("https://www.google.com/search?q=test")));
+  // Assert: Create expectation to call GetDefaultAiPageUrl.
   auto* service = static_cast<MockContextualTasksUiService*>(
       contextual_tasks::ContextualTasksUiServiceFactory::GetForBrowserContext(
           profile_.get()));
+  EXPECT_CALL(*service, GetDefaultAiPageUrl())
+      .WillOnce(Return(GURL("https://example.com")));
   EXPECT_CALL(*service,
               StartTaskUiInSidePanel(
                   mock_browser_window_interface_.get(), &mock_tab_interface_,
-                  GURL("https://www.google.com/search?q=test")))
+                  GURL("https://example.com/?q=test+query"), testing::IsNull()))
       .Times(1);
 
   // Act: Call the method.
@@ -571,18 +546,7 @@
 TEST_F(LensQueryFlowRouterContextualTaskEnabledTest,
        SendMultimodalRequest_RoutesToContextualTasks) {
   // Arrange: Set up and create the router.
-  EXPECT_CALL(*mock_lens_search_controller_,
-              lens_search_contextualization_controller())
-      .WillRepeatedly(Return(contextualization_controller_.get()));
   TestLensQueryFlowRouter router(mock_lens_search_controller_.get());
-  router.create_session_handle_for_testing();
-
-  // Arrange: Set a dummy viewport screenshot on the contextualization
-  // controller. This is needed for creating the image crop.
-  SkBitmap screenshot;
-  screenshot.allocN32Pixels(10, 10);
-  contextualization_controller_->set_viewport_screenshot_for_testing(
-      screenshot);
 
   // Arrange: Set up the parameters.
   base::Time query_start_time = base::Time::Now();
@@ -606,6 +570,7 @@
 
   // Assert: Create expectation to call CreateSearchUrl. We also expect a call
   // to open the side panel, but that is harder to mock, so we omit it for now.
+  EXPECT_CALL(*router.mock_session_handle(), NotifySessionStarted());
   EXPECT_CALL(*router.mock_session_handle(),
               CreateSearchUrl(CreateSearchUrlRequestInfoMatches(
                   expected_request_info.get())))
@@ -616,7 +581,8 @@
   EXPECT_CALL(*service,
               StartTaskUiInSidePanel(
                   mock_browser_window_interface_.get(), &mock_tab_interface_,
-                  GURL("https://www.google.com/search?q=test")))
+                  GURL("https://www.google.com/search?q=test"),
+                  testing::Pointer(router.mock_session_handle())))
       .Times(1);
 
   // Act: Call the method.
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc b/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc
index b407cbf..6839fc3f 100644
--- a/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc
+++ b/chrome/browser/ui/views/extensions/extensions_toolbar_container.cc
@@ -103,7 +103,7 @@
       display_mode_(display_mode),
       action_hover_card_controller_(
           std::make_unique<ToolbarActionHoverCardController>(this)),
-      view_model_(std::make_unique<ExtensionsToolbarContainerViewModel>()) {
+      view_model_(std::make_unique<ExtensionsToolbarViewModel>()) {
   SetProperty(views::kElementIdentifierKey,
               kToolbarExtensionsContainerElementId);
 
diff --git a/chrome/browser/ui/views/extensions/extensions_toolbar_container.h b/chrome/browser/ui/views/extensions/extensions_toolbar_container.h
index 1213e48..110cd9f 100644
--- a/chrome/browser/ui/views/extensions/extensions_toolbar_container.h
+++ b/chrome/browser/ui/views/extensions/extensions_toolbar_container.h
@@ -15,7 +15,7 @@
 #include "base/functional/callback_forward.h"
 #include "base/memory/raw_ptr.h"
 #include "base/scoped_observation.h"
-#include "chrome/browser/ui/extensions/extensions_toolbar_container_view_model.h"
+#include "chrome/browser/ui/extensions/extensions_toolbar_view_model.h"
 #include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
 #include "chrome/browser/ui/views/extensions/extensions_container_views.h"
 #include "chrome/browser/ui/views/extensions/extensions_request_access_button.h"
@@ -333,7 +333,7 @@
       action_hover_card_controller_;
 
   // The view model for this container.
-  std::unique_ptr<ExtensionsToolbarContainerViewModel> view_model_;
+  std::unique_ptr<ExtensionsToolbarViewModel> view_model_;
 
   // View for every action, does not imply pinned or currently shown.
   ToolbarIcons icons_;
diff --git a/chrome/browser/ui/views/frame/browser_frame_view_chromeos_browsertest.cc b/chrome/browser/ui/views/frame/browser_frame_view_chromeos_browsertest.cc
index aca9b1a..c45da7ab 100644
--- a/chrome/browser/ui/views/frame/browser_frame_view_chromeos_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_frame_view_chromeos_browsertest.cc
@@ -940,6 +940,27 @@
                browser_view->web_app_frame_toolbar_for_testing()->GetVisible());
 }
 
+IN_PROC_BROWSER_TEST_P(BrowserFrameViewChromeOSTest,
+                       FocusOmniboxRevealTopChrome) {
+  EnterImmersiveFullscreenMode(browser());
+  auto* const immersive_mode_controller =
+      ImmersiveModeController::From(browser());
+  EXPECT_TRUE(immersive_mode_controller->IsEnabled());
+  // TODO(crbug.com/463559714): Replace the loop with EXPECT_TRUE, when the
+  // mechanism to disable gfx::Animation is added.
+  ASSERT_TRUE(base::test::RunUntil(
+      [&]() -> bool { return !immersive_mode_controller->IsRevealed(); }));
+
+  ui::test::EventGenerator generator(
+      browser()->window()->GetNativeWindow()->GetRootWindow());
+  // Focus omnibox using shortcut.
+  generator.PressKey(ui::KeyboardCode::VKEY_CONTROL, 0);
+  generator.PressKey(ui::KeyboardCode::VKEY_L, ui::EF_CONTROL_DOWN);
+  generator.ReleaseKey(ui::KeyboardCode::VKEY_L, ui::EF_CONTROL_DOWN);
+  generator.ReleaseKey(ui::KeyboardCode::VKEY_CONTROL, 0);
+  EXPECT_TRUE(immersive_mode_controller->IsRevealed());
+}
+
 // Test the normal type browser's kTopViewInset is always 0.
 IN_PROC_BROWSER_TEST_P(BrowserFrameViewChromeOSTest, TopViewInset) {
   auto* const immersive_mode_controller =
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 52e597f..56a5476 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -2213,11 +2213,21 @@
     return;
   }
 #endif
+  LocationBarView* location_bar = GetLocationBarView();
+
+  // Focusing the omnibox by a user action (e.g. ctrl-l) in immersive mode
+  // should reveal topchrome.  Make sure the omnibox is focusable.
+  if (overlay_view_tracker_ && is_user_initiated) {
+    overlay_view_tracker_.view()->SetVisible(true);
+    toolbar_->SetVisible(true);
+    location_bar->omnibox_view()->SetFocusBehavior(
+        views::View::FocusBehavior::ALWAYS);
+  }
+
   if (!IsLocationBarVisible()) {
     return;
   }
 
-  LocationBarView* location_bar = GetLocationBarView();
   location_bar->FocusLocation(is_user_initiated);
   if (!location_bar->omnibox_view()->HasFocus()) {
     // If none of location bar got focus, then clear focus.
diff --git a/chrome/browser/ui/views/frame/vertical_tab_strip_region_view.h b/chrome/browser/ui/views/frame/vertical_tab_strip_region_view.h
index 6cfcfe78..227ddd1 100644
--- a/chrome/browser/ui/views/frame/vertical_tab_strip_region_view.h
+++ b/chrome/browser/ui/views/frame/vertical_tab_strip_region_view.h
@@ -65,6 +65,8 @@
     return tab_strip_view_->GetUnpinnedTabsContainerForTesting();
   }
 
+  RootTabCollectionNode* root_node_for_testing() { return root_node_.get(); }
+
   VerticalTabStripTopContainer* GetTopContainer() {
     return top_button_container_;
   }
diff --git a/chrome/browser/ui/views/tabs/vertical/vertical_split_tab_view.cc b/chrome/browser/ui/views/tabs/vertical/vertical_split_tab_view.cc
index 4f7f51f..7fc8327f 100644
--- a/chrome/browser/ui/views/tabs/vertical/vertical_split_tab_view.cc
+++ b/chrome/browser/ui/views/tabs/vertical/vertical_split_tab_view.cc
@@ -5,15 +5,21 @@
 #include "chrome/browser/ui/views/tabs/vertical/vertical_split_tab_view.h"
 
 #include <numeric>
+#include <vector>
 
+#include "chrome/browser/ui/color/chrome_color_id.h"
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/views/tabs/vertical/tab_collection_node.h"
+#include "components/tabs/public/tab_collection.h"
+#include "components/tabs/public/tab_interface.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
 #include "ui/gfx/geometry/rect.h"
+#include "ui/views/border.h"
 #include "ui/views/layout/delegating_layout_manager.h"
 #include "ui/views/layout/proposed_layout.h"
 #include "ui/views/view.h"
 #include "ui/views/view_class_properties.h"
+#include "ui/views/widget/widget.h"
 
 VerticalSplitTabView::VerticalSplitTabView(TabCollectionNode* collection_node)
     : collection_node_(collection_node) {
@@ -21,10 +27,30 @@
   node_destroyed_subscription_ =
       collection_node_->RegisterWillDestroyCallback(base::BindOnce(
           &VerticalSplitTabView::ResetCollectionNode, base::Unretained(this)));
+  data_changed_subscription_ =
+      collection_node_->RegisterDataChangedCallback(base::BindRepeating(
+          &VerticalSplitTabView::OnDataChanged, base::Unretained(this)));
+
+  OnDataChanged();
 }
 
 VerticalSplitTabView::~VerticalSplitTabView() = default;
 
+void VerticalSplitTabView::OnThemeChanged() {
+  views::View::OnThemeChanged();
+  UpdateBorder();
+}
+
+void VerticalSplitTabView::AddedToWidget() {
+  paint_as_active_subscription_ =
+      GetWidget()->RegisterPaintAsActiveChangedCallback(base::BindRepeating(
+          &VerticalSplitTabView::UpdateBorder, base::Unretained(this)));
+}
+
+void VerticalSplitTabView::RemovedFromWidget() {
+  paint_as_active_subscription_ = {};
+}
+
 views::ProposedLayout VerticalSplitTabView::CalculateProposedLayout(
     const views::SizeBounds& size_bounds) const {
   views::ProposedLayout layouts;
@@ -79,5 +105,27 @@
   collection_node_ = nullptr;
 }
 
+void VerticalSplitTabView::OnDataChanged() {
+  UpdateBorder();
+}
+
+void VerticalSplitTabView::UpdateBorder() {
+  const tabs::TabCollection* tab_collection =
+      std::get<const tabs::TabCollection*>(collection_node_->GetNodeData());
+  const std::vector<tabs::TabInterface*> tabs =
+      tab_collection->GetTabsRecursive();
+  if (tabs[0]->IsPinned()) {
+    const bool is_frame_active =
+        GetWidget() ? GetWidget()->ShouldPaintAsActive() : true;
+    SetBorder(views::CreateRoundedRectBorder(
+        GetLayoutConstant(VERTICAL_TAB_PINNED_BORDER_THICKNESS),
+        GetLayoutConstant(VERTICAL_TAB_CORNER_RADIUS),
+        is_frame_active ? kColorTabDividerFrameActive
+                        : kColorTabDividerFrameInactive));
+  } else {
+    SetBorder(nullptr);
+  }
+}
+
 BEGIN_METADATA(VerticalSplitTabView)
 END_METADATA
diff --git a/chrome/browser/ui/views/tabs/vertical/vertical_split_tab_view.h b/chrome/browser/ui/views/tabs/vertical/vertical_split_tab_view.h
index cff03f8..25a718e 100644
--- a/chrome/browser/ui/views/tabs/vertical/vertical_split_tab_view.h
+++ b/chrome/browser/ui/views/tabs/vertical/vertical_split_tab_view.h
@@ -23,16 +23,25 @@
   VerticalSplitTabView& operator=(const VerticalSplitTabView&) = delete;
   ~VerticalSplitTabView() override;
 
+  // views::View
+  void OnThemeChanged() override;
+  void AddedToWidget() override;
+  void RemovedFromWidget() override;
+
   // LayoutDelegate:
   views::ProposedLayout CalculateProposedLayout(
       const views::SizeBounds& size_bounds) const override;
 
  private:
   void ResetCollectionNode();
+  void OnDataChanged();
+  void UpdateBorder();
 
   raw_ptr<TabCollectionNode> collection_node_ = nullptr;
 
+  base::CallbackListSubscription data_changed_subscription_;
   base::CallbackListSubscription node_destroyed_subscription_;
+  base::CallbackListSubscription paint_as_active_subscription_;
 };
 
 #endif  // CHROME_BROWSER_UI_VIEWS_TABS_VERTICAL_VERTICAL_SPLIT_TAB_VIEW_H_
diff --git a/chrome/browser/ui/views/tabs/vertical/vertical_tab_view.cc b/chrome/browser/ui/views/tabs/vertical/vertical_tab_view.cc
index 64c0cc4..f12fc765 100644
--- a/chrome/browser/ui/views/tabs/vertical/vertical_tab_view.cc
+++ b/chrome/browser/ui/views/tabs/vertical/vertical_tab_view.cc
@@ -42,7 +42,6 @@
 constexpr int kTitleHeight = 18;
 // TODO(crbug.com/454686636): Determine what this min width should be.
 constexpr int kVerticalTabExpandedMinWidth = 50;
-constexpr int kVerticalTabRoundedCornerRadius = 7;
 
 class VerticalTabTitle : public views::Label {
   METADATA_HEADER(VerticalTabTitle, views::Label)
@@ -88,7 +87,6 @@
   data_changed_subscription_ =
       collection_node_->RegisterDataChangedCallback(base::BindRepeating(
           &VerticalTabView::OnDataChanged, base::Unretained(this)));
-  // TODO(crbug.com/444283717): Separate pinned and unpinned tabs.
 
   OnDataChanged();
 
@@ -122,6 +120,8 @@
       GetSelectionState(), hovered_, GetHoverAnimationValue(), IsFrameActive(),
       GetColorProvider()));
   canvas->DrawRect(GetLocalBounds(), flags);
+
+  views::View::OnPaint(canvas);
 }
 
 void VerticalTabView::AddedToWidget() {
@@ -279,8 +279,8 @@
 }
 
 void VerticalTabView::OnDataChanged() {
-  const tabs::TabInterface* tab =
-      std::get<const tabs::TabInterface*>(collection_node_->GetNodeData());
+  const tabs::TabInterface* tab = GetTabInterface();
+  CHECK(tab);
 
   active_ = tab->IsActivated();
   selected_ = tab->IsSelected();
@@ -294,7 +294,10 @@
   icon_->SetActiveState(active_);
   icon_->SetAttention(TabIcon::AttentionType::kBlockedWebContents,
                       active_ && tab_data.blocked);
+
   title_->SetText(tab_data.title);
+  title_->SetVisible(!tab->IsPinned());
+
   alert_indicator_->TransitionToAlertState(
       tabs::TabAlertController::GetAlertStateToShow(tab_data.alert_state));
   UpdateAlertIndicatorVisibility();
@@ -304,6 +307,19 @@
   InvalidateLayout();
 }
 
+void VerticalTabView::UpdateBorder() {
+  const tabs::TabInterface* tab = GetTabInterface();
+  if (tab && tab->IsPinned() && !tab->IsSplit()) {
+    SetBorder(views::CreateRoundedRectBorder(
+        GetLayoutConstant(VERTICAL_TAB_PINNED_BORDER_THICKNESS),
+        GetLayoutConstant(VERTICAL_TAB_CORNER_RADIUS),
+        IsFrameActive() ? kColorTabDividerFrameActive
+                        : kColorTabDividerFrameInactive));
+  } else {
+    SetBorder(nullptr);
+  }
+}
+
 void VerticalTabView::UpdateAlertIndicatorVisibility() {
   alert_indicator_->UpdateAlertIndicatorAnimation();
   alert_indicator_->SetVisible(
@@ -311,7 +327,8 @@
 }
 
 void VerticalTabView::UpdateCloseButtonVisibility() {
-  close_button_->SetVisible(active_ || hovered_);
+  close_button_->SetVisible((active_ || hovered_) &&
+                            !GetTabInterface()->IsPinned());
 }
 
 void VerticalTabView::UpdateColors() {
@@ -322,6 +339,9 @@
   title_->SetEnabledColor(colors.foreground_color);
   close_button_->SetColors(colors);
   alert_indicator_->OnParentTabButtonColorChanged();
+
+  UpdateBorder();
+
   // TODO(crbug.com/465159185): Update focus ring colors.
   SchedulePaint();
 }
@@ -360,8 +380,8 @@
 }
 
 SkPath VerticalTabView::GetPath() const {
-  SkVector radius = {kVerticalTabRoundedCornerRadius,
-                     kVerticalTabRoundedCornerRadius};
+  const float corner_radius = GetLayoutConstant(VERTICAL_TAB_CORNER_RADIUS);
+  SkVector radius = {corner_radius, corner_radius};
   const SkVector radii[4] = {radius, radius, radius, radius};
   SkPathBuilder path;
   path.addRRect(
@@ -379,5 +399,8 @@
                               : TabStyle::TabSelectionState::kInactive);
 }
 
-BEGIN_METADATA(VerticalTabView)
-END_METADATA
+const tabs::TabInterface* VerticalTabView::GetTabInterface() {
+  return std::get<const tabs::TabInterface*>(collection_node_->GetNodeData());
+}
+
+BEGIN_METADATA(VerticalTabView) END_METADATA
diff --git a/chrome/browser/ui/views/tabs/vertical/vertical_tab_view.h b/chrome/browser/ui/views/tabs/vertical/vertical_tab_view.h
index 914e857..92d06dd1 100644
--- a/chrome/browser/ui/views/tabs/vertical/vertical_tab_view.h
+++ b/chrome/browser/ui/views/tabs/vertical/vertical_tab_view.h
@@ -9,6 +9,7 @@
 #include "chrome/browser/ui/tabs/tab_style.h"
 #include "chrome/browser/ui/views/tabs/alert_indicator_button.h"
 #include "chrome/browser/ui/views/tabs/tab_context_menu_controller.h"
+#include "components/tabs/public/tab_interface.h"
 #include "ui/base/metadata/metadata_header_macros.h"
 #include "ui/gfx/canvas.h"
 #include "ui/views/context_menu_controller.h"
@@ -80,6 +81,8 @@
 
   void OnDataChanged();
 
+  void UpdateBorder();
+
   void UpdateAlertIndicatorVisibility();
   void UpdateCloseButtonVisibility();
 
@@ -94,6 +97,8 @@
   bool IsFrameActive() const;
   TabStyle::TabSelectionState GetSelectionState() const;
 
+  const tabs::TabInterface* GetTabInterface();
+
   raw_ptr<TabCollectionNode> collection_node_ = nullptr;
 
   const raw_ptr<const TabStyle> tab_style_;
diff --git a/chrome/browser/ui/views/tabs/vertical/vertical_tab_view_browsertest.cc b/chrome/browser/ui/views/tabs/vertical/vertical_tab_view_browsertest.cc
index 6873d66..9385f4fc 100644
--- a/chrome/browser/ui/views/tabs/vertical/vertical_tab_view_browsertest.cc
+++ b/chrome/browser/ui/views/tabs/vertical/vertical_tab_view_browsertest.cc
@@ -48,7 +48,26 @@
 };
 
 class VerticalTabViewTest
-    : public VerticalTabsBrowserTestMixin<InProcessBrowserTest> {};
+    : public VerticalTabsBrowserTestMixin<InProcessBrowserTest> {
+ public:
+  RootTabCollectionNode* root_node() {
+    VerticalTabStripRegionView* region_view =
+        BrowserView::GetBrowserViewForBrowser(browser())
+            ->vertical_tab_strip_region_view();
+    return region_view->root_node_for_testing();
+  }
+
+  content::WebContents* AppendPinnedTab() {
+    std::unique_ptr<content::WebContents> contents =
+        content::WebContents::Create(
+            content::WebContents::CreateParams(browser()->profile()));
+    content::WebContents* raw_contents = contents.get();
+    browser()->tab_strip_model()->InsertWebContentsAt(
+        browser()->tab_strip_model()->count(), std::move(contents),
+        ADD_INHERIT_OPENER | ADD_ACTIVE | ADD_PINNED);
+    return raw_contents;
+  }
+};
 
 IN_PROC_BROWSER_TEST_F(VerticalTabViewTest, IconDataChanged) {
   ASSERT_TRUE(embedded_test_server()->Start());
@@ -217,3 +236,34 @@
 
 // TODO(crbug.com/465540287): Determine how to test the background changing
 // based on active/selected/hovered states.
+
+IN_PROC_BROWSER_TEST_F(VerticalTabViewTest, PinnedTabsHideCloseButton) {
+  AppendPinnedTab();
+
+  // The initial tab is the first child of the pinned collection which is the
+  // first child of the root node.
+  TabCollectionNode* tab_node = root_node()->children()[0]->children()[0].get();
+  VerticalTabView* tab =
+      static_cast<VerticalTabView*>(tab_node->get_view_for_testing());
+
+  // The favicon should be visible but the close button is not.
+  EXPECT_TRUE(tab->icon_for_testing()->GetVisible());
+  EXPECT_FALSE(tab->alert_indicator_for_testing()->GetVisible());
+}
+
+IN_PROC_BROWSER_TEST_F(VerticalTabViewTest, PinnedTabsRenderBorder) {
+  AppendPinnedTab();
+
+  // The initial tab is the first child of the pinned collection which is the
+  // first child of the root node.
+  TabCollectionNode* tab_node = root_node()->children()[0]->children()[0].get();
+  VerticalTabView* tab =
+      static_cast<VerticalTabView*>(tab_node->get_view_for_testing());
+
+  EXPECT_TRUE(tab->GetBorder());
+
+  // Unpin the tab.
+  browser()->tab_strip_model()->SetTabPinned(0, false);
+
+  EXPECT_FALSE(tab->GetBorder());
+}
diff --git a/chrome/browser/ui/webui/ash/sys_internals/sys_internals_message_handler.cc b/chrome/browser/ui/webui/ash/sys_internals/sys_internals_message_handler.cc
index ae67eef..96761bb1 100644
--- a/chrome/browser/ui/webui/ash/sys_internals/sys_internals_message_handler.cc
+++ b/chrome/browser/ui/webui/ash/sys_internals/sys_internals_message_handler.cc
@@ -12,7 +12,7 @@
 #include <utility>
 #include <vector>
 
-#include "base/byte_count.h"
+#include "base/byte_size.h"
 #include "base/compiler_specific.h"
 #include "base/files/file_util.h"
 #include "base/functional/bind.h"
@@ -141,9 +141,8 @@
 }
 
 double GetAvailablePhysicalMemory(const base::SystemMemoryInfo& info) {
-  base::ByteCount available =
+  const base::ByteSize available =
       info.available.is_zero() ? info.free + info.reclaimable : info.available;
-
   return available.InBytesF();
 }
 
diff --git a/chrome/browser/ui/webui/help/version_updater_mac.mm b/chrome/browser/ui/webui/help/version_updater_mac.mm
index d619a64..83c77c3 100644
--- a/chrome/browser/ui/webui/help/version_updater_mac.mm
+++ b/chrome/browser/ui/webui/help/version_updater_mac.mm
@@ -24,7 +24,8 @@
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
 #include "base/version.h"
-#include "chrome/browser/updater/updater.h"
+#include "chrome/browser/updater/browser_updater_client.h"
+#include "chrome/browser/updater/browser_updater_client_util.h"
 #include "chrome/browser/upgrade_detector/upgrade_detector.h"
 #include "chrome/grit/branded_strings.h"
 #include "chrome/grit/generated_resources.h"
@@ -121,13 +122,33 @@
   // VersionUpdater implementation.
   void CheckForUpdate(StatusCallback status_callback,
                       PromoteCallback promote_callback) override {
-    updater::EnsureUpdater(
+    EnsureUpdater(
         base::TaskPriority::USER_VISIBLE,
-        base::BindOnce(promote_callback, PromotionState::PROMOTE_ENABLED),
-        base::BindOnce(&updater::CheckForUpdate,
-                       base::BindRepeating(&UpdateStatus, status_callback)));
+        base::BindOnce(
+            [](PromoteCallback prompt) {
+              prompt.Run(PromotionState::PROMOTE_ENABLED);
+            },
+            promote_callback),
+        base::BindOnce(
+            [](base::RepeatingCallback<void(
+                   const updater::UpdateService::UpdateState&)>
+                   status_callback) {
+              base::ThreadPool::PostTaskAndReplyWithResult(
+                  FROM_HERE, {base::MayBlock()},
+                  base::BindOnce(&GetBrowserUpdaterScope),
+                  base::BindOnce(
+                      [](base::RepeatingCallback<void(
+                             const updater::UpdateService::UpdateState&)>
+                             status_callback,
+                         updater::UpdaterScope scope) {
+                        BrowserUpdaterClient::Create(scope)->CheckForUpdate(
+                            status_callback);
+                      },
+                      status_callback));
+            },
+            base::BindRepeating(&UpdateStatus, status_callback)));
   }
-  void PromoteUpdater() override { updater::SetUpSystemUpdater(); }
+  void PromoteUpdater() override { SetupSystemUpdater(); }
 };
 
 }  // namespace
diff --git a/chrome/browser/ui/webui/top_chrome/untrusted_top_chrome_web_ui_controller.cc b/chrome/browser/ui/webui/top_chrome/untrusted_top_chrome_web_ui_controller.cc
index b72041a..b8c0c370 100644
--- a/chrome/browser/ui/webui/top_chrome/untrusted_top_chrome_web_ui_controller.cc
+++ b/chrome/browser/ui/webui/top_chrome/untrusted_top_chrome_web_ui_controller.cc
@@ -20,3 +20,8 @@
 
 UntrustedTopChromeWebUIController::~UntrustedTopChromeWebUIController() =
     default;
+
+content::WebUIController::TrustPolicy
+UntrustedTopChromeWebUIController::GetTrustPolicy() {
+  return content::WebUIController::kUntrusted;
+}
diff --git a/chrome/browser/ui/webui/top_chrome/untrusted_top_chrome_web_ui_controller.h b/chrome/browser/ui/webui/top_chrome/untrusted_top_chrome_web_ui_controller.h
index a809e4a..1c251d6 100644
--- a/chrome/browser/ui/webui/top_chrome/untrusted_top_chrome_web_ui_controller.h
+++ b/chrome/browser/ui/webui/top_chrome/untrusted_top_chrome_web_ui_controller.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_WEBUI_TOP_CHROME_UNTRUSTED_TOP_CHROME_WEB_UI_CONTROLLER_H_
 
 #include "chrome/browser/ui/webui/top_chrome/top_chrome_web_ui_controller.h"
+#include "content/public/browser/web_ui_browser_interface_broker_registry.h"
 
 namespace content {
 class WebUI;
@@ -24,6 +25,8 @@
       delete;
   UntrustedTopChromeWebUIController& operator=(
       const UntrustedTopChromeWebUIController&) = delete;
+
+  content::WebUIController::TrustPolicy GetTrustPolicy() override;
 };
 
 #endif  // CHROME_BROWSER_UI_WEBUI_TOP_CHROME_UNTRUSTED_TOP_CHROME_WEB_UI_CONTROLLER_H_
diff --git a/chrome/browser/updater/BUILD.gn b/chrome/browser/updater/BUILD.gn
index 4da6a64d..8e95c0a62 100644
--- a/chrome/browser/updater/BUILD.gn
+++ b/chrome/browser/updater/BUILD.gn
@@ -5,30 +5,22 @@
 import("//build/config/chrome_build.gni")
 import("//chrome/browser/buildflags.gni")
 
-source_set("updater") {
-  public = [ "updater.h" ]
-
-  public_deps = [
-    "//base",
-    "//chrome/updater/mojom",
-  ]
-
-  friend = [ "//chrome/test:unit_tests" ]
-
-  if (enable_updater && (is_mac || is_win)) {
+if (is_win || is_mac) {
+  source_set("browser_updater_client") {
     sources = [
       "browser_updater_client.cc",
       "browser_updater_client.h",
       "browser_updater_client_util.cc",
       "browser_updater_client_util.h",
-      "check_updater_health_task.cc",
       "check_updater_health_task.h",
-      "scheduler.cc",
-      "scheduler.h",
-      "scheduler_impl.cc",
-      "updater.cc",
     ]
 
+    if (enable_updater) {
+      sources += [ "check_updater_health_task.cc" ]
+    } else {
+      sources += [ "check_updater_health_task_no_updater.cc" ]
+    }
+
     deps = [
       "//base",
       "//chrome/browser:buildflags",
@@ -36,45 +28,85 @@
       "//chrome/updater:branding_header",
       "//chrome/updater:browser_sources",
       "//chrome/updater/mojom",
+      "//components/version_info",
     ]
 
     if (is_win) {
-      sources += [
-        "browser_updater_client_util_win.cc",
-        "browser_updater_client_win.cc",
-        "scheduler_win.cc",
-      ]
+      sources += [ "browser_updater_client_win.cc" ]
+
+      if (enable_updater) {
+        sources += [ "browser_updater_client_util_win.cc" ]
+      } else {
+        sources += [ "browser_updater_client_util_no_updater.cc" ]
+      }
+
       deps += [
         "//chrome/browser/google",
         "//chrome/install_static:install_static_util",
         "//chrome/installer/util:with_no_strings",
-        "//chrome/updater:browser_sources",
       ]
     }
 
     if (is_mac) {
       sources += [
         "browser_updater_client_mac.mm",
-        "browser_updater_client_util_mac.mm",
         "browser_updater_helper_client_mac.h",
         "browser_updater_helper_client_mac.mm",
-        "scheduler_mac.cc",
       ]
 
+      if (enable_updater) {
+        sources += [ "browser_updater_client_util_mac.mm" ]
+      } else {
+        sources += [ "browser_updater_client_util_no_updater.cc" ]
+      }
+
       deps += [
         "//chrome/app:branded_strings_grit",
         "//chrome/app:generated_resources_grit",
         "//chrome/browser/google",
-        "//chrome/common",
         "//chrome/common:channel_info",
         "//chrome/common:chrome_features",
-        "//chrome/updater:browser_sources",
         "//ui/base",
       ]
-      frameworks = [ "OpenDirectory.framework" ]
+    }
+
+    frameworks = [ "OpenDirectory.framework" ]
+  }
+}
+
+source_set("scheduler") {
+  sources = [
+    "scheduler.cc",
+    "scheduler.h",
+  ]
+
+  deps = [ "//base" ]
+
+  if (enable_updater) {
+    if (is_mac) {
+      sources += [
+        "scheduler_impl.cc",
+        "scheduler_mac.cc",
+      ]
+      deps += [
+        ":browser_updater_client",
+        "//chrome/browser/ui",
+        "//chrome/common",
+        "//chrome/updater:browser_sources",
+      ]
+    } else if (is_win) {
+      sources += [
+        "scheduler_impl.cc",
+        "scheduler_win.cc",
+      ]
+      deps += [
+        ":browser_updater_client",
+        "//chrome/updater:browser_sources",
+      ]
+    } else {
+      sources += [ "scheduler_noimpl.cc" ]
     }
   } else {
-    sources = [ "updater_no_updater.cc" ]
-    deps = [ "//components/version_info" ]
+    sources += [ "scheduler_noimpl.cc" ]
   }
 }
diff --git a/chrome/browser/updater/browser_updater_client.cc b/chrome/browser/updater/browser_updater_client.cc
index 8d7645ee..bf67b37 100644
--- a/chrome/browser/updater/browser_updater_client.cc
+++ b/chrome/browser/updater/browser_updater_client.cc
@@ -24,30 +24,37 @@
 #include "base/version.h"
 #include "chrome/updater/branded_constants.h"
 #include "chrome/updater/constants.h"
-#include "chrome/updater/mojom/updater_service.mojom.h"
 #include "chrome/updater/service_proxy_factory.h"
 #include "chrome/updater/update_service.h"
 #include "components/version_info/version_info.h"
 
-namespace updater {
+namespace {
 
-std::optional<mojom::AppState>& GetLastKnownBrowserRegistrationStorage() {
-  static base::NoDestructor<std::optional<mojom::AppState>> storage;
-  return *storage;
+std::optional<updater::UpdateService::AppState>*
+GetLastKnownBrowserRegistrationStorage() {
+  static base::NoDestructor<std::optional<updater::UpdateService::AppState>>
+      storage;
+  return storage.get();
 }
 
-std::optional<mojom::AppState>& GetLastKnownUpdaterRegistrationStorage() {
-  static base::NoDestructor<std::optional<mojom::AppState>> storage;
-  return *storage;
+std::optional<updater::UpdateService::AppState>*
+GetLastKnownUpdaterRegistrationStorage() {
+  static base::NoDestructor<std::optional<updater::UpdateService::AppState>>
+      storage;
+  return storage.get();
 }
 
-std::optional<mojom::UpdateState>& GetLastOnDemandUpdateStateStorage() {
-  static base::NoDestructor<std::optional<mojom::UpdateState>> storage;
-  return *storage;
+std::optional<updater::UpdateService::UpdateState>*
+GetLastOnDemandUpdateStateStorage() {
+  static base::NoDestructor<std::optional<updater::UpdateService::UpdateState>>
+      storage;
+  return storage.get();
 }
 
+}  // namespace
+
 BrowserUpdaterClient::BrowserUpdaterClient(
-    scoped_refptr<UpdateService> update_service)
+    scoped_refptr<updater::UpdateService> update_service)
     : update_service_(update_service) {}
 
 BrowserUpdaterClient::~BrowserUpdaterClient() {
@@ -62,8 +69,8 @@
       base::BindOnce(&BrowserUpdaterClient::GetRegistrationRequest, this),
       base::BindOnce(
           [](base::OnceCallback<void(int)> callback,
-             scoped_refptr<UpdateService> update_service,
-             const RegistrationRequest& request) {
+             scoped_refptr<updater::UpdateService> update_service,
+             const updater::RegistrationRequest& request) {
             update_service->RegisterApp(request, std::move(callback));
           },
           base::BindPostTaskToCurrentDefault(
@@ -75,7 +82,7 @@
 void BrowserUpdaterClient::RegistrationCompleted(base::OnceClosure complete,
                                                  int result) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (result != kRegistrationSuccess) {
+  if (result != updater::kRegistrationSuccess) {
     VLOG(1) << "Updater registration error: " << result;
   }
   std::move(complete).Run();
@@ -98,19 +105,21 @@
 }
 
 void BrowserUpdaterClient::CheckForUpdate(
-    base::RepeatingCallback<void(const UpdateService::UpdateState&)>
+    base::RepeatingCallback<void(const updater::UpdateService::UpdateState&)>
         version_updater_callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  UpdateService::UpdateState update_state;
-  update_state.state = UpdateService::UpdateState::State::kCheckingForUpdates;
+  updater::UpdateService::UpdateState update_state;
+  update_state.state =
+      updater::UpdateService::UpdateState::State::kCheckingForUpdates;
   version_updater_callback.Run(update_state);
   update_service_->Update(
-      GetAppId(), {}, UpdateService::Priority::kForeground,
-      UpdateService::PolicySameVersionUpdate::kNotAllowed,
+      GetAppId(), {}, updater::UpdateService::Priority::kForeground,
+      updater::UpdateService::PolicySameVersionUpdate::kNotAllowed,
       /*language=*/{},
       base::BindPostTaskToCurrentDefault(
-          base::BindRepeating([](const UpdateService::UpdateState& state) {
+          base::BindRepeating([](const updater::UpdateService::UpdateState&
+                                     state) {
             *GetLastOnDemandUpdateStateStorage() = state;
             return state;
           }).Then(version_updater_callback)),
@@ -120,20 +129,22 @@
 }
 
 void BrowserUpdaterClient::UpdateCompleted(
-    base::RepeatingCallback<void(const UpdateService::UpdateState&)> callback,
-    UpdateService::Result result) {
+    base::RepeatingCallback<void(const updater::UpdateService::UpdateState&)>
+        callback,
+    updater::UpdateService::Result result) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   VLOG(1) << "Result of update was: " << result;
 
-  if (result == UpdateService::Result::kSuccess ||
-      result == UpdateService::Result::kUpdateCheckFailed) {
+  if (result == updater::UpdateService::Result::kSuccess ||
+      result == updater::UpdateService::Result::kUpdateCheckFailed) {
     // These statuses will have sent more descriptive information in the status
     // callback, don't overwrite it.
     return;
   }
-  UpdateService::UpdateState update_state;
-  update_state.state = UpdateService::UpdateState::State::kUpdateError;
-  update_state.error_category = UpdateService::ErrorCategory::kUpdateCheck;
+  updater::UpdateService::UpdateState update_state;
+  update_state.state = updater::UpdateService::UpdateState::State::kUpdateError;
+  update_state.error_category =
+      updater::UpdateService::ErrorCategory::kUpdateCheck;
   update_state.error_code = static_cast<int>(result);
   callback.Run(update_state);
 }
@@ -161,28 +172,30 @@
 
 void BrowserUpdaterClient::IsBrowserRegisteredCompleted(
     base::OnceCallback<void(bool)> callback,
-    const std::vector<UpdateService::AppState>& apps) {
+    const std::vector<updater::UpdateService::AppState>& apps) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  const auto updater =
-      std::ranges::find_if(apps, [](const UpdateService::AppState& state) {
-        return base::EqualsCaseInsensitiveASCII(state.app_id, kUpdaterAppId);
+  const auto updater = std::ranges::find_if(
+      apps, [](const updater::UpdateService::AppState& state) {
+        return base::EqualsCaseInsensitiveASCII(state.app_id,
+                                                updater::kUpdaterAppId);
       });
   if (updater != apps.end()) {
-    GetLastKnownUpdaterRegistrationStorage() = *updater;
+    *GetLastKnownUpdaterRegistrationStorage() = *updater;
   }
   const auto app =
       std::ranges::find_if(apps, &BrowserUpdaterClient::AppMatches);
   if (app != apps.end()) {
-    GetLastKnownBrowserRegistrationStorage() = *app;
+    *GetLastKnownBrowserRegistrationStorage() = *app;
   }
   std::move(callback).Run(app != apps.end());
 }
 
 // User and System BrowserUpdaterClients must be kept separate - the template
 // function causes there to be two static variables instead of one.
-template <UpdaterScope scope>
+template <updater::UpdaterScope scope>
 scoped_refptr<BrowserUpdaterClient> BrowserUpdaterClient::GetClient(
-    base::RepeatingCallback<scoped_refptr<UpdateService>()> proxy_provider) {
+    base::RepeatingCallback<scoped_refptr<updater::UpdateService>()>
+        proxy_provider) {
   // Multiple UpdateServiceProxies interfere with each other. Reuse a current
   // BrowserUpdaterClient if possible. BrowserUpdaterClients are refcounted, but
   // bad to keep around indefinitely since they can hold the RPC server open.
@@ -206,18 +219,32 @@
 }
 
 scoped_refptr<BrowserUpdaterClient> BrowserUpdaterClient::Create(
-    UpdaterScope scope) {
-  return Create(
-      base::BindRepeating(&CreateUpdateServiceProxy, scope, base::Seconds(15)),
-      scope);
+    updater::UpdaterScope scope) {
+  return Create(base::BindRepeating(&updater::CreateUpdateServiceProxy, scope,
+                                    base::Seconds(15)),
+                scope);
 }
 
 scoped_refptr<BrowserUpdaterClient> BrowserUpdaterClient::Create(
-    base::RepeatingCallback<scoped_refptr<UpdateService>()> proxy_provider,
-    UpdaterScope scope) {
-  return scope == UpdaterScope::kSystem
-             ? GetClient<UpdaterScope::kSystem>(proxy_provider)
-             : GetClient<UpdaterScope::kUser>(proxy_provider);
+    base::RepeatingCallback<scoped_refptr<updater::UpdateService>()>
+        proxy_provider,
+    updater::UpdaterScope scope) {
+  return scope == updater::UpdaterScope::kSystem
+             ? GetClient<updater::UpdaterScope::kSystem>(proxy_provider)
+             : GetClient<updater::UpdaterScope::kUser>(proxy_provider);
 }
 
-}  // namespace updater
+std::optional<updater::UpdateService::UpdateState>
+BrowserUpdaterClient::GetLastOnDemandUpdateState() {
+  return *GetLastOnDemandUpdateStateStorage();
+}
+
+std::optional<updater::UpdateService::AppState>
+BrowserUpdaterClient::GetLastKnownBrowserRegistration() {
+  return *GetLastKnownBrowserRegistrationStorage();
+}
+
+std::optional<updater::UpdateService::AppState>
+BrowserUpdaterClient::GetLastKnownUpdaterRegistration() {
+  return *GetLastKnownUpdaterRegistrationStorage();
+}
diff --git a/chrome/browser/updater/browser_updater_client.h b/chrome/browser/updater/browser_updater_client.h
index 3d0728f..277503c5a 100644
--- a/chrome/browser/updater/browser_updater_client.h
+++ b/chrome/browser/updater/browser_updater_client.h
@@ -14,7 +14,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
 #include "base/task/sequenced_task_runner.h"
-#include "chrome/updater/mojom/updater_service.mojom.h"
 #include "chrome/updater/registration_data.h"
 #include "chrome/updater/update_service.h"
 #include "chrome/updater/updater_scope.h"
@@ -24,8 +23,6 @@
 class FilePath;
 }
 
-namespace updater {
-
 // Cross-platform client to communicate between the browser and the Chromium
 // updater. It helps the browser register to the Chromium updater and invokes
 // on-demand updates.
@@ -33,12 +30,21 @@
     : public base::RefCountedThreadSafe<BrowserUpdaterClient> {
  public:
   // Must be called on the program's main sequence.
-  static scoped_refptr<BrowserUpdaterClient> Create(UpdaterScope scope);
   static scoped_refptr<BrowserUpdaterClient> Create(
-      base::RepeatingCallback<scoped_refptr<UpdateService>()> proxy_provider,
-      UpdaterScope scope);
+      updater::UpdaterScope scope);
+  static scoped_refptr<BrowserUpdaterClient> Create(
+      base::RepeatingCallback<scoped_refptr<updater::UpdateService>()>
+          proxy_provider,
+      updater::UpdaterScope scope);
+  static std::optional<updater::UpdateService::UpdateState>
+  GetLastOnDemandUpdateState();
+  static std::optional<updater::UpdateService::AppState>
+  GetLastKnownBrowserRegistration();
+  static std::optional<updater::UpdateService::AppState>
+  GetLastKnownUpdaterRegistration();
 
-  explicit BrowserUpdaterClient(scoped_refptr<UpdateService> update_service);
+  explicit BrowserUpdaterClient(
+      scoped_refptr<updater::UpdateService> update_service);
 
   // Registers the browser to the Chromium updater via IPC registration API.
   // When registration is completed, it will call RegistrationCompleted().
@@ -52,7 +58,7 @@
   // completes. Must be called on the sequence on which the BrowserUpdateClient
   // was created. `version_updater_callback` will be run on the same sequence.
   void CheckForUpdate(
-      base::RepeatingCallback<void(const UpdateService::UpdateState&)>
+      base::RepeatingCallback<void(const updater::UpdateService::UpdateState&)>
           version_updater_callback);
 
   // Launches the updater to run its periodic background tasks. This is a
@@ -86,33 +92,29 @@
 
  private:
   SEQUENCE_CHECKER(sequence_checker_);
-  static bool AppMatches(const UpdateService::AppState& app);
-  RegistrationRequest GetRegistrationRequest();
+  static bool AppMatches(const updater::UpdateService::AppState& app);
+  updater::RegistrationRequest GetRegistrationRequest();
 
   void RegistrationCompleted(base::OnceClosure complete, int result);
   void GetUpdaterVersionCompleted(
       base::OnceCallback<void(const base::Version&)> callback,
       const base::Version& version);
   void UpdateCompleted(
-      base::RepeatingCallback<void(const UpdateService::UpdateState&)> callback,
-      UpdateService::Result result);
+      base::RepeatingCallback<void(const updater::UpdateService::UpdateState&)>
+          callback,
+      updater::UpdateService::Result result);
   void RunPeriodicTasksCompleted(base::OnceClosure callback);
   void IsBrowserRegisteredCompleted(
       base::OnceCallback<void(bool)> callback,
-      const std::vector<UpdateService::AppState>& apps);
+      const std::vector<updater::UpdateService::AppState>& apps);
 
-  template <UpdaterScope scope>
+  template <updater::UpdaterScope scope>
   static scoped_refptr<BrowserUpdaterClient> GetClient(
-      base::RepeatingCallback<scoped_refptr<UpdateService>()> proxy_provider);
+      base::RepeatingCallback<scoped_refptr<updater::UpdateService>()>
+          proxy_provider);
 
-  scoped_refptr<UpdateService> update_service_;
+  scoped_refptr<updater::UpdateService> update_service_;
   base::WeakPtrFactory<BrowserUpdaterClient> weak_ptr_factory_{this};
 };
 
-std::optional<mojom::AppState>& GetLastKnownBrowserRegistrationStorage();
-std::optional<mojom::AppState>& GetLastKnownUpdaterRegistrationStorage();
-std::optional<mojom::UpdateState>& GetLastOnDemandUpdateStateStorage();
-
-}  // namespace updater
-
 #endif  // CHROME_BROWSER_UPDATER_BROWSER_UPDATER_CLIENT_H_
diff --git a/chrome/browser/updater/browser_updater_client_mac.mm b/chrome/browser/updater/browser_updater_client_mac.mm
index 382ec03..f72df576 100644
--- a/chrome/browser/updater/browser_updater_client_mac.mm
+++ b/chrome/browser/updater/browser_updater_client_mac.mm
@@ -16,8 +16,6 @@
 #include "chrome/updater/registration_data.h"
 #include "components/version_info/version_info.h"
 
-namespace updater {
-
 std::string BrowserUpdaterClient::GetAppId() {
   return std::string(base::apple::BaseBundleID());
 }
@@ -26,9 +24,9 @@
   return base::apple::OuterBundlePath();
 }
 
-RegistrationRequest BrowserUpdaterClient::GetRegistrationRequest() {
+updater::RegistrationRequest BrowserUpdaterClient::GetRegistrationRequest() {
   base::FilePath bundle = base::apple::OuterBundlePath();
-  RegistrationRequest req;
+  updater::RegistrationRequest req;
   req.app_id = GetAppId();
   google_brand::GetBrand(&req.brand_code);
   req.version = version_info::GetVersionNumber();
@@ -39,9 +37,8 @@
   return req;
 }
 
-bool BrowserUpdaterClient::AppMatches(const UpdateService::AppState& app) {
+bool BrowserUpdaterClient::AppMatches(
+    const updater::UpdateService::AppState& app) {
   return base::EqualsCaseInsensitiveASCII(app.app_id, GetAppId()) &&
          app.ecp == GetExpectedEcp();
 }
-
-}  // namespace updater
diff --git a/chrome/browser/updater/browser_updater_client_testutils.cc b/chrome/browser/updater/browser_updater_client_testutils.cc
index 95b1630f..137147b 100644
--- a/chrome/browser/updater/browser_updater_client_testutils.cc
+++ b/chrome/browser/updater/browser_updater_client_testutils.cc
@@ -10,11 +10,8 @@
 
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
-#include "base/functional/callback_helpers.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/run_loop.h"
 #include "base/version.h"
-#include "chrome/browser/updater/browser_updater_client.h"
 #include "chrome/updater/update_service.h"
 
 namespace policy {
@@ -121,29 +118,4 @@
       result, states);
 }
 
-base::ScopedClosureRunner OverrideService(
-    UpdateService::Result result,
-    const std::vector<UpdateService::AppState>& states) {
-  return base::ScopedClosureRunner(base::BindOnce(
-      [](scoped_refptr<BrowserUpdaterClient>) {},
-      BrowserUpdaterClient::Create(MakeFakeService(result, states),
-                                   UpdaterScope::kUser)));
-}
-
-void LoadAppStates() {
-  base::RunLoop loop;
-  BrowserUpdaterClient::Create(updater::UpdaterScope::kUser)
-      ->IsBrowserRegistered(
-          base::BindOnce([](bool) {}).Then(loop.QuitClosure()));
-  loop.Run();
-}
-
-std::string GetAppId() {
-  return BrowserUpdaterClient::GetAppId();
-}
-
-base::FilePath GetExpectedEcp() {
-  return BrowserUpdaterClient::GetExpectedEcp();
-}
-
 }  // namespace updater
diff --git a/chrome/browser/updater/browser_updater_client_testutils.h b/chrome/browser/updater/browser_updater_client_testutils.h
index cfd915f8..25d5113 100644
--- a/chrome/browser/updater/browser_updater_client_testutils.h
+++ b/chrome/browser/updater/browser_updater_client_testutils.h
@@ -5,32 +5,18 @@
 #ifndef CHROME_BROWSER_UPDATER_BROWSER_UPDATER_CLIENT_TESTUTILS_H_
 #define CHROME_BROWSER_UPDATER_BROWSER_UPDATER_CLIENT_TESTUTILS_H_
 
-#include <string>
 #include <vector>
 
 #include "base/functional/callback_forward.h"
 #include "base/memory/scoped_refptr.h"
 #include "chrome/updater/update_service.h"
 
-namespace base {
-class ScopedClosureRunner;
-}
-
 namespace updater {
 
-base::ScopedClosureRunner OverrideService(
-    UpdateService::Result result,
-    const std::vector<UpdateService::AppState>& states);
-
 base::RepeatingCallback<scoped_refptr<UpdateService>()> MakeFakeService(
     UpdateService::Result result,
     const std::vector<UpdateService::AppState>& states);
 
-void LoadAppStates();
-
-std::string GetAppId();
-base::FilePath GetExpectedEcp();
-
 }  // namespace updater
 
 #endif  // CHROME_BROWSER_UPDATER_BROWSER_UPDATER_CLIENT_TESTUTILS_H_
diff --git a/chrome/browser/updater/browser_updater_client_unittest.cc b/chrome/browser/updater/browser_updater_client_unittest.cc
index 2d595a5..f8b52992 100644
--- a/chrome/browser/updater/browser_updater_client_unittest.cc
+++ b/chrome/browser/updater/browser_updater_client_unittest.cc
@@ -16,27 +16,24 @@
 #include "base/test/task_environment.h"
 #include "base/version.h"
 #include "chrome/browser/updater/browser_updater_client_testutils.h"
-#include "chrome/browser/updater/updater.h"
 #include "chrome/updater/branded_constants.h"
 #include "chrome/updater/update_service.h"
 #include "chrome/updater/updater_scope.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace updater {
-
 TEST(BrowserUpdaterClientTest, Reuse) {
   scoped_refptr<BrowserUpdaterClient> user1 = BrowserUpdaterClient::Create(
-      MakeFakeService(UpdateService::Result::kSuccess, {}),
-      UpdaterScope::kUser);
+      updater::MakeFakeService(updater::UpdateService::Result::kSuccess, {}),
+      updater::UpdaterScope::kUser);
   scoped_refptr<BrowserUpdaterClient> user2 = BrowserUpdaterClient::Create(
-      MakeFakeService(UpdateService::Result::kSuccess, {}),
-      UpdaterScope::kUser);
+      updater::MakeFakeService(updater::UpdateService::Result::kSuccess, {}),
+      updater::UpdaterScope::kUser);
   scoped_refptr<BrowserUpdaterClient> system1 = BrowserUpdaterClient::Create(
-      MakeFakeService(UpdateService::Result::kSuccess, {}),
-      UpdaterScope::kSystem);
+      updater::MakeFakeService(updater::UpdateService::Result::kSuccess, {}),
+      updater::UpdaterScope::kSystem);
   scoped_refptr<BrowserUpdaterClient> system2 = BrowserUpdaterClient::Create(
-      MakeFakeService(UpdateService::Result::kSuccess, {}),
-      UpdaterScope::kSystem);
+      updater::MakeFakeService(updater::UpdateService::Result::kSuccess, {}),
+      updater::UpdaterScope::kSystem);
   EXPECT_EQ(user1, user2);
   EXPECT_EQ(system1, system2);
   EXPECT_NE(system1, user1);
@@ -52,10 +49,10 @@
     int num_called = 0;
     base::RunLoop loop;
     BrowserUpdaterClient::Create(
-        MakeFakeService(UpdateService::Result::kSuccess, {}),
-        UpdaterScope::kUser)
+        updater::MakeFakeService(updater::UpdateService::Result::kSuccess, {}),
+        updater::UpdaterScope::kUser)
         ->CheckForUpdate(base::BindLambdaForTesting(
-            [&](const UpdateService::UpdateState& status) {
+            [&](const updater::UpdateService::UpdateState& status) {
               num_called++;
               loop.QuitWhenIdle();
             }));
@@ -67,10 +64,11 @@
     int num_called = 0;
     base::RunLoop loop;
     BrowserUpdaterClient::Create(
-        MakeFakeService(UpdateService::Result::kUpdateCheckFailed, {}),
-        UpdaterScope::kUser)
+        updater::MakeFakeService(
+            updater::UpdateService::Result::kUpdateCheckFailed, {}),
+        updater::UpdaterScope::kUser)
         ->CheckForUpdate(base::BindLambdaForTesting(
-            [&](const UpdateService::UpdateState& status) {
+            [&](const updater::UpdateService::UpdateState& status) {
               num_called++;
               loop.QuitWhenIdle();
             }));
@@ -82,10 +80,11 @@
     int num_called = 0;
     base::RunLoop loop;
     BrowserUpdaterClient::Create(
-        MakeFakeService(UpdateService::Result::kIPCConnectionFailed, {}),
-        UpdaterScope::kUser)
+        updater::MakeFakeService(
+            updater::UpdateService::Result::kIPCConnectionFailed, {}),
+        updater::UpdaterScope::kUser)
         ->CheckForUpdate(base::BindLambdaForTesting(
-            [&](const UpdateService::UpdateState& status) {
+            [&](const updater::UpdateService::UpdateState& status) {
               num_called++;
               loop.QuitWhenIdle();
             }));
@@ -99,36 +98,36 @@
   {
     base::RunLoop loop;
     BrowserUpdaterClient::Create(
-        MakeFakeService(UpdateService::Result::kSuccess, {}),
-        UpdaterScope::kUser)
+        updater::MakeFakeService(updater::UpdateService::Result::kSuccess, {}),
+        updater::UpdaterScope::kUser)
         ->CheckForUpdate(base::BindLambdaForTesting(
-            [&](const UpdateService::UpdateState& status) {
+            [&](const updater::UpdateService::UpdateState& status) {
               loop.QuitWhenIdle();
             }));
     loop.Run();
   }
-  EXPECT_TRUE(GetLastOnDemandUpdateState());
-  EXPECT_EQ(GetLastOnDemandUpdateState()->state,
-            UpdateService::UpdateState::State::kNoUpdate);
+  EXPECT_TRUE(BrowserUpdaterClient::GetLastOnDemandUpdateState());
+  EXPECT_EQ(BrowserUpdaterClient::GetLastOnDemandUpdateState()->state,
+            updater::UpdateService::UpdateState::State::kNoUpdate);
 }
 
 TEST(BrowserUpdaterClientTest, StoreRetrieveLastAppState) {
   base::test::SingleThreadTaskEnvironment task_environment;
-  UpdateService::AppState app1;
-  app1.app_id = kUpdaterAppId;
-  UpdateService::AppState app2;
+  updater::UpdateService::AppState app1;
+  app1.app_id = updater::kUpdaterAppId;
+  updater::UpdateService::AppState app2;
   app2.app_id = BrowserUpdaterClient::GetAppId();
   app2.ecp = BrowserUpdaterClient::GetExpectedEcp();
   {
     base::RunLoop loop;
     bool is_registered = false;
     BrowserUpdaterClient::Create(
-        MakeFakeService(UpdateService::Result::kSuccess,
-                        {
-                            app1,
-                            app2,
-                        }),
-        UpdaterScope::kUser)
+        updater::MakeFakeService(updater::UpdateService::Result::kSuccess,
+                                 {
+                                     app1,
+                                     app2,
+                                 }),
+        updater::UpdaterScope::kUser)
         ->IsBrowserRegistered(base::BindLambdaForTesting([&](bool registered) {
           is_registered = registered;
           loop.QuitWhenIdle();
@@ -136,8 +135,6 @@
     loop.Run();
     EXPECT_TRUE(is_registered);
   }
-  EXPECT_TRUE(GetLastKnownBrowserRegistration());
-  EXPECT_TRUE(GetLastKnownUpdaterRegistration());
+  EXPECT_TRUE(BrowserUpdaterClient::GetLastKnownBrowserRegistration());
+  EXPECT_TRUE(BrowserUpdaterClient::GetLastKnownUpdaterRegistration());
 }
-
-}  // namespace updater
diff --git a/chrome/browser/updater/browser_updater_client_util.cc b/chrome/browser/updater/browser_updater_client_util.cc
index dd0342bc..f82f96e 100644
--- a/chrome/browser/updater/browser_updater_client_util.cc
+++ b/chrome/browser/updater/browser_updater_client_util.cc
@@ -6,9 +6,5 @@
 
 #include "chrome/updater/updater_branding.h"
 
-namespace updater {
-
 const char kUpdaterName[] = PRODUCT_FULLNAME_STRING;
 const char kPrivilegedHelperName[] = PRIVILEGED_HELPER_NAME;
-
-}  // namespace updater
diff --git a/chrome/browser/updater/browser_updater_client_util.h b/chrome/browser/updater/browser_updater_client_util.h
index ece042a01..3df36ea 100644
--- a/chrome/browser/updater/browser_updater_client_util.h
+++ b/chrome/browser/updater/browser_updater_client_util.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_UPDATER_BROWSER_UPDATER_CLIENT_UTIL_H_
 #define CHROME_BROWSER_UPDATER_BROWSER_UPDATER_CLIENT_UTIL_H_
 
+#include <string>
+
 #include "base/functional/callback_forward.h"
 #include "chrome/updater/updater_scope.h"
 
@@ -12,17 +14,28 @@
 enum class TaskPriority : uint8_t;
 }
 
-namespace updater {
-
 extern const char kUpdaterName[];
 extern const char kPrivilegedHelperName[];
 
+// Get the current installed version of the browser.
+std::string CurrentlyInstalledVersion();
+
 // System level updater should only be used if the browser is owned by root.
 // During promotion, the browser will be changed to be owned by root and wheel.
 // A browser must go through promotion before it can utilize the system-level
 // updater.
-UpdaterScope GetBrowserUpdaterScope();
+updater::UpdaterScope GetBrowserUpdaterScope();
 
-}  // namespace updater
+// If this build should integrate with an updater, makes sure that an updater
+// is installed and that the browser is registered with it for updates. Must be
+// called on a sequenced task runner. In cases where user intervention is
+// necessary, calls `prompt` (on the same sequence).  After the updater is made
+// present (or cannot be made present), calls `complete` on the same sequence.
+void EnsureUpdater(base::TaskPriority priority,
+                   base::OnceClosure prompt,
+                   base::OnceClosure complete);
+
+// Prompts the user for credentials and sets up a system-level updater.
+void SetupSystemUpdater();
 
 #endif  // CHROME_BROWSER_UPDATER_BROWSER_UPDATER_CLIENT_UTIL_H_
diff --git a/chrome/browser/updater/browser_updater_client_util_mac.mm b/chrome/browser/updater/browser_updater_client_util_mac.mm
index 9ea73d9..30441fb 100644
--- a/chrome/browser/updater/browser_updater_client_util_mac.mm
+++ b/chrome/browser/updater/browser_updater_client_util_mac.mm
@@ -38,7 +38,6 @@
 #include "chrome/browser/updater/browser_updater_client.h"
 #include "chrome/browser/updater/browser_updater_client_util.h"
 #include "chrome/browser/updater/browser_updater_helper_client_mac.h"
-#include "chrome/browser/updater/updater.h"
 #include "chrome/grit/branded_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/updater/constants.h"
@@ -47,8 +46,6 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 
-namespace updater {
-
 namespace {
 
 constexpr char kInstallCommand[] = "install";
@@ -143,8 +140,9 @@
 int RunCommand(const base::FilePath& exe_path, const char* cmd_switch) {
   base::CommandLine command(exe_path);
   command.AppendSwitch(cmd_switch);
-  command.AppendSwitch(kEnableLoggingSwitch);
-  command.AppendSwitchASCII(kLoggingModuleSwitch, kLoggingModuleSwitchValue);
+  command.AppendSwitch(updater::kEnableLoggingSwitch);
+  command.AppendSwitchASCII(updater::kLoggingModuleSwitch,
+                            updater::kLoggingModuleSwitchValue);
 
   int exit_code = -1;
   auto process = base::LaunchProcess(command, {});
@@ -158,7 +156,7 @@
 
 // Only works in kUser scope.
 void RegisterBrowser(base::OnceClosure complete) {
-  BrowserUpdaterClient::Create(UpdaterScope::kUser)
+  BrowserUpdaterClient::Create(updater::UpdaterScope::kUser)
       ->Register(std::move(complete));
 }
 
@@ -223,21 +221,22 @@
 
 }  // namespace
 
-base::Version CurrentlyInstalledVersion() {
+std::string CurrentlyInstalledVersion() {
   base::ScopedBlockingCall blocks(FROM_HERE, base::BlockingType::WILL_BLOCK);
   base::FilePath outer_bundle = base::apple::OuterBundlePath();
   base::FilePath plist_path =
       outer_bundle.Append("Contents").Append("Info.plist");
   NSDictionary* info_plist = [NSDictionary
       dictionaryWithContentsOfFile:base::apple::FilePathToNSString(plist_path)];
-  return base::Version(base::SysNSStringToUTF8(base::apple::ObjCCast<NSString>(
-      info_plist[@"CFBundleShortVersionString"])));
+  return base::SysNSStringToUTF8(base::apple::ObjCCast<NSString>(
+      info_plist[@"CFBundleShortVersionString"]));
 }
 
-UpdaterScope GetBrowserUpdaterScope() {
+updater::UpdaterScope GetBrowserUpdaterScope() {
   std::optional<uid_t> owner = GetBundleOwner();
-  return owner && (*owner == 0 || *owner != geteuid()) ? UpdaterScope::kSystem
-                                                       : UpdaterScope::kUser;
+  return owner && (*owner == 0 || *owner != geteuid())
+             ? updater::UpdaterScope::kSystem
+             : updater::UpdaterScope::kUser;
 }
 
 void EnsureUpdater(base::TaskPriority priority,
@@ -254,7 +253,7 @@
       base::BindOnce(&GetBrowserUpdaterScope),
       base::BindOnce(
           [](base::TaskPriority priority, base::OnceClosure prompt,
-             base::OnceClosure complete, UpdaterScope scope) {
+             base::OnceClosure complete, updater::UpdaterScope scope) {
             scoped_refptr<BrowserUpdaterClient> client =
                 BrowserUpdaterClient::Create(scope);
             client->IsBrowserRegistered(base::BindOnce(
@@ -301,7 +300,7 @@
           priority, std::move(prompt), std::move(complete)));
 }
 
-void SetUpSystemUpdater() {
+void SetupSystemUpdater() {
   NSString* prompt = l10n_util::GetNSStringFWithFixup(
       IDS_PROMOTE_AUTHENTICATION_PROMPT,
       l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
@@ -334,5 +333,3 @@
             << result;
       }));
 }
-
-}  // namespace updater
diff --git a/chrome/browser/updater/browser_updater_client_util_no_updater.cc b/chrome/browser/updater/browser_updater_client_util_no_updater.cc
new file mode 100644
index 0000000..d66730c8
--- /dev/null
+++ b/chrome/browser/updater/browser_updater_client_util_no_updater.cc
@@ -0,0 +1,27 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/functional/callback.h"
+#include "base/task/task_traits.h"
+#include "chrome/browser/updater/browser_updater_client_util.h"
+#include "chrome/updater/updater_scope.h"
+#include "components/version_info/version_info.h"
+
+std::string CurrentlyInstalledVersion() {
+  return std::string(version_info::GetVersionNumber());
+}
+
+updater::UpdaterScope GetBrowserUpdaterScope() {
+  return updater::UpdaterScope::kUser;
+}
+
+void EnsureUpdater(base::TaskPriority /*priority*/,
+                   base::OnceClosure /*prompt*/,
+                   base::OnceClosure complete) {
+  std::move(complete).Run();
+}
+
+void SetupSystemUpdater() {}
diff --git a/chrome/browser/updater/browser_updater_client_util_win.cc b/chrome/browser/updater/browser_updater_client_util_win.cc
index 2635cd5..eff069c 100644
--- a/chrome/browser/updater/browser_updater_client_util_win.cc
+++ b/chrome/browser/updater/browser_updater_client_util_win.cc
@@ -7,11 +7,7 @@
 #include "chrome/installer/util/install_util.h"
 #include "chrome/updater/updater_scope.h"
 
-namespace updater {
-
-UpdaterScope GetBrowserUpdaterScope() {
-  return InstallUtil::IsPerUserInstall() ? UpdaterScope::kUser
-                                         : UpdaterScope::kSystem;
+updater::UpdaterScope GetBrowserUpdaterScope() {
+  return InstallUtil::IsPerUserInstall() ? updater::UpdaterScope::kUser
+                                         : updater::UpdaterScope::kSystem;
 }
-
-}  // namespace updater
diff --git a/chrome/browser/updater/browser_updater_client_win.cc b/chrome/browser/updater/browser_updater_client_win.cc
index 4a73c0e..739540f 100644
--- a/chrome/browser/updater/browser_updater_client_win.cc
+++ b/chrome/browser/updater/browser_updater_client_win.cc
@@ -15,8 +15,6 @@
 #include "chrome/updater/registration_data.h"
 #include "components/version_info/version_info.h"
 
-namespace updater {
-
 std::string BrowserUpdaterClient::GetAppId() {
   return base::SysWideToUTF8(
       std::wstring(install_static::InstallDetails::Get().app_guid()));
@@ -26,8 +24,8 @@
   return {};
 }
 
-RegistrationRequest BrowserUpdaterClient::GetRegistrationRequest() {
-  RegistrationRequest req;
+updater::RegistrationRequest BrowserUpdaterClient::GetRegistrationRequest() {
+  updater::RegistrationRequest req;
   req.app_id = GetAppId();
   google_brand::GetBrand(&req.brand_code);
   req.version = version_info::GetVersionNumber();
@@ -36,8 +34,7 @@
   return req;
 }
 
-bool BrowserUpdaterClient::AppMatches(const UpdateService::AppState& app) {
+bool BrowserUpdaterClient::AppMatches(
+    const updater::UpdateService::AppState& app) {
   return base::EqualsCaseInsensitiveASCII(app.app_id, GetAppId());
 }
-
-}  // namespace updater
diff --git a/chrome/browser/updater/browser_updater_helper_client_mac.h b/chrome/browser/updater/browser_updater_helper_client_mac.h
index 2db8762..d2585f1 100644
--- a/chrome/browser/updater/browser_updater_helper_client_mac.h
+++ b/chrome/browser/updater/browser_updater_helper_client_mac.h
@@ -14,8 +14,6 @@
 #include "base/task/sequenced_task_runner.h"
 #include "chrome/updater/mac/privileged_helper/service_protocol.h"
 
-namespace updater {
-
 // Client that will create a connection between the browser and the privileged
 // helper for the Chromium updater. Helps with setting up the system-level
 // updater during promotion.
@@ -42,6 +40,4 @@
                               int result);
 };
 
-}  // namespace updater
-
 #endif  // CHROME_BROWSER_UPDATER_BROWSER_UPDATER_HELPER_CLIENT_MAC_H_
diff --git a/chrome/browser/updater/browser_updater_helper_client_mac.mm b/chrome/browser/updater/browser_updater_helper_client_mac.mm
index fa4b101..4b4c18a 100644
--- a/chrome/browser/updater/browser_updater_helper_client_mac.mm
+++ b/chrome/browser/updater/browser_updater_helper_client_mac.mm
@@ -19,8 +19,6 @@
 #include "chrome/browser/updater/browser_updater_client_util.h"
 #include "chrome/updater/mac/privileged_helper/service_protocol.h"
 
-namespace updater {
-
 namespace {
 const int kPrivilegedHelperConnectionFailed = -10000;
 }
@@ -81,5 +79,3 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   std::move(callback).Run(result);
 }
-
-}  // namespace updater
diff --git a/chrome/browser/updater/scheduler.cc b/chrome/browser/updater/scheduler.cc
index dbabc0f..62c2f78 100644
--- a/chrome/browser/updater/scheduler.cc
+++ b/chrome/browser/updater/scheduler.cc
@@ -5,32 +5,27 @@
 #include "chrome/browser/updater/scheduler.h"
 
 #include "base/functional/bind.h"
-#include "base/functional/callback.h"
 #include "base/task/sequenced_task_runner.h"
+#include "base/task/task_traits.h"
 #include "base/time/time.h"
 
 namespace updater {
 
 namespace {
 
-void RunAndReschedule(base::RepeatingClosure prompt) {
-  DoPeriodicTasks(
-      prompt,
-      base::BindOnce(
-          [](base::RepeatingClosure prompt) {
-            base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
-                FROM_HERE, base::BindOnce(&RunAndReschedule, prompt),
-                base::Hours(5));
-          },
-          prompt));
+void RunAndReschedule() {
+  DoPeriodicTasks(base::BindOnce([]() {
+    base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
+        FROM_HERE, base::BindOnce(&RunAndReschedule), base::Hours(5));
+  }));
 }
 
 }  // namespace
 
-void SchedulePeriodicTasks(base::RepeatingClosure prompt) {
+void SchedulePeriodicTasks() {
   // Delay a little bit to get out of the way of browser startup.
   base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
-      FROM_HERE, base::BindOnce(&RunAndReschedule, prompt), base::Seconds(19));
+      FROM_HERE, base::BindOnce(&RunAndReschedule), base::Seconds(19));
 }
 
 }  // namespace updater
diff --git a/chrome/browser/updater/scheduler.h b/chrome/browser/updater/scheduler.h
index 6ae5933b..2b2908b9 100644
--- a/chrome/browser/updater/scheduler.h
+++ b/chrome/browser/updater/scheduler.h
@@ -9,9 +9,13 @@
 
 namespace updater {
 
-// Do the periodic tasks right away, invoking `callback` when done. If user
-// intervention is needed, calls `prompt`.
-void DoPeriodicTasks(base::RepeatingClosure prompt, base::OnceClosure callback);
+// Schedule updater periodic tasks to run five minutes later and every five
+// hours thereafter. This is a backup scheduler so that even if the updater's
+// scheduler is broken or disabled, it will run tasks while Chrome is running.
+void SchedulePeriodicTasks();
+
+// Do the periodic tasks right away, invoking `callback` when done.
+void DoPeriodicTasks(base::OnceClosure callback);
 
 // Wake up all existing updater instances. May block.
 void WakeAllUpdaters();
diff --git a/chrome/browser/updater/scheduler_mac.cc b/chrome/browser/updater/scheduler_mac.cc
index 72d3140..1ee1c376 100644
--- a/chrome/browser/updater/scheduler_mac.cc
+++ b/chrome/browser/updater/scheduler_mac.cc
@@ -8,16 +8,16 @@
 #include "base/functional/callback.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
+#include "chrome/browser/ui/cocoa/keystone_infobar_delegate.h"
 #include "chrome/browser/updater/browser_updater_client.h"
 #include "chrome/browser/updater/browser_updater_client_util.h"
-#include "chrome/browser/updater/updater.h"
 
 namespace updater {
 
-void DoPeriodicTasks(base::RepeatingClosure prompt,
-                     base::OnceClosure callback) {
+void DoPeriodicTasks(base::OnceClosure callback) {
   EnsureUpdater(
-      base::TaskPriority::BEST_EFFORT, prompt,
+      base::TaskPriority::BEST_EFFORT,
+      base::BindOnce(&ShowUpdaterPromotionInfoBar),
       base::BindOnce(
           [](base::OnceClosure callback) {
             // Run updater periodic tasks in case the launchd scheduled task is
diff --git a/chrome/browser/updater/scheduler_noimpl.cc b/chrome/browser/updater/scheduler_noimpl.cc
new file mode 100644
index 0000000..8219c66
--- /dev/null
+++ b/chrome/browser/updater/scheduler_noimpl.cc
@@ -0,0 +1,20 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <utility>
+
+#include "base/functional/callback.h"
+#include "chrome/browser/updater/scheduler.h"
+
+namespace updater {
+
+void DoPeriodicTasks(base::OnceClosure callback) {
+  std::move(callback).Run();
+}
+
+void WakeAllUpdaters(base::OnceClosure callback) {
+  std::move(callback).Run();
+}
+
+}  // namespace updater
diff --git a/chrome/browser/updater/scheduler_win.cc b/chrome/browser/updater/scheduler_win.cc
index fbb3a7a..b3fee00 100644
--- a/chrome/browser/updater/scheduler_win.cc
+++ b/chrome/browser/updater/scheduler_win.cc
@@ -16,8 +16,7 @@
 
 namespace updater {
 
-void DoPeriodicTasks(base::RepeatingClosure /*prompt*/,
-                     base::OnceClosure callback) {
+void DoPeriodicTasks(base::OnceClosure callback) {
   base::MakeRefCounted<CheckUpdaterHealthTask>(GetBrowserUpdaterScope())
       ->Run(base::BindOnce(
           [](base::OnceClosure callback) {
diff --git a/chrome/browser/updater/updater.cc b/chrome/browser/updater/updater.cc
deleted file mode 100644
index 89f6dd8..0000000
--- a/chrome/browser/updater/updater.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// 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/updater/updater.h"
-
-#include <optional>
-
-#include "base/functional/bind.h"
-#include "base/functional/callback.h"
-#include "base/task/task_traits.h"
-#include "base/task/thread_pool.h"
-#include "chrome/browser/updater/browser_updater_client.h"
-#include "chrome/browser/updater/browser_updater_client_util.h"
-#include "chrome/updater/mojom/updater_service.mojom.h"
-#include "chrome/updater/updater_scope.h"
-
-namespace updater {
-
-std::optional<mojom::UpdateState> GetLastOnDemandUpdateState() {
-  return GetLastOnDemandUpdateStateStorage();
-}
-
-std::optional<mojom::AppState> GetLastKnownBrowserRegistration() {
-  return GetLastKnownBrowserRegistrationStorage();
-}
-
-std::optional<mojom::AppState> GetLastKnownUpdaterRegistration() {
-  return GetLastKnownUpdaterRegistrationStorage();
-}
-
-void CheckForUpdate(
-    base::RepeatingCallback<void(const UpdateService::UpdateState&)> callback) {
-  base::ThreadPool::PostTaskAndReplyWithResult(
-      FROM_HERE, {base::MayBlock()}, base::BindOnce(&GetBrowserUpdaterScope),
-      base::BindOnce(
-          [](base::RepeatingCallback<void(
-                 const updater::UpdateService::UpdateState&)> callback,
-             updater::UpdaterScope scope) {
-            BrowserUpdaterClient::Create(scope)->CheckForUpdate(callback);
-          },
-          callback));
-}
-
-}  // namespace updater
diff --git a/chrome/browser/updater/updater.h b/chrome/browser/updater/updater.h
deleted file mode 100644
index 9d840dd..0000000
--- a/chrome/browser/updater/updater.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// 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_UPDATER_UPDATER_H_
-#define CHROME_BROWSER_UPDATER_UPDATER_H_
-
-#include <cstdint>
-#include <optional>
-
-#include "base/functional/callback_forward.h"
-#include "chrome/updater/mojom/updater_service.mojom.h"
-
-namespace base {
-enum class TaskPriority : uint8_t;
-class Version;
-}  // namespace base
-
-// This module contains a number of functions to interact with the browser's
-// updater (ChromiumUpdater) on Windows / macOS / Linux.
-namespace updater {
-
-// Triggers an on-demand update, reporting status updates to the callback. Must
-// be called on a sequenced task runner. `callback` will be
-// run on the same sequence with status updates.
-void CheckForUpdate(
-    base::RepeatingCallback<void(const mojom::UpdateState&)> callback);
-
-// Get the current installed version of the browser, according to the updater.
-// May block.
-base::Version CurrentlyInstalledVersion();
-
-// If this build should integrate with an updater, makes sure that an updater
-// is installed and that the browser is registered with it for updates. Must be
-// called on a sequenced task runner. In cases where user intervention is
-// necessary, calls `prompt` (on the same sequence). After the updater is made
-// present (or cannot be made present), calls `complete` on the same sequence.
-void EnsureUpdater(base::TaskPriority priority,
-                   base::OnceClosure prompt,
-                   base::OnceClosure complete);
-
-// Sets up a system-level updater, if possible. May prompt the user to enter
-// credentials.
-void SetUpSystemUpdater();
-
-// Schedule updater periodic tasks to run five minutes later and every five
-// hours thereafter. This is a backup scheduler so that even if the updater's
-// scheduler is broken or disabled, it will run tasks while Chrome is running.
-// Must be called on a sequenced task runner. If user intervention is needed,
-// calls `prompt` on the same sequence.
-void SchedulePeriodicTasks(base::RepeatingClosure prompt);
-
-std::optional<mojom::UpdateState> GetLastOnDemandUpdateState();
-
-std::optional<mojom::AppState> GetLastKnownBrowserRegistration();
-
-std::optional<mojom::AppState> GetLastKnownUpdaterRegistration();
-
-}  // namespace updater
-
-#endif  // CHROME_BROWSER_UPDATER_UPDATER_H_
diff --git a/chrome/browser/updater/updater_no_updater.cc b/chrome/browser/updater/updater_no_updater.cc
deleted file mode 100644
index 7f0f67b..0000000
--- a/chrome/browser/updater/updater_no_updater.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// 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/updater/updater.h"
-
-#include <optional>
-
-#include "base/functional/bind.h"
-#include "base/functional/callback.h"
-#include "base/task/sequenced_task_runner.h"
-#include "base/task/task_traits.h"
-#include "base/version.h"
-#include "base/version_info/version_info.h"
-#include "chrome/updater/mojom/updater_service.mojom.h"
-
-namespace updater {
-
-base::Version CurrentlyInstalledVersion() {
-  return version_info::GetVersion();
-}
-
-void EnsureUpdater(base::TaskPriority /*priority*/,
-                   base::OnceClosure /*prompt*/,
-                   base::OnceClosure complete) {
-  base::SequencedTaskRunner::GetCurrentDefault()->PostTask(FROM_HERE,
-                                                           std::move(complete));
-}
-
-void SetUpSystemUpdater() {}
-
-void CheckForUpdate(base::RepeatingCallback<void(const mojom::UpdateState&)>
-                        version_updater_callback) {
-  mojom::UpdateState state;
-  state.state = mojom::UpdateState::State::kUpdateError;
-  base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
-      FROM_HERE, base::BindOnce(version_updater_callback, state));
-}
-
-void SchedulePeriodicTasks(base::RepeatingClosure prompt) {}
-
-std::optional<mojom::UpdateState> GetLastOnDemandUpdateState() {
-  return std::nullopt;
-}
-
-std::optional<mojom::AppState> GetLastKnownBrowserRegistration() {
-  return std::nullopt;
-}
-
-std::optional<mojom::AppState> GetLastKnownUpdaterRegistration() {
-  return std::nullopt;
-}
-
-}  // namespace updater
diff --git a/chrome/browser/upgrade_detector/BUILD.gn b/chrome/browser/upgrade_detector/BUILD.gn
index 4721599..6c8ae44 100644
--- a/chrome/browser/upgrade_detector/BUILD.gn
+++ b/chrome/browser/upgrade_detector/BUILD.gn
@@ -123,7 +123,7 @@
       "directory_monitor.cc",
       "get_installed_version_mac.mm",
     ]
-    deps += [ "//chrome/browser/updater" ]
+    deps += [ "//chrome/browser/updater:browser_updater_client" ]
   }
 
   if (is_linux) {
diff --git a/chrome/browser/upgrade_detector/get_installed_version_mac.mm b/chrome/browser/upgrade_detector/get_installed_version_mac.mm
index d8a3d40..436fef4 100644
--- a/chrome/browser/upgrade_detector/get_installed_version_mac.mm
+++ b/chrome/browser/upgrade_detector/get_installed_version_mac.mm
@@ -11,7 +11,7 @@
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
 #include "base/version.h"
-#include "chrome/browser/updater/updater.h"
+#include "chrome/browser/updater/browser_updater_client_util.h"
 
 void GetInstalledVersion(InstalledVersionCallback callback) {
   base::ThreadPool::PostTaskAndReplyWithResult(
@@ -20,7 +20,7 @@
        base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
       base::BindOnce([] {
         return InstalledAndCriticalVersion(
-            updater::CurrentlyInstalledVersion());
+            base::Version(CurrentlyInstalledVersion()));
       }),
       std::move(callback));
 }
diff --git a/chrome/build/android-arm32.pgo.txt b/chrome/build/android-arm32.pgo.txt
index 43ad273..fd5d6ee 100644
--- a/chrome/build/android-arm32.pgo.txt
+++ b/chrome/build/android-arm32.pgo.txt
@@ -1 +1 @@
-chrome-android32-main-1765238282-110c02e1f97977b0658d03a3d32e9fe009113158-b06d56b7c8d9e3f52f40f10cb851270c90723b2f.profdata
+chrome-android32-main-1765324710-d823021bbb98493e92334aacd2a29335f23d0b81-5c1ba8531bd7f21f5f123e60e3d5677bda27895e.profdata
diff --git a/chrome/build/android-desktop-x64.pgo.txt b/chrome/build/android-desktop-x64.pgo.txt
index 97b3e10d..e09daec 100644
--- a/chrome/build/android-desktop-x64.pgo.txt
+++ b/chrome/build/android-desktop-x64.pgo.txt
@@ -1 +1 @@
-chrome-android-desktop-x64-main-1765303009-bf2af6500aae46a845ff9b076937a51f1b04eb9a-4b2e572ce8915e4b97ce972f7d765c0d562f1f01.profdata
+chrome-android-desktop-x64-main-1765324710-46a8d615c861f57ca458d22405a1b0586273ddc3-5c1ba8531bd7f21f5f123e60e3d5677bda27895e.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt
index 44720570..952ffd14 100644
--- a/chrome/build/mac-arm.pgo.txt
+++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@
-chrome-mac-arm-main-1765310156-4ac2abc4ee4f4580cfc560e363dc63dbb4cfd080-8ba337d4f2b0819c0278c3406f639ab3cca80242.profdata
+chrome-mac-arm-main-1765324710-e586de8e3919d35954ab5e5d561e08d87c63c00f-5c1ba8531bd7f21f5f123e60e3d5677bda27895e.profdata
diff --git a/chrome/build/win-arm64.pgo.txt b/chrome/build/win-arm64.pgo.txt
index be34207..5b5a5f8f 100644
--- a/chrome/build/win-arm64.pgo.txt
+++ b/chrome/build/win-arm64.pgo.txt
@@ -1 +1 @@
-chrome-win-arm64-main-1765280892-63676529b0918788608f353cd610e44f199c28dc-63964caf8cd9d569b77ea05c1e16b55383ac13eb.profdata
+chrome-win-arm64-main-1765324710-937b6306c6e4b61004501d4bedab4a6da6d2c774-5c1ba8531bd7f21f5f123e60e3d5677bda27895e.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 78c5c7e..344240a 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1765292065-6aaf576e76da17c872bc55b9f78bec2c65247c42-7f6bbd655cb6f64b8f924d6ebdd1d4f7b2046309.profdata
+chrome-win32-main-1765303009-01db1604ab4ae4ef525c18ebc05244721ccc691a-4b2e572ce8915e4b97ce972f7d765c0d562f1f01.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 8470c2ce..e1b1282 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1765270527-2b3c24c2fbf65b719dbe065b6c34a562b3315ab7-3515cea40bdbb0a1e83ff434a7aa19180f5b9d75.profdata
+chrome-win64-main-1765292065-882fc022fa1f0d4d6f5a3984092db997129fd282-7f6bbd655cb6f64b8f924d6ebdd1d4f7b2046309.profdata
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 72282da..bb578e7 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1638,6 +1638,7 @@
       "../browser/extensions/extension_keybinding_browsertest.cc",
       "../browser/extensions/extension_override_apitest.cc",
       "../browser/extensions/extension_tab_util_browsertest.cc",
+      "../browser/extensions/manifest_v3_browsertest.cc",
       "../browser/extensions/permissions/permissions_manager_browsertest.cc",
       "../browser/extensions/permissions/permissions_updater_browsertest.cc",
       "../browser/extensions/permissions/site_permissions_helper_browsertest.cc",
@@ -4776,7 +4777,6 @@
         "../browser/extensions/loading_predictor_extension_browsertest.cc",
         "../browser/extensions/locked_fullscreen_window_apitest.cc",
         "../browser/extensions/manifest_v2_experiment_manager_browsertest.cc",
-        "../browser/extensions/manifest_v3_browsertest.cc",
         "../browser/extensions/mutation_observers_apitest.cc",
         "../browser/extensions/native_bindings_apitest.cc",
         "../browser/extensions/navigation_extension_enabler_browsertest.cc",
@@ -7067,7 +7067,6 @@
     "//chrome/browser/ui/toolbar/pinned_toolbar",
     "//chrome/browser/ui/webui",
     "//chrome/browser/ui/webui/internal_debug_pages_disabled",
-    "//chrome/browser/updater",
     "//chrome/browser/updates/announcement_notification:unit_tests",
     "//chrome/browser/upgrade_detector:unit_tests",
     "//chrome/browser/vr:unit_tests",
@@ -7516,23 +7515,19 @@
     sources += [
       "../browser/enterprise/platform_auth/platform_auth_navigation_throttle_unittest.cc",
       "../browser/enterprise/platform_auth/platform_auth_provider_manager_unittest.cc",
+      "../browser/updater/browser_updater_client_testutils.cc",
+      "../browser/updater/browser_updater_client_testutils.h",
+      "../browser/updater/browser_updater_client_unittest.cc",
     ]
     deps += [
       "//chrome/browser/enterprise/platform_auth:test_utils",
       "//chrome/browser/ui/pdf/infobar:unit_tests",
       "//chrome/browser/ui/startup/default_browser_prompt/pin_infobar:unit_tests",
+      "//chrome/browser/updater:browser_updater_client",
+      "//chrome/updater:browser_sources",
     ]
   }
 
-  if (enable_updater && (is_win || is_mac)) {
-    sources += [
-      "../browser/updater/browser_updater_client_testutils.cc",
-      "../browser/updater/browser_updater_client_testutils.h",
-      "../browser/updater/browser_updater_client_unittest.cc",
-    ]
-    deps += [ "//chrome/updater:browser_sources" ]
-  }
-
   if (is_win || is_mac || is_linux) {
     deps += [ "//chrome/browser/ui/views/session_restore_infobar:unit_tests" ]
   }
@@ -7623,6 +7618,7 @@
       "//chrome/installer/util:strings",
       "//chrome/installer/util:with_no_strings",
       "//chrome/services/util_win:lib",
+      "//chrome/updater:browser_sources",
       "//chrome/windows_services/elevated_tracing_service:tracing_service_idl",
       "//components/performance_manager/scenario_api",
       "//third_party/iaccessible2",
@@ -7724,11 +7720,13 @@
       "//chrome/app_shim",
       "//chrome/browser/apps/app_shim",
       "//chrome/browser/renderer_host:history_swiper",
+      "//chrome/browser/updater:browser_updater_client",
       "//chrome/common/notifications",
       "//chrome/common/safe_browsing:archive_analyzer_results",
       "//chrome/common/safe_browsing:disk_image_type_sniffer_mac",
       "//chrome/services/mac_notifications:unit_tests",
       "//chrome/services/mac_notifications/public/mojom",
+      "//chrome/updater:browser_sources",
       "//chrome/utility/safe_browsing",
       "//chrome/utility/safe_browsing/mac:dmg_common",
       "//components/power_metrics",
@@ -10374,7 +10372,6 @@
   }
   if (is_win || is_mac) {
     sources += [ "../browser/component_updater/updater_state_unittest.cc" ]
-    deps += [ "//chrome/updater:browser_sources" ]
   }
   if (is_win || is_mac || is_chromeos) {
     deps += [ "//chrome/common/notifications:unit_tests" ]
diff --git a/chrome/test/base/ash/mojo_web_ui_browser_test.cc b/chrome/test/base/ash/mojo_web_ui_browser_test.cc
index 66e06be..2fe17c1a 100644
--- a/chrome/test/base/ash/mojo_web_ui_browser_test.cc
+++ b/chrome/test/base/ash/mojo_web_ui_browser_test.cc
@@ -78,11 +78,22 @@
                             base::Unretained(this)));
   }
 
-  void RegisterWebUIInterfaceBrokers(
+  void RegisterTrustedWebUIInterfaceBrokers(
       content::WebUIBrowserInterfaceBrokerRegistry& registry) override {
-    ChromeContentBrowserClient::RegisterWebUIInterfaceBrokers(registry);
+    ChromeContentBrowserClient::RegisterTrustedWebUIInterfaceBrokers(registry);
+    AddTestRunnerService(registry);
+  }
 
-    registry.AddBinderForTesting(base::BindLambdaForTesting(
+  void RegisterUntrustedWebUIInterfaceBrokers(
+      content::WebUIBrowserInterfaceBrokerRegistry& registry) override {
+    ChromeContentBrowserClient::RegisterUntrustedWebUIInterfaceBrokers(
+        registry);
+    AddTestRunnerService(registry);
+  }
+
+  void AddTestRunnerService(
+      content::WebUIBrowserInterfaceBrokerRegistry& registry) {
+    registry.AddGlobal(base::BindLambdaForTesting(
         [&](content::WebUIController* controller,
             mojo::PendingReceiver<web_ui_test::mojom::TestRunner> receiver) {
           content::RenderFrameHost* rfh =
diff --git a/chrome/test/data/extensions/api_test/override/bookmarks/bookmarks.html b/chrome/test/data/extensions/api_test/override/bookmarks/bookmarks.html
new file mode 100644
index 0000000..55dfe0270
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/override/bookmarks/bookmarks.html
@@ -0,0 +1,7 @@
+<!--
+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.
+-->
+<script src="bookmarks.js"></script>
+New Tab Override!
diff --git a/chrome/test/data/extensions/api_test/override/bookmarks/bookmarks.js b/chrome/test/data/extensions/api_test/override/bookmarks/bookmarks.js
new file mode 100644
index 0000000..ee5459f
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/override/bookmarks/bookmarks.js
@@ -0,0 +1,5 @@
+// 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.
+
+chrome.test.notifyPass();
diff --git a/chrome/test/data/extensions/api_test/override/bookmarks/manifest.json b/chrome/test/data/extensions/api_test/override/bookmarks/manifest.json
new file mode 100644
index 0000000..68d4df6
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/override/bookmarks/manifest.json
@@ -0,0 +1,9 @@
+{
+  "name": "Bookmarks override test",
+  "version": "0.1",
+  "manifest_version": 3,
+  "description": "Test chrome://bookmarks override",
+  "chrome_url_overrides": {
+    "bookmarks": "bookmarks.html"
+  }
+}
diff --git a/chrome/test/data/extensions/api_test/override/bookmarks_split_mode/bookmarks.html b/chrome/test/data/extensions/api_test/override/bookmarks_split_mode/bookmarks.html
new file mode 100644
index 0000000..55dfe0270
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/override/bookmarks_split_mode/bookmarks.html
@@ -0,0 +1,7 @@
+<!--
+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.
+-->
+<script src="bookmarks.js"></script>
+New Tab Override!
diff --git a/chrome/test/data/extensions/api_test/override/bookmarks_split_mode/bookmarks.js b/chrome/test/data/extensions/api_test/override/bookmarks_split_mode/bookmarks.js
new file mode 100644
index 0000000..ee5459f
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/override/bookmarks_split_mode/bookmarks.js
@@ -0,0 +1,5 @@
+// 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.
+
+chrome.test.notifyPass();
diff --git a/chrome/test/data/extensions/api_test/override/bookmarks_split_mode/manifest.json b/chrome/test/data/extensions/api_test/override/bookmarks_split_mode/manifest.json
new file mode 100644
index 0000000..d8dd368
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/override/bookmarks_split_mode/manifest.json
@@ -0,0 +1,10 @@
+{
+  "name": "Bookmarks override test for incognito split mode",
+  "version": "0.1",
+  "manifest_version": 3,
+  "description": "Test chrome://bookmarks override",
+  "incognito": "split",
+  "chrome_url_overrides": {
+    "bookmarks": "bookmarks.html"
+  }
+}
diff --git a/chrome/test/data/extensions/api_test/override/newtab_split_mode/manifest.json b/chrome/test/data/extensions/api_test/override/newtab_split_mode/manifest.json
new file mode 100644
index 0000000..f12803f
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/override/newtab_split_mode/manifest.json
@@ -0,0 +1,10 @@
+{
+  "name": "New tab override test with incognito split mode",
+  "version": "0.1",
+  "manifest_version": 3,
+  "description": "Test chrome://newtab override",
+  "incognito": "split",
+  "chrome_url_overrides": {
+    "newtab": "newtab.html"
+  }
+}
diff --git a/chrome/test/data/extensions/api_test/override/newtab_split_mode/newtab.html b/chrome/test/data/extensions/api_test/override/newtab_split_mode/newtab.html
new file mode 100644
index 0000000..473e6eb
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/override/newtab_split_mode/newtab.html
@@ -0,0 +1,7 @@
+<!--
+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.
+-->
+<script src="newtab.js"></script>
+New Tab Override!
diff --git a/chrome/test/data/extensions/api_test/override/newtab_split_mode/newtab.js b/chrome/test/data/extensions/api_test/override/newtab_split_mode/newtab.js
new file mode 100644
index 0000000..ee5459f
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/override/newtab_split_mode/newtab.js
@@ -0,0 +1,5 @@
+// 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.
+
+chrome.test.notifyPass();
diff --git a/chrome/test/data/webui/mojo/mojo_js_interface_broker_browsertest.cc b/chrome/test/data/webui/mojo/mojo_js_interface_broker_browsertest.cc
index 790e5ef..d564745d 100644
--- a/chrome/test/data/webui/mojo/mojo_js_interface_broker_browsertest.cc
+++ b/chrome/test/data/webui/mojo/mojo_js_interface_broker_browsertest.cc
@@ -258,9 +258,13 @@
         delete;
     ~TestContentBrowserClient() override = default;
 
-    void RegisterWebUIInterfaceBrokers(
+    void RegisterTrustedWebUIInterfaceBrokers(
         content::WebUIBrowserInterfaceBrokerRegistry& registry) override {
       registry.ForWebUI<FooUI>().Add<::test::mojom::Foo>();
+    }
+
+    void RegisterUntrustedWebUIInterfaceBrokers(
+        content::WebUIBrowserInterfaceBrokerRegistry& registry) override {
       registry.ForWebUI<BarUI>().Add<::test::mojom::Bar>();
     }
   };
@@ -284,8 +288,6 @@
                                  "  return resp.value;"
                                  "})()"));
 
-  auto* broker1 =
-      web_contents->GetWebUI()->GetController()->broker_for_testing();
   // Refresh to trigger a RenderFrame reuse.
   content::TestNavigationObserver observer(web_contents, 1);
   // TODO(crbug.com/40160974): migrate to ExecJs.
@@ -293,9 +295,6 @@
   observer.Wait();
 
   // Verify a new broker is created, and Foo still works.
-  auto* broker2 =
-      web_contents->GetWebUI()->GetController()->broker_for_testing();
-  EXPECT_NE(broker1, broker2);
   EXPECT_EQ("foo", EvalStatement("(async () => {"
                                  "  let fooRemote = window.Foo.getRemote();"
                                  "  let resp = await fooRemote.getFoo();"
@@ -305,9 +304,6 @@
   // Perform a same-document navigation, verify the current broker persists, and
   // Foo still works.
   ASSERT_TRUE(NavigateToURL(web_contents, GURL(kFooURL).Resolve("#fragment")));
-  auto* broker3 =
-      web_contents->GetWebUI()->GetController()->broker_for_testing();
-  EXPECT_EQ(broker2, broker3);
   EXPECT_EQ("foo", EvalStatement("(async () => {"
                                  "  let fooRemote = window.Foo.getRemote();"
                                  "  let resp = await fooRemote.getFoo();"
diff --git a/chromeos/ash/components/dbus/resourced/resourced_client.cc b/chromeos/ash/components/dbus/resourced/resourced_client.cc
index 8635643..450dba0 100644
--- a/chromeos/ash/components/dbus/resourced/resourced_client.cc
+++ b/chromeos/ash/components/dbus/resourced/resourced_client.cc
@@ -5,6 +5,7 @@
 #include "chromeos/ash/components/dbus/resourced/resourced_client.h"
 
 #include "base/byte_count.h"
+#include "base/byte_size.h"
 #include "base/check_op.h"
 #include "base/functional/callback_helpers.h"
 #include "base/logging.h"
@@ -133,7 +134,7 @@
 ResourcedClientImpl::ResourcedClientImpl() {
   base::SystemMemoryInfo info;
   if (base::GetSystemMemoryInfo(&info)) {
-    total_memory_ = info.total;
+    total_memory_ = base::ByteCount::FromUnsigned(info.total.InBytes());
   } else {
     PLOG(ERROR) << "Error reading total memory.";
   }
diff --git a/chromeos/ash/experiences/arc/session/arc_vm_client_adapter_unittest.cc b/chromeos/ash/experiences/arc/session/arc_vm_client_adapter_unittest.cc
index 5c90fd2..bf908d5 100644
--- a/chromeos/ash/experiences/arc/session/arc_vm_client_adapter_unittest.cc
+++ b/chromeos/ash/experiences/arc/session/arc_vm_client_adapter_unittest.cc
@@ -17,7 +17,7 @@
 #include <vector>
 
 #include "ash/constants/ash_features.h"
-#include "base/byte_count.h"
+#include "base/byte_size.h"
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
 #include "base/containers/contains.h"
@@ -2263,7 +2263,7 @@
     bool GetSystemMemoryInfo(base::SystemMemoryInfo* info) override {
       // Return a value larger than k32bitVmRamMaxMib to verify that the VM
       // memory size is actually limited.
-      info->total = base::MiB(k32bitVmRamMaxMib + 1000);
+      info->total = base::MiBU(k32bitVmRamMaxMib + 1000);
       return true;
     }
     bool IsCrosvm32bit() override { return true; }
@@ -2547,7 +2547,7 @@
 TEST_F(ArcVmClientAdapterTest, ArcGuestZramSizeByPercentage_5GbSystem) {
   class TestDelegate : public ArcVmClientAdapterDelegate {
     bool GetSystemMemoryInfo(base::SystemMemoryInfo* info) override {
-      info->total = base::GiB(5);
+      info->total = base::GiBU(5);
       return true;
     }
     bool IsCrosvm32bit() override { return false; }
@@ -2572,7 +2572,7 @@
 TEST_F(ArcVmClientAdapterTest, ArcGuestZramSizeByPercentage_4GbSystem) {
   class TestDelegate : public ArcVmClientAdapterDelegate {
     bool GetSystemMemoryInfo(base::SystemMemoryInfo* info) override {
-      info->total = base::GiB(4);
+      info->total = base::GiBU(4);
       return true;
     }
     bool IsCrosvm32bit() override { return false; }
@@ -2597,7 +2597,7 @@
 TEST_F(ArcVmClientAdapterTest, ArcGuestZramSizeByPercentage_CustomMem) {
   class TestDelegate : public ArcVmClientAdapterDelegate {
     bool GetSystemMemoryInfo(base::SystemMemoryInfo* info) override {
-      info->total = base::GiB(6);
+      info->total = base::GiBU(6);
       return true;
     }
     bool IsCrosvm32bit() override { return false; }
diff --git a/clank b/clank
index 696228b..c600588 160000
--- a/clank
+++ b/clank
@@ -1 +1 @@
-Subproject commit 696228be97b40a0a6389a8e36c4404ac88b22927
+Subproject commit c600588721e3fccf9df6df3194ae84d3811d2eb7
diff --git a/components/autofill/core/browser/payments/credit_card_save_manager.cc b/components/autofill/core/browser/payments/credit_card_save_manager.cc
index 7bf68fd..8637b20 100644
--- a/components/autofill/core/browser/payments/credit_card_save_manager.cc
+++ b/components/autofill/core/browser/payments/credit_card_save_manager.cc
@@ -852,9 +852,9 @@
               base::UTF16ToUTF8(card_save_candidate_.LastFourDigits())))
           .with_card_save_type(card_save_type);
 
-  // If |show_save_prompt_|'s value is false, desktop builds will still offer
-  // save in the omnibox without popping-up the bubble. Mobile builds,
-  // however, should not display the offer-to-save infobar at all.
+  // If `show_save_prompt_` is false: 1) desktop builds will still offer save in
+  // the omnibox but won't pop up the bubble, and 2) mobile builds will not show
+  // any offer to save prompt at all.
   if (!is_mobile_build || show_save_prompt_.value_or(true)) {
     if (observer_for_testing_) {
       observer_for_testing_->OnOfferLocalSave();
diff --git a/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheet.java b/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheet.java
index 1028d6a6..8182a11 100644
--- a/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheet.java
+++ b/components/browser_ui/bottomsheet/android/internal/java/src/org/chromium/components/browser_ui/bottomsheet/BottomSheet.java
@@ -23,6 +23,7 @@
 import androidx.annotation.StringRes;
 import androidx.annotation.VisibleForTesting;
 import androidx.core.content.ContextCompat;
+import androidx.core.view.ViewCompat;
 
 import org.chromium.base.Callback;
 import org.chromium.base.Log;
@@ -644,7 +645,7 @@
         // If the sheet contents are cleared out before #onSheetClosed is called, do not try to
         // retrieve the accessibility string.
         if (getCurrentSheetContent() != null) {
-            announceForAccessibility(
+            updateA11yPaneTitle(
                     getResources()
                             .getString(
                                     getCurrentSheetContent()
@@ -1076,7 +1077,7 @@
                     mCurrentState == SheetState.FULL
                             ? getCurrentSheetContent().getSheetFullHeightAccessibilityStringId()
                             : getCurrentSheetContent().getSheetHalfHeightAccessibilityStringId();
-            setAccessibilityPaneTitle(getResources().getString(resId));
+            updateA11yPaneTitle(getResources().getString(resId));
 
             // TalkBack will announce the content description if it has changed, so wait to set the
             // content description until after announcing full/half height.
@@ -1502,6 +1503,12 @@
         mContentDesiredHeight = HEIGHT_UNSPECIFIED;
     }
 
+    private void updateA11yPaneTitle(CharSequence msg) {
+        // Set the pane title for the container. The bottom sheet view is not always accessible
+        // e.g. when sheet is dismissed.
+        ViewCompat.setAccessibilityPaneTitle(mSheetContainer, msg);
+    }
+
     /**
      * WARNING: This destroys the state of the BottomSheet. Only use in tests and only use once.
      * Puts the sheet into a scrolling state that can't be reached in tests otherwise.
diff --git a/components/browser_ui/settings/android/java/src/org/chromium/components/browser_ui/settings/search/SettingsIndexData.java b/components/browser_ui/settings/android/java/src/org/chromium/components/browser_ui/settings/search/SettingsIndexData.java
index 708e7d87..46e1b47 100644
--- a/components/browser_ui/settings/android/java/src/org/chromium/components/browser_ui/settings/search/SettingsIndexData.java
+++ b/components/browser_ui/settings/android/java/src/org/chromium/components/browser_ui/settings/search/SettingsIndexData.java
@@ -7,6 +7,8 @@
 import android.os.Bundle;
 import android.text.TextUtils;
 
+import org.chromium.base.ContextUtils;
+import org.chromium.build.annotations.EnsuresNonNull;
 import org.chromium.build.annotations.NullMarked;
 import org.chromium.build.annotations.Nullable;
 
@@ -31,6 +33,24 @@
     // Map from a child fragment's class name to the list of preference keys that can link to it.
     private final Map<String, List<String>> mChildFragmentToParentKeys = new HashMap<>();
 
+    private static @Nullable SettingsIndexData sInstance;
+
+    @EnsuresNonNull("sInstance")
+    public static SettingsIndexData createInstance() {
+        assert sInstance == null;
+        sInstance = new SettingsIndexData();
+        return sInstance;
+    }
+
+    @Nullable
+    public static SettingsIndexData getInstance() {
+        return sInstance;
+    }
+
+    public static void reset() {
+        sInstance = null;
+    }
+
     /**
      * Normalizes a string for search by converting it to lowercase and stripping diacritics.
      *
@@ -209,35 +229,67 @@
     /**
      * Adds a new searchable preference entry to the index.
      *
-     * @param key The unique key of the preference. This is used as the primary identifier in the
+     * @param id The unique ID of the preference. This is used as the primary identifier in the
      *     internal map.
      * @param entry The {@link Entry} object containing all the data for this preference.
      * @throws IllegalStateException If a preference with the same key already exists in the index.
      */
-    public void addEntry(String key, Entry entry) {
-        if (mEntries.containsKey(key)) {
-            throw new IllegalStateException("Duplicate preference key found: " + key);
+    public void addEntry(String id, Entry entry) {
+        if (mEntries.containsKey(id)) {
+            throw new IllegalStateException("Duplicate ID found: " + id);
         }
-        mEntries.put(key, entry);
+        mEntries.put(id, entry);
+    }
+
+    /**
+     * Adds a new searchable preference entry to the index.
+     *
+     * @param prefFragment Full class name of the Fragment where the entry belongs.
+     * @param key The name of the key for the preference entry.
+     * @param titleId String resource ID of the title.
+     */
+    public void addEntryForKey(String prefFragment, String key, int titleId) {
+        String id = PreferenceParser.createUniqueId(prefFragment, key);
+        String title = ContextUtils.getApplicationContext().getString(titleId);
+        addEntry(id, new Entry.Builder(id, key, title, prefFragment).build());
     }
 
     @Nullable
-    public Entry getEntry(String key) {
-        return mEntries.get(key);
+    public Entry getEntry(String id) {
+        return mEntries.get(id);
     }
 
     /**
      * Replaces an existing entry with a new one.
      *
-     * @param key The key of the {@link Entry} to replace.
+     * @param id The ID of the {@link Entry} to replace.
      * @param updatedEntry The new {@link Entry} to place in place of the existing one.
      */
-    public void updateEntry(String key, Entry updatedEntry) {
-        mEntries.put(key, updatedEntry);
+    public void updateEntry(String id, Entry updatedEntry) {
+        mEntries.put(id, updatedEntry);
     }
 
     /**
-     * Removes a preference entry from the index without disabling its target fragment.
+     * Replaces an existing entry with a new one.
+     *
+     * @param prefFragment Full class name of the Fragment where the entry belongs.
+     * @param key The name of the key for the preference entry.
+     * @param titleId String resource ID of the title.
+     * @throws IllegalStateException If a preference with the same key does not exist in the index.
+     */
+    public void updateEntryForKey(String prefFragment, String key, int titleId) {
+        String id = PreferenceParser.createUniqueId(prefFragment, key);
+        String title = ContextUtils.getApplicationContext().getString(titleId);
+        Entry entry = getEntry(id);
+        if (entry != null) {
+            updateEntry(id, new Entry.Builder(entry).setTitle(title).build());
+        } else {
+            throw new IllegalStateException("Existing ID cannot be found: " + id);
+        }
+    }
+
+    /**
+     * Removes a preference entry from the index.
      *
      * <p>This method should be used when a link to a fragment is being hidden from one screen, but
      * the fragment itself is still reachable via another path and should remain searchable.
@@ -247,10 +299,20 @@
      * "Appearance" screen. In this case, the MainSettings provider should call this method to
      * remove only the redundant link, without disabling the {@code TabsSettings} fragment.
      *
-     * @param key The unique key of the preference link to remove.
+     * @param id The unique ID of the preference link to remove.
      */
-    public void removeEntry(String key) {
-        mEntries.remove(key);
+    public void removeEntry(String id) {
+        mEntries.remove(id);
+    }
+
+    /**
+     * Removes a preference entry of a given key from the index.
+     *
+     * @param prefFragment Full class name of the Fragment where the key belongs.
+     * @param key Key name of the preference entry.
+     */
+    public void removeEntryForKey(String prefFragment, String key) {
+        removeEntry(PreferenceParser.createUniqueId(prefFragment, key));
     }
 
     /** Set the flag indicating the index became stale and needs reindexing. */
diff --git a/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeSwitchPreference.java b/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeSwitchPreference.java
index bf0b26d0..3e5a543 100644
--- a/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeSwitchPreference.java
+++ b/components/browser_ui/settings/android/widget/java/src/org/chromium/components/browser_ui/settings/ChromeSwitchPreference.java
@@ -185,4 +185,11 @@
     public @BackgroundStyle int getCustomBackgroundStyle() {
         return mBackgroundStyle;
     }
+
+    @Override
+    public int getCustomMinHeight() {
+        return getContext()
+                .getResources()
+                .getDimensionPixelSize(R.dimen.settings_toggle_item_min_height);
+    }
 }
diff --git a/components/browser_ui/widget/android/java/res/values/dimens.xml b/components/browser_ui/widget/android/java/res/values/dimens.xml
index 150aee6..7d282c0 100644
--- a/components/browser_ui/widget/android/java/res/values/dimens.xml
+++ b/components/browser_ui/widget/android/java/res/values/dimens.xml
@@ -62,6 +62,7 @@
     <dimen name="settings_item_default_padding">16dp</dimen>
     <dimen name="settings_item_vertical_padding_multi_line">12dp</dimen>
     <dimen name="settings_title_margin">32dp</dimen>
+    <dimen name="settings_toggle_item_min_height">57.5dp</dimen>
 
     <!-- Drag-Reorderable List dimensions -->
     <dimen name="list_item_dragged_elevation">6dp</dimen>
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/containment/ContainerStyle.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/containment/ContainerStyle.java
index f4b98a7c..d7c7b1e2 100644
--- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/containment/ContainerStyle.java
+++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/containment/ContainerStyle.java
@@ -5,8 +5,8 @@
 package org.chromium.components.browser_ui.widget.containment;
 
 import static org.chromium.components.browser_ui.widget.containment.ContainmentItem.DEFAULT_COLOR;
-import static org.chromium.components.browser_ui.widget.containment.ContainmentItem.DEFAULT_MARGIN;
 import static org.chromium.components.browser_ui.widget.containment.ContainmentItem.DEFAULT_RADIUS;
+import static org.chromium.components.browser_ui.widget.containment.ContainmentItem.DEFAULT_VALUE;
 
 import org.chromium.build.annotations.NullMarked;
 
@@ -19,6 +19,7 @@
     private final int mBottomMargin;
     private final int mHorizontalMargin;
     private final int mVerticalPadding;
+    private final int mMinHeight;
     private final int mBackgroundColor;
 
     /** A container with no background. */
@@ -31,6 +32,7 @@
         mBottomMargin = builder.mBottomMargin;
         mHorizontalMargin = builder.mHorizontalMargin;
         mVerticalPadding = builder.mVerticalPadding;
+        mMinHeight = builder.mMinHeight;
         mBackgroundColor = builder.mBackgroundColor;
     }
 
@@ -38,10 +40,11 @@
     public static class Builder {
         private float mTopRadius = DEFAULT_RADIUS;
         private float mBottomRadius = DEFAULT_RADIUS;
-        private int mTopMargin = DEFAULT_MARGIN;
-        private int mBottomMargin = DEFAULT_MARGIN;
-        private int mHorizontalMargin = DEFAULT_MARGIN;
-        private int mVerticalPadding = DEFAULT_MARGIN;
+        private int mTopMargin = DEFAULT_VALUE;
+        private int mBottomMargin = DEFAULT_VALUE;
+        private int mHorizontalMargin = DEFAULT_VALUE;
+        private int mVerticalPadding = DEFAULT_VALUE;
+        private int mMinHeight = DEFAULT_VALUE;
         private int mBackgroundColor = DEFAULT_COLOR;
 
         public Builder setTopRadius(float topRadius) {
@@ -74,6 +77,11 @@
             return this;
         }
 
+        public Builder setMinHeight(int minHeight) {
+            mMinHeight = minHeight;
+            return this;
+        }
+
         public Builder setBackgroundColor(int backgroundColor) {
             mBackgroundColor = backgroundColor;
             return this;
@@ -127,6 +135,13 @@
     }
 
     /**
+     * @return The minimum height in pixels.
+     */
+    public int getMinHeight() {
+        return mMinHeight;
+    }
+
+    /**
      * @return The background color for the container.
      */
     public int getBackgroundColor() {
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/containment/ContainmentItem.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/containment/ContainmentItem.java
index 39ff1bd..352c390 100644
--- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/containment/ContainmentItem.java
+++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/containment/ContainmentItem.java
@@ -4,6 +4,8 @@
 
 package org.chromium.components.browser_ui.widget.containment;
 
+import android.graphics.Color;
+
 import androidx.annotation.IntDef;
 
 import org.chromium.build.annotations.NullMarked;
@@ -14,9 +16,9 @@
 /** An interface for container that should have custom background styling applied to them. */
 @NullMarked
 public interface ContainmentItem {
-    int DEFAULT_MARGIN = -1;
-    int DEFAULT_COLOR = -1;
+    int DEFAULT_COLOR = Color.WHITE;
     float DEFAULT_RADIUS = -1f;
+    int DEFAULT_VALUE = -1;
 
     // LINT.IfChange
     @IntDef({BackgroundStyle.CARD, BackgroundStyle.NONE, BackgroundStyle.STANDARD})
@@ -39,27 +41,11 @@
     }
 
     /**
-     * @return The custom top margin for the container in pixels. If DEFAULT_MARGIN, the default
-     *     margin will be used.
+     * @return The custom minimum height for the container in pixels. If DEFAULT_VALUE the default
+     *     height will be used.
      */
-    default int getCustomTopMargin() {
-        return DEFAULT_MARGIN;
-    }
-
-    /**
-     * @return The custom bottom margin for the container in pixels. If DEFAULT_MARGIN, the default
-     *     margin will be used.
-     */
-    default int getCustomBottomMargin() {
-        return DEFAULT_MARGIN;
-    }
-
-    /**
-     * @return The custom horizontal margin for the container in pixels. If DEFAULT_MARGIN, the
-     *     default margin will be used.
-     */
-    default int getCustomHorizontalMargin() {
-        return DEFAULT_MARGIN;
+    default int getCustomMinHeight() {
+        return DEFAULT_VALUE;
     }
 
     /**
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/containment/ContainmentItemController.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/containment/ContainmentItemController.java
index 0f17606..1987269 100644
--- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/containment/ContainmentItemController.java
+++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/containment/ContainmentItemController.java
@@ -6,7 +6,7 @@
 
 import static org.chromium.components.browser_ui.styles.SemanticColorUtils.getSettingsContainerBackgroundColor;
 import static org.chromium.components.browser_ui.widget.containment.ContainmentItem.DEFAULT_COLOR;
-import static org.chromium.components.browser_ui.widget.containment.ContainmentItem.DEFAULT_MARGIN;
+import static org.chromium.components.browser_ui.widget.containment.ContainmentItem.DEFAULT_VALUE;
 
 import android.content.Context;
 import android.graphics.Color;
@@ -26,21 +26,16 @@
 /**
  * Controller that assigns styling to items in a settings screen.
  *
- * <p>This controller is responsible for generating {@link ContainerStyle} objects for both {@link
- * Preference} items and generic {@link View}s.
+ * <p>This controller generates {@link ContainerStyle} objects for {@link Preference} items and
+ * generic {@link View}s. It determines styles based on an item's position within a styling section
+ * and its custom styling properties. Styling is composed by calling a series of helper methods:
  *
- * <p>The core logic is based on the concept of a "styling section," which is a contiguous block of
- * standard items. Special items that require custom styling (see {@link
- * #isCustomStyledPreference(Preference)} and {@link #isCustomStyledView(View)}) act as delimiters
- * that break up these sections.
- *
- * <p>For a standard item (either a Preference or a View), the controller determines if it's at the
- * top, middle, bottom, or is a standalone item in its section. This position is then passed to
- * {@link #createBuilderWithDefaultStyle}, which creates the final style with the correct corner
- * radii and default margins.
- *
- * <p>Custom preferences are handled separately in {@link #getStyleForCustomContainer}, where their
- * own styling values are prioritized over the controller's defaults.
+ * <ul>
+ *   <li>{@link #addStandardStyling}: Applies standard margins and padding.
+ *   <li>{@link #addPositionBasedStyling}: Applies corner radii and margins based on the item's
+ *       position in a section.
+ *   <li>{@link #addCustomStyling}: Applies custom styles from {@link ContainmentItem}.
+ * </ul>
  */
 @NullMarked
 public class ContainmentItemController {
@@ -112,7 +107,14 @@
     }
 
     /**
-     * Determines the style for a preference based on its position in the list.
+     * Determines the style for a preference based on its position in the list and its custom
+     * styling properties.
+     *
+     * <p>This method evaluates the preference's position relative to its neighbors to determine if
+     * it's at the top, middle, bottom, or a standalone item in a section. It also checks if the
+     * preference implements {@link ContainmentItem} to apply custom styles. The final {@link
+     * ContainerStyle} is composed by calling helper methods to add position-based and custom
+     * styling.
      *
      * @param visiblePreferences The list of all visible preferences.
      * @param position The position of the current preference in the list.
@@ -121,31 +123,41 @@
     private @NonNull ContainerStyle getPreferenceStyleForPosition(
             ArrayList<Preference> visiblePreferences, int position) {
         Preference currentPref = visiblePreferences.get(position);
-        boolean isSingleLine = currentPref.getSummary() == null;
 
-        if (isCustomStyledPreference(currentPref)) {
-            if (currentPref instanceof PreferenceCategory) {
-                return new ContainerStyle.Builder()
-                        .setBottomMargin(mDefaultMargin)
-                        .setHorizontalMargin(mDefaultMargin)
-                        .setBackgroundColor(TRANSPARENT_BACKGROUND_COLOR)
-                        .build();
+        if (currentPref instanceof PreferenceCategory) {
+            return new ContainerStyle.Builder()
+                    .setBottomMargin(mDefaultMargin)
+                    .setHorizontalMargin(mDefaultMargin)
+                    .setBackgroundColor(TRANSPARENT_BACKGROUND_COLOR)
+                    .build();
+        }
+        if (currentPref instanceof ContainmentItem customStyledPreference) {
+            if (customStyledPreference.getCustomBackgroundStyle() == BackgroundStyle.NONE) {
+                return ContainerStyle.EMPTY;
             }
-            return getStyleForCustomContainer((ContainmentItem) currentPref, isSingleLine);
         }
 
-        // For standard items, styling is determined by their position within a section.
+        ContainerStyle.Builder containerStyleBuilder = new ContainerStyle.Builder();
 
+        // Evaluate position of preference
         Preference prefAbove = (position > 0) ? visiblePreferences.get(position - 1) : null;
         Preference prefBelow =
                 (position < visiblePreferences.size() - 1)
                         ? visiblePreferences.get(position + 1)
                         : null;
-
         boolean isTop = (prefAbove == null) || isCustomStyledPreference(prefAbove);
         boolean isBottom = (prefBelow == null) || isCustomStyledPreference(prefBelow);
 
-        return createBuilderWithDefaultStyle(isTop, isBottom, isSingleLine);
+        addStandardStyling(containerStyleBuilder, currentPref.getSummary() == null);
+        if (currentPref instanceof ContainmentItem customStyledPreference) {
+            if (customStyledPreference.getCustomBackgroundStyle() == BackgroundStyle.CARD) {
+                isTop = true;
+                isBottom = true;
+            }
+            addCustomStyling(containerStyleBuilder, customStyledPreference);
+        }
+        addPositionBasedStyling(containerStyleBuilder, isTop, isBottom);
+        return containerStyleBuilder.build();
     }
 
     /**
@@ -163,25 +175,39 @@
     }
 
     /**
-     * Determines the style for a view based on its position in the list.
+     * Determines the style for a view based on its position in a list. This method only applies
+     * styling to views that implement the {@link ContainmentItem} interface.
+     *
+     * <p>The method determines the view's position in a styling section (e.g., top, bottom) based
+     * on its {@link BackgroundStyle} and its neighbors. It then composes the final {@link
+     * ContainerStyle} by calling helper methods for custom and position-based styling.
      *
      * @param views The list of all views to be styled.
      * @param position The position of the current view in the list.
-     * @return The {@link ContainerStyle} for the view.
+     * @return The {@link ContainerStyle} for the view, or {@link ContainerStyle#EMPTY} if the view
+     *     is not a {@link ContainmentItem}.
      */
     private ContainerStyle getViewStyleForPosition(List<View> views, int position) {
         View view = views.get(position);
 
-        if (isCustomStyledView(view)) {
-            return getStyleForCustomContainer((ContainmentItem) view, /* isSingleLine= */ true);
+        if (!(view instanceof ContainmentItem customStyledView)
+                || customStyledView.getCustomBackgroundStyle() == BackgroundStyle.NONE) {
+            return ContainerStyle.EMPTY;
         }
 
-        // For standard items, styling is determined by their position within a section.
-
         boolean isTop = position == 0 || isCustomStyledView(views.get(position - 1));
         boolean isBottom =
                 position == views.size() - 1 || isCustomStyledView(views.get(position + 1));
-        return createBuilderWithDefaultStyle(isTop, isBottom, /* isSingleLine= */ false);
+
+        ContainerStyle.Builder containerStyleBuilder = new ContainerStyle.Builder();
+        addStandardStyling(containerStyleBuilder, /* isSingleLine= */ true);
+        if (customStyledView.getCustomBackgroundStyle() == BackgroundStyle.CARD) {
+            isTop = true;
+            isBottom = true;
+        }
+        addCustomStyling(containerStyleBuilder, customStyledView);
+        addPositionBasedStyling(containerStyleBuilder, isTop, isBottom);
+        return containerStyleBuilder.build();
     }
 
     /**
@@ -199,62 +225,74 @@
     }
 
     /**
-     * Creates a {@link ContainerStyle} for a {@link ContainmentItem}. This method respects the
-     * custom values provided by the container, falling back to controller defaults if they are not
-     * provided.
-     *
-     * @param container The container to generate a style for.
-     * @param isSingleLine Whether the item is single line.
-     * @return The {@link ContainerStyle} for the container.
-     */
-    private ContainerStyle getStyleForCustomContainer(
-            ContainmentItem container, boolean isSingleLine) {
-        if (container.getCustomBackgroundStyle() == BackgroundStyle.CARD) {
-            int topMargin = container.getCustomTopMargin();
-            if (topMargin == DEFAULT_MARGIN) topMargin = mDefaultContainerVerticalMargin;
-
-            int bottomMargin = container.getCustomBottomMargin();
-            if (bottomMargin == DEFAULT_MARGIN) {
-                bottomMargin = mDefaultContainerVerticalMargin + mSectionBottomAdditionalMargin;
-            }
-
-            int horizontalMargin = container.getCustomHorizontalMargin();
-            if (horizontalMargin == DEFAULT_MARGIN) {
-                horizontalMargin = mDefaultMargin;
-            }
-
-            int backgroundColor = container.getCustomBackgroundColor();
-            if (backgroundColor == DEFAULT_COLOR) backgroundColor = mDefaultBackgroundColor;
-
-            return new ContainerStyle.Builder()
-                    .setTopRadius(mDefaultRadius)
-                    .setBottomRadius(mDefaultRadius)
-                    .setTopMargin(topMargin)
-                    .setBottomMargin(bottomMargin)
-                    .setVerticalPadding(isSingleLine ? mDefaultPadding : mMultiLineVerticalPadding)
-                    .setHorizontalMargin(horizontalMargin)
-                    .setBackgroundColor(backgroundColor)
-                    .build();
-        }
-
-        return ContainerStyle.EMPTY;
-    }
-
-    /**
-     * Creates a default {@link ContainerStyle} for a standard item. The style is determined by
-     * whether the item is at the top or bottom of a styling section.
+     * Creates a {@link ContainerStyle.Builder} and applies standard, custom, and position-based
+     * styling.
      *
      * @param isTop Whether the item is at the top of a section.
      * @param isBottom Whether the item is at the bottom of a section.
-     * @param isSingleLine Whether the item is single line.
-     * @return The {@link ContainerStyle} for the item.
+     * @param isSingleLine Whether the item is single-line, affecting vertical padding.
+     * @return A {@link ContainerStyle.Builder} with all styles applied.
      */
-    public ContainerStyle createBuilderWithDefaultStyle(
+    public ContainerStyle.Builder createStandardBuilder(
             boolean isTop, boolean isBottom, boolean isSingleLine) {
+        ContainerStyle.Builder containerStyleBuilder = new ContainerStyle.Builder();
+        addStandardStyling(containerStyleBuilder, isSingleLine);
+        addPositionBasedStyling(containerStyleBuilder, isTop, isBottom);
+        return containerStyleBuilder;
+    }
+
+    /**
+     * Applies standard margins, padding, and the default background color to a {@link
+     * ContainerStyle.Builder}.
+     *
+     * @param containerStyleBuilder The {@link ContainerStyle.Builder} to apply the styles to.
+     * @param isSingleLine Whether the item is single-line, affecting vertical padding.
+     */
+    private void addStandardStyling(
+            ContainerStyle.Builder containerStyleBuilder, boolean isSingleLine) {
+        containerStyleBuilder
+                .setTopMargin(mDefaultContainerVerticalMargin)
+                .setHorizontalMargin(mDefaultMargin)
+                .setVerticalPadding(isSingleLine ? mDefaultPadding : mMultiLineVerticalPadding)
+                .setBackgroundColor(mDefaultBackgroundColor);
+    }
+
+    /**
+     * Applies custom styling from a {@link ContainmentItem} to a {@link ContainerStyle.Builder}.
+     * This includes background color and minimum height. If the item does not specify custom
+     * values, defaults are used.
+     *
+     * @param containerStyleBuilder The {@link ContainerStyle.Builder} to apply the styles to.
+     * @param container The {@link ContainmentItem} from which to source custom styles.
+     */
+    public void addCustomStyling(
+            ContainerStyle.Builder containerStyleBuilder, ContainmentItem container) {
+
+        int backgroundColor = container.getCustomBackgroundColor();
+        if (backgroundColor == DEFAULT_COLOR) backgroundColor = mDefaultBackgroundColor;
+
+        containerStyleBuilder.setBackgroundColor(backgroundColor);
+
+        int minHeight = container.getCustomMinHeight();
+        if (minHeight != DEFAULT_VALUE) {
+            // Only set the default height if a custom value was provided
+            containerStyleBuilder.setMinHeight(minHeight);
+        }
+    }
+
+    /**
+     * Applies corner radii and bottom margin to a {@link ContainerStyle.Builder} based on the
+     * item's position within a styling section (top, bottom, middle, or standalone).
+     *
+     * @param containerStyleBuilder The {@link ContainerStyle.Builder} to apply the styles to.
+     * @param isTop Whether the item is at the top of a section.
+     * @param isBottom Whether the item is at the bottom of a section.
+     */
+    public void addPositionBasedStyling(
+            ContainerStyle.Builder containerStyleBuilder, boolean isTop, boolean isBottom) {
         float topRadius = mDefaultRadius;
         float bottomRadius = mDefaultRadius;
         int bottomMargin = mDefaultContainerVerticalMargin;
-        int verticalPadding = isSingleLine ? mDefaultPadding : mMultiLineVerticalPadding;
 
         if (isTop && isBottom) { // Standalone
             // Standalone items have an additional bottom margin
@@ -270,14 +308,9 @@
             bottomRadius = mInnerRadius;
         }
 
-        return new ContainerStyle.Builder()
-                .setTopRadius(topRadius)
-                .setBottomRadius(bottomRadius)
-                .setTopMargin(mDefaultContainerVerticalMargin)
+        containerStyleBuilder
                 .setBottomMargin(bottomMargin)
-                .setHorizontalMargin(mDefaultMargin)
-                .setVerticalPadding(verticalPadding)
-                .setBackgroundColor(mDefaultBackgroundColor)
-                .build();
+                .setTopRadius(topRadius)
+                .setBottomRadius(bottomRadius);
     }
 }
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/containment/ContainmentItemControllerTest.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/containment/ContainmentItemControllerTest.java
index 1557d0c..1e26e14 100644
--- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/containment/ContainmentItemControllerTest.java
+++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/containment/ContainmentItemControllerTest.java
@@ -9,8 +9,6 @@
 import static org.junit.Assert.assertSame;
 
 import static org.chromium.components.browser_ui.styles.SemanticColorUtils.getSettingsContainerBackgroundColor;
-import static org.chromium.components.browser_ui.widget.containment.ContainmentItem.DEFAULT_COLOR;
-import static org.chromium.components.browser_ui.widget.containment.ContainmentItem.DEFAULT_MARGIN;
 import static org.chromium.components.browser_ui.widget.containment.ContainmentItemController.TRANSPARENT_BACKGROUND_COLOR;
 
 import android.content.Context;
@@ -28,7 +26,6 @@
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Batch;
 import org.chromium.components.browser_ui.settings.BlankUiTestActivitySettingsTestRule;
-import org.chromium.components.browser_ui.settings.ChromeBasePreference;
 import org.chromium.components.browser_ui.settings.PlaceholderSettingsForTest;
 import org.chromium.components.browser_ui.settings.SettingsUtils;
 import org.chromium.components.browser_ui.widget.containment.ContainmentItem.BackgroundStyle;
@@ -88,9 +85,6 @@
                 .getPreferenceFragment()
                 .addPreferencesFromResource(R.xml.test_settings_custom_preference_screen);
 
-        // Manually add preferences with custom margins
-        addPreferencesWithCustomMargins();
-
         mVisiblePreferences = SettingsUtils.getVisiblePreferences(mPreferenceScreen);
         mPreferenceStyles = mController.generatePreferenceStyles(mVisiblePreferences);
     }
@@ -119,6 +113,10 @@
         ContainerStyle textMessagePreferenceStyle = getPreferenceStyle("text_message_preference");
         assertEquals(mDefaultRadius, textMessagePreferenceStyle.getTopRadius(), 0);
         assertEquals(mDefaultRadius, textMessagePreferenceStyle.getBottomRadius(), 0);
+        assertEquals(mDefaultContainerVerticalMargin, textMessagePreferenceStyle.getTopMargin());
+        assertEquals(
+                mDefaultContainerVerticalMargin + mSectionBottomMargin,
+                textMessagePreferenceStyle.getBottomMargin());
         assertEquals(TRANSPARENT_BACKGROUND_COLOR, textMessagePreferenceStyle.getBackgroundColor());
     }
 
@@ -204,56 +202,12 @@
 
     @Test
     @SmallTest
-    public void testCustomStyledPreference_WithCustomMargins() {
-        ContainerStyle customMarginPreferenceStyle =
-                getPreferenceStyle("preference_with_custom_margins");
-        assertEquals(CUSTOM_TOP_MARGIN, customMarginPreferenceStyle.getTopMargin());
-        assertEquals(CUSTOM_BOTTOM_MARGIN, customMarginPreferenceStyle.getBottomMargin());
-        assertEquals(mDefaultMargin, customMarginPreferenceStyle.getHorizontalMargin());
-    }
-
-    @Test
-    @SmallTest
-    public void testCustomStyledPreference_WithTopMarginOnly() {
-        ContainerStyle topMarginOnlyPreferenceStyle =
-                getPreferenceStyle("preference_with_top_margin_only");
-        assertEquals(CUSTOM_TOP_MARGIN, topMarginOnlyPreferenceStyle.getTopMargin());
-        assertEquals(
-                mDefaultContainerVerticalMargin + mSectionBottomMargin,
-                topMarginOnlyPreferenceStyle.getBottomMargin());
-        assertEquals(mDefaultMargin, topMarginOnlyPreferenceStyle.getHorizontalMargin());
-    }
-
-    @Test
-    @SmallTest
-    public void testCustomStyledPreference_WithBottomMarginOnly() {
-        ContainerStyle bottomMarginOnlyPreferenceStyle =
-                getPreferenceStyle("preference_with_bottom_margin_only");
-        assertEquals(
-                mDefaultContainerVerticalMargin, bottomMarginOnlyPreferenceStyle.getTopMargin());
-        assertEquals(CUSTOM_BOTTOM_MARGIN, bottomMarginOnlyPreferenceStyle.getBottomMargin());
-        assertEquals(mDefaultMargin, bottomMarginOnlyPreferenceStyle.getHorizontalMargin());
-    }
-
-    @Test
-    @SmallTest
-    public void testCustomStyledPreference_WithBottomAndHorizontalMargin() {
-        ContainerStyle bottomAndHorizontalMarginsPreferenceStyle =
-                getPreferenceStyle("preference_with_bottom_and_horizontal_margins");
-        assertEquals(
-                mDefaultContainerVerticalMargin,
-                bottomAndHorizontalMarginsPreferenceStyle.getTopMargin());
-        assertEquals(
-                CUSTOM_BOTTOM_MARGIN, bottomAndHorizontalMarginsPreferenceStyle.getBottomMargin());
-        assertEquals(
-                CUSTOM_HORIZONTAL_MARGIN,
-                bottomAndHorizontalMarginsPreferenceStyle.getHorizontalMargin());
-    }
-
-    @Test
-    @SmallTest
     public void testGenerateViewStyles_Layout() {
-        List<View> views = List.of(new View(mContext), new View(mContext), new View(mContext));
+        List<View> views =
+                List.of(
+                        new CustomView(mContext, BackgroundStyle.STANDARD),
+                        new CustomView(mContext, BackgroundStyle.STANDARD),
+                        new CustomView(mContext, BackgroundStyle.STANDARD));
         ArrayList<ContainerStyle> viewStyles = mController.generateViewStyles(views);
 
         // Top view style
@@ -278,7 +232,7 @@
         List<View> views =
                 List.of(
                         new CustomView(mContext, BackgroundStyle.NONE),
-                        new View(mContext),
+                        new CustomView(mContext, BackgroundStyle.STANDARD),
                         new CustomView(mContext, BackgroundStyle.NONE));
         ArrayList<ContainerStyle> viewStyles = mController.generateViewStyles(views);
 
@@ -314,87 +268,6 @@
                 cardStyle.getBottomMargin());
     }
 
-    private ChromeBasePreference createCustomPreference(
-            @BackgroundStyle int backgroundStyle,
-            int topMargin,
-            int bottomMargin,
-            int horizontalMargin,
-            int backgroundColor) {
-        return new ChromeBasePreference(mContext, null) {
-            @Override
-            public int getCustomBackgroundStyle() {
-                return backgroundStyle;
-            }
-
-            @Override
-            public int getCustomTopMargin() {
-                return topMargin;
-            }
-
-            @Override
-            public int getCustomBottomMargin() {
-                return bottomMargin;
-            }
-
-            @Override
-            public int getCustomHorizontalMargin() {
-                return horizontalMargin;
-            }
-
-            @Override
-            public int getCustomBackgroundColor() {
-                return backgroundColor;
-            }
-        };
-    }
-
-    private void addPreferencesWithCustomMargins() {
-        // Scenario 1: Custom top and bottom margins
-        ChromeBasePreference customMarginsPreference =
-                createCustomPreference(
-                        BackgroundStyle.CARD,
-                        CUSTOM_TOP_MARGIN,
-                        CUSTOM_BOTTOM_MARGIN,
-                        DEFAULT_MARGIN,
-                        DEFAULT_COLOR);
-        customMarginsPreference.setKey("preference_with_custom_margins");
-        mPreferenceScreen.addPreference(customMarginsPreference);
-
-        // Scenario 2: Custom top margin only
-        ChromeBasePreference topMarginOnlyPreference =
-                createCustomPreference(
-                        BackgroundStyle.CARD,
-                        CUSTOM_TOP_MARGIN,
-                        DEFAULT_MARGIN,
-                        DEFAULT_MARGIN,
-                        DEFAULT_COLOR);
-        topMarginOnlyPreference.setKey("preference_with_top_margin_only");
-        mPreferenceScreen.addPreference(topMarginOnlyPreference);
-
-        // Scenario 3: Custom bottom margin only
-        ChromeBasePreference bottomMarginOnlyPreference =
-                createCustomPreference(
-                        BackgroundStyle.CARD,
-                        DEFAULT_MARGIN,
-                        CUSTOM_BOTTOM_MARGIN,
-                        DEFAULT_MARGIN,
-                        DEFAULT_COLOR);
-        bottomMarginOnlyPreference.setKey("preference_with_bottom_margin_only");
-        mPreferenceScreen.addPreference(bottomMarginOnlyPreference);
-
-        // Scenario 4: Custom bottom and horizontal margins
-        ChromeBasePreference bottomAndHorizontalMarginsPreference =
-                createCustomPreference(
-                        BackgroundStyle.CARD,
-                        DEFAULT_MARGIN,
-                        CUSTOM_BOTTOM_MARGIN,
-                        CUSTOM_HORIZONTAL_MARGIN,
-                        DEFAULT_COLOR);
-        bottomAndHorizontalMarginsPreference.setKey(
-                "preference_with_bottom_and_horizontal_margins");
-        mPreferenceScreen.addPreference(bottomAndHorizontalMarginsPreference);
-    }
-
     private ContainerStyle getPreferenceStyle(String key) {
         Preference preference = mPreferenceScreen.findPreference(key);
         int preferenceIndex = mVisiblePreferences.indexOf(preference);
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/containment/ContainmentViewStyler.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/containment/ContainmentViewStyler.java
index b8f6b9161..0d466af 100644
--- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/containment/ContainmentViewStyler.java
+++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/containment/ContainmentViewStyler.java
@@ -51,6 +51,10 @@
                 style.getHorizontalMargin(),
                 style.getBottomMargin());
         view.setLayoutParams(layoutParams);
+
+        if (style.getMinHeight() != ContainmentItem.DEFAULT_VALUE) {
+            view.setMinimumHeight(style.getMinHeight());
+        }
     }
 
     /**
diff --git a/components/contextual_search/contextual_search_service_unittest.cc b/components/contextual_search/contextual_search_service_unittest.cc
index 202d9de..0bfccc8 100644
--- a/components/contextual_search/contextual_search_service_unittest.cc
+++ b/components/contextual_search/contextual_search_service_unittest.cc
@@ -5,6 +5,7 @@
 #include "components/contextual_search/contextual_search_service.h"
 
 #include "base/test/task_environment.h"
+#include "components/contextual_search/contextual_search_types.h"
 #include "components/contextual_search/fake_variations_client.h"
 #include "components/contextual_search/mock_contextual_search_context_controller.h"
 #include "components/search_engines/search_engines_test_environment.h"
@@ -218,4 +219,152 @@
   EXPECT_TRUE(session_handle->GetSubmittedContextTokens().empty());
 }
 
+TEST_F(ContextualSearchServiceTest, FileInfoTest) {
+  auto mock_controller =
+      std::make_unique<MockContextualSearchContextController>();
+  auto metrics_recorder = std::make_unique<ContextualSearchMetricsRecorder>(
+      ContextualSearchSource::kUnknown);
+
+  MockContextualSearchContextController* mock_controller_ptr =
+      mock_controller.get();
+
+  auto session_handle = service_->CreateSessionForTesting(
+      std::move(mock_controller), std::move(metrics_recorder));
+
+  // Create tokens and FileInfo objects.
+  base::UnguessableToken token1 = base::UnguessableToken::Create();
+  FileInfo file_info1;
+  file_info1.file_token = token1;
+  file_info1.file_name = "file1.pdf";
+
+  base::UnguessableToken token2 = base::UnguessableToken::Create();
+  FileInfo file_info2;
+  file_info2.file_token = token2;
+  file_info2.file_name = "file2.jpg";
+
+  base::UnguessableToken tab_token1 = base::UnguessableToken::Create();
+  FileInfo tab_info1;
+  tab_info1.file_token = tab_token1;
+  tab_info1.tab_url = GURL("http://example.com/tab1");
+  tab_info1.tab_title = "Tab 1 Title";
+  tab_info1.tab_session_id = SessionID::FromSerializedValue(123);
+
+  base::UnguessableToken tab_token2 = base::UnguessableToken::Create();
+  FileInfo tab_info2;
+  tab_info2.file_token = tab_token2;
+  tab_info2.tab_url = GURL("http://example.com/tab2");
+  tab_info2.tab_title = "Tab 2 Title";
+  tab_info2.tab_session_id = SessionID::FromSerializedValue(456);
+
+  // Mock GetFileInfo.
+  EXPECT_CALL(*mock_controller_ptr, GetFileInfo(token1))
+      .WillRepeatedly(testing::Return(&file_info1));
+  EXPECT_CALL(*mock_controller_ptr, GetFileInfo(token2))
+      .WillRepeatedly(testing::Return(&file_info2));
+  EXPECT_CALL(*mock_controller_ptr, GetFileInfo(tab_token1))
+      .WillRepeatedly(testing::Return(&tab_info1));
+  EXPECT_CALL(*mock_controller_ptr, GetFileInfo(tab_token2))
+      .WillRepeatedly(testing::Return(&tab_info2));
+
+  // Test GetUploadedContextFileInfos.
+  session_handle->GetUploadedContextTokensForTesting().push_back(token1);
+  session_handle->GetUploadedContextTokensForTesting().push_back(tab_token1);
+  std::vector<FileInfo> uploaded_infos =
+      session_handle->GetUploadedContextFileInfos();
+  ASSERT_EQ(uploaded_infos.size(), 2u);
+  EXPECT_THAT(uploaded_infos,
+              testing::UnorderedElementsAre(
+                  testing::Field(&FileInfo::file_token, token1),
+                  testing::Field(&FileInfo::file_token, tab_token1)));
+
+  session_handle->GetUploadedContextTokensForTesting().push_back(token2);
+  session_handle->GetUploadedContextTokensForTesting().push_back(tab_token2);
+  uploaded_infos = session_handle->GetUploadedContextFileInfos();
+  EXPECT_THAT(uploaded_infos,
+              testing::UnorderedElementsAre(
+                  testing::Field(&FileInfo::file_token, token1),
+                  testing::Field(&FileInfo::file_token, token2),
+                  testing::Field(&FileInfo::file_token, tab_token1),
+                  testing::Field(&FileInfo::file_token, tab_token2)));
+
+  // Test GetSubmittedContextFileInfos (after moving tokens).
+  EXPECT_CALL(*mock_controller_ptr, CreateClientToAimRequest(_))
+      .WillOnce(testing::Invoke(
+          this, &ContextualSearchServiceTest::CaptureClientToAimRequest));
+
+  auto create_client_to_aim_request_info = std::make_unique<
+      ContextualSearchContextController::CreateClientToAimRequestInfo>();
+  session_handle->CreateClientToAimRequest(
+      std::move(create_client_to_aim_request_info));
+
+  std::vector<FileInfo> submitted_infos =
+      session_handle->GetSubmittedContextFileInfos();
+  EXPECT_THAT(submitted_infos,
+              testing::UnorderedElementsAre(
+                  testing::Field(&FileInfo::file_token, token1),
+                  testing::Field(&FileInfo::file_token, token2),
+                  testing::Field(&FileInfo::file_token, tab_token1),
+                  testing::Field(&FileInfo::file_token, tab_token2)));
+
+  // Also check that uploaded files is now empty.
+  uploaded_infos = session_handle->GetUploadedContextFileInfos();
+  EXPECT_TRUE(uploaded_infos.empty());
+
+  // Add a new file to uploaded, and make sure submitted remains the same.
+  base::UnguessableToken token3 = base::UnguessableToken::Create();
+  FileInfo file_info3;
+  file_info3.file_token = token3;
+  file_info3.file_name = "file3.png";
+
+  EXPECT_CALL(*mock_controller_ptr, GetFileInfo(token3))
+      .WillRepeatedly(testing::Return(&file_info3));
+
+  session_handle->GetUploadedContextTokensForTesting().push_back(token3);
+
+  uploaded_infos = session_handle->GetUploadedContextFileInfos();
+  ASSERT_EQ(uploaded_infos.size(), 1u);
+  EXPECT_EQ(uploaded_infos[0].file_token, token3);
+
+  submitted_infos = session_handle->GetSubmittedContextFileInfos();
+  EXPECT_THAT(submitted_infos,
+              testing::UnorderedElementsAre(
+                  testing::Field(&FileInfo::file_token, token1),
+                  testing::Field(&FileInfo::file_token, token2),
+                  testing::Field(&FileInfo::file_token, tab_token1),
+                  testing::Field(&FileInfo::file_token, tab_token2)));
+
+  // Test that a token with no FileInfo is ignored.
+  base::UnguessableToken token4 = base::UnguessableToken::Create();
+  EXPECT_CALL(*mock_controller_ptr, GetFileInfo(token4))
+      .WillRepeatedly(testing::Return(nullptr));
+  session_handle->GetUploadedContextTokensForTesting().push_back(token4);
+  uploaded_infos = session_handle->GetUploadedContextFileInfos();
+  ASSERT_EQ(uploaded_infos.size(), 1u);
+  EXPECT_EQ(uploaded_infos[0].file_token, token3);
+}
+
+TEST_F(ContextualSearchServiceTest, NullController) {
+  // Create a session.
+  auto config_params =
+      std::make_unique<ContextualSearchContextController::ConfigParams>();
+  auto session_handle = service_->CreateSession(
+      std::move(config_params), ContextualSearchSource::kUnknown);
+  ASSERT_THAT(session_handle, NotNull());
+
+  // Add some dummy tokens.
+  session_handle->GetUploadedContextTokensForTesting().push_back(
+      base::UnguessableToken::Create());
+  auto create_client_to_aim_request_info = std::make_unique<
+      ContextualSearchContextController::CreateClientToAimRequestInfo>();
+  session_handle->CreateClientToAimRequest(
+      std::move(create_client_to_aim_request_info));
+
+  // Destroy the service. This will cause GetController() to return nullptr.
+  service_.reset();
+
+  // These calls should not crash.
+  EXPECT_TRUE(session_handle->GetUploadedContextFileInfos().empty());
+  EXPECT_TRUE(session_handle->GetSubmittedContextFileInfos().empty());
+}
+
 }  // namespace contextual_search
diff --git a/components/contextual_search/contextual_search_session_handle.cc b/components/contextual_search/contextual_search_session_handle.cc
index c7ade2409..a4b7155 100644
--- a/components/contextual_search/contextual_search_session_handle.cc
+++ b/components/contextual_search/contextual_search_session_handle.cc
@@ -4,6 +4,8 @@
 
 #include "components/contextual_search/contextual_search_session_handle.h"
 
+#include <vector>
+
 #include "base/memory/ptr_util.h"
 #include "base/unguessable_token.h"
 #include "components/contextual_search/contextual_search_context_controller.h"
@@ -11,9 +13,32 @@
 #include "components/contextual_search/contextual_search_service.h"
 #include "components/lens/contextual_input.h"
 #include "components/lens/proto/server/lens_overlay_response.pb.h"
+#include "contextual_search_context_controller.h"
+#include "contextual_search_types.h"
 
 namespace contextual_search {
 
+namespace {
+
+std::vector<FileInfo> TokensToFileInfos(
+    ContextualSearchContextController* controller,
+    const std::vector<base::UnguessableToken>& tokens) {
+  std::vector<FileInfo> file_infos;
+  if (!controller) {
+    return file_infos;
+  }
+  for (const auto& token : tokens) {
+    const auto* file_info = controller->GetFileInfo(token);
+    if (!file_info) {
+      continue;
+    }
+    file_infos.push_back(*file_info);
+  }
+  return file_infos;
+}
+
+}  // namespace
+
 ContextualSearchSessionHandle::ContextualSearchSessionHandle(
     base::WeakPtr<ContextualSearchService> service,
     const base::UnguessableToken& session_id)
@@ -261,6 +286,16 @@
   return submitted_context_tokens_;
 }
 
+std::vector<FileInfo>
+ContextualSearchSessionHandle::GetUploadedContextFileInfos() const {
+  return TokensToFileInfos(GetController(), uploaded_context_tokens_);
+}
+
+std::vector<FileInfo>
+ContextualSearchSessionHandle::GetSubmittedContextFileInfos() const {
+  return TokensToFileInfos(GetController(), submitted_context_tokens_);
+}
+
 void ContextualSearchSessionHandle::ClearSubmittedContextTokens() {
   submitted_context_tokens_.clear();
 }
diff --git a/components/contextual_search/contextual_search_session_handle.h b/components/contextual_search/contextual_search_session_handle.h
index cad6d0e..16bf9f2 100644
--- a/components/contextual_search/contextual_search_session_handle.h
+++ b/components/contextual_search/contextual_search_session_handle.h
@@ -115,6 +115,10 @@
   // particular instance of the session.
   std::vector<base::UnguessableToken> GetUploadedContextTokens() const;
 
+  // Returns the list of uploaded but not yet committed FileInfo for this
+  // particular instance of the session.
+  std::vector<FileInfo> GetUploadedContextFileInfos() const;
+
   // Returns the list of uploaded but not yet committed context tokens for this
   // particular instance of the session, editable for testing.
   std::vector<base::UnguessableToken>& GetUploadedContextTokensForTesting() {
@@ -131,6 +135,11 @@
   // that it has received the submitted context.
   void ClearSubmittedContextTokens();
 
+  // Returns the list of submitted FileInfo for this particular instance
+  // of the session. These are uploaded and submitted, but we have not received
+  // confirmation that they are available on the server.
+  std::vector<FileInfo> GetSubmittedContextFileInfos() const;
+
  private:
   friend class ContextualSearchService;
   friend class MockContextualSearchSessionHandle;
diff --git a/components/contextual_search/contextual_search_types.cc b/components/contextual_search/contextual_search_types.cc
index 9115213a..09757dab 100644
--- a/components/contextual_search/contextual_search_types.cc
+++ b/components/contextual_search/contextual_search_types.cc
@@ -7,6 +7,8 @@
 namespace contextual_search {
 
 FileInfo::FileInfo() = default;
+FileInfo::FileInfo(const FileInfo& other) = default;
+FileInfo& FileInfo::operator=(const FileInfo& other) = default;
 FileInfo::~FileInfo() = default;
 
 }  // namespace contextual_search
diff --git a/components/contextual_search/contextual_search_types.h b/components/contextual_search/contextual_search_types.h
index 67d04e6..9c10ac2 100644
--- a/components/contextual_search/contextual_search_types.h
+++ b/components/contextual_search/contextual_search_types.h
@@ -62,6 +62,8 @@
 struct FileInfo {
  public:
   FileInfo();
+  FileInfo(const FileInfo& other);
+  FileInfo& operator=(const FileInfo& other);
   virtual ~FileInfo();
 
   // Client-side unique identifier.
diff --git a/components/omnibox/browser/url_index_private_data.cc b/components/omnibox/browser/url_index_private_data.cc
index 99cf855..34d585a1 100644
--- a/components/omnibox/browser/url_index_private_data.cc
+++ b/components/omnibox/browser/url_index_private_data.cc
@@ -16,6 +16,8 @@
 #include <utility>
 #include <vector>
 
+#include "base/check.h"
+#include "base/check_op.h"
 #include "base/containers/flat_set.h"
 #include "base/containers/stack.h"
 #include "base/debug/crash_logging.h"
@@ -780,7 +782,7 @@
   HistoryID history_id = static_cast<HistoryID>(row.id());
   // Split URL into individual, unique words then add in the title words.
   const GURL& gurl(row.url());
-  DCHECK(gurl.is_valid());
+  CHECK(gurl.is_valid());
   const std::u16string& url = omnibox::CleanUpUrlForMatching(gurl, nullptr);
   String16Set url_words = String16SetFromString16(
       url, word_starts ? &word_starts->url_word_starts_ : nullptr);
@@ -789,10 +791,10 @@
       title, word_starts ? &word_starts->title_word_starts_ : nullptr);
   for (const auto& word :
        base::STLSetUnion<String16Set>(url_words, title_words)) {
-    // Speculative fix for crbug.com/348617573.
-    if (word.empty()) {
-      continue;
-    }
+    CHECK(!word.empty());
+    // Confirm no corruption after `CleanUpTitleForMatching()` above, which
+    // limits to `kCleanedUpTitleMaxLength` (1024).
+    CHECK_LT(word.length(), 1024u);
     // Some crash keys if the fix doesn't work.
     SCOPED_CRASH_KEY_STRING256("Bug348617573", "url", gurl.spec());
     SCOPED_CRASH_KEY_STRING32("Bug348617573", "word", base::UTF16ToUTF8(word));
diff --git a/components/optimization_guide/internal b/components/optimization_guide/internal
index b8ccce3..81611cb 160000
--- a/components/optimization_guide/internal
+++ b/components/optimization_guide/internal
@@ -1 +1 @@
-Subproject commit b8ccce3600d400ae32ed129caa42fdf0282b0118
+Subproject commit 81611cb4974460c7328b226e2d44d79ea2023304
diff --git a/components/performance_manager/freezing/freezing_policy.cc b/components/performance_manager/freezing/freezing_policy.cc
index c692615..26cd948e 100644
--- a/components/performance_manager/freezing/freezing_policy.cc
+++ b/components/performance_manager/freezing/freezing_policy.cc
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/byte_count.h"
+#include "base/byte_size.h"
 #include "base/check.h"
 #include "base/containers/contains.h"
 #include "base/containers/enum_set.h"
@@ -1425,8 +1426,8 @@
   const int kPressureThresholdPercent =
       features::kInfiniteTabsFreezingOnMemoryPressurePercent.Get();
 
-  base::ByteCount total = info.total;
-  base::ByteCount avail = info.avail_phys;
+  base::ByteSize total = info.total;
+  base::ByteSize avail = info.avail_phys;
 
   int available_percent = 0;
   if (total.is_positive()) {
diff --git a/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc b/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc
index a5bd8ea..02bd47dc 100644
--- a/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc
+++ b/components/safe_browsing/core/browser/safe_browsing_url_checker_impl.cc
@@ -281,9 +281,6 @@
                   perfetto::Track::FromPointer(this), "url", url.spec());
 
   const bool is_prefetch = (load_flags_ & net::LOAD_PREFETCH);
-  base::UmaHistogramBoolean("SafeBrowsing.CheckUrl.IsDocumentCheckPrefetch",
-                            is_prefetch);
-
   // Handle main frame and subresources. We do this to catch resources flagged
   // as phishing even if the top frame isn't flagged.
   if (!is_prefetch && threat_type == SB_THREAT_TYPE_URL_PHISHING &&
diff --git a/components/search/BUILD.gn b/components/search/BUILD.gn
index dba3c53..09836b8 100644
--- a/components/search/BUILD.gn
+++ b/components/search/BUILD.gn
@@ -35,7 +35,6 @@
     "//components/search_engines",
     "//components/signin/public/identity_manager",
     "//net",
-    "//services/data_decoder/public/cpp",
     "//services/network/public/cpp",
     "//url",
   ]
@@ -62,7 +61,6 @@
     "//components/search_engines:test_support",
     "//components/signin/public/base:test_support",
     "//components/signin/public/identity_manager:test_support",
-    "//services/data_decoder/public/cpp:test_support",
     "//testing/gmock",
     "//testing/gtest",
   ]
diff --git a/components/search/DEPS b/components/search/DEPS
index 37b9445c..5ac4f8f 100644
--- a/components/search/DEPS
+++ b/components/search/DEPS
@@ -3,7 +3,6 @@
   "+components/omnibox/browser",
   "+components/search_engines",
   "+net",
-  "+services/data_decoder/public",
   "+services/network/public",
   "+services/network/test",
 ]
diff --git a/components/search/start_suggest_service.cc b/components/search/start_suggest_service.cc
index fede312..73cf8b5 100644
--- a/components/search/start_suggest_service.cc
+++ b/components/search/start_suggest_service.cc
@@ -12,6 +12,7 @@
 
 #include "base/functional/bind.h"
 #include "base/functional/callback_helpers.h"
+#include "base/json/json_reader.h"
 #include "base/rand_util.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
@@ -198,36 +199,29 @@
     *response = response->substr(strlen(kXSSIResponsePreamble));
   }
 
-  data_decoder::DataDecoder::ParseJsonIsolated(
-      *response,
-      base::BindOnce(&StartSuggestService::SuggestionsParsed,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
+  base::JSONReader::Result result =
+      base::JSONReader::ReadAndReturnValueWithError(*response,
+                                                    base::JSON_PARSE_RFC);
 
-void StartSuggestService::SuggestionsParsed(
-    SuggestResultCallback callback,
-    data_decoder::DataDecoder::ValueOrError result) {
-  std::move(callback).Run([&] {
-    QuerySuggestions query_suggestions;
-    if (result.has_value() && result.value().is_list()) {
-      SearchSuggestionParser::Results results;
-      AutocompleteInput input;
-      if (SearchSuggestionParser::ParseSuggestResults(
-              result->GetList(), input, *scheme_classifier_,
-              /*default_result_relevance=*/-1, /*is_keyword_result=*/false,
-              &results)) {
-        for (SearchSuggestionParser::SuggestResult suggest :
-             results.suggest_results) {
-          QuerySuggestion query;
-          query.query = suggest.suggestion();
-          query.destination_url = GetQueryDestinationURL(
-              query.query, template_url_service_->GetDefaultSearchProvider());
-          query_suggestions.push_back(std::move(query));
-        }
-        suggestions_cache_[kTrendingQuerySuggestionCachedResults] =
-            query_suggestions;
+  QuerySuggestions query_suggestions;
+  if (result.has_value() && result.value().is_list()) {
+    SearchSuggestionParser::Results results;
+    AutocompleteInput input;
+    if (SearchSuggestionParser::ParseSuggestResults(
+            result->GetList(), input, *scheme_classifier_,
+            /*default_result_relevance=*/-1, /*is_keyword_result=*/false,
+            &results)) {
+      for (SearchSuggestionParser::SuggestResult suggest :
+           results.suggest_results) {
+        QuerySuggestion query;
+        query.query = suggest.suggestion();
+        query.destination_url = GetQueryDestinationURL(
+            query.query, template_url_service_->GetDefaultSearchProvider());
+        query_suggestions.push_back(std::move(query));
       }
+      suggestions_cache_[kTrendingQuerySuggestionCachedResults] =
+          query_suggestions;
     }
-    return query_suggestions;
-  }());
+  }
+  std::move(callback).Run(std::move(query_suggestions));
 }
diff --git a/components/search/start_suggest_service.h b/components/search/start_suggest_service.h
index 38201cd..d450f19 100644
--- a/components/search/start_suggest_service.h
+++ b/components/search/start_suggest_service.h
@@ -17,7 +17,6 @@
 #include "base/observer_list.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/search_engines/template_url.h"
-#include "services/data_decoder/public/cpp/data_decoder.h"
 #include "url/gurl.h"
 
 class AutocompleteSchemeClassifier;
@@ -85,8 +84,6 @@
   void SuggestResponseLoaded(network::SimpleURLLoader* loader,
                              SuggestResultCallback callback,
                              std::optional<std::string> response);
-  void SuggestionsParsed(SuggestResultCallback callback,
-                         data_decoder::DataDecoder::ValueOrError result);
 
   // Cannot be null. Must outlive `this`.
   raw_ptr<TemplateURLService> template_url_service_;
diff --git a/components/search/start_suggest_service_unittest.cc b/components/search/start_suggest_service_unittest.cc
index ef97a639..eb754c5 100644
--- a/components/search/start_suggest_service_unittest.cc
+++ b/components/search/start_suggest_service_unittest.cc
@@ -14,7 +14,6 @@
 #include "components/search/search_provider_observer.h"
 #include "components/search_engines/search_engines_test_environment.h"
 #include "components/search_engines/template_url_service.h"
-#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/test/test_url_loader_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -166,7 +165,6 @@
   base::test::TaskEnvironment task_environment_{
       base::test::SingleThreadTaskEnvironment::MainThreadType::UI};
   search_engines::SearchEnginesTestEnvironment search_engines_test_environment_;
-  data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
   network::TestURLLoaderFactory test_url_loader_factory_;
   std::unique_ptr<TestStartSuggestService> service_;
 
diff --git a/components/services/storage/dom_storage/async_dom_storage_database.cc b/components/services/storage/dom_storage/async_dom_storage_database.cc
index 53c91d8..42c8fa6 100644
--- a/components/services/storage/dom_storage/async_dom_storage_database.cc
+++ b/components/services/storage/dom_storage/async_dom_storage_database.cc
@@ -10,24 +10,40 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/stringprintf.h"
 #include "base/task/sequenced_task_runner.h"
+#include "base/task/thread_pool.h"
 #include "components/services/storage/dom_storage/leveldb/dom_storage_batch_operation_leveldb.h"
 #include "third_party/leveldatabase/env_chromium.h"
 
 namespace storage {
 
 // static
+scoped_refptr<base::SequencedTaskRunner>
+AsyncDomStorageDatabase::GetTaskRunnerForDb(const base::FilePath& directory,
+                                            const std::string& dbname) {
+  CHECK(!directory.empty());
+  return base::ThreadPool::CreateSequencedTaskRunnerForResource(
+      {base::MayBlock(), base::WithBaseSyncPrimitives(),
+       base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
+      directory.AppendASCII(dbname));
+}
+
+// static
 std::unique_ptr<AsyncDomStorageDatabase> AsyncDomStorageDatabase::Open(
     StorageType storage_type,
     const base::FilePath& directory,
     const std::string& dbname,
     const std::optional<base::trace_event::MemoryAllocatorDumpGuid>&
         memory_dump_id,
-    scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
     StatusCallback callback) {
   std::unique_ptr<AsyncDomStorageDatabase> db(new AsyncDomStorageDatabase);
   DomStorageDatabaseFactory::Open(
       storage_type, directory, dbname, memory_dump_id,
-      std::move(blocking_task_runner),
+      // For the in-memory case, blocking shutdown is only important to avoid
+      // leaking the SequenceBound on shutdown (and triggering ASAN failures).
+      directory.empty() ? base::ThreadPool::CreateSequencedTaskRunner(
+                              {base::WithBaseSyncPrimitives(),
+                               base::TaskShutdownBehavior::BLOCK_SHUTDOWN})
+                        : GetTaskRunnerForDb(directory, dbname),
       base::BindOnce(&AsyncDomStorageDatabase::OnDatabaseOpened,
                      db->weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
   return db;
diff --git a/components/services/storage/dom_storage/async_dom_storage_database.h b/components/services/storage/dom_storage/async_dom_storage_database.h
index a7754e2c..8aaa95d 100644
--- a/components/services/storage/dom_storage/async_dom_storage_database.h
+++ b/components/services/storage/dom_storage/async_dom_storage_database.h
@@ -55,11 +55,17 @@
 
   ~AsyncDomStorageDatabase();
 
-  // Creates an `AsyncDomStorageDatabase` then posts a task to open the database
-  // on `blocking_task_runner`. Callers may immediately start using the
-  // returned `AsyncDomStorageDatabase`. Runs `callback` with the open database
-  // result. After failing to open, `AsyncDomStorageDatabase` must be
-  // discarded because no database tasks will run.
+  // May only be called on a non-empty `directory`. This will always return the
+  // same task runner for a given `directory` and `dbname`.
+  static scoped_refptr<base::SequencedTaskRunner> GetTaskRunnerForDb(
+      const base::FilePath& directory,
+      const std::string& dbname);
+
+  // Creates an `AsyncDomStorageDatabase` then asynchronously opens the
+  // database. Callers may immediately start using the returned
+  // `AsyncDomStorageDatabase`. Runs `callback` with the open database result.
+  // After failing to open, `AsyncDomStorageDatabase` must be discarded because
+  // no database tasks will run.
   //
   // To create an in-memory database, provide an empty `directory`.
   static std::unique_ptr<AsyncDomStorageDatabase> Open(
@@ -68,7 +74,6 @@
       const std::string& dbname,
       const std::optional<base::trace_event::MemoryAllocatorDumpGuid>&
           memory_dump_id,
-      scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
       StatusCallback callback);
 
   // Represents a batch of changes from a single commit source. There will be
diff --git a/components/services/storage/dom_storage/async_dom_storage_database_unittest.cc b/components/services/storage/dom_storage/async_dom_storage_database_unittest.cc
index c3d5e71c..b919a5c 100644
--- a/components/services/storage/dom_storage/async_dom_storage_database_unittest.cc
+++ b/components/services/storage/dom_storage/async_dom_storage_database_unittest.cc
@@ -166,20 +166,13 @@
       },
   };
 
-  // Start the database open task.
-  scoped_refptr<base::SequencedTaskRunner> database_task_runner =
-      base::ThreadPool::CreateSequencedTaskRunner(
-          {base::MayBlock(), base::WithBaseSyncPrimitives(),
-           base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
-
   // Open an in-memory LevelDB.
   base::test::TestFuture<DbStatus> open_status_future;
   std::unique_ptr<AsyncDomStorageDatabase> database =
       AsyncDomStorageDatabase::Open(
           StorageType::kLocalStorage, /*directory=*/base::FilePath(),
           "TestPendingTasks",
-          /*memory_dump_id=*/std::nullopt, database_task_runner,
-          open_status_future.GetCallback());
+          /*memory_dump_id=*/std::nullopt, open_status_future.GetCallback());
 
   // Immediately start using the database, which will enqueue pending tasks
   // while opening.
diff --git a/components/services/storage/dom_storage/local_storage_impl.cc b/components/services/storage/dom_storage/local_storage_impl.cc
index d885fcf..3611b811 100644
--- a/components/services/storage/dom_storage/local_storage_impl.cc
+++ b/components/services/storage/dom_storage/local_storage_impl.cc
@@ -30,8 +30,6 @@
 #include "base/strings/string_view_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/system/sys_info.h"
-#include "base/task/sequenced_task_runner.h"
-#include "base/task/single_thread_task_runner.h"
 #include "base/task/thread_pool.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "build/build_config.h"
@@ -210,20 +208,17 @@
 
 LocalStorageImpl::LocalStorageImpl(
     const base::FilePath& storage_root,
-    scoped_refptr<base::SequencedTaskRunner> task_runner,
     DestructLocalStorageCallback destruct_callback,
     mojo::PendingReceiver<mojom::LocalStorageControl> receiver)
     : destruct_callback_(std::move(destruct_callback)),
       directory_(storage_root.empty() ? storage_root
                                       : storage_root.Append(kLocalStoragePath)),
-      database_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
-          {base::MayBlock(), base::WithBaseSyncPrimitives(),
-           base::TaskShutdownBehavior::BLOCK_SHUTDOWN})),
       memory_dump_id_(base::StringPrintf("LocalStorage/0x%" PRIXPTR,
                                          reinterpret_cast<uintptr_t>(this))) {
   base::trace_event::MemoryDumpManager::GetInstance()
       ->RegisterDumpProviderWithSequencedTaskRunner(
-          this, "LocalStorage", task_runner, MemoryDumpProvider::Options());
+          this, "LocalStorage", base::SequencedTaskRunner::GetCurrentDefault(),
+          MemoryDumpProvider::Options());
 
   if (receiver) {
     control_receiver_.Bind(std::move(receiver));
@@ -531,7 +526,7 @@
     in_memory_ = false;
     database_ = AsyncDomStorageDatabase::Open(
         StorageType::kLocalStorage, directory_, kLocalStorageLeveldbName,
-        memory_dump_id_, database_task_runner_,
+        memory_dump_id_,
         base::BindOnce(&LocalStorageImpl::OnDatabaseOpened,
                        weak_ptr_factory_.GetWeakPtr()));
     return;
@@ -542,7 +537,6 @@
   database_ = AsyncDomStorageDatabase::Open(
       StorageType::kLocalStorage,
       /*directory=*/base::FilePath(), "local-storage", memory_dump_id_,
-      database_task_runner_,
       base::BindOnce(&LocalStorageImpl::OnDatabaseOpened,
                      weak_ptr_factory_.GetWeakPtr()));
 }
@@ -606,12 +600,13 @@
 
   // If tried to recreate database on disk already, try again but this time
   // in memory.
-  if (tried_to_recreate_during_open_ && !in_memory_) {
+  if (tried_to_recreate_during_open_) {
+    if (in_memory_) {
+      // Give up completely, run without any database.
+      OnConnectionFinished();
+      return;
+    }
     recreate_in_memory = true;
-  } else if (tried_to_recreate_during_open_) {
-    // Give up completely, run without any database.
-    OnConnectionFinished();
-    return;
   }
 
   tried_to_recreate_during_open_ = true;
@@ -619,7 +614,9 @@
   // Destroy database, and try again.
   if (!in_memory_) {
     DomStorageDatabaseFactory::Destroy(
-        directory_, kLocalStorageLeveldbName, database_task_runner_,
+        directory_, kLocalStorageLeveldbName,
+        AsyncDomStorageDatabase::GetTaskRunnerForDb(directory_,
+                                                    kLocalStorageLeveldbName),
         base::BindOnce(&LocalStorageImpl::OnDBDestroyed,
                        weak_ptr_factory_.GetWeakPtr(), recreate_in_memory));
   } else {
@@ -760,9 +757,16 @@
   DCHECK(shutdown_complete_callback_);
   // Flush any final tasks on the DB task runner before invoking the callback.
   PurgeAllStorageAreas();
+  bool database_created = !!database_;
   database_.reset();
-  database_task_runner_->PostTaskAndReply(
-      FROM_HERE, base::DoNothing(), std::move(shutdown_complete_callback_));
+  if (database_created && !in_memory_) {
+    AsyncDomStorageDatabase::GetTaskRunnerForDb(directory_,
+                                                kLocalStorageLeveldbName)
+        ->PostTaskAndReply(FROM_HERE, base::DoNothing(),
+                           std::move(shutdown_complete_callback_));
+  } else {
+    std::move(shutdown_complete_callback_).Run();
+  }
 }
 
 void LocalStorageImpl::GetStatistics(size_t* total_cache_size,
diff --git a/components/services/storage/dom_storage/local_storage_impl.h b/components/services/storage/dom_storage/local_storage_impl.h
index abc74d3..fc5644b 100644
--- a/components/services/storage/dom_storage/local_storage_impl.h
+++ b/components/services/storage/dom_storage/local_storage_impl.h
@@ -17,7 +17,6 @@
 #include "base/functional/callback_forward.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/task/sequenced_task_runner.h"
 #include "base/threading/sequence_bound.h"
 #include "base/trace_event/memory_allocator_dump.h"
 #include "base/trace_event/memory_dump_provider.h"
@@ -48,13 +47,10 @@
   using DestructLocalStorageCallback =
       base::OnceCallback<void(LocalStorageImpl*)>;
   // Constructs a Local Storage implementation which will create its root
-  // "Local Storage" directory in |storage_root| if non-empty. |task_runner|
-  // run tasks on the same sequence as the one which constructs this object.
-  // |legacy_task_runner| must support blocking operations and its tasks must
-  // be able to block shutdown. If valid, |receiver| will be bound to this
-  // object to allow for remote control via the LocalStorageControl interface.
+  // "Local Storage" directory in |storage_root| if non-empty.If valid,
+  // |receiver| will be bound to this object to allow for remote control via the
+  // LocalStorageControl interface.
   LocalStorageImpl(const base::FilePath& storage_root,
-                   scoped_refptr<base::SequencedTaskRunner> task_runner,
                    DestructLocalStorageCallback destruct_callback,
                    mojo::PendingReceiver<mojom::LocalStorageControl> receiver);
   ~LocalStorageImpl() override;
@@ -172,8 +168,6 @@
 
   bool force_keep_session_state_ = false;
 
-  const scoped_refptr<base::SequencedTaskRunner> database_task_runner_;
-
   base::trace_event::MemoryAllocatorDumpGuid memory_dump_id_;
 
   std::unique_ptr<AsyncDomStorageDatabase> database_;
diff --git a/components/services/storage/dom_storage/local_storage_impl_unittest.cc b/components/services/storage/dom_storage/local_storage_impl_unittest.cc
index e63236a2..0f492bf 100644
--- a/components/services/storage/dom_storage/local_storage_impl_unittest.cc
+++ b/components/services/storage/dom_storage/local_storage_impl_unittest.cc
@@ -141,10 +141,9 @@
 
   void InitializeStorage(const base::FilePath& path) {
     DCHECK(!storage_);
-    storage_ = std::make_unique<LocalStorageImpl>(
-        path, base::SingleThreadTaskRunner::GetCurrentDefault(),
-        base::NullCallback(),
-        /*receiver=*/mojo::NullReceiver());
+    storage_ =
+        std::make_unique<LocalStorageImpl>(path, base::NullCallback(),
+                                           /*receiver=*/mojo::NullReceiver());
   }
 
   void ShutDownStorage() {
diff --git a/components/services/storage/dom_storage/session_storage_area_impl_unittest.cc b/components/services/storage/dom_storage/session_storage_area_impl_unittest.cc
index 5f10434..415b06d 100644
--- a/components/services/storage/dom_storage/session_storage_area_impl_unittest.cc
+++ b/components/services/storage/dom_storage/session_storage_area_impl_unittest.cc
@@ -65,9 +65,7 @@
     leveldb_database_ = AsyncDomStorageDatabase::Open(
         StorageType::kSessionStorage,
         /*directory=*/base::FilePath(), "SessionStorageAreaImplTestDatabase",
-        /*memory_dump_id=*/std::nullopt,
-        base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()}),
-        base::DoNothing());
+        /*memory_dump_id=*/std::nullopt, base::DoNothing());
     leveldb_database_->RunDatabaseTask(
         base::BindOnce([](DomStorageDatabaseLevelDB& db) {
           return db.Put(StdStringToUint8Vector("map-0-key1"),
diff --git a/components/services/storage/dom_storage/session_storage_data_map_unittest.cc b/components/services/storage/dom_storage/session_storage_data_map_unittest.cc
index 1cdde1b..d99574b4 100644
--- a/components/services/storage/dom_storage/session_storage_data_map_unittest.cc
+++ b/components/services/storage/dom_storage/session_storage_data_map_unittest.cc
@@ -81,7 +81,6 @@
         StorageType::kSessionStorage,
         /*directory=*/base::FilePath(), "SessionStorageDataMapTest",
         /*memory_dump_id=*/std::nullopt,
-        base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()}),
         base::BindLambdaForTesting([&](DbStatus status) {
           ASSERT_TRUE(status.ok());
           loop.Quit();
diff --git a/components/services/storage/dom_storage/session_storage_impl.cc b/components/services/storage/dom_storage/session_storage_impl.cc
index 6fb2ca4a..e6a13bd 100644
--- a/components/services/storage/dom_storage/session_storage_impl.cc
+++ b/components/services/storage/dom_storage/session_storage_impl.cc
@@ -94,8 +94,6 @@
 
 SessionStorageImpl::SessionStorageImpl(
     const base::FilePath& partition_directory,
-    scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
-    scoped_refptr<base::SequencedTaskRunner> memory_dump_task_runner,
     BackingMode backing_mode,
     std::string database_name,
     DestructSessionStorageCallback destruct_callback,
@@ -104,7 +102,6 @@
       backing_mode_(backing_mode),
       database_name_(std::move(database_name)),
       partition_directory_(partition_directory),
-      database_task_runner_(std::move(blocking_task_runner)),
       memory_dump_id_(base::StringPrintf("SessionStorage/0x%" PRIXPTR,
                                          reinterpret_cast<uintptr_t>(this))),
       receiver_(this, std::move(receiver)),
@@ -112,7 +109,8 @@
           base::SysInfo::IsLowEndDeviceOrPartialLowEndModeEnabled()) {
   base::trace_event::MemoryDumpManager::GetInstance()
       ->RegisterDumpProviderWithSequencedTaskRunner(
-          this, "SessionStorage", std::move(memory_dump_task_runner),
+          this, "SessionStorage",
+          base::SequencedTaskRunner::GetCurrentDefault(),
           base::trace_event::MemoryDumpProvider::Options());
   receiver_.set_disconnect_handler(
       base::BindOnce(&SessionStorageImpl::OnReceiverDisconnected,
@@ -762,15 +760,17 @@
       !partition_directory_.empty()) {
     // We were given a subdirectory to write to, so use a disk backed database.
     if (backing_mode_ == BackingMode::kClearDiskStateOnOpen) {
-      DomStorageDatabaseFactory::Destroy(partition_directory_, database_name_,
-                                         database_task_runner_,
-                                         base::DoNothing());
+      DomStorageDatabaseFactory::Destroy(
+          partition_directory_, database_name_,
+          AsyncDomStorageDatabase::GetTaskRunnerForDb(partition_directory_,
+                                                      database_name_),
+          base::DoNothing());
     }
 
     in_memory_ = false;
     database_ = AsyncDomStorageDatabase::Open(
         StorageType::kSessionStorage, partition_directory_, database_name_,
-        memory_dump_id_, database_task_runner_,
+        memory_dump_id_,
         base::BindOnce(&SessionStorageImpl::OnDatabaseOpened,
                        weak_ptr_factory_.GetWeakPtr()));
     return;
@@ -781,7 +781,6 @@
   database_ = AsyncDomStorageDatabase::Open(
       StorageType::kSessionStorage,
       /*directory=*/base::FilePath(), "SessionStorageDatabase", memory_dump_id_,
-      database_task_runner_,
       base::BindOnce(&SessionStorageImpl::OnDatabaseOpened,
                      weak_ptr_factory_.GetWeakPtr()));
 }
@@ -870,12 +869,13 @@
 
   // If tried to recreate database on disk already, try again but this time
   // in memory.
-  if (tried_to_recreate_during_open_ && !in_memory_) {
+  if (tried_to_recreate_during_open_) {
+    if (in_memory_) {
+      // Give up completely, run without any database.
+      OnConnectionFinished();
+      return;
+    }
     recreate_in_memory = true;
-  } else if (tried_to_recreate_during_open_) {
-    // Give up completely, run without any database.
-    OnConnectionFinished();
-    return;
   }
 
   tried_to_recreate_during_open_ = true;
@@ -885,7 +885,9 @@
   // Destroy database, and try again.
   if (!in_memory_) {
     DomStorageDatabaseFactory::Destroy(
-        partition_directory_, database_name_, database_task_runner_,
+        partition_directory_, database_name_,
+        AsyncDomStorageDatabase::GetTaskRunnerForDb(partition_directory_,
+                                                    database_name_),
         base::BindOnce(&SessionStorageImpl::OnDBDestroyed,
                        weak_ptr_factory_.GetWeakPtr(), recreate_in_memory));
   } else {
@@ -906,9 +908,16 @@
   DCHECK(shutdown_complete_callback_);
   // Flush any final tasks on the DB task runner before invoking the callback.
   PurgeAllNamespaces();
+  bool database_created = !!database_;
   database_.reset();
-  database_task_runner_->PostTaskAndReply(
-      FROM_HERE, base::DoNothing(), std::move(shutdown_complete_callback_));
+  if (database_created && !in_memory_) {
+    AsyncDomStorageDatabase::GetTaskRunnerForDb(partition_directory_,
+                                                database_name_)
+        ->PostTaskAndReply(FROM_HERE, base::DoNothing(),
+                           std::move(shutdown_complete_callback_));
+  } else {
+    std::move(shutdown_complete_callback_).Run();
+  }
 }
 
 void SessionStorageImpl::GetStatistics(size_t* total_cache_size,
diff --git a/components/services/storage/dom_storage/session_storage_impl.h b/components/services/storage/dom_storage/session_storage_impl.h
index 18cf9fd..3cd9c71 100644
--- a/components/services/storage/dom_storage/session_storage_impl.h
+++ b/components/services/storage/dom_storage/session_storage_impl.h
@@ -32,10 +32,6 @@
 #include "storage/common/database/db_status.h"
 #include "third_party/blink/public/mojom/dom_storage/session_storage_namespace.mojom.h"
 
-namespace base {
-class SequencedTaskRunner;
-}  // namespace base
-
 namespace blink {
 class StorageKey;
 }  // namespace blink
@@ -70,8 +66,6 @@
       base::OnceCallback<void(SessionStorageImpl*)>;
   SessionStorageImpl(
       const base::FilePath& partition_directory,
-      scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
-      scoped_refptr<base::SequencedTaskRunner> memory_dump_task_runner,
       BackingMode backing_option,
       std::string database_name,
       DestructSessionStorageCallback destruct_callback,
@@ -221,13 +215,15 @@
   } connection_state_ = NO_CONNECTION;
 
   const base::FilePath partition_directory_;
-  const scoped_refptr<base::SequencedTaskRunner> database_task_runner_;
 
   base::trace_event::MemoryAllocatorDumpGuid memory_dump_id_;
 
   mojo::Receiver<mojom::SessionStorageControl> receiver_;
 
   std::unique_ptr<AsyncDomStorageDatabase> database_;
+  // This can be true even if the profile is not in-memory, since we attempt
+  // to create an in-memory DB if on-disk fails. This variable has no meaning
+  // if `database_` is null.
   bool in_memory_ = false;
   bool tried_to_recreate_during_open_ = false;
 
diff --git a/components/services/storage/dom_storage/session_storage_impl_unittest.cc b/components/services/storage/dom_storage/session_storage_impl_unittest.cc
index cb3897e..2e0457a 100644
--- a/components/services/storage/dom_storage/session_storage_impl_unittest.cc
+++ b/components/services/storage/dom_storage/session_storage_impl_unittest.cc
@@ -79,9 +79,8 @@
     if (!session_storage_) {
       remote_session_storage_.reset();
       session_storage_ = std::make_unique<SessionStorageImpl>(
-          temp_path(), blocking_task_runner_,
-          base::SequencedTaskRunner::GetCurrentDefault(), backing_mode_,
-          kSessionStorageDirectory, base::DoNothing(),
+          temp_path(), backing_mode_, kSessionStorageDirectory,
+          base::DoNothing(),
           remote_session_storage_.BindNewPipeAndPassReceiver());
     }
     return session_storage_.get();
@@ -155,9 +154,6 @@
   base::ScopedTempDir temp_dir_;
   SessionStorageImpl::BackingMode backing_mode_ =
       SessionStorageImpl::BackingMode::kRestoreDiskState;
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_{
-      base::ThreadPool::CreateSequencedTaskRunner(
-          {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN})};
   std::unique_ptr<SessionStorageImpl> session_storage_;
   mojo::Remote<mojom::SessionStorageControl> remote_session_storage_;
 };
diff --git a/components/services/storage/dom_storage/session_storage_metadata_unittest.cc b/components/services/storage/dom_storage/session_storage_metadata_unittest.cc
index c3808254..0058ef2 100644
--- a/components/services/storage/dom_storage/session_storage_metadata_unittest.cc
+++ b/components/services/storage/dom_storage/session_storage_metadata_unittest.cc
@@ -57,7 +57,6 @@
         StorageType::kSessionStorage,
         /*directory=*/base::FilePath(), "SessionStorageMetadataTest",
         /*memory_dump_id=*/std::nullopt,
-        base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()}),
         base::BindLambdaForTesting([&](DbStatus) { loop.Quit(); }));
     loop.Run();
 
diff --git a/components/services/storage/dom_storage/session_storage_namespace_impl_unittest.cc b/components/services/storage/dom_storage/session_storage_namespace_impl_unittest.cc
index 8926b051..253556c 100644
--- a/components/services/storage/dom_storage/session_storage_namespace_impl_unittest.cc
+++ b/components/services/storage/dom_storage/session_storage_namespace_impl_unittest.cc
@@ -71,7 +71,6 @@
         StorageType::kSessionStorage,
         /*directory=*/base::FilePath(), "SessionStorageNamespaceImplTest",
         /*memory_dump_id=*/std::nullopt,
-        base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()}),
         base::BindLambdaForTesting([&](DbStatus) { loop.Quit(); }));
     loop.Run();
 
diff --git a/components/services/storage/dom_storage/storage_area_impl_unittest.cc b/components/services/storage/dom_storage/storage_area_impl_unittest.cc
index 000af98e..0d781d2e 100644
--- a/components/services/storage/dom_storage/storage_area_impl_unittest.cc
+++ b/components/services/storage/dom_storage/storage_area_impl_unittest.cc
@@ -158,7 +158,6 @@
         StorageType::kSessionStorage,
         /*directory=*/base::FilePath(), "StorageAreaImplTest",
         /*memory_dump_id=*/std::nullopt,
-        base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()}),
         base::BindLambdaForTesting([&](DbStatus status) { loop.Quit(); }));
     loop.Run();
 
@@ -1225,14 +1224,14 @@
 
 }  // namespace
 
-TEST_F(StorageAreaImplTest, PrefixForkingPsuedoFuzzer) {
+TEST_F(StorageAreaImplTest, PrefixForkingPseudoFuzzer) {
   const std::string kKey1 = "key1";
   const std::vector<uint8_t> kKey1Vec = ToBytes(kKey1);
   const std::string kKey2 = "key2";
   const std::vector<uint8_t> kKey2Vec = ToBytes(kKey2);
   const int kTotalAreas = 1000;
 
-  // This tests tries to throw all possible enumartions of operations and
+  // This tests tries to throw all possible enumerations of operations and
   // forking at areas. The purpose is to hit all edge cases possible to
   // expose any loading bugs.
 
diff --git a/components/services/storage/dom_storage/test_support/dom_storage_database_testing.cc b/components/services/storage/dom_storage/test_support/dom_storage_database_testing.cc
index cb046bc7..b007549 100644
--- a/components/services/storage/dom_storage/test_support/dom_storage_database_testing.cc
+++ b/components/services/storage/dom_storage/test_support/dom_storage_database_testing.cc
@@ -103,16 +103,11 @@
     std::unique_ptr<AsyncDomStorageDatabase>* result) {
   base::test::TestFuture<DbStatus> status_future;
 
-  scoped_refptr<base::SequencedTaskRunner> database_task_runner =
-      base::ThreadPool::CreateSequencedTaskRunner(
-          {base::MayBlock(), base::WithBaseSyncPrimitives(),
-           base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
-
   std::unique_ptr<AsyncDomStorageDatabase> database =
       AsyncDomStorageDatabase::Open(
           storage_type, /*directory=*/base::FilePath(),
           "TestInMemoryDomStorageDatabase", /*memory_dump_id=*/std::nullopt,
-          std::move(database_task_runner), status_future.GetCallback());
+          status_future.GetCallback());
 
   const DbStatus& status = status_future.Get();
   ASSERT_TRUE(status.ok()) << status.ToString();
diff --git a/components/services/storage/storage_service_impl.cc b/components/services/storage/storage_service_impl.cc
index 5f2b6c1..0fd9da8 100644
--- a/components/services/storage/storage_service_impl.cc
+++ b/components/services/storage/storage_service_impl.cc
@@ -144,7 +144,6 @@
 
   auto new_local_storage = std::make_unique<LocalStorageImpl>(
       path.value_or(base::FilePath()),
-      base::SequencedTaskRunner::GetCurrentDefault(),
       base::BindOnce(&StorageServiceImpl::ShutDownAndRemoveLocalStorage,
                      weak_ptr_factory_.GetWeakPtr()),
       std::move(receiver));
@@ -173,10 +172,6 @@
 
   auto new_session_storage = std::make_unique<SessionStorageImpl>(
       path.value_or(base::FilePath()),
-      base::ThreadPool::CreateSequencedTaskRunner(
-          {base::MayBlock(), base::WithBaseSyncPrimitives(),
-           base::TaskShutdownBehavior::BLOCK_SHUTDOWN}),
-      base::SequencedTaskRunner::GetCurrentDefault(),
 #if BUILDFLAG(IS_ANDROID)
       // On Android there is no support for session storage restoring, and since
       // the restoring code is responsible for database cleanup, we must
diff --git a/components/spellcheck/renderer/spellcheck_provider.cc b/components/spellcheck/renderer/spellcheck_provider.cc
index 1c2a934..4ff2182 100644
--- a/components/spellcheck/renderer/spellcheck_provider.cc
+++ b/components/spellcheck/renderer/spellcheck_provider.cc
@@ -42,11 +42,11 @@
 using blink::WebTextCheckingResult;
 using blink::WebTextDecorationType;
 
-static_assert(int(blink::kWebTextDecorationTypeSpelling) ==
-                  int(SpellCheckResult::SPELLING),
+static_assert(static_cast<int>(blink::kWebTextDecorationTypeSpelling) ==
+                  static_cast<int>(SpellCheckResult::SPELLING),
               "mismatching enums");
-static_assert(int(blink::kWebTextDecorationTypeGrammar) ==
-                  int(SpellCheckResult::GRAMMAR),
+static_assert(static_cast<int>(blink::kWebTextDecorationTypeGrammar) ==
+                  static_cast<int>(SpellCheckResult::GRAMMAR),
               "mismatching enums");
 
 class SpellCheckProvider::DictionaryUpdateObserverImpl
diff --git a/components/viz/service/display/direct_renderer.cc b/components/viz/service/display/direct_renderer.cc
index 19e71c4a..e7218b2 100644
--- a/components/viz/service/display/direct_renderer.cc
+++ b/components/viz/service/display/direct_renderer.cc
@@ -292,27 +292,6 @@
         output_surface_->GetDisplayTransform());
     overlay_processor_->SetViewportSize(device_viewport_size);
 
-    // Before ProcessForOverlay calls into the hardware to ask about whether the
-    // overlay setup can be handled, we need to set up the primary plane.
-    std::optional<OverlayCandidate> primary_plane;
-    if (output_surface_->capabilities().renderer_allocates_images) {
-      primary_plane = overlay_processor_->ProcessOutputSurfaceAsOverlay(
-          device_viewport_size, surface_resource_size, frame_si_format,
-          frame_color_space,
-          current_frame()->root_render_pass->has_transparent_background,
-          1.0f /*opacity*/, GetPrimaryPlaneOverlayTestingMailbox());
-
-      if (current_frame()->display_color_spaces.SupportsHDR() &&
-          current_frame()->root_render_pass->content_color_usage ==
-              gfx::ContentColorUsage::kHDR) {
-        primary_plane->hdr_metadata.extended_range.emplace();
-        // TODO(crbug.com/40263227): Track the actual brightness of the
-        // content. For now, assume that all HDR content is 1,000 nits.
-        primary_plane->hdr_metadata.extended_range->desired_headroom =
-            gfx::HdrMetadataExtendedRange::kDefaultHdrHeadroom;
-      }
-    }
-
     // Attempt to replace some or all of the quads of the root render pass with
     // overlays.
     base::ElapsedTimer overlay_processing_timer;
@@ -320,8 +299,25 @@
         resource_provider_, render_passes_in_draw_order,
         output_surface_->color_matrix(), render_pass_filters_,
         render_pass_backdrop_filters_, std::move(surface_damage_rect_list),
-        primary_plane, &current_frame()->overlay_list,
-        &current_frame()->root_damage_rect,
+        OverlayProcessorInterface::PrimaryPlaneParams{
+            .viewport_size = device_viewport_size,
+            .resource_size_in_pixels = surface_resource_size,
+            .supports_hdr =
+                current_frame()->display_color_spaces.SupportsHDR() &&
+                render_passes_in_draw_order->back()->content_color_usage ==
+                    gfx::ContentColorUsage::kHDR,
+            .is_opaque = !render_passes_in_draw_order->back()
+                              ->has_transparent_background,
+#if BUILDFLAG(IS_OZONE)
+            .si_format = frame_si_format,
+            .color_space = frame_color_space,
+            .overlay_testing_mailbox =
+                output_surface_->capabilities().renderer_allocates_images
+                    ? GetPrimaryPlaneOverlayTestingMailbox()
+                    : gpu::Mailbox(),
+#endif
+        },
+        &current_frame()->overlay_list, &current_frame()->root_damage_rect,
         &current_frame()->root_content_bounds);
     auto overlay_processing_time = overlay_processing_timer.Elapsed();
 
@@ -1226,8 +1222,10 @@
   return gfx::Rect();
 }
 
+#if BUILDFLAG(IS_OZONE)
 gpu::Mailbox DirectRenderer::GetPrimaryPlaneOverlayTestingMailbox() {
   NOTREACHED();
 }
+#endif
 
 }  // namespace viz
diff --git a/components/viz/service/display/direct_renderer.h b/components/viz/service/display/direct_renderer.h
index 5da72e7..da3bd0e 100644
--- a/components/viz/service/display/direct_renderer.h
+++ b/components/viz/service/display/direct_renderer.h
@@ -195,9 +195,11 @@
   // 0 < n <= capabilities_.number_of_buffers.
   virtual void EnsureMinNumberOfBuffers(int n) {}
 
+#if BUILDFLAG(IS_OZONE)
   // Gets a mailbox that can be used for overlay testing the primary plane. This
   // does not need to be the next mailbox that will be swapped.
   virtual gpu::Mailbox GetPrimaryPlaneOverlayTestingMailbox();
+#endif
 
   // Return the bounding rect of previously drawn delegated ink trail.
   gfx::Rect GetDelegatedInkTrailDamageRect();
diff --git a/components/viz/service/display/overlay_ca_unittest.cc b/components/viz/service/display/overlay_ca_unittest.cc
index c84e749..667cad7a 100644
--- a/components/viz/service/display/overlay_ca_unittest.cc
+++ b/components/viz/service/display/overlay_ca_unittest.cc
@@ -194,12 +194,14 @@
     output_surface_ = nullptr;
   }
 
-  std::optional<OverlayCandidate>& GetDefaultPrimaryPlane(
-      const gfx::Size& size) {
-    primary_plane_ = OverlayProcessorInterface::ProcessOutputSurfaceAsOverlay(
-        size, size, SinglePlaneFormat::kRGBA_8888,
-        gfx::ColorSpace::CreateSRGB(), false, 1.0, gpu::Mailbox());
-    return primary_plane_;
+  OverlayProcessorInterface::PrimaryPlaneParams GetDefaultPrimaryPlane(
+      const gfx::Size& primary_plane_size) {
+    return OverlayProcessorInterface::PrimaryPlaneParams{
+        .viewport_size = primary_plane_size,
+        .resource_size_in_pixels = primary_plane_size,
+        .supports_hdr = false,
+        .is_opaque = true,
+    };
   }
 
   std::unique_ptr<SkiaOutputSurface> output_surface_;
diff --git a/components/viz/service/display/overlay_dc_unittest.cc b/components/viz/service/display/overlay_dc_unittest.cc
index c2fc1b1..bd442b60 100644
--- a/components/viz/service/display/overlay_dc_unittest.cc
+++ b/components/viz/service/display/overlay_dc_unittest.cc
@@ -2594,8 +2594,6 @@
     overlay_processor_->SetViewportSize(gfx::Size(256, 256));
 
     EXPECT_TRUE(overlay_processor_->IsOverlaySupported());
-
-    output_surface_plane_ = GetDefaultPrimaryPlane(gfx::Size(256, 256));
   }
 
   void TearDown() override {
@@ -2603,14 +2601,16 @@
     OverlayProcessorTestBase::TearDown();
   }
 
-  std::optional<OverlayCandidate> GetDefaultPrimaryPlane(
+  OverlayProcessorInterface::PrimaryPlaneParams GetDefaultPrimaryPlane(
       const gfx::Size& primary_plane_size) {
-    return overlay_processor_->ProcessOutputSurfaceAsOverlay(
-        primary_plane_size, primary_plane_size, SinglePlaneFormat::kBGRA_8888,
-        gfx::ColorSpace::CreateSRGB(), false, 1.0, gpu::Mailbox());
+    return OverlayProcessorInterface::PrimaryPlaneParams{
+        .viewport_size = primary_plane_size,
+        .resource_size_in_pixels = primary_plane_size,
+        .supports_hdr = false,
+        .is_opaque = true,
+    };
   }
 
-  std::optional<OverlayCandidate> output_surface_plane_;
   std::unique_ptr<OverlayProcessorWin> overlay_processor_;
   gfx::Rect damage_rect_;
   std::vector<gfx::Rect> content_bounds_;
@@ -2752,12 +2752,11 @@
                                                      &damage_rect_);
     }
 
-    output_surface_plane_ =
-        GetDefaultPrimaryPlane(render_passes->back()->output_rect.size());
     overlay_processor_->ProcessForOverlays(
         resource_provider_.get(), render_passes, SkM44(),
         std::move(surface_damage_rect_list_in_root_space),
-        output_surface_plane_, candidates, &damage_rect_, &content_bounds_);
+        GetDefaultPrimaryPlane(render_passes->back()->output_rect.size()),
+        candidates, &damage_rect_, &content_bounds_);
   }
 
  private:
@@ -3076,10 +3075,6 @@
   EXPECT_THAT(overlays, testing::ElementsAreArray({
                             test::OverlayIsFullScreen(),
                         }));
-
-  // Check that the next call to `AdjustOutputSurfaceOverlay` clears the primary
-  // plane.
-  EXPECT_FALSE(output_surface_plane_.has_value());
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -3135,12 +3130,6 @@
   DelegationResult TryProcessForDelegatedOverlays(
       AggregatedRenderPassList& pass_list,
       SurfaceDamageRectList surface_damage_rect_list = {}) {
-    if (!output_surface_plane_) {
-      // Reset the output surface plane in case we're calling
-      // |TryProcessForDelegatedOverlays| multiple times.
-      output_surface_plane_ = OverlayCandidate();
-    }
-
     const gfx::Rect original_root_surface_damage =
         pass_list.back()->damage_rect;
 
@@ -3161,8 +3150,9 @@
     overlay_processor_->ProcessForOverlays(
         resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
         render_pass_filters, render_pass_backdrop_filters,
-        std::move(surface_damage_rect_list), output_surface_plane_, &candidates,
-        &damage_rect_, &content_bounds_);
+        std::move(surface_damage_rect_list),
+        GetDefaultPrimaryPlane(pass_list.back()->output_rect.size()),
+        &candidates, &damage_rect_, &content_bounds_);
 
     const bool delegation_succeeded = std::ranges::none_of(
         candidates,
diff --git a/components/viz/service/display/overlay_processor_android.cc b/components/viz/service/display/overlay_processor_android.cc
index ababf9a..c269c79 100644
--- a/components/viz/service/display/overlay_processor_android.cc
+++ b/components/viz/service/display/overlay_processor_android.cc
@@ -197,6 +197,10 @@
   NOTREACHED();
 }
 
+bool OverlayProcessorAndroid::ShouldCreatePrimaryPlane() const {
+  return false;
+}
+
 void OverlayProcessorAndroid::TakeOverlayCandidates(
     OverlayCandidateList* candidate_list) {
   overlay_candidates_.swap(*candidate_list);
diff --git a/components/viz/service/display/overlay_processor_android.h b/components/viz/service/display/overlay_processor_android.h
index aae6860..1e5f196 100644
--- a/components/viz/service/display/overlay_processor_android.h
+++ b/components/viz/service/display/overlay_processor_android.h
@@ -63,6 +63,8 @@
   void InsertPrimaryPlane(OverlayCandidate primary_plane,
                           OverlayCandidateList& candidates) override;
 
+  bool ShouldCreatePrimaryPlane() const override;
+
  private:
   // OverlayProcessor needs to send overlay candidate information to the gpu
   // thread. These two methods are scheduled on the gpu thread to setup and
diff --git a/components/viz/service/display/overlay_processor_delegated.cc b/components/viz/service/display/overlay_processor_delegated.cc
index a91a864..237f490 100644
--- a/components/viz/service/display/overlay_processor_delegated.cc
+++ b/components/viz/service/display/overlay_processor_delegated.cc
@@ -70,7 +70,7 @@
     const DisplayResourceProvider* resource_provider,
     AggregatedRenderPassList* render_pass_list,
     SurfaceDamageRectList* surface_damage_rect_list,
-    std::optional<OverlayCandidate>& primary_plane,
+    const std::optional<OverlayCandidate>& primary_plane,
     OverlayCandidateList* candidates,
     std::vector<gfx::Rect>* content_bounds) {
   DCHECK(candidates->empty());
@@ -187,7 +187,7 @@
     const OverlayProcessorInterface::FilterOperationsMap&
         render_pass_backdrop_filters,
     SurfaceDamageRectList surface_damage_rect_list,
-    std::optional<OverlayCandidate>& primary_plane,
+    const PrimaryPlaneParams& primary_plane_params,
     CandidateList* candidates,
     gfx::Rect* damage_rect,
     std::vector<gfx::Rect>* content_bounds) {
@@ -196,6 +196,9 @@
 
   DebugLogBeforeDelegation(*damage_rect, surface_damage_rect_list);
 
+  std::optional<OverlayCandidate> primary_plane =
+      CreatePrimaryPlane(primary_plane_params);
+
   success = AttemptWithStrategies(
       output_color_matrix, render_pass_filters, render_pass_backdrop_filters,
       resource_provider, render_passes, &surface_damage_rect_list,
@@ -217,10 +220,6 @@
     // This is only relevant when delegating.
     unassigned_damage_ = gfx::RectF();
 
-    CHECK(primary_plane);
-    render_passes->back()->has_transparent_background |=
-        !primary_plane->is_opaque;
-
     // TODO(crbug.com/40775556) : Damage propagation will allow us to remove the
     // primary plan entirely in the case of full delegation.
     InsertPrimaryPlane(std::move(primary_plane).value(), *candidates);
diff --git a/components/viz/service/display/overlay_processor_delegated.h b/components/viz/service/display/overlay_processor_delegated.h
index 2fa78ead..fc72a310 100644
--- a/components/viz/service/display/overlay_processor_delegated.h
+++ b/components/viz/service/display/overlay_processor_delegated.h
@@ -54,7 +54,7 @@
       const FilterOperationsMap& render_pass_filters,
       const FilterOperationsMap& render_pass_backdrop_filters,
       SurfaceDamageRectList surface_damage_rect_list,
-      std::optional<OverlayCandidate>& primary_plane,
+      const PrimaryPlaneParams& primary_plane_params,
       CandidateList* overlay_candidates,
       gfx::Rect* damage_rect,
       std::vector<gfx::Rect>* content_bounds) final;
@@ -79,7 +79,7 @@
       const DisplayResourceProvider* resource_provider,
       AggregatedRenderPassList* render_pass_list,
       SurfaceDamageRectList* surface_damage_rect_list,
-      std::optional<OverlayCandidate>& primary_plane,
+      const std::optional<OverlayCandidate>& primary_plane,
       OverlayCandidateList* candidates,
       std::vector<gfx::Rect>* content_bounds);
 
diff --git a/components/viz/service/display/overlay_processor_interface.cc b/components/viz/service/display/overlay_processor_interface.cc
index a534000..61c62a8 100644
--- a/components/viz/service/display/overlay_processor_interface.cc
+++ b/components/viz/service/display/overlay_processor_interface.cc
@@ -186,14 +186,9 @@
   return false;
 }
 
-OverlayCandidate OverlayProcessorInterface::ProcessOutputSurfaceAsOverlay(
-    const gfx::Size& viewport_size,
-    const gfx::Size& resource_size,
-    const SharedImageFormat si_format,
-    const gfx::ColorSpace& color_space,
-    bool has_alpha,
-    float opacity,
-    const gpu::Mailbox& mailbox) {
+// static
+OverlayCandidate OverlayProcessorInterface::CreatePrimaryPlane(
+    const PrimaryPlaneParams& params) {
   OverlayCandidate overlay_plane;
   overlay_plane.is_root_render_pass = true;
 #if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_WIN)
@@ -201,27 +196,40 @@
 #else
   overlay_plane.transform = gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE;
 #endif
-  overlay_plane.uv_rect = gfx::RectF(
-      0.f, 0.f,
-      viewport_size.width() / static_cast<float>(resource_size.width()),
-      viewport_size.height() / static_cast<float>(resource_size.height()));
-  overlay_plane.resource_size_in_pixels = resource_size;
-  overlay_plane.format = si_format;
-  overlay_plane.color_space = color_space;
-  overlay_plane.is_opaque = !has_alpha;
-  overlay_plane.opacity = opacity;
-  overlay_plane.mailbox = mailbox;
+  overlay_plane.is_opaque = params.is_opaque;
+  overlay_plane.opacity = 1.0f;
   overlay_plane.priority_hint = gfx::OverlayPriorityHint::kRegular;
   overlay_plane.rounded_corners = gfx::RRectF();
 
   // Adjust transformation and display_rect based on display rotation.
-  overlay_plane.display_rect =
-      gfx::RectF(viewport_size.width(), viewport_size.height());
+  overlay_plane.display_rect = gfx::RectF(params.viewport_size);
+  overlay_plane.resource_size_in_pixels = params.resource_size_in_pixels;
+  overlay_plane.uv_rect = gfx::RectF(
+      0.f, 0.f,
+      overlay_plane.display_rect.width() /
+          static_cast<float>(overlay_plane.resource_size_in_pixels.width()),
+      overlay_plane.display_rect.height() /
+          static_cast<float>(overlay_plane.resource_size_in_pixels.height()));
 
 #if BUILDFLAG(ALWAYS_ENABLE_BLENDING_FOR_PRIMARY)
   // On Chromecast, always use RGBA as the scanout format for the primary plane.
   overlay_plane.is_opaque = false;
 #endif
+
+#if BUILDFLAG(IS_OZONE)
+  overlay_plane.format = params.si_format;
+  overlay_plane.color_space = params.color_space;
+  overlay_plane.mailbox = params.overlay_testing_mailbox;
+#endif
+
+  if (params.supports_hdr) {
+    overlay_plane.hdr_metadata.extended_range.emplace();
+    // TODO(crbug.com/40263227): Track the actual brightness of the
+    // content. For now, assume that all HDR content is 1,000 nits.
+    overlay_plane.hdr_metadata.extended_range->desired_headroom =
+        gfx::HdrMetadataExtendedRange::kDefaultHdrHeadroom;
+  }
+
   return overlay_plane;
 }
 
@@ -230,7 +238,7 @@
     AggregatedRenderPassList* render_passes,
     const SkM44& output_color_matrix,
     SurfaceDamageRectList surface_damage_rect_list,
-    std::optional<OverlayCandidate>& primary_plane,
+    const PrimaryPlaneParams& primary_plane_params,
     CandidateList* overlay_candidates,
     gfx::Rect* damage_rect,
     std::vector<gfx::Rect>* content_bounds) {
@@ -238,7 +246,7 @@
   ProcessForOverlays(resource_provider, render_passes, output_color_matrix,
                      /*render_pass_filters=*/{},
                      /*render_pass_backdrop_filters=*/{},
-                     surface_damage_rect_list, primary_plane,
+                     surface_damage_rect_list, primary_plane_params,
                      overlay_candidates, damage_rect, content_bounds);
 }
 
diff --git a/components/viz/service/display/overlay_processor_interface.h b/components/viz/service/display/overlay_processor_interface.h
index 6cf92ad..a414ecc 100644
--- a/components/viz/service/display/overlay_processor_interface.h
+++ b/components/viz/service/display/overlay_processor_interface.h
@@ -66,18 +66,6 @@
       bool has_occluding_surface_damage,
       bool zero_damage_rect);
 
-  // TODO(weiliangc): Eventually the asymmetry between primary plane and
-  // non-primary places should be internalized and should not have a special
-  // API.
-  static OverlayCandidate ProcessOutputSurfaceAsOverlay(
-      const gfx::Size& viewport_size,
-      const gfx::Size& resource_size,
-      const SharedImageFormat si_format,
-      const gfx::ColorSpace& color_space,
-      bool has_alpha,
-      float opacity,
-      const gpu::Mailbox& mailbox);
-
   static std::unique_ptr<OverlayProcessorInterface> CreateOverlayProcessor(
       OutputSurface* output_surface,
       gpu::SurfaceHandle surface_handle,
@@ -102,6 +90,23 @@
   // processor.
   virtual bool NeedsSurfaceDamageRectList() const = 0;
 
+  struct PrimaryPlaneParams {
+    const gfx::Size viewport_size;
+    const gfx::Size resource_size_in_pixels;
+    bool supports_hdr = false;
+    bool is_opaque = false;
+
+#if BUILDFLAG(IS_OZONE)
+    // Ozone requires checking for overlay support with an actual buffer. To
+    // create the primary plane, `OverlayProcessorOzone` will use an existing
+    // `overlay_testing_mailbox` (usually, the last swapped primary plane
+    // buffer) or will make a dummy buffer using `si_format` and `color_space`.
+    const SharedImageFormat si_format;
+    const gfx::ColorSpace color_space;
+    const gpu::Mailbox overlay_testing_mailbox;
+#endif
+  };
+
   // Attempts to replace quads from the specified root render pass with overlays
   // or CALayers. This must be called every frame.
   // TODO(crbug.com/444264038): Delete this overload when the RPDQ refactor is
@@ -113,7 +118,7 @@
       const FilterOperationsMap& render_pass_filters,
       const FilterOperationsMap& render_pass_backdrop_filters,
       SurfaceDamageRectList surface_damage_rect_list,
-      std::optional<OverlayCandidate>& primary_plane,
+      const PrimaryPlaneParams& primary_plane_params,
       CandidateList* overlay_candidates,
       gfx::Rect* damage_rect,
       std::vector<gfx::Rect>* content_bounds) = 0;
@@ -122,7 +127,7 @@
                           AggregatedRenderPassList* render_passes,
                           const SkM44& output_color_matrix,
                           SurfaceDamageRectList surface_damage_rect_list,
-                          std::optional<OverlayCandidate>& primary_plane,
+                          const PrimaryPlaneParams& primary_plane_params,
                           CandidateList* overlay_candidates,
                           gfx::Rect* damage_rect,
                           std::vector<gfx::Rect>* content_bounds);
@@ -176,6 +181,8 @@
 
  protected:
   OverlayProcessorInterface() = default;
+
+  static OverlayCandidate CreatePrimaryPlane(const PrimaryPlaneParams& params);
 };
 
 }  // namespace viz
diff --git a/components/viz/service/display/overlay_processor_mac.cc b/components/viz/service/display/overlay_processor_mac.cc
index 0cbe45f..76fa8119 100644
--- a/components/viz/service/display/overlay_processor_mac.cc
+++ b/components/viz/service/display/overlay_processor_mac.cc
@@ -48,7 +48,7 @@
     const OverlayProcessorInterface::FilterOperationsMap&
         render_pass_backdrop_filters,
     SurfaceDamageRectList surface_damage_rect_list,
-    std::optional<OverlayCandidate>& primary_plane,
+    const PrimaryPlaneParams& primary_plane_params,
     CandidateList* candidates,
     gfx::Rect* damage_rect,
     std::vector<gfx::Rect>* content_bounds) {
@@ -79,13 +79,9 @@
         &render_pass->quad_list, render_pass_filters,
         render_pass_backdrop_filters, candidates);
 
-    CHECK(primary_plane);
-    render_pass->has_transparent_background |= !primary_plane->is_opaque;
-
     // Mac doesn't use the plane_z_order field and it needs to have primary
     // plane last in the list of overlays.
-    candidates->push_back(std::move(primary_plane).value());
-    primary_plane.reset();
+    candidates->push_back(CreatePrimaryPlane(primary_plane_params));
   }
 }
 
diff --git a/components/viz/service/display/overlay_processor_mac.h b/components/viz/service/display/overlay_processor_mac.h
index 7cbe033..cb41887 100644
--- a/components/viz/service/display/overlay_processor_mac.h
+++ b/components/viz/service/display/overlay_processor_mac.h
@@ -57,7 +57,7 @@
       const FilterOperationsMap& render_pass_filters,
       const FilterOperationsMap& render_pass_backdrop_filters,
       SurfaceDamageRectList surface_damage_rect_list,
-      std::optional<OverlayCandidate>& primary_plane,
+      const PrimaryPlaneParams& primary_plane_params,
       CandidateList* overlay_candidates,
       gfx::Rect* damage_rect,
       std::vector<gfx::Rect>* content_bounds) override;
diff --git a/components/viz/service/display/overlay_processor_ozone.cc b/components/viz/service/display/overlay_processor_ozone.cc
index f34718c..692e835ac 100644
--- a/components/viz/service/display/overlay_processor_ozone.cc
+++ b/components/viz/service/display/overlay_processor_ozone.cc
@@ -498,6 +498,14 @@
   candidates.insert(insert_positon, std::move(primary_plane));
 }
 
+bool OverlayProcessorOzone::ShouldCreatePrimaryPlane() const {
+#if BUILDFLAG(IS_CASTOS)
+  return false;
+#else
+  return true;
+#endif
+}
+
 bool OverlayProcessorOzone::SetNativePixmapForCandidate(
     ui::OverlaySurfaceCandidate* candidate,
     const gpu::Mailbox& mailbox,
diff --git a/components/viz/service/display/overlay_processor_ozone.h b/components/viz/service/display/overlay_processor_ozone.h
index 4d9420a4..e3caead 100644
--- a/components/viz/service/display/overlay_processor_ozone.h
+++ b/components/viz/service/display/overlay_processor_ozone.h
@@ -69,6 +69,8 @@
   void InsertPrimaryPlane(OverlayCandidate primary_plane,
                           OverlayCandidateList& candidates) override;
 
+  bool ShouldCreatePrimaryPlane() const override;
+
  private:
   // Populates |native_pixmap| and |native_pixmap_unique_id| in |candidate|
   // based on |mailbox|. |is_primary| should be true if this is the primary
diff --git a/components/viz/service/display/overlay_processor_stub.h b/components/viz/service/display/overlay_processor_stub.h
index 411f00c..25d1519f 100644
--- a/components/viz/service/display/overlay_processor_stub.h
+++ b/components/viz/service/display/overlay_processor_stub.h
@@ -33,7 +33,7 @@
       const FilterOperationsMap& render_pass_filters,
       const FilterOperationsMap& render_pass_backdrop_filters,
       SurfaceDamageRectList surface_damage_rect_list,
-      std::optional<OverlayCandidate>& primary_plane,
+      const PrimaryPlaneParams& primary_plane_params,
       CandidateList* overlay_candidates,
       gfx::Rect* damage_rect,
       std::vector<gfx::Rect>* content_bounds) final {}
diff --git a/components/viz/service/display/overlay_processor_using_strategy.cc b/components/viz/service/display/overlay_processor_using_strategy.cc
index 385ddbd..c1eb0d1 100644
--- a/components/viz/service/display/overlay_processor_using_strategy.cc
+++ b/components/viz/service/display/overlay_processor_using_strategy.cc
@@ -363,15 +363,13 @@
     const OverlayProcessorInterface::FilterOperationsMap&
         render_pass_backdrop_filters,
     SurfaceDamageRectList surface_damage_rect_list,
-    std::optional<OverlayCandidate>& primary_plane,
+    const PrimaryPlaneParams& primary_plane_params,
     CandidateList* candidates,
     gfx::Rect* damage_rect,
     std::vector<gfx::Rect>* content_bounds) {
 #if BUILDFLAG(IS_CHROMEOS)
   // TODO(b/181974042):  Remove when color space is plumbed.
-  if (primary_plane) {
-    primary_plane_color_space_ = primary_plane->color_space;
-  }
+  primary_plane_color_space_ = primary_plane_params.color_space;
 #endif
   TRACE_EVENT0("viz", "OverlayProcessorUsingStrategy::ProcessForOverlays");
   DCHECK(candidates->empty());
@@ -394,6 +392,10 @@
   // contents.
   bool skip_because_copy_request = BlockForCopyRequests(render_pass);
 
+  std::optional<OverlayCandidate> primary_plane;
+  if (ShouldCreatePrimaryPlane()) {
+    primary_plane = CreatePrimaryPlane(primary_plane_params);
+  }
   if (!skip_because_copy_request && !disable_overlay()) {
     success = AttemptWithStrategies(
         output_color_matrix, render_pass_filters, render_pass_backdrop_filters,
@@ -453,6 +455,10 @@
   candidates.push_back(std::move(primary_plane));
 }
 
+bool OverlayProcessorUsingStrategy::ShouldCreatePrimaryPlane() const {
+  return true;
+}
+
 void OverlayProcessorUsingStrategy::ClearOverlayCombinationCache() {
   overlay_combination_cache_.ClearCache();
 }
diff --git a/components/viz/service/display/overlay_processor_using_strategy.h b/components/viz/service/display/overlay_processor_using_strategy.h
index 46d3d3e..6608732 100644
--- a/components/viz/service/display/overlay_processor_using_strategy.h
+++ b/components/viz/service/display/overlay_processor_using_strategy.h
@@ -72,7 +72,7 @@
       const FilterOperationsMap& render_pass_filters,
       const FilterOperationsMap& render_pass_backdrop_filters,
       SurfaceDamageRectList surface_damage_rect_list,
-      std::optional<OverlayCandidate>& primary_plane,
+      const PrimaryPlaneParams& primary_plane_params,
       CandidateList* overlay_candidates,
       gfx::Rect* damage_rect,
       std::vector<gfx::Rect>* content_bounds)
@@ -148,8 +148,12 @@
   // confirmed in `OverlayProcessorOzone::ReceiveHardwareCapabilities`.
   int max_overlays_considered_ = 1;
 
-#if BUILDFLAG(IS_CHROMEOS)
  protected:
+  // This is used by `OverlayProcessorAndroid` and `OverlayProcessorWebView`,
+  // which do not use an overlay for the primary plane.
+  virtual bool ShouldCreatePrimaryPlane() const;
+
+#if BUILDFLAG(IS_CHROMEOS)
   // TODO(b/181974042):  Remove when color space is plumbed.
   gfx::ColorSpace primary_plane_color_space_;
 #endif
diff --git a/components/viz/service/display/overlay_processor_win.cc b/components/viz/service/display/overlay_processor_win.cc
index f5c58bfe..4efd94ae 100644
--- a/components/viz/service/display/overlay_processor_win.cc
+++ b/components/viz/service/display/overlay_processor_win.cc
@@ -190,7 +190,7 @@
     const OverlayProcessorInterface::FilterOperationsMap&
         render_pass_backdrop_filters,
     SurfaceDamageRectList surface_damage_rect_list_in_root_space,
-    std::optional<OverlayCandidate>& primary_plane,
+    const PrimaryPlaneParams& primary_plane_params,
     CandidateList* candidates,
     gfx::Rect* root_damage_rect,
     std::vector<gfx::Rect>* content_bounds) {
@@ -204,6 +204,7 @@
       render_pass_filters, render_pass_backdrop_filters,
       surface_damage_rect_list_in_root_space, candidates, root_damage_rect);
 
+  std::optional<OverlayCandidate> primary_plane;
   if (status != DelegationStatus::kFullDelegation) {
     // Fall back to promoting overlays from the output surface plane.
     ProcessOverlaysFromOutputSurfacePlane(
@@ -211,7 +212,7 @@
         render_pass_filters, render_pass_backdrop_filters,
         surface_damage_rect_list_in_root_space, candidates, root_damage_rect);
 
-    CHECK(primary_plane);
+    primary_plane = CreatePrimaryPlane(primary_plane_params);
     primary_plane->is_opaque =
         !render_passes->back()->has_transparent_background;
     primary_plane->layer_id = gfx::OverlayLayerId::MakeVizInternalRenderPass(
diff --git a/components/viz/service/display/overlay_processor_win.h b/components/viz/service/display/overlay_processor_win.h
index f0f01f59..66c3ad4 100644
--- a/components/viz/service/display/overlay_processor_win.h
+++ b/components/viz/service/display/overlay_processor_win.h
@@ -66,7 +66,7 @@
       const FilterOperationsMap& render_pass_filters,
       const FilterOperationsMap& render_pass_backdrop_filters,
       SurfaceDamageRectList surface_damage_rect_list_in_root_space,
-      std::optional<OverlayCandidate>& primary_plane,
+      const PrimaryPlaneParams& primary_plane_params,
       OverlayCandidateList* overlay_candidates,
       gfx::Rect* root_damage_rect,
       std::vector<gfx::Rect>* content_bounds) override;
diff --git a/components/viz/service/display/overlay_unittest.cc b/components/viz/service/display/overlay_unittest.cc
index 99ba3395..abc4f5e2 100644
--- a/components/viz/service/display/overlay_unittest.cc
+++ b/components/viz/service/display/overlay_unittest.cc
@@ -102,7 +102,6 @@
 const gfx::Rect kOverlayClipRect(0, 0, 128, 128);
 const gfx::PointF kUVTopLeft(0.1f, 0.2f);
 const gfx::PointF kUVBottomRight(1.0f, 1.0f);
-const SharedImageFormat kDefaultSIFormat = SinglePlaneFormat::kRGBA_8888;
 const OverlayCandidateFactory::OverlayContext kTestOverlayContext;
 
 class TimeTicksOverride {
@@ -153,7 +152,7 @@
       const FilterOperationsMap& render_pass_filters,
       const FilterOperationsMap& render_pass_backdrop_filters,
       SurfaceDamageRectList surface_damage_rect_list,
-      std::optional<OverlayCandidate>& primary_plane,
+      const PrimaryPlaneParams& primary_plane_params,
       CandidateList* overlay_candidates,
       gfx::Rect* damage_rect,
       std::vector<gfx::Rect>* content_bounds) override {
@@ -164,7 +163,7 @@
     OverlayProcessorUsingStrategy::ProcessForOverlays(
         resource_provider, render_passes, output_color_matrix,
         render_pass_filters, render_pass_backdrop_filters,
-        surface_damage_rect_list, primary_plane, overlay_candidates,
+        surface_damage_rect_list, primary_plane_params, overlay_candidates,
         damage_rect, content_bounds);
   }
 
@@ -310,7 +309,7 @@
       const FilterOperationsMap& render_pass_filters,
       const FilterOperationsMap& render_pass_backdrop_filters,
       SurfaceDamageRectList surface_damage_rect_list,
-      std::optional<OverlayCandidate>& primary_plane,
+      const PrimaryPlaneParams& primary_plane_params,
       CandidateList* overlay_candidates,
       gfx::Rect* damage_rect,
       std::vector<gfx::Rect>* content_bounds) override {
@@ -321,7 +320,7 @@
     OverlayProcessorUsingStrategy::ProcessForOverlays(
         resource_provider, render_passes, output_color_matrix,
         render_pass_filters, render_pass_backdrop_filters,
-        surface_damage_rect_list, primary_plane, overlay_candidates,
+        surface_damage_rect_list, primary_plane_params, overlay_candidates,
         damage_rect, content_bounds);
   }
 
@@ -917,18 +916,24 @@
     return resource_factory_->resource_provider();
   }
 
-  std::optional<OverlayCandidate>& GetDefaultPrimaryPlane() {
-    primary_plane_ = OverlayProcessorInterface::ProcessOutputSurfaceAsOverlay(
-        kDisplaySize, kDisplaySize, kDefaultSIFormat,
-        gfx::ColorSpace::CreateSRGB(), false, 1.0, gpu::Mailbox());
-    return primary_plane_;
+  OverlayProcessorInterface::PrimaryPlaneParams GetDefaultPrimaryPlane() {
+    return OverlayProcessorInterface::PrimaryPlaneParams{
+        .viewport_size = kDisplaySize,
+        .resource_size_in_pixels = kDisplaySize,
+        .supports_hdr = false,
+        .is_opaque = true,
+#if BUILDFLAG(IS_OZONE)
+        .si_format = SinglePlaneFormat::kRGBA_8888,
+        .color_space = gfx::ColorSpace::CreateSRGB(),
+        .overlay_testing_mailbox = gpu::Mailbox(),
+#endif
+    };
   }
 
   std::unique_ptr<TestResourceFactory> resource_factory_;
   std::unique_ptr<OverlayProcessorType> overlay_processor_;
   gfx::Rect damage_rect_;
   std::vector<gfx::Rect> content_bounds_;
-  std::optional<OverlayCandidate> primary_plane_;
 };
 
 template <typename OverlayProcessorType>
@@ -3830,14 +3835,9 @@
   pass_list.push_back(std::move(pass));
   SurfaceDamageRectList surface_damage_rect_list;
 
-  std::optional<OverlayCandidate> output_surface_plane =
-      overlay_processor_->ProcessOutputSurfaceAsOverlay(
-          kDisplaySize, kDisplaySize, kDefaultSIFormat, gfx::ColorSpace(),
-          false /* has_alpha */, 1.0f /* opacity */, gpu::Mailbox());
-
   overlay_processor_->ProcessForOverlays(
       resource_provider(), &pass_list, GetIdentityColorMatrix(),
-      std::move(surface_damage_rect_list), output_surface_plane,
+      std::move(surface_damage_rect_list), GetDefaultPrimaryPlane(),
       &candidate_list, &damage_rect_, &content_bounds_);
 
   ASSERT_EQ(1U, test::NumOverlaysExcludingPrimaryPlane(candidate_list));
@@ -4209,8 +4209,8 @@
 
   overlay_processor_->ProcessForOverlays(
       resource_provider(), &pass_list, GetIdentityColorMatrix(),
-      std::move(surface_damage_rect_list), primary_plane_, &candidate_list,
-      &damage_rect_, &content_bounds_);
+      std::move(surface_damage_rect_list), GetDefaultPrimaryPlane(),
+      &candidate_list, &damage_rect_, &content_bounds_);
   ASSERT_EQ(1U, pass_list.size());
   ASSERT_EQ(1U, pass_list.front()->quad_list.size());
   EXPECT_EQ(SkColors::kTransparent, static_cast<SolidColorDrawQuad*>(
@@ -4235,8 +4235,8 @@
 
   overlay_processor_->ProcessForOverlays(
       resource_provider(), &pass_list, GetIdentityColorMatrix(),
-      std::move(surface_damage_rect_list), primary_plane_, &candidate_list,
-      &damage_rect_, &content_bounds_);
+      std::move(surface_damage_rect_list), GetDefaultPrimaryPlane(),
+      &candidate_list, &damage_rect_, &content_bounds_);
   EXPECT_EQ(0U, content_bounds_.size());
 }
 
@@ -4252,8 +4252,8 @@
 
   overlay_processor_->ProcessForOverlays(
       resource_provider(), &pass_list, GetIdentityColorMatrix(),
-      std::move(surface_damage_rect_list), primary_plane_, &candidate_list,
-      &damage_rect_, &content_bounds_);
+      std::move(surface_damage_rect_list), GetDefaultPrimaryPlane(),
+      &candidate_list, &damage_rect_, &content_bounds_);
 
   EXPECT_EQ(1U, content_bounds_.size());
   EXPECT_TRUE(content_bounds_[0].IsEmpty());
@@ -4280,8 +4280,8 @@
 
   overlay_processor_->ProcessForOverlays(
       resource_provider(), &pass_list, GetIdentityColorMatrix(),
-      std::move(surface_damage_rect_list), primary_plane_, &candidate_list,
-      &damage_rect_, &content_bounds_);
+      std::move(surface_damage_rect_list), GetDefaultPrimaryPlane(),
+      &candidate_list, &damage_rect_, &content_bounds_);
 
   EXPECT_EQ(1U, content_bounds_.size());
   EXPECT_TRUE(content_bounds_[0].IsEmpty());
@@ -4301,8 +4301,8 @@
 
   overlay_processor_->ProcessForOverlays(
       resource_provider(), &pass_list, GetIdentityColorMatrix(),
-      std::move(surface_damage_rect_list), primary_plane_, &candidate_list,
-      &damage_rect_, &content_bounds_);
+      std::move(surface_damage_rect_list), GetDefaultPrimaryPlane(),
+      &candidate_list, &damage_rect_, &content_bounds_);
 
   EXPECT_EQ(1U, content_bounds_.size());
   EXPECT_EQ(kOverlayTopLeftRect, content_bounds_[0]);
@@ -4324,8 +4324,8 @@
 
   overlay_processor_->ProcessForOverlays(
       resource_provider(), &pass_list, GetIdentityColorMatrix(),
-      std::move(surface_damage_rect_list), primary_plane_, &candidate_list,
-      &damage_rect_, &content_bounds_);
+      std::move(surface_damage_rect_list), GetDefaultPrimaryPlane(),
+      &candidate_list, &damage_rect_, &content_bounds_);
 
   EXPECT_EQ(1U, content_bounds_.size());
   EXPECT_EQ(kOverlayRect, content_bounds_[0]);
@@ -4353,8 +4353,8 @@
 
   overlay_processor_->ProcessForOverlays(
       resource_provider(), &pass_list, GetIdentityColorMatrix(),
-      std::move(surface_damage_rect_list), primary_plane_, &candidate_list,
-      &damage_rect_, &content_bounds_);
+      std::move(surface_damage_rect_list), GetDefaultPrimaryPlane(),
+      &candidate_list, &damage_rect_, &content_bounds_);
 
   EXPECT_EQ(1U, content_bounds_.size());
   EXPECT_EQ(gfx::Rect(0, 0, 11, 11), content_bounds_[0]);
@@ -4383,8 +4383,8 @@
 
   overlay_processor_->ProcessForOverlays(
       resource_provider(), &pass_list, GetIdentityColorMatrix(),
-      std::move(surface_damage_rect_list), primary_plane_, &candidate_list,
-      &damage_rect_, &content_bounds_);
+      std::move(surface_damage_rect_list), GetDefaultPrimaryPlane(),
+      &candidate_list, &damage_rect_, &content_bounds_);
 
   EXPECT_EQ(1U, content_bounds_.size());
   EXPECT_EQ(kOverlayRect, content_bounds_[0]);
@@ -4402,8 +4402,8 @@
 
   overlay_processor_->ProcessForOverlays(
       resource_provider(), &pass_list, GetIdentityColorMatrix(),
-      std::move(surface_damage_rect_list), primary_plane_, &candidate_list,
-      &damage_rect_, &content_bounds_);
+      std::move(surface_damage_rect_list), GetDefaultPrimaryPlane(),
+      &candidate_list, &damage_rect_, &content_bounds_);
 
   ASSERT_TRUE(candidate_list.empty());
   EXPECT_TRUE(content_bounds_.empty());
@@ -4427,8 +4427,8 @@
 
   overlay_processor_->ProcessForOverlays(
       resource_provider(), &pass_list, GetIdentityColorMatrix(),
-      std::move(surface_damage_rect_list), primary_plane_, &candidate_list,
-      &damage_rect_, &content_bounds_);
+      std::move(surface_damage_rect_list), GetDefaultPrimaryPlane(),
+      &candidate_list, &damage_rect_, &content_bounds_);
 
   ASSERT_EQ(1U, content_bounds_.size());
   EXPECT_TRUE(content_bounds_.front().IsEmpty());
@@ -4458,15 +4458,11 @@
 
   AggregatedRenderPassList pass_list;
   pass_list.push_back(std::move(pass));
-  std::optional<OverlayCandidate> output_surface_plane =
-      overlay_processor_->ProcessOutputSurfaceAsOverlay(
-          kDisplaySize, kDisplaySize, kDefaultSIFormat, gfx::ColorSpace(),
-          false /* has_alpha */, 1.0f /* opacity */, gpu::Mailbox());
 
   SurfaceDamageRectList surface_damage_rect_list;
   overlay_processor_->ProcessForOverlays(
       resource_provider(), &pass_list, GetIdentityColorMatrix(),
-      std::move(surface_damage_rect_list), output_surface_plane,
+      std::move(surface_damage_rect_list), GetDefaultPrimaryPlane(),
       &candidate_list, &damage_rect_, &content_bounds_);
 
   EXPECT_EQ(0U, content_bounds_.size());
@@ -4797,10 +4793,6 @@
   SurfaceDamageRectList surface_damage_rect_list;
 
   render_pass_list.push_back(std::move(root_pass));
-  std::optional<OverlayCandidate> output_surface_plane =
-      overlay_processor_->ProcessOutputSurfaceAsOverlay(
-          kDisplaySize, kDisplaySize, kDefaultSIFormat, gfx::ColorSpace(),
-          false /* has_alpha */, 1.0f /* opacity */, gpu::Mailbox());
 
   // Choose 5 here for testing purpose, this value will not change
   constexpr int kDisableOverlayTestVectorSize =
@@ -4843,7 +4835,7 @@
     OverlayCandidateList candidate_list;
     overlay_processor_->ProcessForOverlays(
         resource_provider(), &render_pass_list, GetIdentityColorMatrix(),
-        surface_damage_rect_list, output_surface_plane, &candidate_list,
+        surface_damage_rect_list, GetDefaultPrimaryPlane(), &candidate_list,
         &damage_rect_, &content_bounds_);
 
     EXPECT_EQ(expected_overlays[i],
@@ -6384,14 +6376,10 @@
   OverlayCandidateList candidate_list;
   AggregatedRenderPassList pass_list;
   pass_list.push_back(std::move(pass));
-  std::optional<OverlayCandidate> output_surface_plane =
-      overlay_processor_->ProcessOutputSurfaceAsOverlay(
-          kDisplaySize, kDisplaySize, kDefaultSIFormat, gfx::ColorSpace(),
-          false /* has_alpha */, 1.0f /* opacity */, gpu::Mailbox());
 
   overlay_processor_->ProcessForOverlays(
       resource_provider(), &pass_list, GetIdentityColorMatrix(),
-      std::move(surface_damage_rect_list), output_surface_plane,
+      std::move(surface_damage_rect_list), GetDefaultPrimaryPlane(),
       &candidate_list, &damage_rect_, &content_bounds_);
 
   if (promoted) {
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index 610490f5..441ad99 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -4248,11 +4248,8 @@
   buffer_queue_->EnsureMinNumberOfBuffers(n);
 }
 
+#if BUILDFLAG(IS_OZONE)
 gpu::Mailbox SkiaRenderer::GetPrimaryPlaneOverlayTestingMailbox() {
-#if BUILDFLAG(IS_WIN)
-  // Windows dcomp uses a swap chain for primary plane instead of BufferQueue.
-  return gpu::Mailbox();
-#else
   // For the purpose of testing the overlay configuration, the mailbox for ANY
   // buffer from BufferQueue is good enough because they're all created with
   // identical properties.
@@ -4262,11 +4259,8 @@
   // previous frame's mailbox.)
   CHECK(buffer_queue_);
   return buffer_queue_->GetLastSwappedBuffer();
-#endif
 }
 
-#if BUILDFLAG(IS_OZONE)
-
 DBG_FLAG_FBOOL("delegated.overlay.background_candidate.colored",
                toggle_background_overlay_color)  // False by default.
 
diff --git a/components/viz/service/display/skia_renderer.h b/components/viz/service/display/skia_renderer.h
index 50f159c..c66201d 100644
--- a/components/viz/service/display/skia_renderer.h
+++ b/components/viz/service/display/skia_renderer.h
@@ -73,7 +73,9 @@
   gfx::Rect GetCurrentFramebufferDamage() const override;
   void Reshape(const OutputSurface::ReshapeParams& reshape_params) override;
   void EnsureMinNumberOfBuffers(int n) override;
+#if BUILDFLAG(IS_OZONE)
   gpu::Mailbox GetPrimaryPlaneOverlayTestingMailbox() override;
+#endif
 
  protected:
   bool CanPartialSwap() override;
diff --git a/content/browser/android/content_feature_map.cc b/content/browser/android/content_feature_map.cc
index 651af14..cdfa2c73 100644
--- a/content/browser/android/content_feature_map.cc
+++ b/content/browser/android/content_feature_map.cc
@@ -53,6 +53,7 @@
     &features::kHidePastePopupOnGSB,
     &features::kReduceGpuPriorityOnBackground,
     &features::kContinueGestureOnLosingFocus,
+    &features::kScrollAfterOSKViewportShrinkFix,
     &features::kSmartZoom,
     &features::kTouchDragAndContextMenu,
     &features::kWebBluetoothNewPermissionsBackend,
diff --git a/content/browser/memory/swap_metrics_driver_impl_linux.cc b/content/browser/memory/swap_metrics_driver_impl_linux.cc
index f50f787f..da7b6b2 100644
--- a/content/browser/memory/swap_metrics_driver_impl_linux.cc
+++ b/content/browser/memory/swap_metrics_driver_impl_linux.cc
@@ -6,7 +6,7 @@
 
 #include <memory>
 
-#include "base/byte_count.h"
+#include "base/byte_size.h"
 #include "base/memory/ptr_util.h"
 #include "base/process/process_metrics.h"
 #include "base/time/time.h"
@@ -20,7 +20,7 @@
   base::SystemMemoryInfo memory_info;
   if (!base::GetSystemMemoryInfo(&memory_info))
     return false;
-  return memory_info.swap_total > base::ByteCount(0);
+  return memory_info.swap_total > base::ByteSize(0);
 }
 
 }  // namespace
diff --git a/content/browser/memory_pressure/user_level_memory_pressure_signal_generator.cc b/content/browser/memory_pressure/user_level_memory_pressure_signal_generator.cc
index cf1c758..35e8e6f 100644
--- a/content/browser/memory_pressure/user_level_memory_pressure_signal_generator.cc
+++ b/content/browser/memory_pressure/user_level_memory_pressure_signal_generator.cc
@@ -9,6 +9,8 @@
 #include <unistd.h>
 
 #include "base/android/child_process_binding_types.h"
+#include "base/byte_count.h"
+#include "base/byte_size.h"
 #include "base/compiler_specific.h"
 #include "base/feature_list.h"
 #include "base/files/file.h"
@@ -126,7 +128,8 @@
   latest_metrics_ = UserLevelMemoryPressureMetrics{
       .total_private_footprint =
           GetTotalPrivateFootprintVisibleOrHigherPriorityRenderers(),
-      .available_memory = meminfo.available,
+      .available_memory =
+          base::ByteCount::FromUnsigned(meminfo.available.InBytes()),
       .total_process_count = total_process_count,
       .visible_renderer_count = visible_renderer_count,
   };
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 28abf88..c91132a 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -6731,6 +6731,17 @@
         (renderer_before_unload_end_time - renderer_before_unload_start_time);
     base::UmaHistogramTimes("Navigation.OnBeforeUnloadOverheadTime",
                             on_before_unload_overhead_time);
+    if (for_legacy) {
+      base::UmaHistogramTimes(
+          "Navigation.OnBeforeUnloadOverheadTime."
+          "NoBeforeUnloadHandlerRegistered",
+          on_before_unload_overhead_time);
+    } else {
+      base::UmaHistogramTimes(
+          "Navigation.OnBeforeUnloadOverheadTime."
+          "BeforeUnloadHandlerRegistered",
+          on_before_unload_overhead_time);
+    }
 
     frame_tree_node_->navigator().LogBeforeUnloadTime(
         renderer_before_unload_start_time, renderer_before_unload_end_time,
@@ -16855,15 +16866,18 @@
                 kDumpWithoutCrashing) &&
         frame_tree()->controller().in_navigate_to_pending_entry();
 
-    base::TimeTicks beforeunload_end_time_for_legacy = base::TimeTicks::Now();
+    base::TimeTicks renderer_before_unload_end_time_for_legacy =
+        base::TimeTicks::Now();
 
     if (is_eligible_for_avoid_unnecessary_beforeunload &&
         IsAvoidUnnecessaryBeforeUnloadCheckSyncEnabledFor(
             features::AvoidUnnecessaryBeforeUnloadCheckSyncMode::
                 kWithSendBeforeUnload)) {
       std::move(before_unload_closure)
-          .Run(/*proceed=*/true, send_before_unload_start_time_,
-               beforeunload_end_time_for_legacy);
+          .Run(/*proceed=*/true, /*renderer_before_unload_start_time=*/
+               send_before_unload_start_time_,
+               /*renderer_before_unload_end_time=*/
+               renderer_before_unload_end_time_for_legacy);
       return;
     }
 
@@ -16875,17 +16889,12 @@
             FROM_HERE,
             base::BindOnce(
                 [](blink::mojom::LocalFrame::BeforeUnloadCallback callback,
-                   base::TimeTicks start_time, base::TimeTicks end_time,
+                   base::TimeTicks renderer_before_unload_start_time,
+                   base::TimeTicks renderer_before_unload_end_time,
                    base::WeakPtr<NavigationControllerImpl>
                        navigation_controller,
                    const bool can_be_in_navigate_to_pending_entry,
                    const bool is_renderer_initiated_navigation) {
-                  // Measures the time a posted task spends in the queue before
-                  // execution. Recorded only when `for_legacy` is true.
-                  base::UmaHistogramTimes(
-                      "Navigation.OnBeforeUnloadOverheadTime."
-                      "NoBeforeUnloadHandlerRegistered",
-                      base::TimeTicks::Now() - end_time);
                   if (can_be_in_navigate_to_pending_entry &&
                       navigation_controller) {
                     navigation_controller
@@ -16893,8 +16902,9 @@
                   }
                   SCOPED_CRASH_KEY_BOOL("RFHI", "is_renderer_init_nav",
                                         is_renderer_initiated_navigation);
-                  std::move(callback).Run(/*proceed=*/true, start_time,
-                                          end_time);
+                  std::move(callback).Run(/*proceed=*/true,
+                                          renderer_before_unload_start_time,
+                                          renderer_before_unload_end_time);
                   if (can_be_in_navigate_to_pending_entry &&
                       navigation_controller) {
                     navigation_controller
@@ -16902,8 +16912,10 @@
                   }
                 },
                 std::move(before_unload_closure),
+                /*renderer_before_unload_start_time=*/
                 send_before_unload_start_time_,
-                beforeunload_end_time_for_legacy,
+                /*renderer_before_unload_end_time=*/
+                renderer_before_unload_end_time_for_legacy,
                 frame_tree()->controller().GetWeakPtr(),
                 can_be_in_navigate_to_pending_entry,
                 is_renderer_initiated_navigation));
diff --git a/content/browser/storage_partition_impl_unittest.cc b/content/browser/storage_partition_impl_unittest.cc
index 2cb184c..6c4e808 100644
--- a/content/browser/storage_partition_impl_unittest.cc
+++ b/content/browser/storage_partition_impl_unittest.cc
@@ -38,6 +38,7 @@
 #include "base/test/mock_callback.h"
 #include "base/test/scoped_command_line.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
 #include "base/test/test_future.h"
 #include "base/threading/sequence_local_storage_slot.h"
 #include "base/threading/thread.h"
@@ -324,27 +325,16 @@
 
 class RemoveLocalStorageTester {
  public:
-  RemoveLocalStorageTester(content::BrowserTaskEnvironment* task_environment,
-                           TestBrowserContext* browser_context)
-      : task_environment_(task_environment),
-        storage_partition_(browser_context->GetDefaultStoragePartition()),
-        dom_storage_context_(storage_partition_->GetDOMStorageContext()) {}
+  explicit RemoveLocalStorageTester(TestBrowserContext* browser_context)
+      : browser_context_(browser_context) {}
 
   RemoveLocalStorageTester(const RemoveLocalStorageTester&) = delete;
   RemoveLocalStorageTester& operator=(const RemoveLocalStorageTester&) = delete;
 
-  ~RemoveLocalStorageTester() {
-    // Tests which bring up a real Local Storage context need to shut it down
-    // and wait for the database to be closed before terminating; otherwise the
-    // TestBrowserContext may fail to delete its temp dir, and it will not be
-    // happy about that.
-    static_cast<DOMStorageContextWrapper*>(dom_storage_context_)->Shutdown();
-    task_environment_->RunUntilIdle();
-  }
+  ~RemoveLocalStorageTester() = default;
 
   // Returns true, if the given origin URL exists.
   bool DOMStorageExistsForOrigin(const url::Origin& origin) {
-    GetLocalStorageUsage();
     for (size_t i = 0; i < infos_.size(); ++i) {
       if (origin == infos_[i].storage_key.origin())
         return true;
@@ -357,31 +347,37 @@
                              const url::Origin& origin3) {
     // NOTE: Tests which call this method depend on implementation details of
     // how exactly the Local Storage subsystem stores persistent data.
+    // NOTE: it's very important to avoid creating the local storage
+    // database/C++ objects before calling this method. That happens when the
+    // storage partition is first created/accessed.
 
     base::RunLoop open_loop;
     auto database = storage::AsyncDomStorageDatabase::Open(
         storage::StorageType::kLocalStorage,
-        storage_partition_->GetPath().Append(storage::kLocalStoragePath),
+        // Technically this should be the partition path, but in this context
+        // it's the same path, and calling `GetStoragePartition()` too early
+        // will cause a race against DOMStorageContextWrapper/LocalStorageImpl
+        // creation.
+        browser_context_->GetPath().Append(storage::kLocalStoragePath),
         storage::kLocalStorageLeveldbName, /*memory_dump_id=*/std::nullopt,
-        base::SingleThreadTaskRunner::GetCurrentDefault(),
         base::BindLambdaForTesting([&](storage::DbStatus status) {
           ASSERT_TRUE(status.ok());
           open_loop.Quit();
         }));
     open_loop.Run();
 
-    base::RunLoop populate_loop;
     database->database().PostTaskWithThisObject(
         base::BindLambdaForTesting([&](storage::DomStorageDatabase* db) {
           PopulateDatabase(&db->GetLevelDB(), origin1, origin2, origin3);
-          populate_loop.Quit();
         }));
-    populate_loop.Run();
-
-    // Ensure that this database is fully closed before returning.
     database.reset();
-    task_environment_->RunUntilIdle();
 
+    // This will trigger creating the `StoragePartitionImpl`, the
+    // `DOMStorageContextWrapper`, etc. It shouldn't race `database->database()`
+    // destruction because the `DomStorageDatabase` used internally will run on
+    // the same sequenced task runner, so opening it will be enqueued behind
+    // destruction activities.
+    GetLocalStorageUsage();
     EXPECT_TRUE(DOMStorageExistsForOrigin(origin1));
     EXPECT_TRUE(DOMStorageExistsForOrigin(origin2));
     EXPECT_TRUE(DOMStorageExistsForOrigin(origin3));
@@ -430,6 +426,33 @@
     ASSERT_TRUE(db->Put(CreateDataKey(origin3), {}).ok());
   }
 
+  // Clears LocalStorage according to parameters, and refreshes the local cache
+  // of metadata.
+  void ClearLocalStorage(
+      content::StoragePartition* partition,
+      const base::Time delete_begin,
+      const base::Time delete_end,
+      BrowsingDataFilterBuilder* filter_builder,
+      StoragePartition::StorageKeyPolicyMatcherFunction storage_key_matcher) {
+    base::RunLoop run_loop;
+    partition->ClearData(StoragePartitionImpl::REMOVE_DATA_MASK_LOCAL_STORAGE,
+                         StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
+                         filter_builder, std::move(storage_key_matcher),
+                         nullptr, false, delete_begin, delete_end,
+                         run_loop.QuitClosure());
+    run_loop.Run();
+    GetLocalStorageUsage();
+  }
+
+  void GetLocalStorageUsage() {
+    base::test::TestFuture<const std::vector<content::StorageUsageInfo>&>
+        future;
+    browser_context_->GetDefaultStoragePartition()
+        ->GetDOMStorageContext()
+        ->GetLocalStorageUsage(future.GetCallback());
+    infos_ = future.Get();
+  }
+
  private:
   static std::vector<uint8_t> CreateDataKey(const url::Origin& origin) {
     auto origin_str = origin.Serialize();
@@ -486,25 +509,7 @@
     return key;
   }
 
-  void GetLocalStorageUsage() {
-    base::RunLoop loop;
-    dom_storage_context_->GetLocalStorageUsage(
-        base::BindOnce(&RemoveLocalStorageTester::OnGotLocalStorageUsage,
-                       base::Unretained(this), loop.QuitClosure()));
-    loop.Run();
-  }
-
-  void OnGotLocalStorageUsage(
-      base::OnceClosure quit_closure,
-      const std::vector<content::StorageUsageInfo>& infos) {
-    infos_ = infos;
-    std::move(quit_closure).Run();
-  }
-
-  // We don't own these pointers.
-  const raw_ptr<BrowserTaskEnvironment> task_environment_;
-  const raw_ptr<StoragePartition> storage_partition_;
-  raw_ptr<DOMStorageContext> dom_storage_context_;
+  raw_ptr<TestBrowserContext> browser_context_;
 
   std::vector<content::StorageUsageInfo> infos_;
 };
@@ -747,11 +752,11 @@
     const base::Time delete_end,
     BrowsingDataFilterBuilder* filter_builder,
     StoragePartition::StorageKeyPolicyMatcherFunction storage_key_matcher,
-    base::RunLoop* run_loop) {
+    base::OnceClosure on_completed) {
   partition->ClearData(
       remove_mask, StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
       filter_builder, std::move(storage_key_matcher), nullptr, false,
-      delete_begin, delete_end, run_loop->QuitClosure());
+      delete_begin, delete_end, std::move(on_completed));
 }
 
 void ClearData(content::StoragePartition* partition, base::RunLoop* run_loop) {
@@ -851,10 +856,7 @@
 
 class StoragePartitionImplTest : public testing::Test {
  public:
-  StoragePartitionImplTest()
-      : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP,
-                          base::test::TaskEnvironment::TimeSource::MOCK_TIME),
-        browser_context_(new TestBrowserContext()) {
+  StoragePartitionImplTest() : browser_context_(new TestBrowserContext()) {
     feature_list_.InitWithFeatures({network::features::kInterestGroupStorage,
                                     network::features::kSharedStorageAPI},
                                    {});
@@ -882,14 +884,13 @@
 
   TestBrowserContext* browser_context() { return browser_context_.get(); }
 
-  content::BrowserTaskEnvironment* task_environment() {
-    return &task_environment_;
-  }
+  base::test::TaskEnvironment* task_environment() { return &task_environment_; }
 
  private:
   base::test::ScopedCommandLine command_line_;
   base::test::ScopedFeatureList feature_list_;
-  content::BrowserTaskEnvironment task_environment_;
+  content::BrowserTaskEnvironment task_environment_{
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
   std::unique_ptr<TestBrowserContext> browser_context_;
   scoped_refptr<storage::MockQuotaManager> quota_manager_;
 };
@@ -897,8 +898,7 @@
 class StoragePartitionShaderClearTest : public testing::Test {
  public:
   StoragePartitionShaderClearTest()
-      : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP),
-        browser_context_(new TestBrowserContext()) {
+      : browser_context_(new TestBrowserContext()) {
     InitGpuDiskCacheFactorySingleton();
 
     gpu::GpuDiskCacheType type = gpu::GpuDiskCacheType::kGlShaders;
@@ -1414,7 +1414,7 @@
   auto mock_policy = base::MakeRefCounted<storage::MockSpecialStoragePolicy>();
   mock_policy->AddProtected(kOrigin1.GetURL());
 
-  RemoveLocalStorageTester tester(task_environment(), browser_context());
+  RemoveLocalStorageTester tester(browser_context());
 
   tester.AddDOMStorageTestData(kOrigin1, kOrigin2, kOrigin3);
 
@@ -1422,20 +1422,10 @@
       browser_context()->GetDefaultStoragePartition());
   partition->OverrideSpecialStoragePolicyForTesting(mock_policy.get());
 
-  base::RunLoop run_loop;
-  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
-      FROM_HERE,
-      base::BindOnce(
-          &ClearStuff, StoragePartitionImpl::REMOVE_DATA_MASK_LOCAL_STORAGE,
-          partition, base::Time(), base::Time::Max(),
-          /*filter_builder=*/nullptr,
-          base::BindRepeating(&DoesOriginMatchForUnprotectedWeb), &run_loop));
-  run_loop.Run();
-  // ClearData only guarantees that tasks to delete data are scheduled when its
-  // callback is invoked. It doesn't guarantee data has actually been cleared.
-  // So run all scheduled tasks to make sure data is cleared.
-  base::RunLoop().RunUntilIdle();
-
+  tester.ClearLocalStorage(
+      partition, base::Time(), base::Time::Max(),
+      /*filter_builder=*/nullptr,
+      base::BindRepeating(&DoesOriginMatchForUnprotectedWeb));
   EXPECT_TRUE(tester.DOMStorageExistsForOrigin(kOrigin1));
   EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin2));
   EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin3));
@@ -1450,7 +1440,7 @@
   auto mock_policy = base::MakeRefCounted<storage::MockSpecialStoragePolicy>();
   mock_policy->AddProtected(kOrigin1.GetURL());
 
-  RemoveLocalStorageTester tester(task_environment(), browser_context());
+  RemoveLocalStorageTester tester(browser_context());
 
   tester.AddDOMStorageTestData(kOrigin1, kOrigin2, kOrigin3);
 
@@ -1458,22 +1448,10 @@
       browser_context()->GetDefaultStoragePartition());
   partition->OverrideSpecialStoragePolicyForTesting(mock_policy.get());
 
-  base::RunLoop run_loop;
-  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&ClearStuff,
-                     StoragePartitionImpl::REMOVE_DATA_MASK_LOCAL_STORAGE,
-                     partition, base::Time(), base::Time::Max(),
-                     /*filter_builder=*/nullptr,
-                     base::BindRepeating(
-                         &DoesOriginMatchForBothProtectedAndUnprotectedWeb),
-                     &run_loop));
-  run_loop.Run();
-  // ClearData only guarantees that tasks to delete data are scheduled when its
-  // callback is invoked. It doesn't guarantee data has actually been cleared.
-  // So run all scheduled tasks to make sure data is cleared.
-  base::RunLoop().RunUntilIdle();
-
+  tester.ClearLocalStorage(
+      partition, base::Time(), base::Time::Max(),
+      /*filter_builder=*/nullptr,
+      base::BindRepeating(&DoesOriginMatchForBothProtectedAndUnprotectedWeb));
   // Even if kOrigin1 is protected, it will be deleted since we specify
   // ClearData to delete protected data.
   EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin1));
@@ -1486,7 +1464,7 @@
   const url::Origin kOrigin2 = url::Origin::Create(GURL("http://host2:1/"));
   const url::Origin kOrigin3 = url::Origin::Create(GURL("http://host3:1/"));
 
-  RemoveLocalStorageTester tester(task_environment(), browser_context());
+  RemoveLocalStorageTester tester(browser_context());
 
   tester.AddDOMStorageTestData(kOrigin1, kOrigin2, kOrigin3);
 
@@ -1494,22 +1472,10 @@
       browser_context()->GetDefaultStoragePartition());
   base::Time a_week_ago = base::Time::Now() - base::Days(7);
 
-  base::RunLoop run_loop;
-  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&ClearStuff,
-                     StoragePartitionImpl::REMOVE_DATA_MASK_LOCAL_STORAGE,
-                     partition, a_week_ago, base::Time::Max(),
-                     /*filter_builder=*/nullptr,
-                     base::BindRepeating(
-                         &DoesOriginMatchForBothProtectedAndUnprotectedWeb),
-                     &run_loop));
-  run_loop.Run();
-  // ClearData only guarantees that tasks to delete data are scheduled when its
-  // callback is invoked. It doesn't guarantee data has actually been cleared.
-  // So run all scheduled tasks to make sure data is cleared.
-  base::RunLoop().RunUntilIdle();
-
+  tester.ClearLocalStorage(
+      partition, a_week_ago, base::Time::Max(),
+      /*filter_builder=*/nullptr,
+      base::BindRepeating(&DoesOriginMatchForBothProtectedAndUnprotectedWeb));
   // kOrigin1 and kOrigin2 do not have age more than a week.
   EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin1));
   EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin2));
@@ -1521,7 +1487,7 @@
   const url::Origin kOrigin2 = url::Origin::Create(GURL("http://host2:1/"));
   const url::Origin kOrigin3 = url::Origin::Create(GURL("http://host3:1/"));
 
-  RemoveLocalStorageTester tester(task_environment(), browser_context());
+  RemoveLocalStorageTester tester(browser_context());
 
   tester.AddDOMStorageTestData(kOrigin1, kOrigin2, kOrigin3);
 
@@ -1533,19 +1499,9 @@
   filter_builder->AddOrigin(kOrigin1);
   filter_builder->AddOrigin(kOrigin2);
 
-  base::RunLoop run_loop;
-  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
-      FROM_HERE,
-      base::BindOnce(
-          &ClearStuff, StoragePartitionImpl::REMOVE_DATA_MASK_LOCAL_STORAGE,
-          partition, base::Time::Min(), base::Time::Max(), filter_builder.get(),
-          StoragePartition::StorageKeyPolicyMatcherFunction(), &run_loop));
-  run_loop.Run();
-  // ClearData only guarantees that tasks to delete data are scheduled when its
-  // callback is invoked. It doesn't guarantee data has actually been cleared.
-  // So run all scheduled tasks to make sure data is cleared.
-  base::RunLoop().RunUntilIdle();
-
+  tester.ClearLocalStorage(partition, base::Time::Min(), base::Time::Max(),
+                           filter_builder.get(),
+                           StoragePartition::StorageKeyPolicyMatcherFunction());
   // kOrigin3 is not filtered by the filter builder.
   EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin1));
   EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin2));
@@ -1558,7 +1514,7 @@
   const url::Origin kOrigin2 = url::Origin::Create(GURL("http://host2:1/"));
   const url::Origin kOrigin3 = url::Origin::Create(GURL("http://host3:1/"));
 
-  RemoveLocalStorageTester tester(task_environment(), browser_context());
+  RemoveLocalStorageTester tester(browser_context());
 
   tester.AddDOMStorageTestData(kOrigin1, kOrigin2, kOrigin3);
 
@@ -1566,16 +1522,10 @@
       browser_context()->GetDefaultStoragePartition());
 
   base::RunLoop run_loop;
-  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&ClearDataForOrigin,
-                     StoragePartitionImpl::REMOVE_DATA_MASK_LOCAL_STORAGE,
-                     partition, kUrl1, &run_loop));
+  ClearDataForOrigin(StoragePartitionImpl::REMOVE_DATA_MASK_LOCAL_STORAGE,
+                     partition, kUrl1, &run_loop);
   run_loop.Run();
-  // ClearData only guarantees that tasks to delete data are scheduled when its
-  // callback is invoked. It doesn't guarantee data has actually been cleared.
-  // So run all scheduled tasks to make sure data is cleared.
-  base::RunLoop().RunUntilIdle();
+  tester.GetLocalStorageUsage();
 
   // kOrigin1 should be cleared.
   EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin1));
@@ -2535,7 +2485,7 @@
                      partition, base::Time(), base::Time::Max(),
                      /*filter_builder=*/nullptr,
                      base::BindRepeating(&DoesOriginMatchForUnprotectedWeb),
-                     &clear_run_loop));
+                     clear_run_loop.QuitClosure()));
   clear_run_loop.Run();
 
   // ClearData only guarantees that tasks to delete data are scheduled when its
@@ -2574,7 +2524,7 @@
                      /*filter_builder=*/nullptr,
                      base::BindRepeating(
                          &DoesOriginMatchForBothProtectedAndUnprotectedWeb),
-                     &clear_run_loop));
+                     clear_run_loop.QuitClosure()));
   clear_run_loop.Run();
 
   // ClearData only guarantees that tasks to delete data are scheduled when its
@@ -2612,7 +2562,7 @@
           /*filter_builder=*/nullptr,
           base::BindRepeating(
               &DoesOriginMatchForBothProtectedAndUnprotectedWeb),
-          &clear_run_loop));
+          clear_run_loop.QuitClosure()));
   clear_run_loop.Run();
 
   // ClearData only guarantees that tasks to delete data are scheduled when its
diff --git a/content/browser/web_ui_browser_interface_broker_registry.cc b/content/browser/web_ui_browser_interface_broker_registry.cc
index 57316a8..7003e03 100644
--- a/content/browser/web_ui_browser_interface_broker_registry.cc
+++ b/content/browser/web_ui_browser_interface_broker_registry.cc
@@ -9,13 +9,43 @@
 
 namespace content {
 
-WebUIBrowserInterfaceBrokerRegistry::WebUIBrowserInterfaceBrokerRegistry() {
-  GetContentClient()->browser()->RegisterWebUIInterfaceBrokers(*this);
-}
-
+WebUIBrowserInterfaceBrokerRegistry::WebUIBrowserInterfaceBrokerRegistry() =
+    default;
 WebUIBrowserInterfaceBrokerRegistry::~WebUIBrowserInterfaceBrokerRegistry() =
     default;
 
+// This registry maintains a mapping from WebUI to its MojoJS interface broker
+// initializer, i.e. callbacks that populate an interface broker's binder map
+// with interfaces exposed to MojoJS. If such a mapping exists, we instantiate
+// the broker in ReadyToCommitNavigation, enable MojoJS bindings for this
+// frame, and ask renderer to use it to handle Mojo.bindInterface calls.
+WebUIBrowserInterfaceBrokerRegistry&
+WebUIBrowserInterfaceBrokerRegistry::GetTrustedRegistry() {
+  static base::NoDestructor<
+      std::unique_ptr<WebUIBrowserInterfaceBrokerRegistry>>
+      trusted_registry([&] {
+        auto trusted = std::make_unique<WebUIBrowserInterfaceBrokerRegistry>();
+        GetContentClient()->browser()->RegisterTrustedWebUIInterfaceBrokers(
+            *trusted);
+        return trusted;
+      }());
+  return **trusted_registry;
+}
+
+WebUIBrowserInterfaceBrokerRegistry&
+WebUIBrowserInterfaceBrokerRegistry::GetUntrustedRegistry() {
+  static base::NoDestructor<
+      std::unique_ptr<WebUIBrowserInterfaceBrokerRegistry>>
+      untrusted_registry([&] {
+        auto untrusted =
+            std::make_unique<WebUIBrowserInterfaceBrokerRegistry>();
+        GetContentClient()->browser()->RegisterUntrustedWebUIInterfaceBrokers(
+            *untrusted);
+        return untrusted;
+      }());
+  return **untrusted_registry;
+}
+
 std::unique_ptr<PerWebUIBrowserInterfaceBroker>
 WebUIBrowserInterfaceBrokerRegistry::CreateInterfaceBroker(
     WebUIController& controller) {
diff --git a/content/browser/webui/web_ui_impl.cc b/content/browser/webui/web_ui_impl.cc
index 53a3368..17f7352 100644
--- a/content/browser/webui/web_ui_impl.cc
+++ b/content/browser/webui/web_ui_impl.cc
@@ -36,6 +36,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_ui_browser_interface_broker_registry.h"
 #include "content/public/browser/web_ui_controller.h"
 #include "content/public/browser/web_ui_message_handler.h"
 #include "content/public/common/bindings_policy.h"
@@ -143,6 +144,7 @@
   // Note: Calling this might delete |web_content_| and |frame_host_|. The two
   // pointers are now potentially dangling.
   // See https://crbug.com/1308391
+  broker_.reset();
   controller_.reset();
 
   remote_.reset();
@@ -222,6 +224,30 @@
       receiver_.BindNewEndpointAndPassRemote());
 }
 
+WebUIBrowserInterfaceBrokerRegistry& GetRegistryFor(
+    WebUIController& controller) {
+  switch (controller.GetTrustPolicy()) {
+    case WebUIController::TrustPolicy::kTrusted:
+      return WebUIBrowserInterfaceBrokerRegistry::GetTrustedRegistry();
+    case WebUIController::TrustPolicy::kUntrusted:
+      return WebUIBrowserInterfaceBrokerRegistry::GetUntrustedRegistry();
+  }
+}
+
+void WebUIImpl::SetUpMojoInterfaceBroker() {
+  CHECK(GetController()) << "controller has not been set yet";
+
+  broker_ =
+      GetRegistryFor(*GetController()).CreateInterfaceBroker(*GetController());
+  if (broker_) {
+    RenderFrameHostImpl* rfh =
+        static_cast<RenderFrameHostImpl*>(GetRenderFrameHost());
+    // If this WebUIController has a per-WebUI interface broker, create the
+    // broker's remote and ask renderer to use it.
+    rfh->EnableMojoJsBindingsWithBroker(broker_->BindNewPipeAndPassRemote());
+  }
+}
+
 void WebUIImpl::TearDownMojoConnection() {
   // This is expected to be called only for outermost main frames.
   if (frame_host_->GetParentOrOuterDocument())
@@ -276,7 +302,8 @@
 }
 
 void WebUIImpl::SetController(std::unique_ptr<WebUIController> controller) {
-  DCHECK(controller);
+  CHECK(controller);
+  CHECK(!controller_) << "controller cannot be set twice";
   controller_ = std::move(controller);
 }
 
diff --git a/content/browser/webui/web_ui_impl.h b/content/browser/webui/web_ui_impl.h
index f1eeb5c9..f42d132 100644
--- a/content/browser/webui/web_ui_impl.h
+++ b/content/browser/webui/web_ui_impl.h
@@ -24,6 +24,7 @@
 
 namespace content {
 class NavigationRequest;
+class PerWebUIBrowserInterfaceBroker;
 class RenderFrameHost;
 class RenderFrameHostImpl;
 class WebUIMainFrameObserver;
@@ -58,6 +59,11 @@
 
   // Called right after AllowBindings is notified to a RenderFrame.
   void SetUpMojoConnection();
+  // Sets up a "broker" object which will accept incoming mojo connections and
+  // set up the appropriate handlers. The controller must already be set before
+  // calling this. This method may be called multiple times if the WebUI is
+  // reused.
+  void SetUpMojoInterfaceBroker();
 
   // Called when a RenderFrame is deleted for a WebUI (i.e. a renderer crash).
   void TearDownMojoConnection();
@@ -158,6 +164,8 @@
   // Notifies this WebUI about notifications in the main frame.
   const std::unique_ptr<WebUIMainFrameObserver> web_contents_observer_;
 
+  // broker_ may change if a WebUI instance if reused.
+  std::unique_ptr<PerWebUIBrowserInterfaceBroker> broker_;
   std::unique_ptr<WebUIController> controller_;
 
   mojo::AssociatedRemote<mojom::WebUI> remote_;
diff --git a/content/browser/webui/web_ui_main_frame_observer.cc b/content/browser/webui/web_ui_main_frame_observer.cc
index f2ad568..5762f9a 100644
--- a/content/browser/webui/web_ui_main_frame_observer.cc
+++ b/content/browser/webui/web_ui_main_frame_observer.cc
@@ -172,8 +172,7 @@
     return;
   }
 
-  web_ui_->GetController()->WebUIReadyToCommitNavigation(
-      web_ui_->GetRenderFrameHost());
+  web_ui_->SetUpMojoInterfaceBroker();
 
   GURL site_url =
       web_ui_->GetRenderFrameHost()->GetSiteInstance()->GetSiteURL();
diff --git a/content/browser/webui/web_ui_managed_interface_browsertest.cc b/content/browser/webui/web_ui_managed_interface_browsertest.cc
index 2c43aa0..a63bb326 100644
--- a/content/browser/webui/web_ui_managed_interface_browsertest.cc
+++ b/content/browser/webui/web_ui_managed_interface_browsertest.cc
@@ -255,11 +255,14 @@
         delete;
     ~TestContentBrowserClient() override = default;
 
-    void RegisterWebUIInterfaceBrokers(
+    void RegisterTrustedWebUIInterfaceBrokers(
         WebUIBrowserInterfaceBrokerRegistry& registry) override {
       registry.ForWebUI<WebUIManagedInterfaceTestUI>()
           .Add<mojom::TestWebUIJsBridge>();
     }
+
+    void RegisterUntrustedWebUIInterfaceBrokers(
+        WebUIBrowserInterfaceBrokerRegistry& registry) override {}
   };
 
   std::unique_ptr<TestFooWebUIControllerFactory> factory_;
diff --git a/content/common/features.cc b/content/common/features.cc
index 74393f28..b32290e 100644
--- a/content/common/features.cc
+++ b/content/common/features.cc
@@ -600,6 +600,13 @@
              base::FEATURE_DISABLED_BY_DEFAULT);
 #endif
 
+// Fix for scrolling to focused editable input fields after tapping to show the
+// on-screen keyboard (crbug.com/462636368).
+#if BUILDFLAG(IS_ANDROID)
+BASE_FEATURE(kScrollAfterOSKViewportShrinkFix,
+             base::FEATURE_ENABLED_BY_DEFAULT);
+#endif
+
 BASE_FEATURE(kServiceWorkerAvoidMainThreadForInitialization,
              base::FEATURE_ENABLED_BY_DEFAULT);
 
diff --git a/content/common/features.h b/content/common/features.h
index 804871b5c..8155191 100644
--- a/content/common/features.h
+++ b/content/common/features.h
@@ -194,6 +194,9 @@
     kResumeNavigationWithSpeculativeRFHProcessGone);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(
     kPartitionAllocSchedulerLoopQuarantineTaskObserverForBrowserUIThread);
+#if BUILDFLAG(IS_ANDROID)
+CONTENT_EXPORT BASE_DECLARE_FEATURE(kScrollAfterOSKViewportShrinkFix);
+#endif
 CONTENT_EXPORT BASE_DECLARE_FEATURE(kSendBeaconThrowForBlobWithNonSimpleType);
 CONTENT_EXPORT BASE_DECLARE_FEATURE(
     kServiceWorkerAvoidMainThreadForInitialization);
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java
index 3b09c1e9..0875cd2b 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java
@@ -72,6 +72,7 @@
 import org.chromium.content.browser.WindowEventObserverManager;
 import org.chromium.content.browser.picker.InputDialogContainer;
 import org.chromium.content.browser.webcontents.WebContentsImpl;
+import org.chromium.content.common.ContentInternalFeatures;
 import org.chromium.content_public.browser.ContentFeatureList;
 import org.chromium.content_public.browser.ContentFeatureMap;
 import org.chromium.content_public.browser.ImeAdapter;
@@ -1715,7 +1716,14 @@
     @CalledByNative
     private void onResizeScrollableViewport(boolean contentsHeightReduced) {
         if (!contentsHeightReduced) {
-            cancelRequestToScrollFocusedEditableNodeIntoView();
+            // Note: When the keyboard is shown, the viewport height can grow and shrink as various
+            // pieces of state are updated asynchronously. If we're waiting to scroll (non-empty
+            // mFocusPreOSKViewportRect), don't scroll yet, but don't cancel the request either.
+            // TODO(b/462636368): Avoid excessive churn in the Blink viewport height.
+            if (!ContentFeatureMap.isEnabled(
+                    ContentInternalFeatures.SCROLL_AFTER_OSK_VIEWPORT_SHRINK_FIX)) {
+                cancelRequestToScrollFocusedEditableNodeIntoView();
+            }
             return;
         }
 
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 9876271..0df44c5f 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -1695,7 +1695,9 @@
   // The exposed interfaces are grouped by the WebUI controller type. For any
   // given WebUI page, only the interfaces corresponding to its controller type
   // will be exposed.
-  virtual void RegisterWebUIInterfaceBrokers(
+  virtual void RegisterTrustedWebUIInterfaceBrokers(
+      WebUIBrowserInterfaceBrokerRegistry& registry) {}
+  virtual void RegisterUntrustedWebUIInterfaceBrokers(
       WebUIBrowserInterfaceBrokerRegistry& registry) {}
 
   // Allows the embedder to register browser channel-associated interfaces that
diff --git a/content/public/browser/web_ui_browser_interface_broker_registry.h b/content/public/browser/web_ui_browser_interface_broker_registry.h
index e5bd3d6..7be0b6f 100644
--- a/content/public/browser/web_ui_browser_interface_broker_registry.h
+++ b/content/public/browser/web_ui_browser_interface_broker_registry.h
@@ -97,12 +97,15 @@
 class CONTENT_EXPORT WebUIBrowserInterfaceBrokerRegistry {
  public:
   WebUIBrowserInterfaceBrokerRegistry();
-  ~WebUIBrowserInterfaceBrokerRegistry();
   WebUIBrowserInterfaceBrokerRegistry(
       const WebUIBrowserInterfaceBrokerRegistry&) = delete;
+  ~WebUIBrowserInterfaceBrokerRegistry();
   WebUIBrowserInterfaceBrokerRegistry& operator=(
       const WebUIBrowserInterfaceBrokerRegistry&) = delete;
 
+  static WebUIBrowserInterfaceBrokerRegistry& GetTrustedRegistry();
+  static WebUIBrowserInterfaceBrokerRegistry& GetUntrustedRegistry();
+
   template <typename ControllerType>
   InterfaceRegistrationHelper<ControllerType> ForWebUI() {
     // WebUIController::GetType() requires a instantiated WebUIController
@@ -158,24 +161,6 @@
   std::unique_ptr<PerWebUIBrowserInterfaceBroker> CreateInterfaceBroker(
       WebUIController& controller);
 
-  // Add interface |binder| to all WebUIs registered here.
-  //
-  // This method should only be used in tests. This method should be called
-  // after ContentBrowserClient::RegisterWebUIInterfaceBrokers and before WebUIs
-  // being created.
-  template <typename Interface>
-  void AddBinderForTesting(
-      base::RepeatingCallback<void(WebUIController*,
-                                   mojo::PendingReceiver<Interface>)> binder) {
-    for (auto& it : binder_initializers_) {
-      it.second.push_back(base::BindRepeating(
-          [](decltype(binder) binder, WebUIBinderMap* binder_map) {
-            binder_map->Add<Interface>(binder);
-          },
-          binder));
-    }
-  }
-
  private:
   // Note: |global_binder_initializers_| are available to all WebUIs with a
   // |PerWebUIBrowserInterfaceBroker|.
diff --git a/content/public/browser/web_ui_controller.cc b/content/public/browser/web_ui_controller.cc
index 83501b0..f318bf6b 100644
--- a/content/public/browser/web_ui_controller.cc
+++ b/content/public/browser/web_ui_controller.cc
@@ -4,26 +4,11 @@
 
 #include "content/public/browser/web_ui_controller.h"
 
-#include "base/no_destructor.h"
-#include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/browser/webui/web_ui_managed_interface.h"
-#include "content/public/browser/web_ui_browser_interface_broker_registry.h"
 #include "url/gurl.h"
 
 namespace content {
 
-namespace {
-// This registry maintains a mapping from WebUI to its MojoJS interface broker
-// initializer, i.e. callbacks that populate an interface broker's binder map
-// with interfaces exposed to MojoJS. If such a mapping exists, we instantiate
-// the broker in ReadyToCommitNavigation, enable MojoJS bindings for this
-// frame, and ask renderer to use it to handle Mojo.bindInterface calls.
-WebUIBrowserInterfaceBrokerRegistry& GetWebUIBrowserInterfaceBrokerRegistry() {
-  static base::NoDestructor<WebUIBrowserInterfaceBrokerRegistry> registry;
-  return *registry;
-}
-}  // namespace
-
 WebUIController::WebUIController(WebUI* web_ui) : web_ui_(web_ui) {}
 
 WebUIController::~WebUIController() {
@@ -41,22 +26,12 @@
   return nullptr;
 }
 
-bool WebUIController::IsJavascriptErrorReportingEnabled() {
-  return true;
+WebUIController::TrustPolicy WebUIController::GetTrustPolicy() {
+  return TrustPolicy::kTrusted;
 }
 
-void WebUIController::WebUIReadyToCommitNavigation(
-    RenderFrameHost* render_frame_host) {
-  broker_ =
-      GetWebUIBrowserInterfaceBrokerRegistry().CreateInterfaceBroker(*this);
-
-  if (broker_) {
-    RenderFrameHostImpl* rfh =
-        static_cast<RenderFrameHostImpl*>(render_frame_host);
-    // If this WebUIController has a per-WebUI interface broker, create the
-    // broker's remote and ask renderer to use it.
-    rfh->EnableMojoJsBindingsWithBroker(broker_->BindNewPipeAndPassRemote());
-  }
+bool WebUIController::IsJavascriptErrorReportingEnabled() {
+  return true;
 }
 
 }  // namespace content
diff --git a/content/public/browser/web_ui_controller.h b/content/public/browser/web_ui_controller.h
index 80843d7..8cf9982 100644
--- a/content/public/browser/web_ui_controller.h
+++ b/content/public/browser/web_ui_controller.h
@@ -18,7 +18,6 @@
 namespace content {
 
 class Page;
-class PerWebUIBrowserInterfaceBroker;
 class RenderFrameHost;
 class WebUI;
 class WebUIBrowserInterfaceBrokerRegistry;
@@ -31,6 +30,11 @@
   // This is used for safe downcasting.
   typedef const void* Type;
 
+  enum TrustPolicy {
+    kTrusted,
+    kUntrusted,
+  };
+
   explicit WebUIController(WebUI* web_ui);
   virtual ~WebUIController();
 
@@ -51,10 +55,6 @@
   // its state if necessary.
   virtual void WebUIPrimaryPageChanged(Page& page) {}
 
-  // Called when a WebUI page load is about to be committed, even if RenderFrame
-  // is reused. This sets up MojoJS interface broker.
-  void WebUIReadyToCommitNavigation(RenderFrameHost* render_frame_host);
-
   WebUI* web_ui() const { return web_ui_; }
 
   // Performs a safe downcast to a WebUIController subclass.
@@ -84,15 +84,10 @@
 
   // TODO(calamity): Make this abstract once all subclasses implement GetType().
   virtual Type GetType();
-
-  PerWebUIBrowserInterfaceBroker* broker_for_testing() { return broker_.get(); }
+  virtual TrustPolicy GetTrustPolicy();
 
  private:
   raw_ptr<WebUI> web_ui_;
-
-  // The interface broker that handles Mojo.bindInterface requests from the
-  // renderer.
-  std::unique_ptr<PerWebUIBrowserInterfaceBroker> broker_;
 };
 
 // This macro declares a static variable inside the class that inherits from
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 0b1c9da60..5f4330e 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -14,6 +14,7 @@
 #include "content/common/buildflags.h"
 #include "content/public/common/btm_utils.h"
 #include "content/public/common/buildflags.h"
+#include "media/base/media_switches.h"
 
 namespace features {
 
@@ -1400,7 +1401,12 @@
 };
 
 VideoCaptureServiceConfiguration GetVideoCaptureServiceConfiguration() {
-#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
+#if BUILDFLAG(IS_ANDROID)
+  if (base::FeatureList::IsEnabled(media::kAndroidZeroCopyVideoCapture)) {
+    return VideoCaptureServiceConfiguration::kEnabledForOutOfProcess;
+  }
+  return VideoCaptureServiceConfiguration::kEnabledForBrowserProcess;
+#elif BUILDFLAG(IS_IOS)
   return VideoCaptureServiceConfiguration::kEnabledForBrowserProcess;
 #else
   return base::FeatureList::IsEnabled(
diff --git a/content/public/test/test_web_ui.cc b/content/public/test/test_web_ui.cc
index 4fc609fe..3acb837 100644
--- a/content/public/test/test_web_ui.cc
+++ b/content/public/test/test_web_ui.cc
@@ -11,6 +11,8 @@
 #include "base/memory/ptr_util.h"
 #include "base/no_destructor.h"
 #include "base/notimplemented.h"
+#include "content/browser/renderer_host/render_frame_host_impl.h"
+#include "content/public/browser/web_ui_browser_interface_broker_registry.h"
 #include "content/public/browser/web_ui_controller.h"
 #include "content/public/browser/web_ui_message_handler.h"
 
diff --git a/content/public/test/test_web_ui.h b/content/public/test/test_web_ui.h
index 8e982885..44a10b1a 100644
--- a/content/public/test/test_web_ui.h
+++ b/content/public/test/test_web_ui.h
@@ -18,6 +18,8 @@
 
 namespace content {
 
+class PerWebUIBrowserInterfaceBroker;
+
 // Test instance of WebUI that tracks the data passed to
 // CallJavascriptFunctionUnsafe().
 class TestWebUI : public WebUI {
@@ -119,6 +121,7 @@
   raw_ptr<RenderFrameHost, AcrossTasksDanglingUntriaged> render_frame_host_ =
       nullptr;
   std::unique_ptr<WebUIController> controller_;
+  std::unique_ptr<PerWebUIBrowserInterfaceBroker> broker_;
 
   // Observers to be notified on all javascript calls.
   base::ObserverList<JavascriptCallObserver> javascript_call_observers_;
diff --git a/content/renderer/media/batching_media_log.cc b/content/renderer/media/batching_media_log.cc
index 4275536..d657a3ee 100644
--- a/content/renderer/media/batching_media_log.cc
+++ b/content/renderer/media/batching_media_log.cc
@@ -74,7 +74,13 @@
 }
 
 void BatchingMediaLog::OnWebMediaPlayerDestroyedLocked() {
+  // The inspector handler will fail to send events after this, so send queued
+  // events now.
   base::AutoLock lock(lock_);
+  if (ipc_send_pending_) {
+    SendQueuedMediaEvents_Locked();
+  }
+
   for (const auto& handler : event_handlers_)
     handler->OnWebMediaPlayerDestroyed();
 }
@@ -221,6 +227,16 @@
   DCHECK(task_runner_->BelongsToCurrentThread());
   base::AutoLock auto_lock(lock_);
 
+  // This is called as a posted task and another task may
+  // decide to immediate emit queued events, so we must
+  // check `ipc_send_pending_` first here.
+  if (ipc_send_pending_) {
+    SendQueuedMediaEvents_Locked();
+  }
+}
+
+void BatchingMediaLog::SendQueuedMediaEvents_Locked() {
+  lock_.AssertAcquired();
   DCHECK(ipc_send_pending_);
   ipc_send_pending_ = false;
 
diff --git a/content/renderer/media/batching_media_log.h b/content/renderer/media/batching_media_log.h
index 08340c50b..53fe3c0 100644
--- a/content/renderer/media/batching_media_log.h
+++ b/content/renderer/media/batching_media_log.h
@@ -61,6 +61,7 @@
   // Posted as a delayed task on |task_runner_| to throttle ipc message
   // frequency.
   void SendQueuedMediaEvents();
+  void SendQueuedMediaEvents_Locked();
 
   void MaybeQueueEvent_Locked(std::unique_ptr<media::MediaLogRecord> event);
 
diff --git a/content/renderer/media/batching_media_log_unittest.cc b/content/renderer/media/batching_media_log_unittest.cc
index 09eae86..12d1e75e 100644
--- a/content/renderer/media/batching_media_log_unittest.cc
+++ b/content/renderer/media/batching_media_log_unittest.cc
@@ -143,6 +143,14 @@
   EXPECT_EQ(2, message_count());
 }
 
+TEST_F(BatchingMediaLogTest, EventSentBeforeDestruction) {
+  AddEvent<media::MediaLogEvent::kPlay>();
+  log_.OnWebMediaPlayerDestroyed();
+
+  // Created, played, destroyed.
+  ASSERT_EQ(3u, GetMediaLogRecords().size());
+}
+
 TEST_F(BatchingMediaLogTest, DurationChanged) {
   AddEvent<media::MediaLogEvent::kPlay>();
   AddEvent<media::MediaLogEvent::kPause>();
diff --git a/content/renderer/renderer_main.cc b/content/renderer/renderer_main.cc
index f7d9713b..cc54c30 100644
--- a/content/renderer/renderer_main.cc
+++ b/content/renderer/renderer_main.cc
@@ -265,14 +265,8 @@
     // Consider CrRendererMain a display critical thread. While some Javascript
     // running on the main thread might not be, experiments demonstrated that
     // overall this improves user-perceived performance.
-    // If kInputScenarioPriorityBoost is enabled, the main thread will only be
-    // display critical when user input is detected.
-    base::ThreadType thread_type =
-        base::FeatureList::IsEnabled(
-            blink::features::kInputScenarioPriorityBoost)
-            ? base::ThreadType::kDefault
-            : base::ThreadType::kDisplayCritical;
-    base::PlatformThread::SetCurrentThreadType(thread_type);
+    base::PlatformThread::SetCurrentThreadType(
+        base::ThreadType::kDisplayCritical);
 
     // Startup tracing creates a tracing thread, which is incompatible on
     // platforms that require single-threaded sandbox initialization. In these
diff --git a/content/test/gpu/gpu_tests/test_expectations/expected_color_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/expected_color_expectations.txt
index aa43da8..f710a48e 100644
--- a/content/test/gpu/gpu_tests/test_expectations/expected_color_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/expected_color_expectations.txt
@@ -137,6 +137,8 @@
 
 crbug.com/458633863 [ win qualcomm-0x36334330 ] ExpectedColor_MediaRecorderFrom2DCanvas [ Failure ]
 
+crbug.com/467247264 [ win11 nvidia-0x2184 ] ExpectedColor_MediaRecorderFromVideoElement [ RetryOnFailure ]
+
 #######################################################################
 # Automated Entries After This Point - Do Not Manually Add Below Here #
 #######################################################################
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
index a6a508a..a481992 100644
--- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -408,7 +408,7 @@
 # are marked as failing until they are confirmed to be stable.
 crbug.com/286989320 [ linux ] Pixel_MeetEffects* [ Failure Slow ]
 crbug.com/286989320 [ win amd ] Pixel_MeetEffects* [ Slow ]
-crbug.com/286989320 [ win nvidia ] Pixel_MeetEffects* [ Failure Slow ]
+crbug.com/286989320 [ win nvidia ] Pixel_MeetEffects* [ Slow ]
 crbug.com/286989320 [ win qualcomm ] Pixel_MeetEffects* [ Failure Slow ]
 crbug.com/286989320 [ win intel-0x4680 ] Pixel_MeetEffects* [ Slow ]
 crbug.com/286989320 [ win intel-0x9bc5 ] Pixel_MeetEffects* [ Failure Slow ]
@@ -581,6 +581,9 @@
 crbug.com/446157733 [ android-pixel-6 android-t angle-vulkan graphite-disabled renderer-skia-vulkan ] Pixel_ViewTransitionsCapture [ Failure ]
 crbug.com/446157733 [ android-pixel-6 angle-vulkan graphite-enabled renderer-skia-gl ] Pixel_ViewTransitionsCapture [ Failure ]
 
+# Flakily runs into OOM issues in 32-bit browsers.
+crbug.com/466113477 [ win nvidia target-cpu-32 ] Pixel_MeetEffects_rainbow_wig_and_eyelashes [ Failure ]
+
 #######################################################################
 # Automated Entries After This Point - Do Not Manually Add Below Here #
 #######################################################################
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
index 70ad771..6ff5c17 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -552,6 +552,10 @@
 crbug.com/angleproject/4417 [ win angle-d3d11 ] conformance2/rendering/framebuffer-render-to-layer-angle-issue.html [ Failure ]
 crbug.com/angleproject/1465 [ win angle-d3d11 ] conformance2/glsl3/tricky-loop-conditions.html [ Failure ]
 
+## Windows 11 ##
+
+crbug.com/467315110 [ win11 angle-d3d11 ] deqp/functional/gles3/* [ RetryOnFailure ]
+
 ## Win / NVIDIA ##
 
 crbug.com/1073613 [ angle-d3d11 win nvidia ] conformance2/textures/misc/tex-3d-mipmap-levels-intel-bug.html [ Failure ]
diff --git a/extensions/OWNERS b/extensions/OWNERS
index 2f3d20f..23c0fe9 100644
--- a/extensions/OWNERS
+++ b/extensions/OWNERS
@@ -12,6 +12,7 @@
 
 set noparent
 rdevlin.cronin@chromium.org
+andreaorru@chromium.org
 emiliapaz@chromium.org
 finnur@chromium.org
 jamescook@chromium.org
diff --git a/extensions/browser/api/web_request/OWNERS b/extensions/browser/api/web_request/OWNERS
index 840f2b6..46d9330 100644
--- a/extensions/browser/api/web_request/OWNERS
+++ b/extensions/browser/api/web_request/OWNERS
@@ -1,4 +1,3 @@
+andreaorru@chromium.org
 battre@chromium.org
 kelvinjiang@chromium.org
-
-# WebRequest + Network Service glue.
diff --git a/extensions/common/api/schema.gni b/extensions/common/api/schema.gni
index 1e391aee..b2dd2689 100644
--- a/extensions/common/api/schema.gni
+++ b/extensions/common/api/schema.gni
@@ -85,7 +85,7 @@
     "sockets_udp.idl",
     "system_display.webidl",
     "system_storage.webidl",
-    "usb.idl",
+    "usb.webidl",
     "virtual_keyboard_private.json",
     "virtual_keyboard.webidl",
     "web_view_internal.json",
@@ -109,7 +109,7 @@
     "clipboard.webidl",
     "scripts_internal.idl",
     "system_display.webidl",
-    "usb.idl",
+    "usb.webidl",
     "virtual_keyboard_private.json",
     "virtual_keyboard.webidl",
   ]
diff --git a/extensions/common/api/usb.webidl b/extensions/common/api/usb.webidl
new file mode 100644
index 0000000..fa0764c9
--- /dev/null
+++ b/extensions/common/api/usb.webidl
@@ -0,0 +1,454 @@
+// 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.
+
+// Direction, Recipient, RequestType, and TransferType all map to their
+// namesakes within the USB specification.
+enum Direction {
+  "in",
+  "out"
+};
+
+enum Recipient {
+  "device",
+  "interface",
+  "endpoint",
+  "other"
+};
+
+enum RequestType {
+  "standard",
+  "class",
+  "vendor",
+  "reserved"
+};
+
+enum TransferType {
+  "control",
+  "interrupt",
+  "isochronous",
+  "bulk"
+};
+
+// For interrupt and isochronous modes, SynchronizationType and UsageType map
+// to their namesakes within the USB specification.
+enum SynchronizationType {
+  "asynchronous",
+  "adaptive",
+  "synchronous"
+};
+
+enum UsageType {
+  "data",
+  "feedback",
+  "explicitFeedback",
+  "periodic",
+  "notification"
+};
+
+dictionary Device {
+  // An opaque ID for the USB device. It remains unchanged until the device is
+  // unplugged.
+  required long device;
+  // The device vendor ID.
+  required long vendorId;
+  // The product ID.
+  required long productId;
+  // The device version (bcdDevice field).
+  required long version;
+  // The iProduct string read from the device, if available.
+  required DOMString productName;
+  // The iManufacturer string read from the device, if available.
+  required DOMString manufacturerName;
+  // The iSerialNumber string read from the device, if available.
+  required DOMString serialNumber;
+};
+
+dictionary ConnectionHandle {
+  // An opaque handle representing this connection to the USB device and all
+  // associated claimed interfaces and pending transfers. A new handle is
+  // created each time the device is opened. The connection handle is
+  // different from $(ref:Device.device).
+  required long handle;
+  // The device vendor ID.
+  required long vendorId;
+  // The product ID.
+  required long productId;
+};
+
+dictionary EndpointDescriptor {
+  // Endpoint address.
+  required long address;
+  // Transfer type.
+  required TransferType type;
+  // Transfer direction.
+  required Direction direction;
+  // Maximum packet size.
+  required long maximumPacketSize;
+  // Transfer synchronization mode (isochronous only).
+  SynchronizationType synchronization;
+  // Endpoint usage hint.
+  UsageType usage;
+  // Polling interval (interrupt and isochronous only).
+  long pollingInterval;
+  // Extra descriptor data associated with this endpoint.
+  required ArrayBuffer extra_data;
+};
+
+dictionary InterfaceDescriptor {
+  // The interface number.
+  required long interfaceNumber;
+  // The interface alternate setting number (defaults to <code>0</code).
+  required long alternateSetting;
+  // The USB interface class.
+  required long interfaceClass;
+  // The USB interface sub-class.
+  required long interfaceSubclass;
+  // The USB interface protocol.
+  required long interfaceProtocol;
+  // Description of the interface.
+  DOMString description;
+  // Available endpoints.
+  required sequence<EndpointDescriptor> endpoints;
+  // Extra descriptor data associated with this interface.
+  required ArrayBuffer extra_data;
+};
+
+dictionary ConfigDescriptor {
+  // Is this the active configuration?
+  required boolean active;
+  // The configuration number.
+  required long configurationValue;
+  // Description of the configuration.
+  DOMString description;
+  // The device is self-powered.
+  required boolean selfPowered;
+  // The device supports remote wakeup.
+  required boolean remoteWakeup;
+  // The maximum power needed by this device in milliamps (mA).
+  required long maxPower;
+  // Available interfaces.
+  required sequence<InterfaceDescriptor> interfaces;
+  // Extra descriptor data associated with this configuration.
+  required ArrayBuffer extra_data;
+};
+
+dictionary ControlTransferInfo {
+  // The transfer direction (<code>"in"</code> or <code>"out"</code>).
+  required Direction direction;
+
+  // The transfer target. The target given by <code>index</code> must be
+  // claimed if <code>"interface"</code> or <code>"endpoint"</code>.
+  required Recipient recipient;
+
+  // The request type.
+  required RequestType requestType;
+
+  // The <code>bRequest</code> field, see <i>Universal Serial Bus
+  // Specification Revision 1.1</i> &sect; 9.3.
+  required long request;
+  // The <code>wValue</code> field, see <i>Ibid</i>.
+  required long value;
+  // The <code>wIndex</code> field, see <i>Ibid</i>.
+  required long index;
+
+  // The maximum number of bytes to receive (required only by input
+  // transfers).
+  long length;
+
+  // The data to transmit (required only by output transfers).
+  ArrayBuffer data;
+
+  // Request timeout (in milliseconds). The default value <code>0</code>
+  // indicates no timeout.
+  long timeout;
+};
+
+dictionary GenericTransferInfo {
+  // The transfer direction (<code>"in"</code> or <code>"out"</code>).
+  required Direction direction;
+
+  // The target endpoint address. The interface containing this endpoint must
+  // be claimed.
+  required long endpoint;
+
+  // The maximum number of bytes to receive (required only by input
+  // transfers).
+  long length;
+
+  // The data to transmit (required only by output transfers).
+  ArrayBuffer data;
+
+  // Request timeout (in milliseconds). The default value <code>0</code>
+  // indicates no timeout.
+  long timeout;
+};
+
+dictionary IsochronousTransferInfo {
+  // Transfer parameters. The transfer length or data buffer specified in this
+  // parameter block is split along <code>packetLength</code> boundaries to
+  // form the individual packets of the transfer.
+  required GenericTransferInfo transferInfo;
+
+  // The total number of packets in this transfer.
+  required long packets;
+
+  // The length of each of the packets in this transfer.
+  required long packetLength;
+};
+
+dictionary TransferResultInfo {
+  // A value of <code>0</code> indicates that the transfer was a success.
+  // Other values indicate failure.
+  long resultCode;
+
+  // The data returned by an input transfer. <code>undefined</code> for output
+  // transfers.
+  ArrayBuffer data;
+};
+
+dictionary DeviceFilter {
+  // Device vendor ID.
+  long vendorId;
+  // Device product ID, checked only if the vendor ID matches.
+  long productId;
+  // USB interface class, matches any interface on the device.
+  long interfaceClass;
+  // USB interface sub-class, checked only if the interface class matches.
+  long interfaceSubclass;
+  // USB interface protocol, checked only if the interface sub-class matches.
+  long interfaceProtocol;
+};
+
+dictionary EnumerateDevicesOptions {
+  [deprecated="Equivalent to setting $(ref:DeviceFilter.vendorId)."]
+  long vendorId;
+  [deprecated="Equivalent to setting $(ref:DeviceFilter.productId)."]
+  long productId;
+  // A device matching any given filter will be returned. An empty filter list
+  // will return all devices the app has permission for.
+  sequence<DeviceFilter> filters;
+};
+
+dictionary EnumerateDevicesAndRequestAccessOptions {
+  // The device vendor ID.
+  required long vendorId;
+  // The product ID.
+  required long productId;
+  // The interface ID to request access to.
+  // Only available on Chrome OS. It has no effect on other platforms.
+  long interfaceId;
+};
+
+dictionary DevicePromptOptions {
+  // Allow the user to select multiple devices.
+  boolean multiple;
+  // Filter the list of devices presented to the user. If multiple filters are
+  // provided devices matching any filter will be displayed.
+  sequence<DeviceFilter> filters;
+};
+
+callback OnDeviceAddedListener = undefined (Device device);
+
+interface OnDeviceAddedEvent : ExtensionEvent {
+  static undefined addListener(OnDeviceAddedListener listener);
+  static undefined removeListener(OnDeviceAddedListener listener);
+  static boolean hasListener(OnDeviceAddedListener listener);
+};
+
+callback OnDeviceRemovedListener = undefined (Device device);
+
+interface OnDeviceRemovedEvent : ExtensionEvent {
+  static undefined addListener(OnDeviceRemovedListener listener);
+  static undefined removeListener(OnDeviceRemovedListener listener);
+  static boolean hasListener(OnDeviceRemovedListener listener);
+};
+
+// Use the <code>chrome.usb</code> API to interact with connected USB
+// devices. This API provides access to USB operations from within the context
+// of an app. Using this API, apps can function as drivers for hardware devices.
+// Errors generated by this API are reported by setting
+// $(ref:runtime.lastError) and executing the function's regular callback. The
+// callback's regular parameters will be undefined in this case.
+interface Usb {
+  // Enumerates connected USB devices.
+  // |options|: The properties to search for on target devices.
+  // |PromiseValue|: devices
+  [requiredCallback] static Promise<sequence<Device>> getDevices(
+      EnumerateDevicesOptions options);
+
+  // Presents a device picker to the user and returns the $(ref:Device)s
+  // selected.
+  // If the user cancels the picker devices will be empty. A user gesture
+  // is required for the dialog to display. Without a user gesture, the
+  // callback will run as though the user cancelled.
+  // |options|: Configuration of the device picker dialog box.
+  // |Returns|: Invoked with a list of chosen $(ref:Device)s.
+  // |PromiseValue|: devices
+  [requiredCallback] static Promise<sequence<Device>> getUserSelectedDevices(
+      DevicePromptOptions options);
+
+  // Returns the full set of device configuration descriptors.
+  // |device|: The $(ref:Device) to fetch descriptors from.
+  // |PromiseValue|: configs
+  [requiredCallback]
+  static Promise<sequence<ConfigDescriptor>> getConfigurations(
+      Device device);
+
+  // Requests access from the permission broker to a device claimed by
+  // Chrome OS if the given interface on the device is not claimed.
+  //
+  // |device|: The $(ref:Device) to request access to.
+  // |interfaceId|: The particular interface requested.
+  // |PromiseValue|: success
+  [deprecated="This function was Chrome OS specific and calling it on other
+    platforms would fail. This operation is now implicitly performed as part of
+    $(ref:openDevice) and this function will return <code>true</code> on all
+    platforms.", requiredCallback]
+  static Promise<boolean> requestAccess(Device device,
+                            long interfaceId);
+
+  // Opens a USB device returned by $(ref:getDevices).
+  // |device|: The $(ref:Device) to open.
+  // |PromiseValue|: handle
+  [requiredCallback] static Promise<ConnectionHandle> openDevice(
+      Device device);
+
+  // Finds USB devices specified by the vendor, product and (optionally)
+  // interface IDs and if permissions allow opens them for use.
+  //
+  // If the access request is rejected or the device fails to be opened a
+  // connection handle will not be created or returned.
+  //
+  // Calling this method is equivalent to calling $(ref:getDevices) followed
+  // by $(ref:openDevice) for each device.
+  //
+  // |options|: The properties to search for on target devices.
+  // |PromiseValue|: handles
+  [requiredCallback] static Promise<sequence<ConnectionHandle>> findDevices(
+      EnumerateDevicesAndRequestAccessOptions options);
+
+  // Closes a connection handle. Invoking operations on a handle after it
+  // has been closed is a safe operation but causes no action to be taken.
+  // |handle|: The $(ref:ConnectionHandle) to close.
+  static Promise<undefined> closeDevice(
+      ConnectionHandle handle);
+
+  // Select a device configuration.
+  //
+  // This function effectively resets the device by selecting one of the
+  // device's available configurations. Only configuration values greater
+  // than <code>0</code> are valid however some buggy devices have a working
+  // configuration <code>0</code> and so this value is allowed.
+  // |handle|: An open connection to the device.
+  [requiredCallback] static Promise<undefined> setConfiguration(
+      ConnectionHandle handle,
+      long configurationValue);
+
+  // Gets the configuration descriptor for the currently selected
+  // configuration.
+  // |handle|: An open connection to the device.
+  // |PromiseValue|: config
+  [requiredCallback] static Promise<ConfigDescriptor> getConfiguration(
+      ConnectionHandle handle);
+
+  // Lists all interfaces on a USB device.
+  // |handle|: An open connection to the device.
+  // |PromiseValue|: descriptors
+  [requiredCallback]
+  static Promise<sequence<InterfaceDescriptor>> listInterfaces(
+      ConnectionHandle handle);
+
+  // Claims an interface on a USB device.
+  // Before data can be transfered to an interface or associated endpoints the
+  // interface must be claimed. Only one connection handle can claim an
+  // interface at any given time. If the interface is already claimed, this
+  // call will fail.
+  //
+  // $(ref:releaseInterface) should be called when the interface is no longer
+  // needed.
+  //
+  // |handle|: An open connection to the device.
+  // |interfaceNumber|: The interface to be claimed.
+  [requiredCallback] static Promise<undefined> claimInterface(
+      ConnectionHandle handle,
+      long interfaceNumber);
+
+  // Releases a claimed interface.
+  // |handle|: An open connection to the device.
+  // |interfaceNumber|: The interface to be released.
+  [requiredCallback] static Promise<undefined> releaseInterface(
+      ConnectionHandle handle,
+      long interfaceNumber);
+
+  // Selects an alternate setting on a previously claimed interface.
+  // |handle|: An open connection to the device where this interface has been
+  //     claimed.
+  // |interfaceNumber|: The interface to configure.
+  // |alternateSetting|: The alternate setting to configure.
+  [requiredCallback] static Promise<undefined> setInterfaceAlternateSetting(
+      ConnectionHandle handle,
+      long interfaceNumber,
+      long alternateSetting);
+
+  // Performs a control transfer on the specified device.
+  //
+  // Control transfers refer to either the device, an interface or an
+  // endpoint. Transfers to an interface or endpoint require the interface to
+  // be claimed.
+  //
+  // |handle|: An open connection to the device.
+  // |PromiseValue|: info
+  [requiredCallback] static Promise<TransferResultInfo> controlTransfer(
+      ConnectionHandle handle,
+      ControlTransferInfo transferInfo);
+
+  // Performs a bulk transfer on the specified device.
+  // |handle|: An open connection to the device.
+  // |transferInfo|: The transfer parameters.
+  // |PromiseValue|: info
+  [requiredCallback] static Promise<TransferResultInfo> bulkTransfer(
+      ConnectionHandle handle,
+      GenericTransferInfo transferInfo);
+
+  // Performs an interrupt transfer on the specified device.
+  // |handle|: An open connection to the device.
+  // |transferInfo|: The transfer parameters.
+  // |PromiseValue|: info
+  [requiredCallback] static Promise<TransferResultInfo> interruptTransfer(
+      ConnectionHandle handle,
+      GenericTransferInfo transferInfo);
+
+  // Performs an isochronous transfer on the specific device.
+  // |handle|: An open connection to the device.
+  // |PromiseValue|: info
+  [requiredCallback] static Promise<TransferResultInfo> isochronousTransfer(
+      ConnectionHandle handle,
+      IsochronousTransferInfo transferInfo);
+
+  // Tries to reset the USB device.
+  // If the reset fails, the given connection handle will be closed and the
+  // USB device will appear to be disconnected then reconnected.
+  // In this case $(ref:getDevices) or $(ref:findDevices) must be called again
+  // to acquire the device.
+  //
+  // |handle|: A connection handle to reset.
+  // |PromiseValue|: success
+  [requiredCallback] static Promise<boolean> resetDevice(
+      ConnectionHandle handle);
+
+  // Event generated when a device is added to the system. Events are only
+  // broadcast to apps and extensions that have permission to access the
+  // device. Permission may have been granted at install time, when the user
+  // accepted an optional permission (see $(ref:permissions.request)), or
+  // through $(ref:getUserSelectedDevices).
+  static attribute OnDeviceAddedEvent onDeviceAdded;
+
+  // Event generated when a device is removed from the system. See
+  // $(ref:onDeviceAdded) for which events are delivered.
+  static attribute OnDeviceRemovedEvent onDeviceRemoved;
+};
+
+partial interface Browser {
+  static attribute Usb usb;
+};
diff --git a/infra/config/generated/builders/ci/Linux Chromium OS ASan LSan Builder/targets/chromium.memory.json b/infra/config/generated/builders/ci/Linux Chromium OS ASan LSan Builder/targets/chromium.memory.json
index 4d8d10d..a3505fd 100644
--- a/infra/config/generated/builders/ci/Linux Chromium OS ASan LSan Builder/targets/chromium.memory.json
+++ b/infra/config/generated/builders/ci/Linux Chromium OS ASan LSan Builder/targets/chromium.memory.json
@@ -972,7 +972,7 @@
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 15
+          "shards": 30
         },
         "test": "interactive_ui_tests",
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
diff --git "a/infra/config/generated/builders/ci/Linux Chromium OS ASan LSan Tests \0501\051/targets/chromium.memory.json" "b/infra/config/generated/builders/ci/Linux Chromium OS ASan LSan Tests \0501\051/targets/chromium.memory.json"
index 4d8d10d..a3505fd 100644
--- "a/infra/config/generated/builders/ci/Linux Chromium OS ASan LSan Tests \0501\051/targets/chromium.memory.json"
+++ "b/infra/config/generated/builders/ci/Linux Chromium OS ASan LSan Tests \0501\051/targets/chromium.memory.json"
@@ -972,7 +972,7 @@
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 15
+          "shards": 30
         },
         "test": "interactive_ui_tests",
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
diff --git a/infra/config/generated/builders/try/linux_chromium_chromeos_asan_rel_ng/targets/chromium.memory.json b/infra/config/generated/builders/try/linux_chromium_chromeos_asan_rel_ng/targets/chromium.memory.json
index 4d8d10d..a3505fd 100644
--- a/infra/config/generated/builders/try/linux_chromium_chromeos_asan_rel_ng/targets/chromium.memory.json
+++ b/infra/config/generated/builders/try/linux_chromium_chromeos_asan_rel_ng/targets/chromium.memory.json
@@ -972,7 +972,7 @@
             "os": "Ubuntu-22.04"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 15
+          "shards": 30
         },
         "test": "interactive_ui_tests",
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg
index 5d4471ed..3ccd0f3a 100644
--- a/infra/config/generated/luci/cr-buildbucket.cfg
+++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -115146,6 +115146,10 @@
         key: "luci.buildbucket.canary_software"
         value: 5
       }
+      experiments {
+        key: "presubmit.resultdb_module"
+        value: 100
+      }
       resultdb {
         enable: true
         bq_exports {
@@ -131433,6 +131437,10 @@
         key: "luci.buildbucket.canary_software"
         value: 5
       }
+      experiments {
+        key: "presubmit.resultdb_module"
+        value: 100
+      }
       resultdb {
         enable: true
         bq_exports {
diff --git a/infra/config/subprojects/chromium/ci/chromium.memory.star b/infra/config/subprojects/chromium/ci/chromium.memory.star
index ae998ddb..71a31cb 100644
--- a/infra/config/subprojects/chromium/ci/chromium.memory.star
+++ b/infra/config/subprojects/chromium/ci/chromium.memory.star
@@ -468,7 +468,7 @@
             "interactive_ui_tests": targets.mixin(
                 # These are slow on the ASan trybot for some reason, crbug.com/1257927
                 swarming = targets.swarming(
-                    shards = 15,
+                    shards = 30,
                 ),
             ),
             "net_unittests": targets.mixin(
diff --git a/infra/config/subprojects/chromium/try/presubmit.star b/infra/config/subprojects/chromium/try/presubmit.star
index c58297b7..bc49927 100644
--- a/infra/config/subprojects/chromium/try/presubmit.star
+++ b/infra/config/subprojects/chromium/try/presubmit.star
@@ -182,6 +182,9 @@
     executable = "recipe:presubmit",
     contact_team_email = "chrome-browser-infra-team@google.com",
     execution_timeout = 40 * time.minute,
+    experiments = {
+        "presubmit.resultdb_module": 100,
+    },
     properties = {
         "$depot_tools/presubmit": {
             "runhooks": True,
@@ -199,6 +202,9 @@
     os = os.WINDOWS_DEFAULT,
     ssd = True,
     execution_timeout = 40 * time.minute,
+    experiments = {
+        "presubmit.resultdb_module": 100,
+    },
     properties = {
         "$depot_tools/presubmit": {
             "runhooks": True,
diff --git a/infra/inclusive_language_presubmit_exempt_dirs.txt b/infra/inclusive_language_presubmit_exempt_dirs.txt
index 29661e0..621cf1e 100644
--- a/infra/inclusive_language_presubmit_exempt_dirs.txt
+++ b/infra/inclusive_language_presubmit_exempt_dirs.txt
@@ -624,9 +624,11 @@
 third_party/rust/chromium_crates_io/vendor/anstyle-v1
 third_party/rust/chromium_crates_io/vendor/anyhow-v1
 third_party/rust/chromium_crates_io/vendor/anyhow-v1/.github/workflows
+third_party/rust/chromium_crates_io/vendor/array-init-v2/.github/workflows
 third_party/rust/chromium_crates_io/vendor/arrayvec-v0_7
 third_party/rust/chromium_crates_io/vendor/arrayvec-v0_7/.github/workflows
 third_party/rust/chromium_crates_io/vendor/base64-v0_22
+third_party/rust/chromium_crates_io/vendor/byteorder-v1/.github/workflows
 third_party/rust/chromium_crates_io/vendor/bytes-v1/.github/workflows
 third_party/rust/chromium_crates_io/vendor/clap_builder-v4/src
 third_party/rust/chromium_crates_io/vendor/clap_builder-v4/src/builder
@@ -683,11 +685,14 @@
 third_party/rust/chromium_crates_io/vendor/log-v0_4/.github/workflows
 third_party/rust/chromium_crates_io/vendor/miniz_oxide-v0_8
 third_party/rust/chromium_crates_io/vendor/num-bigint-v0_4
+third_party/rust/chromium_crates_io/vendor/num-derive-v0_4
 third_party/rust/chromium_crates_io/vendor/num-integer-v0_1
 third_party/rust/chromium_crates_io/vendor/num-rational-v0_4
 third_party/rust/chromium_crates_io/vendor/num-traits-v0_2
 third_party/rust/chromium_crates_io/vendor/proc-macro2-v1
 third_party/rust/chromium_crates_io/vendor/proc-macro2-v1/.github/workflows
+third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2
+third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src
 third_party/rust/chromium_crates_io/vendor/prost-v0_14
 third_party/rust/chromium_crates_io/vendor/qr_code-v2
 third_party/rust/chromium_crates_io/vendor/quote-v1
@@ -725,12 +730,16 @@
 third_party/rust/chromium_crates_io/vendor/syn-v2
 third_party/rust/chromium_crates_io/vendor/syn-v2/src
 third_party/rust/chromium_crates_io/vendor/termcolor-v1/.github/workflows
+third_party/rust/chromium_crates_io/vendor/thiserror-v2
+third_party/rust/chromium_crates_io/vendor/thiserror-v2/.github/workflows
 third_party/rust/chromium_crates_io/vendor/unicode-ident-v1
 third_party/rust/chromium_crates_io/vendor/unicode-ident-v1/.github/workflows
 third_party/rust/chromium_crates_io/vendor/winapi-util-v0_1/.github/workflows
 third_party/rust/chromium_crates_io/vendor/windows-sys-v0_52
 third_party/rust/chromium_crates_io/vendor/windows-sys-v0_52/src/Windows/Wdk/System/SystemServices
 third_party/rust/chromium_crates_io/vendor/windows-sys-v0_52/src/Windows/Win32/Networking/Clustering
+third_party/rust/chromium_crates_io/vendor/zerocopy-v0_8
+third_party/rust/chromium_crates_io/vendor/zerocopy-v0_8/src
 third_party/rust/chromium_crates_io/vendor/zip-v6
 third_party/rust/chromium_crates_io/vendor/zip-v6/src
 third_party/rust/miniz_oxide/v0_8
diff --git a/ios/build/bots/scripts/iossim_util.py b/ios/build/bots/scripts/iossim_util.py
index 8572249..51d199f 100644
--- a/ios/build/bots/scripts/iossim_util.py
+++ b/ios/build/bots/scripts/iossim_util.py
@@ -145,18 +145,32 @@
   Raises:
     test_runner.SimulatorNotFoundError when the version can't be found.
   """
-  for runtime in simulators['runtimes']:
-    # The output might use version with a patch number (e.g. 17.0.1)
-    # but the passed in version does not have a patch number (e.g. 17.0)
-    # Therefore, we should use startswith for substring match.
-    if runtime['version'].startswith(version):
-      if any(supported_device_type['name'] == platform
-             for supported_device_type in runtime['supportedDeviceTypes']):
-        return runtime['identifier']
+  runtimes = simulators['runtimes']
+  max_retries = 2
+  for attempt in range(0, max_retries):
+    version_found = False
+    for runtime in runtimes:
+      # The output might use version with a patch number (e.g. 17.0.1)
+      # but the passed in version does not have a patch number (e.g. 17.0)
+      # Therefore, we should use startswith for substring match.
+      if runtime['version'].startswith(version):
+        version_found = True
+        if any(supported_device_type['name'] == platform
+               for supported_device_type in runtime['supportedDeviceTypes']):
+          return runtime.get('identifier') or runtime.get('runtimeIdentifier')
+    LOGGER.error(f'(attempt {attempt + 1} of {max_retries}) failed to find '
+                 f'simulator matching version: {version} and platform: '
+                 f'{platform}.')
+    if version_found:
+      LOGGER.error('Version found, but not platform.')
+    if attempt + 1 < max_retries:
+      # try again by listing available runtimes with a different command
+      time.sleep(5)
+      runtimes = get_simulator_runtime_list().values()
   # TODO(crbug.com/454911750): remove debugging after bug is resolved
-  debug_missing_simulator(simulators['runtimes'], out_dir)
+  debug_missing_simulator(runtimes, out_dir)
   raise test_runner.SimulatorNotFoundError('Not found "%s" SDK in runtimes %s' %
-                                           (version, simulators['runtimes']))
+                                           (version, runtimes))
 
 
 def get_simulator_runtime_by_device_udid(simulator_udid):
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 876becb..58e84f6c 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -576,12 +576,18 @@
       <message name="IDS_IOS_AUTOFILL_INVALID_CARDHOLDER_NAME_ACCESSIBILITY_ANNOUNCEMENT" desc="The accessibility announcement read by Voice Over when the credit card holder name is invalid. [iOS only]">
         Invalid cardholder name
       </message>
+      <message name="IDS_IOS_AUTOFILL_INVALID_CARD_NUMBER_ACCESSIBILITY_ANNOUNCEMENT" desc="The accessibility announcement read by Voice Over when the credit card number is invalid. [iOS only]">
+        Invalid card number
+      </message>
       <message name="IDS_IOS_AUTOFILL_INVALID_CVC_ACCESSIBILITY_ANNOUNCEMENT" desc="The accessibility announcement read by Voice Over when the credit card security code is invalid. [iOS only]">
         Invalid security code
       </message>
       <message name="IDS_IOS_AUTOFILL_INVALID_EXPIRATION_DATE_ACCESSIBILITY_ANNOUNCEMENT" desc="The accessibility announcement read by Voice Over when the credit card expiration date is invalid. [iOS only]">
         Invalid expiration date
       </message>
+      <message name="IDS_IOS_AUTOFILL_INVALID_NICKNAME_ACCESSIBILITY_ANNOUNCEMENT" desc="The accessibility announcement read by Voice Over when the credit card nickname is invalid. [iOS only]">
+        Invalid nickname
+      </message>
       <message name="IDS_IOS_AUTOFILL_NICKNAME" desc="Title of the field representing the user defined nickname of a credit card. [Length: 15em] [iOS only]">
         Card nickname
       </message>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_AUTOFILL_INVALID_CARD_NUMBER_ACCESSIBILITY_ANNOUNCEMENT.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_AUTOFILL_INVALID_CARD_NUMBER_ACCESSIBILITY_ANNOUNCEMENT.png.sha1
new file mode 100644
index 0000000..fa7153b
--- /dev/null
+++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_AUTOFILL_INVALID_CARD_NUMBER_ACCESSIBILITY_ANNOUNCEMENT.png.sha1
@@ -0,0 +1 @@
+f168480c377a4a72ddc74de8e1efa7608f8eaa25
\ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_AUTOFILL_INVALID_NICKNAME_ACCESSIBILITY_ANNOUNCEMENT.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_AUTOFILL_INVALID_NICKNAME_ACCESSIBILITY_ANNOUNCEMENT.png.sha1
new file mode 100644
index 0000000..04b2add
--- /dev/null
+++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_AUTOFILL_INVALID_NICKNAME_ACCESSIBILITY_ANNOUNCEMENT.png.sha1
@@ -0,0 +1 @@
+785c7da7706e4e971d9de5901bd740990153b57b
\ No newline at end of file
diff --git a/ios/chrome/browser/autofill/ui_bundled/autofill_credit_card_ui_type.h b/ios/chrome/browser/autofill/ui_bundled/autofill_credit_card_ui_type.h
index e0725302..b22449bf 100644
--- a/ios/chrome/browser/autofill/ui_bundled/autofill_credit_card_ui_type.h
+++ b/ios/chrome/browser/autofill/ui_bundled/autofill_credit_card_ui_type.h
@@ -19,7 +19,8 @@
   kExpDate,
   kSecurityCode,
   kBillingAddress,
-  kSaveToChrome
+  kSaveToChrome,
+  kNickname
 };
 
 #endif  // IOS_CHROME_BROWSER_AUTOFILL_UI_BUNDLED_AUTOFILL_CREDIT_CARD_UI_TYPE_H_
diff --git a/ios/chrome/browser/autofill/ui_bundled/autofill_credit_card_ui_type_util.mm b/ios/chrome/browser/autofill/ui_bundled/autofill_credit_card_ui_type_util.mm
index 86f0e9cb..42bdb92 100644
--- a/ios/chrome/browser/autofill/ui_bundled/autofill_credit_card_ui_type_util.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/autofill_credit_card_ui_type_util.mm
@@ -24,6 +24,7 @@
     case AutofillCreditCardUIType::kExpDate:
     case AutofillCreditCardUIType::kBillingAddress:
     case AutofillCreditCardUIType::kSaveToChrome:
+    case AutofillCreditCardUIType::kNickname:
     default:
       NOTREACHED();
   }
diff --git a/ios/chrome/browser/autofill/ui_bundled/form_input_accessory/form_suggestion_view.mm b/ios/chrome/browser/autofill/ui_bundled/form_input_accessory/form_suggestion_view.mm
index b8ab9ecd..4a32c57 100644
--- a/ios/chrome/browser/autofill/ui_bundled/form_input_accessory/form_suggestion_view.mm
+++ b/ios/chrome/browser/autofill/ui_bundled/form_input_accessory/form_suggestion_view.mm
@@ -322,8 +322,22 @@
 
   // Check if the view is in the current hierarchy before performing layouts.
   if (self.stackView.window) {
+    // Because [self.stackView addArrangedSubview:] is called from
+    // createAndInsertArrangedSubviews just before this function is called, it
+    // is possible that a temporary condition (like a zero-height constraint
+    // resolving) may cause the UIStackView to internally decide to remove an
+    // arranged subview from its arrangedSubviews array. Because we use fast
+    // enumeration (for(... in ...)) of self.stackView.arrangedSubviews below,
+    // we have to make a snapshot of the subviews to avoid issues. The
+    // documentation mentions that: "You cannot mutate a collection during fast
+    // enumeration, even if the collection is mutable. If you attempt to add or
+    // remove a collected object from within the loop, you’ll generate a runtime
+    // exception." See:
+    // https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/FoundationTypesandCollections/FoundationTypesandCollections.html#//apple_ref/doc/uid/TP40011210-CH7-SW30
+    NSArray<UIView*>* subviewsSnapshot = [self.stackView.arrangedSubviews copy];
+
     // Make sure all subview layouts are done before computing frame offsets.
-    for (UIView* view in self.stackView.arrangedSubviews) {
+    for (UIView* view in subviewsSnapshot) {
       [view layoutIfNeeded];
     }
   }
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/BUILD.gn b/ios/chrome/browser/content_suggestions/ui_bundled/BUILD.gn
index 04672d7..2c263e4 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/BUILD.gn
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/BUILD.gn
@@ -416,7 +416,6 @@
     "//ios/chrome/browser/flags:system_flags",
     "//ios/chrome/browser/home_customization/ui:constants",
     "//ios/chrome/browser/home_customization/utils",
-    "//ios/chrome/browser/ntp/model:features",
     "//ios/chrome/browser/ntp/ui_bundled:constants",
     "//ios/chrome/browser/ntp/ui_bundled:feature_flags",
     "//ios/chrome/browser/omnibox/public:constants",
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/content_suggestions_egtest.mm b/ios/chrome/browser/content_suggestions/ui_bundled/content_suggestions_egtest.mm
index e05351c..94ddeb1 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/content_suggestions_egtest.mm
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/content_suggestions_egtest.mm
@@ -24,7 +24,6 @@
 #import "ios/chrome/browser/first_run/ui_bundled/first_run_constants.h"
 #import "ios/chrome/browser/home_customization/utils/home_customization_constants.h"
 #import "ios/chrome/browser/home_customization/utils/home_customization_helper.h"
-#import "ios/chrome/browser/ntp/model/features.h"
 #import "ios/chrome/browser/ntp/ui_bundled/new_tab_page_constants.h"
 #import "ios/chrome/browser/ntp/ui_bundled/new_tab_page_feature.h"
 #import "ios/chrome/browser/shared/model/prefs/pref_names.h"
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/magic_stack/coordinator/BUILD.gn b/ios/chrome/browser/content_suggestions/ui_bundled/magic_stack/coordinator/BUILD.gn
index 2ce982a..9e78ebf 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/magic_stack/coordinator/BUILD.gn
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/magic_stack/coordinator/BUILD.gn
@@ -58,7 +58,6 @@
     "//ios/chrome/browser/default_browser/model:utils",
     "//ios/chrome/browser/lens/ui_bundled:lens_availability",
     "//ios/chrome/browser/lens/ui_bundled:lens_entrypoint",
-    "//ios/chrome/browser/ntp/model:features",
     "//ios/chrome/browser/ntp/ui_bundled",
     "//ios/chrome/browser/ntp_tiles/model/tab_resumption:tab_resumption_prefs",
     "//ios/chrome/browser/safety_check/model:constants",
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/magic_stack/coordinator/magic_stack_ranking_model.mm b/ios/chrome/browser/content_suggestions/ui_bundled/magic_stack/coordinator/magic_stack_ranking_model.mm
index c2313c62..23acb3a 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/magic_stack/coordinator/magic_stack_ranking_model.mm
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/magic_stack/coordinator/magic_stack_ranking_model.mm
@@ -82,7 +82,6 @@
 #import "ios/chrome/browser/default_browser/model/utils.h"
 #import "ios/chrome/browser/lens/ui_bundled/lens_availability.h"
 #import "ios/chrome/browser/lens/ui_bundled/lens_entrypoint.h"
-#import "ios/chrome/browser/ntp/model/features.h"
 #import "ios/chrome/browser/ntp/ui_bundled/home_start_data_source.h"
 #import "ios/chrome/browser/ntp_tiles/model/tab_resumption/tab_resumption_prefs.h"
 #import "ios/chrome/browser/safety_check/model/ios_chrome_safety_check_manager_constants.h"
@@ -468,7 +467,8 @@
   inputContext->metadata_args.emplace(
       segmentation_platform::kIsNewUser,
       segmentation_platform::processing::ProcessedValue::FromFloat(
-          IsFirstRunRecent(set_up_list::SetUpListDurationPastFirstRun())));
+          IsFirstRunRecent(
+              set_up_list_utils::SetUpListDurationPastFirstRun())));
 
   inputContext->metadata_args.emplace(
       segmentation_platform::kIsSynced,
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/coordinator/BUILD.gn b/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/coordinator/BUILD.gn
index 5c8ad94..9d5ffd5 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/coordinator/BUILD.gn
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/coordinator/BUILD.gn
@@ -21,7 +21,6 @@
     "//ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/ui",
     "//ios/chrome/browser/credential_provider_promo/ui_bundled:coordinator",
     "//ios/chrome/browser/default_browser/model:utils",
-    "//ios/chrome/browser/ntp/model:features",
     "//ios/chrome/browser/ntp/model:set_up_list",
     "//ios/chrome/browser/ntp/model:set_up_list_item_type",
     "//ios/chrome/browser/ntp/model:set_up_list_prefs",
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/coordinator/set_up_list_mediator.mm b/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/coordinator/set_up_list_mediator.mm
index a7f71bd2..378f8fd 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/coordinator/set_up_list_mediator.mm
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/coordinator/set_up_list_mediator.mm
@@ -27,7 +27,6 @@
 #import "ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/ui/set_up_list_item_view_data.h"
 #import "ios/chrome/browser/credential_provider_promo/ui_bundled/credential_provider_promo_metrics.h"
 #import "ios/chrome/browser/default_browser/model/utils.h"
-#import "ios/chrome/browser/ntp/model/features.h"
 #import "ios/chrome/browser/ntp/model/set_up_list.h"
 #import "ios/chrome/browser/ntp/model/set_up_list_delegate.h"
 #import "ios/chrome/browser/ntp/model/set_up_list_item.h"
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/public/BUILD.gn b/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/public/BUILD.gn
index 5a473866..5f076a2 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/public/BUILD.gn
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/public/BUILD.gn
@@ -20,7 +20,6 @@
     "//base",
     "//components/ntp_tiles:pref_names",
     "//components/prefs",
-    "//ios/chrome/browser/ntp/model:features",
     "//ios/chrome/browser/ntp/model:set_up_list_prefs",
     "//ios/chrome/browser/shared/model/prefs:pref_names",
     "//ios/chrome/browser/shared/model/utils",
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/public/set_up_list_utils.h b/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/public/set_up_list_utils.h
index f45885b..d28ff0c 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/public/set_up_list_utils.h
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/public/set_up_list_utils.h
@@ -5,6 +5,8 @@
 #ifndef IOS_CHROME_BROWSER_CONTENT_SUGGESTIONS_UI_BUNDLED_SET_UP_LIST_PUBLIC_SET_UP_LIST_UTILS_H_
 #define IOS_CHROME_BROWSER_CONTENT_SUGGESTIONS_UI_BUNDLED_SET_UP_LIST_PUBLIC_SET_UP_LIST_UTILS_H_
 
+#import "base/time/time.h"
+
 class PrefService;
 
 namespace set_up_list_utils {
@@ -24,6 +26,11 @@
 // Stack.
 bool ShouldShowCompactedSetUpListModule();
 
+// Duration of the Set Up List past the first run.
+// So if the function returns 1 day, that means the Set Up List will appear one
+// day past the First Run.
+base::TimeDelta SetUpListDurationPastFirstRun();
+
 }  // namespace set_up_list_utils
 
 #endif  // IOS_CHROME_BROWSER_CONTENT_SUGGESTIONS_UI_BUNDLED_SET_UP_LIST_PUBLIC_SET_UP_LIST_UTILS_H_
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/public/set_up_list_utils.mm b/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/public/set_up_list_utils.mm
index 430a1e4..8dd62c52 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/public/set_up_list_utils.mm
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/public/set_up_list_utils.mm
@@ -4,15 +4,18 @@
 
 #import "ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/public/set_up_list_utils.h"
 
-#import "base/time/time.h"
 #import "components/ntp_tiles/pref_names.h"
 #import "components/prefs/pref_service.h"
-#import "ios/chrome/browser/ntp/model/features.h"
 #import "ios/chrome/browser/ntp/model/set_up_list_prefs.h"
 #import "ios/chrome/browser/shared/model/prefs/pref_names.h"
 #import "ios/chrome/browser/shared/model/utils/first_run_util.h"
 #import "ios/chrome/browser/shared/public/features/features.h"
 
+namespace {
+// The number of days after the first run that the Set Up List can be active.
+constexpr int kSetUpListDurationDays = 14;
+}  // namespace
+
 namespace set_up_list_utils {
 
 bool IsSetUpListActive(PrefService* local_prefs,
@@ -28,7 +31,7 @@
     // have been completed yet. In this case, we will wait until the next run.
     return false;
   }
-  if (!IsFirstRunRecent(set_up_list::SetUpListDurationPastFirstRun())) {
+  if (!IsFirstRunRecent(SetUpListDurationPastFirstRun())) {
     // It is past the max duration of the Set Up List, but if user has
     // interacted in the last day the time will be extended.
     base::Time last_interaction =
@@ -45,4 +48,8 @@
   return !IsFirstRun();
 }
 
+base::TimeDelta SetUpListDurationPastFirstRun() {
+  return base::Days(kSetUpListDurationDays);
+}
+
 }  // namespace set_up_list_utils
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/test/BUILD.gn b/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/test/BUILD.gn
index c2c8ca54..4ea1f1b 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/test/BUILD.gn
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/test/BUILD.gn
@@ -12,7 +12,6 @@
     "//ios/chrome/browser/content_suggestions/ui_bundled:eg_test_support+eg2",
     "//ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/public:constants",
     "//ios/chrome/browser/first_run/ui_bundled:constants",
-    "//ios/chrome/browser/ntp/model:features",
     "//ios/chrome/browser/shared/public/features",
     "//ios/chrome/browser/signin/model:fake_system_identity",
     "//ios/chrome/common/ui/promo_style:constants",
diff --git a/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/test/set_up_list_default_browser_egtest.mm b/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/test/set_up_list_default_browser_egtest.mm
index 9055f0f..c19362d6 100644
--- a/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/test/set_up_list_default_browser_egtest.mm
+++ b/ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/test/set_up_list_default_browser_egtest.mm
@@ -6,7 +6,6 @@
 #import "ios/chrome/browser/content_suggestions/ui_bundled/new_tab_page_app_interface.h"
 #import "ios/chrome/browser/content_suggestions/ui_bundled/set_up_list/public/set_up_list_constants.h"
 #import "ios/chrome/browser/first_run/ui_bundled/first_run_constants.h"
-#import "ios/chrome/browser/ntp/model/features.h"
 #import "ios/chrome/browser/shared/public/features/features.h"
 #import "ios/chrome/browser/signin/model/fake_system_identity.h"
 #import "ios/chrome/common/ui/promo_style/constants.h"
diff --git a/ios/chrome/browser/flags/BUILD.gn b/ios/chrome/browser/flags/BUILD.gn
index 5de9d5a..22f248b7 100644
--- a/ios/chrome/browser/flags/BUILD.gn
+++ b/ios/chrome/browser/flags/BUILD.gn
@@ -90,7 +90,6 @@
     "//ios/chrome/browser/incognito_reauth/ui_bundled:features",
     "//ios/chrome/browser/intelligence/features",
     "//ios/chrome/browser/lens/ui_bundled:features",
-    "//ios/chrome/browser/ntp/model:features",
     "//ios/chrome/browser/ntp/ui_bundled:feature_flags",
     "//ios/chrome/browser/omnibox/public:features",
     "//ios/chrome/browser/page_info/ui_bundled:features",
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index d87c178..69e187a7 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -107,7 +107,6 @@
 #import "ios/chrome/browser/incognito_reauth/ui_bundled/features.h"
 #import "ios/chrome/browser/intelligence/features/features.h"
 #import "ios/chrome/browser/lens/ui_bundled/features.h"
-#import "ios/chrome/browser/ntp/model/features.h"
 #import "ios/chrome/browser/ntp/ui_bundled/new_tab_page_feature.h"
 #import "ios/chrome/browser/omnibox/public/omnibox_ui_features.h"
 #import "ios/chrome/browser/policy/model/policy_util.h"
@@ -1000,21 +999,6 @@
              kIOSStartTimeBrowserBackgroundRemediationsUpdateFeedRefreshArm),
          nullptr}};
 
-const FeatureEntry::FeatureParam kSetUpListDuration3Days[] = {
-    {set_up_list::kSetUpListDurationParam, "2"}};
-const FeatureEntry::FeatureParam kSetUpListDuration5Days[] = {
-    {set_up_list::kSetUpListDurationParam, "4"}};
-const FeatureEntry::FeatureParam kSetUpListDuration7Days[] = {
-    {set_up_list::kSetUpListDurationParam, "6"}};
-
-const FeatureEntry::FeatureVariation kSetUpListDurationVariations[] = {
-    {" - 3 Days", kSetUpListDuration3Days, std::size(kSetUpListDuration3Days),
-     nullptr},
-    {" - 5 Days", kSetUpListDuration5Days, std::size(kSetUpListDuration5Days),
-     nullptr},
-    {" - 7 Days", kSetUpListDuration7Days, std::size(kSetUpListDuration7Days),
-     nullptr}};
-
 const FeatureEntry::FeatureParam kUpdatedFirstRunSequenceArm1[] = {
     {first_run::kUpdatedFirstRunSequenceParam, "1"}};
 const FeatureEntry::FeatureParam kUpdatedFirstRunSequenceArm2[] = {
@@ -2221,13 +2205,6 @@
      flag_descriptions::kLensUnaryHttpTransportEnabledName,
      flag_descriptions::kLensUnaryHttpTransportEnabledDescription,
      flags_ui::kOsIos, FEATURE_VALUE_TYPE(kLensUnaryHttpTransportEnabled)},
-    {"set-up-list-shortened-duration",
-     flag_descriptions::kSetUpListShortenedDurationName,
-     flag_descriptions::kSetUpListShortenedDurationDescription,
-     flags_ui::kOsIos,
-     FEATURE_WITH_PARAMS_VALUE_TYPE(set_up_list::kSetUpListShortenedDuration,
-                                    kSetUpListDurationVariations,
-                                    "SetUpListShortenedDuration")},
     {"collaboration-messaging", flag_descriptions::kCollaborationMessagingName,
      flag_descriptions::kCollaborationMessagingDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(collaboration::features::kCollaborationMessaging)},
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index d84d48f..c61382dc 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -1541,10 +1541,6 @@
     "Feature to allow users to send tabs to their iOS device through a system "
     "push notitification.";
 
-const char kSetUpListShortenedDurationName[] = "Set Up List Shortened Duration";
-const char kSetUpListShortenedDurationDescription[] =
-    "Reduces the Set Up List duration in the NTP to the selected parameter.";
-
 const char kSharedHighlightingIOSName[] = "Enable Shared Highlighting features";
 const char kSharedHighlightingIOSDescription[] =
     "Adds a Link to Text option in the Edit Menu which generates URLs with a "
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index 58ed396..7392066 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -923,9 +923,6 @@
 extern const char kSendTabToSelfIOSPushNotificationsName[];
 extern const char kSendTabToSelfIOSPushNotificationsDescription[];
 
-extern const char kSetUpListShortenedDurationName[];
-extern const char kSetUpListShortenedDurationDescription[];
-
 extern const char kSharedHighlightingIOSName[];
 extern const char kSharedHighlightingIOSDescription[];
 
diff --git a/ios/chrome/browser/ntp/model/BUILD.gn b/ios/chrome/browser/ntp/model/BUILD.gn
index ece2f3e..fdcee780 100644
--- a/ios/chrome/browser/ntp/model/BUILD.gn
+++ b/ios/chrome/browser/ntp/model/BUILD.gn
@@ -2,14 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-source_set("features") {
-  sources = [
-    "features.h",
-    "features.mm",
-  ]
-  deps = [ "//base" ]
-}
-
 source_set("model") {
   sources = [
     "browser_policy_new_tab_page_rewriter.h",
@@ -63,7 +55,6 @@
     "set_up_list_item.mm",
   ]
   deps = [
-    ":features",
     ":set_up_list_item_type",
     ":set_up_list_metrics",
     ":set_up_list_prefs",
@@ -122,7 +113,6 @@
     "set_up_list_unittest.mm",
   ]
   deps = [
-    ":features",
     ":set_up_list",
     ":set_up_list_item_type",
     ":set_up_list_prefs",
diff --git a/ios/chrome/browser/ntp/model/features.h b/ios/chrome/browser/ntp/model/features.h
deleted file mode 100644
index 85a971f..0000000
--- a/ios/chrome/browser/ntp/model/features.h
+++ /dev/null
@@ -1,27 +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_NTP_MODEL_FEATURES_H_
-#define IOS_CHROME_BROWSER_NTP_MODEL_FEATURES_H_
-
-#import "base/feature_list.h"
-#import "base/time/time.h"
-
-namespace set_up_list {
-
-// Feature to adjust the Set Up List duration.
-BASE_DECLARE_FEATURE(kSetUpListShortenedDuration);
-
-// Name of the param that indicates the duration of the Set Up List in days.
-extern const char kSetUpListDurationParam[];
-
-// Returns the duration for the SetUpList based off the state of the
-// kSetUpListShortenedDuration feature. Returns the duration past the First Run,
-// so if the function returns 1 day, that means the Set Up List will appear one
-// day past the First Run.
-base::TimeDelta SetUpListDurationPastFirstRun();
-
-}  // namespace set_up_list
-
-#endif  // IOS_CHROME_BROWSER_NTP_MODEL_FEATURES_H_
diff --git a/ios/chrome/browser/ntp/model/features.mm b/ios/chrome/browser/ntp/model/features.mm
deleted file mode 100644
index adab055..0000000
--- a/ios/chrome/browser/ntp/model/features.mm
+++ /dev/null
@@ -1,20 +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/ntp/model/features.h"
-
-#import "base/metrics/field_trial_params.h"
-
-namespace set_up_list {
-
-BASE_FEATURE(kSetUpListShortenedDuration, base::FEATURE_DISABLED_BY_DEFAULT);
-
-const char kSetUpListDurationParam[] = "SetUpListDurationParam";
-
-base::TimeDelta SetUpListDurationPastFirstRun() {
-  return base::Days(base::GetFieldTrialParamByFeatureAsInt(
-      kSetUpListShortenedDuration, kSetUpListDurationParam, 14));
-}
-
-}  // namespace set_up_list
diff --git a/ios/chrome/browser/ntp/model/set_up_list.mm b/ios/chrome/browser/ntp/model/set_up_list.mm
index 567815f..12dc42c 100644
--- a/ios/chrome/browser/ntp/model/set_up_list.mm
+++ b/ios/chrome/browser/ntp/model/set_up_list.mm
@@ -17,7 +17,6 @@
 #import "components/signin/public/identity_manager/identity_manager.h"
 #import "components/sync/base/user_selectable_type.h"
 #import "ios/chrome/browser/default_browser/model/utils.h"
-#import "ios/chrome/browser/ntp/model/features.h"
 #import "ios/chrome/browser/ntp/model/set_up_list_delegate.h"
 #import "ios/chrome/browser/ntp/model/set_up_list_item.h"
 #import "ios/chrome/browser/ntp/model/set_up_list_item_type.h"
diff --git a/ios/chrome/browser/settings/ui_bundled/autofill/BUILD.gn b/ios/chrome/browser/settings/ui_bundled/autofill/BUILD.gn
index 9eb1c91..c1cbd262 100644
--- a/ios/chrome/browser/settings/ui_bundled/autofill/BUILD.gn
+++ b/ios/chrome/browser/settings/ui_bundled/autofill/BUILD.gn
@@ -34,6 +34,8 @@
     "autofill_profile_table_view_controller.mm",
     "autofill_settings_profile_edit_table_view_controller.h",
     "autofill_settings_profile_edit_table_view_controller.mm",
+    "autofill_settings_util.h",
+    "autofill_settings_util.mm",
   ]
   deps = [
     ":constants",
@@ -134,6 +136,7 @@
     "//ios/chrome/browser/autofill/ui_bundled:util",
     "//ios/chrome/browser/autofill/ui_bundled/address_editor:autofill_shared_ui",
     "//ios/chrome/browser/autofill/ui_bundled/address_editor:constants",
+    "//ios/chrome/browser/autofill/ui_bundled/cells",
     "//ios/chrome/browser/net/model:crurl",
     "//ios/chrome/browser/settings/ui_bundled:settings_root",
     "//ios/chrome/browser/settings/ui_bundled:test_support",
diff --git a/ios/chrome/browser/settings/ui_bundled/autofill/autofill_add_credit_card_view_controller.mm b/ios/chrome/browser/settings/ui_bundled/autofill/autofill_add_credit_card_view_controller.mm
index c3456b8..121e79b 100644
--- a/ios/chrome/browser/settings/ui_bundled/autofill/autofill_add_credit_card_view_controller.mm
+++ b/ios/chrome/browser/settings/ui_bundled/autofill/autofill_add_credit_card_view_controller.mm
@@ -8,9 +8,11 @@
 #import "base/feature_list.h"
 #import "base/metrics/user_metrics.h"
 #import "components/autofill/core/common/autofill_payments_features.h"
+#import "ios/chrome/browser/autofill/ui_bundled/autofill_credit_card_ui_type.h"
 #import "ios/chrome/browser/autofill/ui_bundled/cells/autofill_credit_card_edit_item.h"
 #import "ios/chrome/browser/settings/ui_bundled/autofill/autofill_add_credit_card_view_controller_delegate.h"
 #import "ios/chrome/browser/settings/ui_bundled/autofill/autofill_add_credit_card_view_controller_presentation_delegate.h"
+#import "ios/chrome/browser/settings/ui_bundled/autofill/autofill_settings_util.h"
 #import "ios/chrome/browser/shared/public/features/features.h"
 #import "ios/chrome/browser/shared/ui/table_view/cells/table_view_text_edit_item.h"
 #import "ios/chrome/browser/shared/ui/table_view/cells/table_view_text_edit_item_delegate.h"
@@ -213,6 +215,15 @@
   // the user types a character that makes the form valid/invalid.
   [self updateCreditCardData];
 
+  BOOL isValid = [self isItemValid:tableViewTextEditItem];
+
+  // Update Accessibility Label.
+  NSString* error =
+      isValid ? nil : [self errorMessageForItem:tableViewTextEditItem];
+  [AutofillSettingsUtil updateAccessibilityLabelForItem:tableViewTextEditItem
+                                           isInputValid:isValid
+                                           errorMessage:error];
+
   self.navigationItem.rightBarButtonItem.enabled =
       [_delegate addCreditCardViewController:self
                      isValidCreditCardNumber:_cardNumber
@@ -233,40 +244,23 @@
   // Considers a textfield to be valid if it has no data.
   if (tableViewTextEditItem.textFieldValue.length == 0) {
     tableViewTextEditItem.hasValidText = YES;
+    tableViewTextEditItem.cellAccessibilityLabel = nil;
     [self reconfigureCellsForItems:@[ tableViewTextEditItem ]];
     return;
   }
 
-  CHECK_NE(tableViewTextEditItem.type, ItemTypeUseCameraButton);
-  switch (tableViewTextEditItem.type) {
-    case ItemTypeCardNumber:
-      tableViewTextEditItem.hasValidText =
-          [_delegate addCreditCardViewController:self
-                         isValidCreditCardNumber:_cardNumber];
-      break;
-    case ItemTypeExpirationMonth:
-      tableViewTextEditItem.hasValidText =
-          [_delegate addCreditCardViewController:self
-                isValidCreditCardExpirationMonth:_expirationMonth];
-      break;
-    case ItemTypeExpirationYear:
-      tableViewTextEditItem.hasValidText =
-          [_delegate addCreditCardViewController:self
-                 isValidCreditCardExpirationYear:_expirationYear];
-      break;
-    case ItemTypeCardNickname:
-      tableViewTextEditItem.hasValidText =
-          [_delegate addCreditCardViewController:self
-                             isValidCardNickname:_cardNickname];
-      break;
-    case ItemTypeCardCvc:
-      tableViewTextEditItem.hasValidText =
-          [_delegate addCreditCardViewController:self isValidCardCvc:_cardCvc];
-      break;
-    default:
-      // For the 'Name on card' and 'Security code' textfield.
-      tableViewTextEditItem.hasValidText = YES;
-  }
+  BOOL isValid = [self isItemValid:tableViewTextEditItem];
+
+  // Update Visual State
+  tableViewTextEditItem.hasValidText = isValid;
+
+  // Update Accessibility Label
+  NSString* error =
+      isValid ? nil : [self errorMessageForItem:tableViewTextEditItem];
+  [AutofillSettingsUtil updateAccessibilityLabelForItem:tableViewTextEditItem
+                                           isInputValid:isValid
+                                           errorMessage:error];
+
   [self reconfigureCellsForItems:@[ tableViewTextEditItem ]];
 }
 
@@ -493,22 +487,55 @@
                        l10n_util::GetNSString(
                            IDS_IOS_AUTOFILL_DIALOG_PLACEHOLDER_NICKNAME)
                            keyboardType:UIKeyboardTypeDefault
-               autofillCreditCardUIType:AutofillCreditCardUIType::kUnknown];
+               autofillCreditCardUIType:AutofillCreditCardUIType::kNickname];
   return cardNicknameItem;
 }
 
 - (AutofillCreditCardEditItem*)cardCvcItem {
-  AutofillCreditCardEditItem* cardCvcItem =
-      [self createTableViewItemWithType:ItemTypeCardCvc
-                     fieldNameLabelText:l10n_util::GetNSString(
-                                            IDS_IOS_AUTOFILL_SECURITY_CODE)
-                         textFieldValue:_cardCvc
-                   textFieldPlaceholder:
-                       l10n_util::GetNSString(
-                           IDS_IOS_AUTOFILL_DIALOG_PLACEHOLDER_CVC_OPTIONAL)
-                           keyboardType:UIKeyboardTypeNumberPad
-               autofillCreditCardUIType:AutofillCreditCardUIType::kUnknown];
+  AutofillCreditCardEditItem* cardCvcItem = [self
+      createTableViewItemWithType:ItemTypeCardCvc
+               fieldNameLabelText:l10n_util::GetNSString(
+                                      IDS_IOS_AUTOFILL_SECURITY_CODE)
+                   textFieldValue:_cardCvc
+             textFieldPlaceholder:
+                 l10n_util::GetNSString(
+                     IDS_IOS_AUTOFILL_DIALOG_PLACEHOLDER_CVC_OPTIONAL)
+                     keyboardType:UIKeyboardTypeNumberPad
+         autofillCreditCardUIType:AutofillCreditCardUIType::kSecurityCode];
   return cardCvcItem;
 }
 
+#pragma mark - Private Helpers
+
+// Helper to get the localized error message for the item type.
+- (NSString*)errorMessageForItem:(TableViewTextEditItem*)item {
+  AutofillCreditCardEditItem* editItem =
+      base::apple::ObjCCastStrict<AutofillCreditCardEditItem>(item);
+
+  return [AutofillSettingsUtil
+      errorMessageForUIType:editItem.autofillCreditCardUIType];
+}
+
+// Helper to check if the text entered in the item is valid.
+- (BOOL)isItemValid:(TableViewTextEditItem*)item {
+  switch (item.type) {
+    case ItemTypeCardNumber:
+      return [_delegate addCreditCardViewController:self
+                            isValidCreditCardNumber:_cardNumber];
+    case ItemTypeExpirationMonth:
+      return [_delegate addCreditCardViewController:self
+                   isValidCreditCardExpirationMonth:_expirationMonth];
+    case ItemTypeExpirationYear:
+      return [_delegate addCreditCardViewController:self
+                    isValidCreditCardExpirationYear:_expirationYear];
+    case ItemTypeCardNickname:
+      return [_delegate addCreditCardViewController:self
+                                isValidCardNickname:_cardNickname];
+    case ItemTypeCardCvc:
+      return [_delegate addCreditCardViewController:self
+                                     isValidCardCvc:_cardCvc];
+    default:
+      return YES;
+  }
+}
 @end
diff --git a/ios/chrome/browser/settings/ui_bundled/autofill/autofill_credit_card_edit_table_view_controller.mm b/ios/chrome/browser/settings/ui_bundled/autofill/autofill_credit_card_edit_table_view_controller.mm
index a442f90..79bc54a 100644
--- a/ios/chrome/browser/settings/ui_bundled/autofill/autofill_credit_card_edit_table_view_controller.mm
+++ b/ios/chrome/browser/settings/ui_bundled/autofill/autofill_credit_card_edit_table_view_controller.mm
@@ -28,6 +28,7 @@
 #import "ios/chrome/browser/autofill/ui_bundled/autofill_credit_card_util.h"
 #import "ios/chrome/browser/autofill/ui_bundled/cells/autofill_credit_card_edit_item.h"
 #import "ios/chrome/browser/settings/ui_bundled/autofill/autofill_settings_constants.h"
+#import "ios/chrome/browser/settings/ui_bundled/autofill/autofill_settings_util.h"
 #import "ios/chrome/browser/settings/ui_bundled/settings_navigation_controller.h"
 #import "ios/chrome/browser/shared/model/application_context/application_context.h"
 #import "ios/chrome/browser/shared/public/commands/application_commands.h"
@@ -258,19 +259,12 @@
       const char* network = autofill::GetCardNetwork(
           base::SysNSStringToUTF16(item.textFieldValue));
       item.identifyingIcon = [self cardTypeIconFromNetwork:network];
-      [self reconfigureCellsForItems:@[ item ]];
     }
 
-    if (item.type == ItemTypeNickname) {
-      NSString* trimmedText = [item.textFieldValue
-          stringByTrimmingCharactersInSet:
-              [NSCharacterSet whitespaceAndNewlineCharacterSet]];
-      BOOL newNicknameIsValid = autofill::CreditCard::IsNicknameValid(
-          base::SysNSStringToUTF16(trimmedText));
-      self.navigationItem.rightBarButtonItem.enabled = newNicknameIsValid;
-      [item setHasValidText:newNicknameIsValid];
-      [self reconfigureCellsForItems:@[ item ]];
-    }
+    // Validate while typing & update label.
+    [self validateItem:item];
+
+    [self reconfigureCellsForItems:@[ item ]];
   }
 }
 
@@ -287,36 +281,8 @@
     AutofillCreditCardEditItem* item =
         (AutofillCreditCardEditItem*)tableViewTextEditItem;
 
-    switch (item.type) {
-      case ItemTypeCardNumber:
-        tableViewTextEditItem.hasValidText = [AutofillCreditCardUtil
-            isValidCreditCardNumber:item.textFieldValue
-                           appLocal:GetApplicationContext()
-                                        ->GetApplicationLocaleStorage()
-                                        ->Get()];
-        break;
-      case ItemTypeExpirationMonth:
-        tableViewTextEditItem.hasValidText = [AutofillCreditCardUtil
-            isValidCreditCardExpirationMonth:item.textFieldValue];
-        break;
-      case ItemTypeExpirationYear:
-        tableViewTextEditItem.hasValidText = [AutofillCreditCardUtil
-            isValidCreditCardExpirationYear:item.textFieldValue
-                                   appLocal:GetApplicationContext()
-                                                ->GetApplicationLocaleStorage()
-                                                ->Get()];
-        break;
-      case ItemTypeNickname:
-        tableViewTextEditItem.hasValidText =
-            [AutofillCreditCardUtil isValidCardNickname:item.textFieldValue];
-        break;
-      case ItemTypeCardholderName:
-      case ItemTypeCvc:
-      default:
-        // For the 'Name on card' and 'CVC' textfields.
-        tableViewTextEditItem.hasValidText = YES;
-        break;
-    }
+    // Validate on tab out & update label
+    [self validateItem:item];
 
     // Reconfigure to trigger appropiate icon change.
     [self reconfigureCellsForItems:@[ item ]];
@@ -500,6 +466,7 @@
   nicknameItem.textFieldPlaceholder =
       l10n_util::GetNSString(IDS_IOS_AUTOFILL_DIALOG_PLACEHOLDER_NICKNAME);
   nicknameItem.textFieldEnabled = isEditing;
+  nicknameItem.autofillCreditCardUIType = AutofillCreditCardUIType::kNickname;
   nicknameItem.keyboardType = UIKeyboardTypeDefault;
   nicknameItem.hideIcon = !isEditing;
   nicknameItem.delegate = self;
@@ -557,4 +524,57 @@
   return item.textFieldValue;
 }
 
+// Helper to get the localized error message.
+- (NSString*)errorMessageForItem:(TableViewTextEditItem*)item {
+  AutofillCreditCardEditItem* autofillItem =
+      base::apple::ObjCCastStrict<AutofillCreditCardEditItem>(item);
+
+  return [AutofillSettingsUtil
+      errorMessageForUIType:autofillItem.autofillCreditCardUIType];
+}
+
+// Helper to validate item and update its state.
+- (void)validateItem:(AutofillCreditCardEditItem*)item {
+  BOOL isValid = YES;
+  switch (item.type) {
+    case ItemTypeCardNumber:
+      isValid = [AutofillCreditCardUtil
+          isValidCreditCardNumber:item.textFieldValue
+                         appLocal:GetApplicationContext()
+                                      ->GetApplicationLocaleStorage()
+                                      ->Get()];
+      break;
+    case ItemTypeExpirationMonth:
+      isValid = [AutofillCreditCardUtil
+          isValidCreditCardExpirationMonth:item.textFieldValue];
+      break;
+    case ItemTypeExpirationYear:
+      isValid = [AutofillCreditCardUtil
+          isValidCreditCardExpirationYear:item.textFieldValue
+                                 appLocal:GetApplicationContext()
+                                              ->GetApplicationLocaleStorage()
+                                              ->Get()];
+      break;
+    case ItemTypeNickname:
+      isValid = [AutofillCreditCardUtil
+          isValidCardNickname:[item.textFieldValue
+                                  stringByTrimmingCharactersInSet:
+                                      [NSCharacterSet
+                                          whitespaceAndNewlineCharacterSet]]];
+      break;
+    case ItemTypeCvc:
+      isValid = [AutofillCreditCardUtil isValidCardCvc:item.textFieldValue];
+      break;
+    default:
+      isValid = YES;
+      break;
+  }
+
+  item.hasValidText = isValid;
+
+  NSString* error = isValid ? nil : [self errorMessageForItem:item];
+  [AutofillSettingsUtil updateAccessibilityLabelForItem:item
+                                           isInputValid:isValid
+                                           errorMessage:error];
+}
 @end
diff --git a/ios/chrome/browser/settings/ui_bundled/autofill/autofill_credit_card_table_view_controller_unittest.mm b/ios/chrome/browser/settings/ui_bundled/autofill/autofill_credit_card_table_view_controller_unittest.mm
index d7c37b2..fa44a5d 100644
--- a/ios/chrome/browser/settings/ui_bundled/autofill/autofill_credit_card_table_view_controller_unittest.mm
+++ b/ios/chrome/browser/settings/ui_bundled/autofill/autofill_credit_card_table_view_controller_unittest.mm
@@ -20,16 +20,24 @@
 #import "components/autofill/core/common/autofill_payments_features.h"
 #import "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/autofill/model/personal_data_manager_factory.h"
+#import "ios/chrome/browser/autofill/ui_bundled/cells/autofill_credit_card_edit_item.h"
+#import "ios/chrome/browser/settings/ui_bundled/autofill/autofill_add_credit_card_view_controller.h"
+#import "ios/chrome/browser/settings/ui_bundled/autofill/autofill_add_credit_card_view_controller_delegate.h"
+#import "ios/chrome/browser/settings/ui_bundled/autofill/autofill_credit_card_edit_table_view_controller.h"
 #import "ios/chrome/browser/settings/ui_bundled/autofill/cells/autofill_card_item.h"
 #import "ios/chrome/browser/shared/model/application_context/application_context.h"
 #import "ios/chrome/browser/shared/model/browser/test/test_browser.h"
 #import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h"
+#import "ios/chrome/browser/shared/ui/table_view/cells/table_view_text_edit_item_delegate.h"
 #import "ios/chrome/browser/shared/ui/table_view/legacy_chrome_table_view_controller_test.h"
 #import "ios/chrome/browser/webdata_services/model/web_data_service_factory.h"
 #import "ios/chrome/common/ui/reauthentication/reauthentication_module.h"
+#import "ios/chrome/grit/ios_strings.h"
 #import "ios/chrome/test/ios_chrome_scoped_testing_local_state.h"
 #import "ios/web/public/test/web_task_environment.h"
 #import "testing/gtest/include/gtest/gtest.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+#import "third_party/ocmock/gtest_support.h"
 #import "ui/base/l10n/l10n_util.h"
 
 namespace {
@@ -336,4 +344,181 @@
                    "AutofillCreditCardDeletedAndHadCvc"));
 }
 
+class AutofillAddCreditCardViewControllerTest
+    : public LegacyChromeTableViewControllerTest {
+ protected:
+  AutofillAddCreditCardViewControllerTest() {
+    feature_list_.InitAndEnableFeature(
+        autofill::features::kAutofillEnableCvcStorageAndFilling);
+  }
+
+  LegacyChromeTableViewController* InstantiateController() override {
+    mock_delegate_ =
+        OCMProtocolMock(@protocol(AddCreditCardViewControllerDelegate));
+    return [[AutofillAddCreditCardViewController alloc]
+        initWithDelegate:mock_delegate_];
+  }
+
+  AutofillAddCreditCardViewController* GetAddController() {
+    return base::apple::ObjCCastStrict<AutofillAddCreditCardViewController>(
+        controller());
+  }
+
+  // Helper to find item by UI Type (public property)
+  AutofillCreditCardEditItem* GetItem(AutofillCreditCardUIType uiType) {
+    TableViewModel* model = [controller() tableViewModel];
+    for (NSInteger section = 0; section < [model numberOfSections]; ++section) {
+      NSInteger itemCount = [model numberOfItemsInSection:section];
+      for (NSInteger itemIndex = 0; itemIndex < itemCount; ++itemIndex) {
+        NSIndexPath* path = [NSIndexPath indexPathForItem:itemIndex
+                                                inSection:section];
+        id item = [model itemAtIndexPath:path];
+        AutofillCreditCardEditItem* editItem =
+            base::apple::ObjCCast<AutofillCreditCardEditItem>(item);
+        if (editItem && editItem.autofillCreditCardUIType == uiType) {
+          return editItem;
+        }
+      }
+    }
+    return nil;
+  }
+
+  base::test::ScopedFeatureList feature_list_;
+  id mock_delegate_;
+};
+
+TEST_F(AutofillAddCreditCardViewControllerTest,
+       AccessibilityLabel_InvalidInput) {
+  CreateController();
+  CheckController();
+
+  AutofillCreditCardEditItem* item = GetItem(AutofillCreditCardUIType::kNumber);
+  ASSERT_TRUE(item);
+
+  // Mock invalid result
+  OCMStub([mock_delegate_ addCreditCardViewController:[OCMArg any]
+                              isValidCreditCardNumber:[OCMArg any]])
+      .andReturn(NO);
+
+  item.textFieldValue = @"1234";
+  // Cast to delegate to call protocol method
+  [(id<TableViewTextEditItemDelegate>)GetAddController()
+      tableViewItemDidChange:item];
+
+  // Verify accessibility label contains the error message
+  NSString* error = l10n_util::GetNSString(
+      IDS_IOS_AUTOFILL_INVALID_CARD_NUMBER_ACCESSIBILITY_ANNOUNCEMENT);
+  EXPECT_TRUE([item.cellAccessibilityLabel containsString:error]);
+}
+
+TEST_F(AutofillAddCreditCardViewControllerTest,
+       AccessibilityLabel_ValidInputWithPlaceholder) {
+  CreateController();
+  CheckController();
+  AutofillCreditCardEditItem* item =
+      GetItem(AutofillCreditCardUIType::kExpMonth);
+  ASSERT_TRUE(item);
+
+  OCMStub([mock_delegate_ addCreditCardViewController:[OCMArg any]
+                     isValidCreditCardExpirationMonth:[OCMArg any]])
+      .andReturn(YES);
+
+  item.textFieldValue = @"12";
+  [(id<TableViewTextEditItemDelegate>)GetAddController()
+      tableViewItemDidChange:item];
+
+  // Verify label contains placeholder
+  EXPECT_TRUE(item.textFieldPlaceholder.length > 0);
+  EXPECT_TRUE(
+      [item.cellAccessibilityLabel containsString:item.textFieldPlaceholder]);
+}
+
+class AutofillCreditCardEditTableViewControllerTest
+    : public LegacyChromeTableViewControllerTest {
+ protected:
+  AutofillCreditCardEditTableViewControllerTest() {
+    TestProfileIOS::Builder builder;
+    builder.AddTestingFactory(ios::WebDataServiceFactory::GetInstance(),
+                              ios::WebDataServiceFactory::GetDefaultFactory());
+    profile_ = std::move(builder).Build();
+    browser_ = std::make_unique<TestBrowser>(profile_.get());
+    feature_list_.InitAndEnableFeature(
+        autofill::features::kAutofillEnableCvcStorageAndFilling);
+  }
+
+  LegacyChromeTableViewController* InstantiateController() override {
+    autofill::CreditCard credit_card =
+        autofill::CreditCard(base::Uuid::GenerateRandomV4().AsLowercaseString(),
+                             "https://www.example.com/");
+
+    return [[AutofillCreditCardEditTableViewController alloc]
+         initWithCreditCard:credit_card
+        personalDataManager:autofill::PersonalDataManagerFactory::GetForProfile(
+                                profile_.get())];
+  }
+
+  AutofillCreditCardEditTableViewController* GetEditController() {
+    return base::apple::ObjCCastStrict<
+        AutofillCreditCardEditTableViewController>(controller());
+  }
+
+  AutofillCreditCardEditItem* GetItem(AutofillCreditCardUIType uiType) {
+    TableViewModel* model = [controller() tableViewModel];
+    for (NSInteger section = 0; section < [model numberOfSections]; ++section) {
+      NSInteger itemCount = [model numberOfItemsInSection:section];
+      for (NSInteger itemIndex = 0; itemIndex < itemCount; ++itemIndex) {
+        NSIndexPath* path = [NSIndexPath indexPathForItem:itemIndex
+                                                inSection:section];
+        id item = [model itemAtIndexPath:path];
+        AutofillCreditCardEditItem* editItem =
+            base::apple::ObjCCast<AutofillCreditCardEditItem>(item);
+        if (editItem && editItem.autofillCreditCardUIType == uiType) {
+          return editItem;
+        }
+      }
+    }
+    return nil;
+  }
+
+  web::WebTaskEnvironment task_environment_;
+  std::unique_ptr<TestProfileIOS> profile_;
+  std::unique_ptr<Browser> browser_;
+  base::test::ScopedFeatureList feature_list_;
+};
+
+TEST_F(AutofillCreditCardEditTableViewControllerTest,
+       AccessibilityLabel_InvalidCVC) {
+  CreateController();
+  CheckController();
+  // Use kSecurityCode for CVC
+  AutofillCreditCardEditItem* item =
+      GetItem(AutofillCreditCardUIType::kSecurityCode);
+  ASSERT_TRUE(item);
+
+  item.textFieldValue = @"1";
+  [(id<TableViewTextEditItemDelegate>)GetEditController()
+      tableViewItemDidChange:item];
+
+  NSString* error = l10n_util::GetNSString(
+      IDS_IOS_AUTOFILL_INVALID_CVC_ACCESSIBILITY_ANNOUNCEMENT);
+  EXPECT_TRUE([item.cellAccessibilityLabel containsString:error]);
+}
+
+TEST_F(AutofillCreditCardEditTableViewControllerTest,
+       AccessibilityLabel_ValidCVCWithPlaceholder) {
+  CreateController();
+  CheckController();
+  AutofillCreditCardEditItem* item =
+      GetItem(AutofillCreditCardUIType::kSecurityCode);
+  ASSERT_TRUE(item);
+
+  item.textFieldValue = @"123";
+  [(id<TableViewTextEditItemDelegate>)GetEditController()
+      tableViewItemDidChange:item];
+
+  // Should contain "Optional" placeholder
+  EXPECT_TRUE(
+      [item.cellAccessibilityLabel containsString:item.textFieldPlaceholder]);
+}
+
 }  // namespace
diff --git a/ios/chrome/browser/settings/ui_bundled/autofill/autofill_settings_util.h b/ios/chrome/browser/settings/ui_bundled/autofill/autofill_settings_util.h
new file mode 100644
index 0000000..a8e7ab5
--- /dev/null
+++ b/ios/chrome/browser/settings/ui_bundled/autofill/autofill_settings_util.h
@@ -0,0 +1,31 @@
+// 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 IOS_CHROME_BROWSER_SETTINGS_UI_BUNDLED_AUTOFILL_AUTOFILL_SETTINGS_UTIL_H_
+#define IOS_CHROME_BROWSER_SETTINGS_UI_BUNDLED_AUTOFILL_AUTOFILL_SETTINGS_UTIL_H_
+
+#import <Foundation/Foundation.h>
+
+#import "ios/chrome/browser/autofill/ui_bundled/autofill_credit_card_ui_type.h"
+
+@class TableViewTextEditItem;
+
+// Utility class for Autofill Settings UI.
+@interface AutofillSettingsUtil : NSObject
+
+// Updates the `cellAccessibilityLabel` of the given `item` to include:
+// 1. The Field Name (e.g., "Card Number").
+// 2. The Essential Placeholder (e.g., "MM/YY" or "Optional"), but only if the
+//    field has text (since iOS hides the visual placeholder).
+// 3. The `errorMessage` (e.g., "Invalid Card Number"), if `isValid` is NO.
++ (void)updateAccessibilityLabelForItem:(TableViewTextEditItem*)item
+                           isInputValid:(BOOL)isValid
+                           errorMessage:(NSString*)errorMessage;
+
+// Returns the localized error message for the given credit card field type.
++ (NSString*)errorMessageForUIType:(AutofillCreditCardUIType)type;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_SETTINGS_UI_BUNDLED_AUTOFILL_AUTOFILL_SETTINGS_UTIL_H_
diff --git a/ios/chrome/browser/settings/ui_bundled/autofill/autofill_settings_util.mm b/ios/chrome/browser/settings/ui_bundled/autofill/autofill_settings_util.mm
new file mode 100644
index 0000000..29af458
--- /dev/null
+++ b/ios/chrome/browser/settings/ui_bundled/autofill/autofill_settings_util.mm
@@ -0,0 +1,76 @@
+// 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 "ios/chrome/browser/settings/ui_bundled/autofill/autofill_settings_util.h"
+
+#import "components/strings/grit/components_strings.h"
+#import "ios/chrome/browser/shared/ui/table_view/cells/table_view_text_edit_item.h"
+#import "ios/chrome/grit/ios_strings.h"
+#import "ui/base/l10n/l10n_util.h"
+
+@implementation AutofillSettingsUtil
+
++ (void)updateAccessibilityLabelForItem:(TableViewTextEditItem*)item
+                           isInputValid:(BOOL)isValid
+                           errorMessage:(NSString*)errorMessage {
+  NSMutableArray* labelParts = [NSMutableArray array];
+
+  if (item.fieldNameLabelText.length > 0) {
+    [labelParts addObject:item.fieldNameLabelText];
+  }
+
+  // Essential Placeholder. By default, iOS stops announcing the placeholder
+  // once a text field has a value. However, for these specific fields, the
+  // placeholder conveys critical constraints that shouldn't disappear. This
+  // block checks if the field has text (meaning the default announcement is
+  // gone) and manually appends the placeholder back to the accessibility label
+  // if it matches one of the essential types.
+  if (item.textFieldValue.length > 0) {
+    NSString* optionalPlaceholder = l10n_util::GetNSString(
+        IDS_IOS_AUTOFILL_DIALOG_PLACEHOLDER_CVC_OPTIONAL);
+    NSString* monthPlaceholder = l10n_util::GetNSString(
+        IDS_IOS_AUTOFILL_DIALOG_PLACEHOLDER_EXPIRY_MONTH);
+    NSString* yearPlaceholder = l10n_util::GetNSString(
+        IDS_IOS_AUTOFILL_DIALOG_PLACEHOLDER_EXPIRATION_YEAR);
+
+    BOOL isEssential =
+        [item.textFieldPlaceholder isEqualToString:optionalPlaceholder] ||
+        [item.textFieldPlaceholder isEqualToString:monthPlaceholder] ||
+        [item.textFieldPlaceholder isEqualToString:yearPlaceholder];
+
+    if (isEssential) {
+      [labelParts addObject:item.textFieldPlaceholder];
+    }
+  }
+
+  if (!isValid && errorMessage.length > 0) {
+    [labelParts addObject:errorMessage];
+  }
+
+  item.cellAccessibilityLabel = [labelParts componentsJoinedByString:@", "];
+}
+
++ (NSString*)errorMessageForUIType:(AutofillCreditCardUIType)type {
+  switch (type) {
+    case AutofillCreditCardUIType::kNumber:
+      return l10n_util::GetNSString(
+          IDS_IOS_AUTOFILL_INVALID_CARD_NUMBER_ACCESSIBILITY_ANNOUNCEMENT);
+    case AutofillCreditCardUIType::kExpMonth:
+    case AutofillCreditCardUIType::kExpYear:
+      return l10n_util::GetNSString(
+          IDS_IOS_AUTOFILL_INVALID_EXPIRATION_DATE_ACCESSIBILITY_ANNOUNCEMENT);
+    case AutofillCreditCardUIType::kSecurityCode:
+      return l10n_util::GetNSString(
+          IDS_IOS_AUTOFILL_INVALID_CVC_ACCESSIBILITY_ANNOUNCEMENT);
+    case AutofillCreditCardUIType::kFullName:
+      return l10n_util::GetNSString(
+          IDS_IOS_AUTOFILL_INVALID_CARDHOLDER_NAME_ACCESSIBILITY_ANNOUNCEMENT);
+    case AutofillCreditCardUIType::kNickname:
+      return l10n_util::GetNSString(
+          IDS_IOS_AUTOFILL_INVALID_NICKNAME_ACCESSIBILITY_ANNOUNCEMENT);
+    default:
+      return nil;
+  }
+}
+@end
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 f20d6ba..982737c 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
@@ -556,7 +556,6 @@
   item.text = l10n_util::GetNSString(
       IDS_IOS_GOOGLE_ACCOUNT_SETTINGS_SWITCH_ACCOUNT_ITEM);
   item.textColor = [UIColor colorNamed:kBlueColor];
-  item.accessibilityTraits |= UIAccessibilityTraitButton;
   [model addItem:item
       toSectionWithIdentifier:SwitchAccountAndSignOutSectionIdentifier];
 
@@ -564,7 +563,6 @@
   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:SwitchAccountAndSignOutSectionIdentifier];
   if (self.forcedSigninEnabled) {
@@ -837,7 +835,6 @@
     switchItem.target = self;
     switchItem.selector = @selector(itemSwitchToggled:);
     switchItem.tag = itemType;
-    switchItem.accessibilityTraits = UIAccessibilityTraitToggleButton;
     switchItem.accessibilityIdentifier = accessibilityIdentifier;
     return switchItem;
   } else {
@@ -847,7 +844,6 @@
     button.textColor = [UIColor colorNamed:kTextSecondaryColor];
     button.statusText = GetNSString(IDS_IOS_SETTING_OFF);
     button.accessibilityIdentifier = accessibilityIdentifier;
-    button.accessibilityTraits = UIAccessibilityTraitButton;
     button.target = self;
     button.selector = @selector(itemButtonTapped:);
     return button;
diff --git a/ios/chrome/browser/settings/ui_bundled/privacy/privacy_safe_browsing_egtest.mm b/ios/chrome/browser/settings/ui_bundled/privacy/privacy_safe_browsing_egtest.mm
index 1565a8a..4e2eaff9 100644
--- a/ios/chrome/browser/settings/ui_bundled/privacy/privacy_safe_browsing_egtest.mm
+++ b/ios/chrome/browser/settings/ui_bundled/privacy/privacy_safe_browsing_egtest.mm
@@ -349,7 +349,8 @@
   return config;
 }
 
-- (void)testSBERCellIsPresent {
+// TODO(crbug.com/467409016): Fix and re-enable this test.
+- (void)DISABLED_testSBERCellIsPresent {
   OpenPrivacySafeBrowsingSettings();
   PressInfoButtonForCell(kSettingsSafeBrowsingStandardProtectionCellId);
   [ElementInteractionWithGreyMatcher(
diff --git a/ios/chrome/browser/tips_notifications/model/BUILD.gn b/ios/chrome/browser/tips_notifications/model/BUILD.gn
index be2d0d8..f99e088a 100644
--- a/ios/chrome/browser/tips_notifications/model/BUILD.gn
+++ b/ios/chrome/browser/tips_notifications/model/BUILD.gn
@@ -26,7 +26,6 @@
     "//ios/chrome/browser/default_browser/model:utils",
     "//ios/chrome/browser/feature_engagement/model",
     "//ios/chrome/browser/lens/ui_bundled:lens_availability",
-    "//ios/chrome/browser/ntp/model:features",
     "//ios/chrome/browser/ntp/model:set_up_list_prefs",
     "//ios/chrome/browser/push_notification/model:constants",
     "//ios/chrome/browser/push_notification/model:push_notification_client",
diff --git a/ios/chrome/browser/tips_notifications/model/tips_notification_criteria.mm b/ios/chrome/browser/tips_notifications/model/tips_notification_criteria.mm
index 822d717..3200920 100644
--- a/ios/chrome/browser/tips_notifications/model/tips_notification_criteria.mm
+++ b/ios/chrome/browser/tips_notifications/model/tips_notification_criteria.mm
@@ -18,7 +18,6 @@
 #import "ios/chrome/browser/default_browser/model/utils.h"
 #import "ios/chrome/browser/feature_engagement/model/tracker_factory.h"
 #import "ios/chrome/browser/lens/ui_bundled/lens_availability.h"
-#import "ios/chrome/browser/ntp/model/features.h"
 #import "ios/chrome/browser/ntp/model/set_up_list_prefs.h"
 #import "ios/chrome/browser/search_engines/model/template_url_service_factory.h"
 #import "ios/chrome/browser/shared/model/application_context/application_context.h"
@@ -153,7 +152,7 @@
   // Up List minus the trigger interval after FirstRun.
   TimeDelta trigger_delta = TipsNotificationTriggerDelta(
       reactivation_, GetTipsNotificationUserType(local_state_));
-  if (!IsFirstRunRecent(set_up_list::SetUpListDurationPastFirstRun() -
+  if (!IsFirstRunRecent(set_up_list_utils::SetUpListDurationPastFirstRun() -
                         trigger_delta)) {
     return false;
   }
diff --git a/ios/chrome/browser/webui/ui_bundled/optimization_guide_internals/optimization_guide_internals_page_egtest.mm b/ios/chrome/browser/webui/ui_bundled/optimization_guide_internals/optimization_guide_internals_page_egtest.mm
index c765e249..dd21eaa 100644
--- a/ios/chrome/browser/webui/ui_bundled/optimization_guide_internals/optimization_guide_internals_page_egtest.mm
+++ b/ios/chrome/browser/webui/ui_bundled/optimization_guide_internals/optimization_guide_internals_page_egtest.mm
@@ -41,9 +41,7 @@
   GURL url = WebUIPageUrlWithHost(
       optimization_guide_internals::kChromeUIOptimizationGuideInternalsHost);
   [ChromeEarlGrey loadURL:url];
-
-  GREYAssert(WaitForOmniboxURLString(url.spec(), false),
-             @"Omnibox did not contain URL.");
+  [ChromeEarlGrey waitForWebStateVisibleURL:url];
 
   // Validates that some of the expected text on the page exists.
   [ChromeEarlGrey waitForWebStateContainingText:"Optimization Guide Internals"];
@@ -54,8 +52,7 @@
   [ChromeEarlGrey openNewTab];
   GURL fooURL = GURL("https://foo");
   [ChromeEarlGrey loadURL:fooURL];
-  GREYAssert(WaitForOmniboxURLString(fooURL.spec(), false),
-             @"Omnibox did not contain URL.");
+  [ChromeEarlGrey waitForWebStateVisibleURL:fooURL];
   // Call `-canApplyOptimization:type:metadata:` for its side-effect of logging
   // to HintsManager. The event logged should then become visible in the WebUI.
   [OptimizationGuideTestAppInterface
diff --git a/ios/chrome/browser/webui/ui_bundled/web_ui_egtest.mm b/ios/chrome/browser/webui/ui_bundled/web_ui_egtest.mm
index dd3dd47..be47522 100644
--- a/ios/chrome/browser/webui/ui_bundled/web_ui_egtest.mm
+++ b/ios/chrome/browser/webui/ui_bundled/web_ui_egtest.mm
@@ -81,8 +81,7 @@
   [ChromeEarlGrey evaluateJavaScriptForSideEffect:clickLinkScript];
 
   // Verify that the resulting page is chrome://terms.
-  GREYAssert(WaitForOmniboxURLString(kChromeUITermsURL),
-             @"Omnibox does not contain URL.");
+  [ChromeEarlGrey waitForWebStateVisibleURL:GURL(kChromeUITermsURL)];
   const std::string kTermsText = "Terms of Service";
   [ChromeEarlGrey waitForWebStateContainingText:kTermsText];
 }
@@ -100,8 +99,7 @@
   [ChromeEarlGrey evaluateJavaScriptForSideEffect:clickLinkScript];
 
   // Verify that the resulting page is chrome://version.
-  GREYAssert(WaitForOmniboxURLString(kChromeUIVersionURL),
-             @"Omnibox did not contain URL.");
+  [ChromeEarlGrey waitForWebStateVisibleURL:GURL(kChromeUIVersionURL)];
   [ChromeEarlGrey
       waitForWebStateContainingText:l10n_util::GetStringUTF8(
                                         IDS_IOS_ABOUT_VERSION_COMPANY_NAME)];
@@ -109,8 +107,7 @@
   // Tap the back button in the toolbar and verify that the resulting page is
   // the previously visited page chrome://chrome-urls.
   [[EarlGrey selectElementWithMatcher:BackButton()] performAction:grey_tap()];
-  GREYAssert(WaitForOmniboxURLString(kChromeUIChromeURLsURL),
-             @"Omnibox did not contain URL.");
+  [ChromeEarlGrey waitForWebStateVisibleURL:GURL(kChromeUIChromeURLsURL)];
   [ChromeEarlGrey waitForWebStateContainingText:"List of Chrome URLs"];
 }
 
@@ -126,29 +123,25 @@
   // Tap the back button in the toolbar and verify that the resulting page's URL
   // corresponds to the first URL chrome://version that was loaded.
   [[EarlGrey selectElementWithMatcher:BackButton()] performAction:grey_tap()];
-  GREYAssert(WaitForOmniboxURLString(kChromeUIVersionURL),
-             @"Omnibox did not contain URL.");
+  [ChromeEarlGrey waitForWebStateVisibleURL:GURL(kChromeUIVersionURL)];
 
   // Tap the forward button in the toolbar and verify that the resulting page's
   // URL corresponds the second URL chrome://chrome-urls that was loaded.
   [[EarlGrey selectElementWithMatcher:ForwardButton()]
       performAction:grey_tap()];
-  GREYAssert(WaitForOmniboxURLString(kChromeUIChromeURLsURL),
-             @"Omnibox did not contain URL.");
+  [ChromeEarlGrey waitForWebStateVisibleURL:GURL(kChromeUIChromeURLsURL)];
 
   // Tap the back button in the toolbar then reload, and verify that the
   // resulting page corresponds to the first URL.
   [[EarlGrey selectElementWithMatcher:BackButton()] performAction:grey_tap()];
   [ChromeEarlGrey waitForPageToFinishLoading];
   [ChromeEarlGrey reload];
-  GREYAssert(WaitForOmniboxURLString(kChromeUIVersionURL),
-             @"Omnibox did not contain URL.");
+  [ChromeEarlGrey waitForWebStateVisibleURL:GURL(kChromeUIVersionURL)];
 
   // Make sure forward navigation is still possible.
   [[EarlGrey selectElementWithMatcher:ForwardButton()]
       performAction:grey_tap()];
-  GREYAssert(WaitForOmniboxURLString(kChromeUIChromeURLsURL),
-             @"Omnibox did not contain URL.");
+  [ChromeEarlGrey waitForWebStateVisibleURL:GURL(kChromeUIChromeURLsURL)];
 }
 
 // Tests that all URLs on chrome://chrome-urls page load without error.
@@ -162,20 +155,18 @@
     GURL URL = WebUIPageUrlWithHost(host);
     [ChromeEarlGrey loadURL:URL];
 
-    GREYAssert(WaitForOmniboxURLString(URL.spec()),
-               @"Omnibox did not contain URL.");
+    [ChromeEarlGrey waitForWebStateVisibleURL:URL];
   }
 }
 
 // Tests that loading an invalid Chrome URL results in an error page.
 - (void)testChromeURLInvalid {
   // Navigate to the native error page chrome://invalidchromeurl.
-  const std::string kChromeInvalidURL = "chrome://invalidchromeurl";
-  [ChromeEarlGrey loadURL:GURL(kChromeInvalidURL)];
+  GURL kChromeInvalidURL = WebUIPageUrlWithHost("invalidchromeurl");
+  [ChromeEarlGrey loadURL:kChromeInvalidURL];
 
   // Verify that the resulting page is an error page.
-  GREYAssert(WaitForOmniboxURLString(kChromeInvalidURL),
-             @"Omnibox did not contain URL.");
+  [ChromeEarlGrey waitForWebStateVisibleURL:kChromeInvalidURL];
   std::string errorMessage = net::ErrorToShortString(net::ERR_INVALID_URL);
   [ChromeEarlGrey waitForWebStateContainingText:errorMessage];
 }
@@ -188,10 +179,9 @@
       l10n_util::GetStringUTF8(IDS_IOS_ABOUT_VERSION_COMPANY_NAME);
   const char kWebPageText[] = "pony";
 
-  [ChromeEarlGrey loadURL:GURL(kChromeUIVersionURL)];
-
-  GREYAssert(WaitForOmniboxURLString(kChromeUIVersionURL),
-             @"Omnibox did not contain URL.");
+  GURL chromeUIVersionGURL = GURL(kChromeUIVersionURL);
+  [ChromeEarlGrey loadURL:chromeUIVersionGURL];
+  [ChromeEarlGrey waitForWebStateVisibleURL:chromeUIVersionGURL];
   [ChromeEarlGrey waitForWebStateContainingText:chromeVersionWebText];
 
   GURL webURL = self.testServer->GetURL("/pony.html");
@@ -199,16 +189,14 @@
   [ChromeEarlGrey waitForWebStateContainingText:kWebPageText];
 
   [ChromeEarlGrey goBack];
-  GREYAssert(WaitForOmniboxURLString(kChromeUIVersionURL),
-             @"Omnibox did not contain URL.");
+  [ChromeEarlGrey waitForWebStateVisibleURL:chromeUIVersionGURL];
   [ChromeEarlGrey waitForWebStateContainingText:chromeVersionWebText];
 
   [ChromeEarlGrey goForward];
   [ChromeEarlGrey waitForWebStateContainingText:kWebPageText];
 
   [ChromeEarlGrey goBack];
-  GREYAssert(WaitForOmniboxURLString(kChromeUIVersionURL),
-             @"Omnibox did not contain URL.");
+  [ChromeEarlGrey waitForWebStateVisibleURL:chromeUIVersionGURL];
   [ChromeEarlGrey waitForWebStateContainingText:chromeVersionWebText];
 }
 
@@ -216,8 +204,7 @@
   // Start with NTP and load chrome://flags.
   [ChromeEarlGrey loadURL:GURL(kChromeUIFlagsURL)];
 
-  GREYAssert(WaitForOmniboxURLString(kChromeUIFlagsURL),
-             @"Omnibox did not contain URL.");
+  [ChromeEarlGrey waitForWebStateVisibleURL:GURL(kChromeUIFlagsURL)];
 
   // Validates that some of the expected text on the page exists.
   [ChromeEarlGrey waitForWebStateContainingText:"Experiments"];
@@ -252,8 +239,7 @@
   // Then load chrome://flags in the same tab that has loaded a website.
   [ChromeEarlGrey loadURL:WebUIPageUrlWithHost(kChromeUIFlagsHost)];
 
-  GREYAssert(WaitForOmniboxURLString(kChromeUIFlagsURL),
-             @"Omnibox did not contain URL.");
+  [ChromeEarlGrey waitForWebStateVisibleURL:GURL(kChromeUIFlagsURL)];
 
   // Validates that some of the expected text on the page exists.
   [ChromeEarlGrey waitForWebStateContainingText:"Experiments"];
@@ -279,8 +265,7 @@
   GURL URL = WebUIPageUrlWithHost(kChromeUIPasswordManagerInternalsHost);
   [ChromeEarlGrey loadURL:URL];
 
-  GREYAssert(WaitForOmniboxURLString(URL.spec()),
-             @"Omnibox did not contain URL.");
+  [ChromeEarlGrey waitForWebStateVisibleURL:URL];
 
   // Validates that some of the expected text on the page exists.
   [ChromeEarlGrey waitForWebStateContainingText:"Variations"];
@@ -293,8 +278,7 @@
 
   // Autofill-Internals stores the log filter configuration in the URL's
   // fragment identifier (after the hash).
-  GREYAssert(WaitForOmniboxURLString(URL.spec(), false),
-             @"Omnibox did not contain URL.");
+  [ChromeEarlGrey waitForWebStateVisibleURL:URL];
 
   // Validates that some of the expected text on the page exists.
   [ChromeEarlGrey waitForWebStateContainingText:"Variations"];
@@ -314,8 +298,7 @@
 
   // Autofill-Internals stores the log filter configuration in the URL's
   // fragment identifier (after the hash).
-  GREYAssert(WaitForOmniboxURLString(URL.spec()),
-             @"Omnibox did not contain URL");
+  [ChromeEarlGrey waitForWebStateVisibleURL:URL];
 
   // Validates that some of the expected text on the page exists.
   [ChromeEarlGrey waitForWebStateContainingText:"List of user defaults:"];
@@ -335,8 +318,7 @@
 
   // Autofill-Internals stores the log filter configuration in the URL's
   // fragment identifier (after the hash).
-  GREYAssert(WaitForOmniboxURLString(URL.spec()),
-             @"Omnibox did not contain URL");
+  [ChromeEarlGrey waitForWebStateVisibleURL:URL];
 
   // Validates that some of the expected text on the page exists.
   [ChromeEarlGrey waitForWebStateContainingText:
diff --git a/ios/chrome/browser/webui/ui_bundled/web_ui_test_utils.h b/ios/chrome/browser/webui/ui_bundled/web_ui_test_utils.h
index abc610d..d127c2b 100644
--- a/ios/chrome/browser/webui/ui_bundled/web_ui_test_utils.h
+++ b/ios/chrome/browser/webui/ui_bundled/web_ui_test_utils.h
@@ -15,9 +15,4 @@
 // invalid URL.
 GURL WebUIPageUrlWithHost(std::string_view host);
 
-// Waits for omnibox text to equal (if `exact_match`) or contain (else) `URL`
-// and returns true if it was found or false on timeout. Strips trailing URL
-// slash if present as the omnibox does not display them.
-bool WaitForOmniboxURLString(std::string_view url, bool exact_match = true);
-
 #endif  // IOS_CHROME_BROWSER_WEBUI_UI_BUNDLED_WEB_UI_TEST_UTILS_H_
diff --git a/ios/chrome/browser/webui/ui_bundled/web_ui_test_utils.mm b/ios/chrome/browser/webui/ui_bundled/web_ui_test_utils.mm
index 48943c0..913756591 100644
--- a/ios/chrome/browser/webui/ui_bundled/web_ui_test_utils.mm
+++ b/ios/chrome/browser/webui/ui_bundled/web_ui_test_utils.mm
@@ -7,45 +7,19 @@
 #import "base/strings/strcat.h"
 #import "base/strings/string_util.h"
 #import "base/strings/stringprintf.h"
-#import "base/test/ios/wait_util.h"
-#import "ios/chrome/test/earl_grey/chrome_matchers.h"
 #import "ios/components/webui/web_ui_url_constants.h"
-#import "ios/testing/earl_grey/earl_grey_test.h"
 #import "url/gurl.h"
 
 using base::TrimPositions;
-using chrome_test_util::OmniboxContainingText;
-using chrome_test_util::OmniboxText;
 
 // Returns the url to the web ui page `host`. `url::SchemeHostPort` can not be
 // used when this test is run using EarlGrey2 because the chrome scheme is not
 // registered in the test process and `url::SchemeHostPort` will not build an
 // invalid URL.
 GURL WebUIPageUrlWithHost(std::string_view host) {
-  return GURL(base::StrCat({kChromeUIScheme, "://", host}));
-}
-
-// Waits for omnibox text to equal (if `exact_match`) or contain (else) `URL`
-// and returns true if it was found or false on timeout. Strips trailing URL
-// slash if present as the omnibox does not display them.
-bool WaitForOmniboxURLString(std::string_view url, bool exact_match) {
-  const std::string trimmed_URL(
-      base::TrimString(url, "/", TrimPositions::TRIM_TRAILING));
-
-  // TODO(crbug.com/41272687): Unify with the omniboxText matcher or move to the
-  // same location with the omniboxText matcher.
-  return base::test::ios::WaitUntilConditionOrTimeout(
-      base::test::ios::kWaitForUIElementTimeout, ^{
-        NSError* error = nil;
-        if (exact_match) {
-          [[EarlGrey selectElementWithMatcher:OmniboxText(trimmed_URL)]
-              assertWithMatcher:grey_notNil()
-                          error:&error];
-        } else {
-          [[EarlGrey selectElementWithMatcher:chrome_test_util::Omnibox()]
-              assertWithMatcher:OmniboxContainingText(trimmed_URL)
-                          error:&error];
-        }
-        return error == nil;
-      });
+  // Make sure the host doesn't have a trailing slash, as it is added
+  // explicitly.
+  const std::string trimmed_host(
+      base::TrimString(host, "/", TrimPositions::TRIM_TRAILING));
+  return GURL(base::StrCat({kChromeUIScheme, "://", host, "/"}));
 }
diff --git a/ios/chrome/credential_provider_extension/credential_provider_extension_localize_strings_config.plist b/ios/chrome/credential_provider_extension/credential_provider_extension_localize_strings_config.plist
index bf8e12d6..395e4fe9 100644
--- a/ios/chrome/credential_provider_extension/credential_provider_extension_localize_strings_config.plist
+++ b/ios/chrome/credential_provider_extension/credential_provider_extension_localize_strings_config.plist
@@ -94,8 +94,6 @@
 				<string>IDS_IOS_CREDENTIAL_PROVIDER_BRANDED_TITLE</string>
 				<string>IDS_IOS_CREDENTIAL_PROVIDER_PASSKEY_ERROR_ALERT_BUTTON_TITLE</string>
 				<string>IDS_IOS_CREDENTIAL_PROVIDER_PASSKEY_CREATION_USER_DISABLED_TITLE</string>
-				<string>IDS_IOS_CREDENTIAL_PROVIDER_PASSKEY_CREATION_USER_DISABLED_IN_PASSWORD_SETTINGS_SUBTITLE</string>
-				<string>IDS_IOS_CREDENTIAL_PROVIDER_PASSKEY_CREATION_USER_DISABLED_FOR_ACCOUNT_SUBTITLE</string>
 			</array>
 		</dict>
 	</array>
diff --git a/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings.grd b/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings.grd
index 208eb6d0..2c97b17 100644
--- a/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings.grd
+++ b/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings.grd
@@ -354,12 +354,6 @@
       <message name="IDS_IOS_CREDENTIAL_PROVIDER_PASSKEY_CREATION_ENTERPRISE_DISABLED_TITLE" desc="Title for the screen informing the user that passkey creation is disabled by an enterprise policy.">
         Passkeys are turned off by your organization
       </message>
-      <message name="IDS_IOS_CREDENTIAL_PROVIDER_PASSKEY_CREATION_USER_DISABLED_FOR_ACCOUNT_SUBTITLE" desc="Subtitle for the screen informing the user that they can enable passkey creation by turning on the 'Passwords' toggle in their Google Account Settings.">
-        Open Chrome settings, choose your account, and turn on Passwords
-      </message>
-      <message name="IDS_IOS_CREDENTIAL_PROVIDER_PASSKEY_CREATION_USER_DISABLED_IN_PASSWORD_SETTINGS_SUBTITLE" desc="Subtitle for the screen informing the user that they can enable passkey creation by turning on the 'Offer to save passwords' toggle in Password Settings.">
-        Open Chrome settings &gt; Password Manager &gt; Settings and turn on Offer to save passwords
-      </message>
       <message name="IDS_IOS_CREDENTIAL_PROVIDER_PASSKEY_CREATION_USER_DISABLED_TITLE" desc="Title of the screen informing the user of the steps they need to take to enable passkey creation.">
         To create passkeys
       </message>
diff --git a/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings_grd/IDS_IOS_CREDENTIAL_PROVIDER_PASSKEY_CREATION_USER_DISABLED_FOR_ACCOUNT_SUBTITLE.png.sha1 b/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings_grd/IDS_IOS_CREDENTIAL_PROVIDER_PASSKEY_CREATION_USER_DISABLED_FOR_ACCOUNT_SUBTITLE.png.sha1
deleted file mode 100644
index dab9ae0..0000000
--- a/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings_grd/IDS_IOS_CREDENTIAL_PROVIDER_PASSKEY_CREATION_USER_DISABLED_FOR_ACCOUNT_SUBTITLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-53c35531402428c50de701a75a96f5c1af818dbe
\ No newline at end of file
diff --git a/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings_grd/IDS_IOS_CREDENTIAL_PROVIDER_PASSKEY_CREATION_USER_DISABLED_IN_PASSWORD_SETTINGS_SUBTITLE.png.sha1 b/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings_grd/IDS_IOS_CREDENTIAL_PROVIDER_PASSKEY_CREATION_USER_DISABLED_IN_PASSWORD_SETTINGS_SUBTITLE.png.sha1
deleted file mode 100644
index f823ad6..0000000
--- a/ios/chrome/credential_provider_extension/strings/ios_credential_provider_extension_strings_grd/IDS_IOS_CREDENTIAL_PROVIDER_PASSKEY_CREATION_USER_DISABLED_IN_PASSWORD_SETTINGS_SUBTITLE.png.sha1
+++ /dev/null
@@ -1 +0,0 @@
-7d2f00ac4f046bcba02b80277c41fb20a9f286e4
\ No newline at end of file
diff --git a/ios/third_party/earl_grey2/src b/ios/third_party/earl_grey2/src
index d67ae75..df685be 160000
--- a/ios/third_party/earl_grey2/src
+++ b/ios/third_party/earl_grey2/src
@@ -1 +1 @@
-Subproject commit d67ae75220c564eff015db2ac35c7e31cdd8159c
+Subproject commit df685be0513ad0849abdf91e2eb5435eb29fb649
diff --git a/ios_internal b/ios_internal
index 37a0c1f..5cfcae4 160000
--- a/ios_internal
+++ b/ios_internal
@@ -1 +1 @@
-Subproject commit 37a0c1f41e948f23b572d150e5dba5927d68ce17
+Subproject commit 5cfcae409eb3a15e16dea856a258b3cabe9e39c9
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn
index 795e2db..4fb4b17 100644
--- a/media/base/BUILD.gn
+++ b/media/base/BUILD.gn
@@ -19,7 +19,10 @@
   # is a roll-up target which is part of the //media component. Most other DEPs
   # should be using //media and not directly DEP this roll-up target.
   visibility = media_subcomponent_deps
-  visibility += [ "//media" ]
+  visibility += [
+    "//media",
+    "//media/capture/video/android",
+  ]
 
   if (!enable_library_cdms) {
     # cdm_type_conversion is not part of media_subcomponent_deps.
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index a91baa3..74633d0 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -1023,6 +1023,9 @@
 // NdkVideoEncodeAccelerator on Android.
 BASE_FEATURE(kSurfaceInputForAndroidVEA, base::FEATURE_DISABLED_BY_DEFAULT);
 
+// Enables zero-copy video capture on Android.
+BASE_FEATURE(kAndroidZeroCopyVideoCapture, base::FEATURE_DISABLED_BY_DEFAULT);
+
 // Enables block model (LinearBlock) on supported devices.
 // TODO(crbug.com/327625558): Currently block model is buggy and can't be
 // enabled, we need to test it again when Android 17 is released.
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index 4e66e47..f92dc56 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -350,6 +350,7 @@
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kEnableAudioMonitoringOnAndroid);
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kContextMenuPictureInPictureAndroid);
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kSurfaceInputForAndroidVEA);
+MEDIA_EXPORT BASE_DECLARE_FEATURE(kAndroidZeroCopyVideoCapture);
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kMediaCodecBlockModel);
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kMediaCodecLowDelayMode);
 MEDIA_EXPORT BASE_DECLARE_FEATURE(kMediaControlsExpandGesture);
diff --git a/media/capture/video/android/BUILD.gn b/media/capture/video/android/BUILD.gn
index 61f5ce6..3c140e6 100644
--- a/media/capture/video/android/BUILD.gn
+++ b/media/capture/video/android/BUILD.gn
@@ -25,7 +25,9 @@
   configs += [ "//media:media_config" ]
   deps = [
     ":capture_jni_headers",
+    "//media/base",
     "//media/capture:capture_device_specific",
+    "//media/capture:capture_gpu_channel",
     "//media/capture/mojom:image_capture",
     "//media/capture/mojom:image_capture_types",
     "//third_party/libyuv",
diff --git a/media/capture/video/android/java/src/org/chromium/media/VideoCapture.java b/media/capture/video/android/java/src/org/chromium/media/VideoCapture.java
index fbd42d7..24768ec6 100644
--- a/media/capture/video/android/java/src/org/chromium/media/VideoCapture.java
+++ b/media/capture/video/android/java/src/org/chromium/media/VideoCapture.java
@@ -8,6 +8,7 @@
 
 import android.content.Context;
 import android.graphics.ImageFormat;
+import android.hardware.HardwareBuffer;
 import android.hardware.display.DisplayManager;
 import android.view.Display;
 import android.view.Surface;
@@ -71,7 +72,11 @@
     // Allocate necessary resources for capture.
     @CalledByNative
     public abstract boolean allocate(
-            int width, int height, int frameRate, boolean enableFaceDetection);
+            int width,
+            int height,
+            int frameRate,
+            boolean enableFaceDetection,
+            boolean useHardwareBuffers);
 
     // Success is indicated by returning true and a callback to
     // VideoCaptureJni.get().onStarted(,  VideoCapture.this), which may occur synchronously or
@@ -333,6 +338,20 @@
         }
     }
 
+    protected void onHardwareBufferAvailable(
+            HardwareBuffer hardwareBuffer, int rotation, long timestamp) {
+        synchronized (mNativeVideoCaptureLock) {
+            if (mNativeVideoCaptureDeviceAndroid != 0) {
+                VideoCaptureJni.get()
+                        .onHardwareBufferAvailable(
+                                mNativeVideoCaptureDeviceAndroid,
+                                hardwareBuffer,
+                                rotation,
+                                timestamp);
+            }
+        }
+    }
+
     protected void onError(int androidVideoCaptureError, String message) {
         synchronized (mNativeVideoCaptureLock) {
             if (mNativeVideoCaptureDeviceAndroid != 0) {
@@ -413,6 +432,12 @@
                 int rotation,
                 long timestamp);
 
+        void onHardwareBufferAvailable(
+                long nativeVideoCaptureDeviceAndroid,
+                HardwareBuffer hardwareBuffer,
+                int rotation,
+                long timestamp);
+
         // Method for VideoCapture implementations to signal an asynchronous error.
         void onError(
                 long nativeVideoCaptureDeviceAndroid, int androidVideoCaptureError, String message);
diff --git a/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java b/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java
index 9ee77d94..705c45c9 100644
--- a/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java
+++ b/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java
@@ -7,6 +7,7 @@
 import android.content.Context;
 import android.graphics.ImageFormat;
 import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CameraCaptureSession;
 import android.hardware.camera2.CameraCharacteristics;
@@ -138,10 +139,12 @@
                                     TotalCaptureResult result) {
                                 // Since |result| is not guaranteed to contain a value for
                                 // key |SENSOR_EXPOSURE_TIME| we have to check for null.
-                                Long exposure_time_value =
+                                Long exposureTimeValue =
                                         result.get(CaptureResult.SENSOR_EXPOSURE_TIME);
-                                if (exposure_time_value == null) return;
-                                mLastExposureTimeNs = exposure_time_value;
+                                if (exposureTimeValue == null) {
+                                    return;
+                                }
+                                mLastExposureTimeNs = exposureTimeValue;
                             }
                         },
                         null);
@@ -185,10 +188,9 @@
             mPreviewSession = null;
         }
     }
-    ;
 
     // Internal class implementing an ImageReader listener for Preview frames. Gets pinged when a
-    // new frame is been captured and downloads it to memory-backed buffers.
+    // new frame is been captured and downloads it to a HardwareBuffer or memory-backed buffers.
     private class CrPreviewReaderListener implements ImageReader.OnImageAvailableListener {
         @Override
         public void onImageAvailable(ImageReader reader) {
@@ -202,17 +204,6 @@
                     return;
                 }
 
-                if (image.getFormat() != ImageFormat.YUV_420_888 || image.getPlanes().length != 3) {
-                    onError(
-                            AndroidVideoCaptureError
-                                    .ANDROID_API_2_IMAGE_READER_UNEXPECTED_IMAGE_FORMAT,
-                            "Unexpected image format: "
-                                    + image.getFormat()
-                                    + " or #planes: "
-                                    + image.getPlanes().length);
-                    throw new IllegalStateException();
-                }
-
                 if (reader.getWidth() != image.getWidth()
                         || reader.getHeight() != image.getHeight()) {
                     onError(
@@ -230,17 +221,43 @@
                     throw new IllegalStateException();
                 }
 
-                onI420FrameAvailable(
-                        image.getPlanes()[0].getBuffer(),
-                        image.getPlanes()[0].getRowStride(),
-                        image.getPlanes()[1].getBuffer(),
-                        image.getPlanes()[2].getBuffer(),
-                        image.getPlanes()[1].getRowStride(),
-                        image.getPlanes()[1].getPixelStride(),
-                        image.getWidth(),
-                        image.getHeight(),
-                        getCameraRotation(),
-                        image.getTimestamp());
+                if (mUseHardwareBuffers) {
+                    try (HardwareBuffer hardwareBuffer = image.getHardwareBuffer()) {
+                        if (hardwareBuffer == null) {
+                            onError(
+                                    AndroidVideoCaptureError
+                                            .ANDROID_API_2_IMAGE_READER_UNEXPECTED_IMAGE_FORMAT,
+                                    "Hardware buffer is null");
+                            return;
+                        }
+                        onHardwareBufferAvailable(
+                                hardwareBuffer, getCameraRotation(), image.getTimestamp());
+                    }
+                } else {
+                    if (image.getFormat() != ImageFormat.YUV_420_888
+                            || image.getPlanes().length != 3) {
+                        onError(
+                                AndroidVideoCaptureError
+                                        .ANDROID_API_2_IMAGE_READER_UNEXPECTED_IMAGE_FORMAT,
+                                "Unexpected image format: "
+                                        + image.getFormat()
+                                        + " or #planes: "
+                                        + image.getPlanes().length);
+                        throw new IllegalStateException();
+                    }
+
+                    onI420FrameAvailable(
+                            image.getPlanes()[0].getBuffer(),
+                            image.getPlanes()[0].getRowStride(),
+                            image.getPlanes()[1].getBuffer(),
+                            image.getPlanes()[2].getBuffer(),
+                            image.getPlanes()[1].getRowStride(),
+                            image.getPlanes()[1].getPixelStride(),
+                            image.getWidth(),
+                            image.getHeight(),
+                            getCameraRotation(),
+                            image.getTimestamp());
+                }
             } catch (IllegalStateException ex) {
                 Log.e(TAG, "acquireLatestImage():", ex);
             }
@@ -392,11 +409,11 @@
             }
             int minIso = 0;
             int maxIso = 0;
-            final Range<Integer> iso_range =
+            final Range<Integer> isoRange =
                     cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE);
-            if (iso_range != null) {
-                minIso = iso_range.getLower();
-                maxIso = iso_range.getUpper();
+            if (isoRange != null) {
+                minIso = isoRange.getLower();
+                maxIso = isoRange.getUpper();
             }
             builder.setInt(PhotoCapabilityInt.MIN_ISO, minIso)
                     .setInt(PhotoCapabilityInt.MAX_ISO, maxIso)
@@ -517,11 +534,11 @@
                     focusModes.add(Integer.valueOf(AndroidMeteringMode.FIXED));
                     // Smallest step by which focus distance can be changed. This value is not
                     // exposed by Android.
-                    float mStepFocusDistance = 0.01f;
+                    float stepFocusDistance = 0.01f;
                     builder.setDouble(PhotoCapabilityDouble.MIN_FOCUS_DISTANCE, minFocusDistance)
                             .setDouble(PhotoCapabilityDouble.MAX_FOCUS_DISTANCE, maxFocusDistance)
                             .setDouble(
-                                    PhotoCapabilityDouble.STEP_FOCUS_DISTANCE, mStepFocusDistance);
+                                    PhotoCapabilityDouble.STEP_FOCUS_DISTANCE, stepFocusDistance);
                 } else if (mode == CameraMetadata.CONTROL_AF_MODE_AUTO
                         || mode == CameraMetadata.CONTROL_AF_MODE_MACRO) {
                     // CONTROL_AF_MODE_{AUTO,MACRO} do not imply continuously focusing.
@@ -614,9 +631,9 @@
                 }
             }
             try {
-                Boolean ae_lock_available =
+                Boolean aeLockAvailable =
                         cameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE);
-                if (ae_lock_available != null && ae_lock_available.booleanValue()) {
+                if (aeLockAvailable != null && aeLockAvailable.booleanValue()) {
                     exposureModes.add(Integer.valueOf(AndroidMeteringMode.FIXED));
                 }
             } catch (NoSuchFieldError e) {
@@ -667,9 +684,9 @@
                 }
             }
             try {
-                Boolean awb_lock_available =
+                Boolean awbLockAvailable =
                         cameraCharacteristics.get(CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE);
-                if (awb_lock_available != null && awb_lock_available.booleanValue()) {
+                if (awbLockAvailable != null && awbLockAvailable.booleanValue()) {
                     whiteBalanceModes.add(Integer.valueOf(AndroidMeteringMode.FIXED));
                 }
             } catch (NoSuchFieldError e) {
@@ -1128,6 +1145,7 @@
     private int mFillLightMode = AndroidFillLightMode.OFF;
     private boolean mTorch;
     private boolean mEnableFaceDetection;
+    private boolean mUseHardwareBuffers;
 
     // Service function to grab CameraCharacteristics and handle exceptions.
     private static @Nullable CameraCharacteristics getCameraCharacteristics(int id) {
@@ -1136,8 +1154,8 @@
                         ContextUtils.getApplicationContext()
                                 .getSystemService(Context.CAMERA_SERVICE);
         try {
-            final String str_id = String.valueOf(id);
-            return manager.getCameraCharacteristics(str_id);
+            final String strId = String.valueOf(id);
+            return manager.getCameraCharacteristics(strId);
         } catch (CameraAccessException
                 | IllegalArgumentException
                 | AssertionError
@@ -1161,16 +1179,28 @@
         assert mCameraThreadHandler.getLooper() == Looper.myLooper() : "called on wrong thread";
         if (mCameraDevice == null) return false;
 
-        try (TraceEvent trace_event =
+        try (TraceEvent traceEvent =
                 TraceEvent.scoped("VideoCaptureCamera2.createPreviewObjectsAndStartPreview")) {
             // Create an ImageReader and plug a thread looper into it to have
             // readback take place on its own thread.
-            mImageReader =
-                    ImageReader.newInstance(
-                            mCaptureFormat.getWidth(),
-                            mCaptureFormat.getHeight(),
-                            mCaptureFormat.getPixelFormat(),
-                            /* maxImages= */ 2);
+            if (mUseHardwareBuffers) {
+                mImageReader =
+                        ImageReader.newInstance(
+                                mCaptureFormat.getWidth(),
+                                mCaptureFormat.getHeight(),
+                                mCaptureFormat.getPixelFormat(),
+                                /* maxImages= */ 2,
+                                HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE
+                                        | HardwareBuffer.USAGE_VIDEO_ENCODE
+                                        | HardwareBuffer.USAGE_CPU_READ_RARELY);
+            } else {
+                mImageReader =
+                        ImageReader.newInstance(
+                                mCaptureFormat.getWidth(),
+                                mCaptureFormat.getHeight(),
+                                mCaptureFormat.getPixelFormat(),
+                                /* maxImages= */ 2);
+            }
             final CrPreviewReaderListener imageReaderListener = new CrPreviewReaderListener();
             mImageReader.setOnImageAvailableListener(imageReaderListener, mCameraThreadHandler);
 
@@ -1247,7 +1277,7 @@
 
     private void configureCommonCaptureSettings(CaptureRequest.Builder requestBuilder) {
         assert mCameraThreadHandler.getLooper() == Looper.myLooper() : "called on wrong thread";
-        try (TraceEvent trace_event =
+        try (TraceEvent traceEvent =
                 TraceEvent.scoped("VideoCaptureCamera2.configureCommonCaptureSettings")) {
             final CameraCharacteristics cameraCharacteristics = getCameraCharacteristics(mId);
 
@@ -1713,7 +1743,12 @@
     }
 
     @Override
-    public boolean allocate(int width, int height, int frameRate, boolean enableFaceDetection) {
+    public boolean allocate(
+            int width,
+            int height,
+            int frameRate,
+            boolean enableFaceDetection,
+            boolean useHardwareBuffers) {
         Log.d(TAG, "allocate: requested (%d x %d) @%dfps", width, height, frameRate);
         dCheckCurrentlyOnIncomingTaskRunner();
         synchronized (mCameraStateLock) {
@@ -1784,6 +1819,7 @@
                         == CameraCharacteristics.LENS_FACING_BACK;
 
         mEnableFaceDetection = enableFaceDetection;
+        mUseHardwareBuffers = useHardwareBuffers;
         return true;
     }
 
@@ -1820,7 +1856,7 @@
     @Override
     public boolean stopCaptureAndBlockUntilStopped() {
         dCheckCurrentlyOnIncomingTaskRunner();
-        try (TraceEvent trace_event =
+        try (TraceEvent traceEvent =
                 TraceEvent.scoped("VideoCaptureCamera2.stopCaptureAndBlockUntilStopped")) {
             // With Camera2 API, the capture is started asynchronously, which will cause problem if
             // stopCapture comes too quickly. Without stopping the previous capture properly, the
diff --git a/media/capture/video/android/video_capture_device_android.cc b/media/capture/video/android/video_capture_device_android.cc
index 1fb5886..91e334e 100644
--- a/media/capture/video/android/video_capture_device_android.cc
+++ b/media/capture/video/android/video_capture_device_android.cc
@@ -4,6 +4,8 @@
 
 #include "media/capture/video/android/video_capture_device_android.h"
 
+#include <android/hardware_buffer.h>
+#include <android/hardware_buffer_jni.h>
 #include <stdint.h>
 
 #include <algorithm>
@@ -12,6 +14,7 @@
 #include "base/android/jni_android.h"
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
+#include "base/android/scoped_hardware_buffer_handle.h"
 #include "base/containers/heap_array.h"
 #include "base/functional/bind.h"
 #include "base/numerics/safe_conversions.h"
@@ -19,11 +22,15 @@
 #include "base/system/system_monitor.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/trace_event/trace_event.h"
+#include "media/base/media_switches.h"
 #include "media/capture/mojom/image_capture_types.h"
 #include "media/capture/video/android/photo_capabilities.h"
 #include "media/capture/video/android/video_capture_device_factory_android.h"
+#include "media/capture/video/video_capture_gpu_channel_host.h"
 #include "third_party/libyuv/include/libyuv.h"
+#include "ui/gfx/color_space.h"
 #include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/size.h"
 
 // Must come after all headers that specialize FromJniType() / ToJniType().
 #include "media/capture/video/android/capture_jni_headers/VideoCapture_jni.h"
@@ -143,12 +150,15 @@
     got_first_frame_ = false;
   }
 
-  JNIEnv* env = AttachCurrentThread();
+  bool enable_hardware_buffer_capture =
+      base::FeatureList::IsEnabled(media::kAndroidZeroCopyVideoCapture);
 
+  JNIEnv* env = AttachCurrentThread();
   jboolean ret = Java_VideoCapture_allocate(
       env, j_capture_, params.requested_format.frame_size.width(),
       params.requested_format.frame_size.height(),
-      params.requested_format.frame_rate, params.enable_face_detection);
+      params.requested_format.frame_rate, params.enable_face_detection,
+      enable_hardware_buffer_capture);
   if (!ret) {
     SetErrorState(media::VideoCaptureError::kAndroidFailedToAllocate, FROM_HERE,
                   "failed to allocate");
@@ -333,9 +343,7 @@
     jlong timestamp) {
   if (!IsClientConfigured())
     return;
-  const int64_t absolute_micro =
-      timestamp / base::Time::kNanosecondsPerMicrosecond;
-  const base::TimeDelta capture_time = base::Microseconds(absolute_micro);
+  const base::TimeDelta capture_time = base::Nanoseconds(timestamp);
 
   const base::TimeTicks current_time = base::TimeTicks::Now();
   ProcessFirstFrameAvailable(current_time);
@@ -376,6 +384,116 @@
                            capture_time);
 }
 
+void VideoCaptureDeviceAndroid::OnHardwareBufferAvailableOnMainThread(
+    base::android::ScopedHardwareBufferHandle ahb_handle,
+    jint rotation,
+    jlong timestamp) {
+  DCHECK(main_task_runner_->BelongsToCurrentThread());
+
+  const base::TimeTicks current_time = base::TimeTicks::Now();
+  ProcessFirstFrameAvailable(current_time);
+
+  // Deliver the frame when it doesn't arrive too early.
+  if (ThrottleFrame(current_time)) {
+    client_->OnFrameDropped(VideoCaptureFrameDropReason::kAndroidThrottling);
+    return;
+  }
+
+  AHardwareBuffer_Desc desc;
+  AHardwareBuffer_describe(ahb_handle.get(), &desc);
+
+  VideoPixelFormat video_pixel_format;
+  viz::SharedImageFormat shared_image_format;
+  switch (desc.format) {
+    case AndroidImageFormat::ANDROID_IMAGE_FORMAT_YUV_420_888:
+      video_pixel_format = PIXEL_FORMAT_I420;
+      shared_image_format = viz::MultiPlaneFormat::kYV12;
+      break;
+    case AndroidImageFormat::ANDROID_IMAGE_FORMAT_YV12:
+      video_pixel_format = PIXEL_FORMAT_NV12;
+      shared_image_format = viz::MultiPlaneFormat::kNV12;
+      break;
+    default:
+      LOG(ERROR) << "Unsupported AHardwareBuffer format: " << desc.format;
+      return;
+  }
+
+  // TODO(crbug.com/467351937): Determine the correct color space.
+  gfx::ColorSpace color_space = gfx::ColorSpace::CreateREC601();
+  VideoCaptureFormat format(gfx::Size(desc.width, desc.height),
+                            capture_format_.frame_rate, video_pixel_format);
+
+  auto sii =
+      VideoCaptureGpuChannelHost::GetInstance().GetSharedImageInterface();
+  if (!sii) {
+    LOG(ERROR) << "Failed to get SharedImageInterface.";
+    SetErrorState(media::VideoCaptureError::kAndroidFailedToStartCapture,
+                  FROM_HERE, "Failed to get SharedImageInterface.");
+    return;
+  }
+
+  gfx::GpuMemoryBufferHandle gmb_handle;
+  gmb_handle.type = gfx::ANDROID_HARDWARE_BUFFER;
+  gmb_handle.android_hardware_buffer = ahb_handle.Clone();
+
+  constexpr auto kSharedImageUsage = gpu::SHARED_IMAGE_USAGE_GLES2_READ |
+                                     gpu::SHARED_IMAGE_USAGE_DISPLAY_READ |
+                                     gpu::SHARED_IMAGE_USAGE_RASTER_READ;
+  auto shared_image = sii->CreateSharedImage(
+      {shared_image_format, gfx::Size(desc.width, desc.height), color_space,
+       kSharedImageUsage, "AndroidCaptureDevice"},
+      std::move(gmb_handle));
+
+  if (!shared_image) {
+    DLOG(ERROR) << "Failed to create a shared image.";
+    SetErrorState(media::VideoCaptureError::kAndroidFailedToStartCapture,
+                  FROM_HERE, "Failed to create a shared image.");
+    return;
+  }
+
+  const base::TimeDelta capture_time = base::Nanoseconds(timestamp);
+  base::AutoLock lock(lock_);
+  if (!client_) {
+    return;
+  }
+
+  client_->OnIncomingCapturedImage(std::move(shared_image), format, 0,
+                                   base::TimeTicks(), capture_time,
+                                   /*capture_begin_timestamp=*/{},
+                                   /*metadata=*/{});
+}
+
+void VideoCaptureDeviceAndroid::OnHardwareBufferAvailable(
+    JNIEnv* env,
+    const base::android::JavaRef<jobject>& hardware_buffer,
+    jint rotation,
+    jlong timestamp) {
+  if (!IsClientConfigured()) {
+    return;
+  }
+
+  auto ahb_handle = base::android::ScopedHardwareBufferHandle::Create(
+      AHardwareBuffer_fromHardwareBuffer(env, hardware_buffer.obj()));
+
+  if (!ahb_handle.is_valid()) {
+    SetErrorState(media::VideoCaptureError::kAndroidFailedToStartCapture,
+                  FROM_HERE, "Failed to get AHardwareBuffer from Java");
+    return;
+  }
+
+  if (!main_task_runner_->BelongsToCurrentThread()) {
+    main_task_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            &VideoCaptureDeviceAndroid::OnHardwareBufferAvailableOnMainThread,
+            weak_ptr_factory_.GetWeakPtr(), std::move(ahb_handle), rotation,
+            timestamp));
+    return;
+  }
+  OnHardwareBufferAvailableOnMainThread(std::move(ahb_handle), rotation,
+                                        timestamp);
+}
+
 void VideoCaptureDeviceAndroid::OnError(
     JNIEnv* env,
     int android_video_capture_error,
diff --git a/media/capture/video/android/video_capture_device_android.h b/media/capture/video/android/video_capture_device_android.h
index acc27dab..20c8850 100644
--- a/media/capture/video/android/video_capture_device_android.h
+++ b/media/capture/video/android/video_capture_device_android.h
@@ -97,13 +97,18 @@
                        SetPhotoOptionsCallback callback) override;
   void TakePhoto(TakePhotoCallback callback) override;
 
-  // Implement org.chromium.media.VideoCapture.nativeOnFrameAvailable.
+  void OnHardwareBufferAvailableOnMainThread(
+      base::android::ScopedHardwareBufferHandle ahb_handle,
+      jint rotation,
+      jlong timestamp);
+
+  // Implement org.chromium.media.VideoCapture.Natives.OnFrameAvailable.
   void OnFrameAvailable(JNIEnv* env,
                         const base::android::JavaRef<jbyteArray>& data,
                         jint length,
                         jint rotation);
 
-  // Implement org.chromium.media.VideoCapture.nativeOnI420FrameAvailable.
+  // Implement org.chromium.media.VideoCapture.Natives.OnI420FrameAvailable.
   void OnI420FrameAvailable(JNIEnv* env,
                             const base::android::JavaRef<jobject>& y_buffer,
                             jint y_stride,
@@ -116,7 +121,15 @@
                             jint rotation,
                             jlong timestamp);
 
-  // Implement org.chromium.media.VideoCapture.nativeOnError.
+  // Implement
+  // org.chromium.media.VideoCapture.Natives.onHardwareBufferAvailable.
+  void OnHardwareBufferAvailable(
+      JNIEnv* env,
+      const base::android::JavaRef<jobject>& hardwareBuffer,
+      jint rotation,
+      jlong timestamp);
+
+  // Implement org.chromium.media.VideoCapture.Natives.OnError.
   void OnError(JNIEnv* env,
                int android_video_capture_error,
                const base::android::JavaRef<jstring>& message);
diff --git a/sandbox/win/BUILD.gn b/sandbox/win/BUILD.gn
index 3ac44da..8a91953 100644
--- a/sandbox/win/BUILD.gn
+++ b/sandbox/win/BUILD.gn
@@ -289,7 +289,6 @@
     "src/restricted_token_unittest.cc",
     "src/sandbox_nt_util_unittest.cc",
     "src/service_resolver_unittest.cc",
-    "src/target_process_unittest.cc",
     "src/threadpool_unittest.cc",
     "src/win_utils_unittest.cc",
     "tests/common/test_utils.cc",
diff --git a/sandbox/win/src/target_process.cc b/sandbox/win/src/target_process.cc
index c4836ca..aba22eb 100644
--- a/sandbox/win/src/target_process.cc
+++ b/sandbox/win/src/target_process.cc
@@ -44,24 +44,6 @@
 
 namespace {
 
-// Parses a null-terminated input string of an environment block. The key is
-// placed into the given string, and the total length of the line, including
-// the terminating null, is returned.
-size_t ParseEnvLine(const wchar_t* input, std::wstring* key) {
-  // Skip to the equals or end of the string, this is the key.
-  size_t cur = 0;
-  while (input[cur] && input[cur] != '=') {
-    cur++;
-  }
-  *key = std::wstring(&input[0], cur);
-
-  // Now just skip to the end of the string.
-  while (input[cur]) {
-    cur++;
-  }
-  return cur + 1;
-}
-
 void CopyPolicyToTarget(base::span<const uint8_t> source, void* dest) {
   if (!source.size()) {
     return;
@@ -435,28 +417,4 @@
   return target;
 }
 
-// static
-std::wstring TargetProcess::FilterEnvironment(
-    const wchar_t* env,
-    const base::span<const std::wstring_view> to_keep) {
-  std::wstring result;
-
-  // Iterate all of the environment strings.
-  const wchar_t* ptr = env;
-  while (*ptr) {
-    std::wstring key;
-    size_t line_length = ParseEnvLine(ptr, &key);
-
-    // Keep only values specified in the keep vector.
-    if (std::find(to_keep.begin(), to_keep.end(), key) != to_keep.end()) {
-      result.append(ptr, line_length);
-    }
-    ptr += line_length;
-  }
-
-  // Add the terminating NUL.
-  result.push_back('\0');
-  return result;
-}
-
 }  // namespace sandbox
diff --git a/sandbox/win/src/target_process.h b/sandbox/win/src/target_process.h
index e9172afb..8f6be3d 100644
--- a/sandbox/win/src/target_process.h
+++ b/sandbox/win/src/target_process.h
@@ -94,16 +94,9 @@
       HMODULE base_address);
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(TargetProcessTest, FilterEnvironment);
   // Verify the target process looks the same as the broker process.
   ResultCode VerifySentinels();
 
-  // Filters an environment to only include those that have an entry in
-  // `to_keep`.
-  static std::wstring FilterEnvironment(
-      const wchar_t* env,
-      const base::span<const std::wstring_view> to_keep);
-
   // Details of the target process.
   base::win::ScopedProcessInformation sandbox_process_info_;
   // The token associated with the process. It provides the core of the
diff --git a/sandbox/win/src/target_process_unittest.cc b/sandbox/win/src/target_process_unittest.cc
deleted file mode 100644
index 21bb672..0000000
--- a/sandbox/win/src/target_process_unittest.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2022 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "sandbox/win/src/target_process.h"
-
-#include <string>
-#include <string_view>
-#include <vector>
-
-#include "base/strings/string_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace sandbox {
-
-namespace {
-
-void ExpectEnvironmentBlock(const std::vector<std::wstring>& vars,
-                            const std::wstring& block) {
-  std::wstring expected;
-  for (const auto& var : vars) {
-    expected += var;
-    expected.push_back('\0');
-  }
-  expected.push_back('\0');
-  EXPECT_EQ(expected, block);
-}
-
-}  // namespace
-
-using TargetProcessTest = testing::Test;
-
-TEST_F(TargetProcessTest, FilterEnvironment) {
-  const wchar_t empty[] = {'\0'};
-  const wchar_t a2b3c4[] = {'A',  '=', '2', '\0', 'B',  '=', '3',
-                            '\0', 'C', '=', '4',  '\0', '\0'};
-
-  // Empty filter should filter everything.
-  std::vector<std::wstring_view> to_keep;
-  auto res = TargetProcess::FilterEnvironment(empty, to_keep);
-  ExpectEnvironmentBlock({}, res);
-
-  res = TargetProcess::FilterEnvironment(a2b3c4, to_keep);
-  ExpectEnvironmentBlock({}, res);
-
-  to_keep.push_back(L"B");
-  res = TargetProcess::FilterEnvironment(a2b3c4, to_keep);
-  ExpectEnvironmentBlock({L"B=3"}, res);
-
-  res = TargetProcess::FilterEnvironment(empty, to_keep);
-  ExpectEnvironmentBlock({}, res);
-
-  to_keep.push_back(L"D");
-  // D should be ignored, but B should still appear.
-  res = TargetProcess::FilterEnvironment(a2b3c4, to_keep);
-  ExpectEnvironmentBlock({L"B=3"}, res);
-
-  to_keep.clear();
-  to_keep.push_back(L"D");
-  // D should be ignored.
-  res = TargetProcess::FilterEnvironment(a2b3c4, to_keep);
-  ExpectEnvironmentBlock({}, res);
-
-  to_keep.push_back(L"A");
-  to_keep.push_back(L"C");
-  // Once again D should be ignored but this time A and C should match.
-  res = TargetProcess::FilterEnvironment(a2b3c4, to_keep);
-  ExpectEnvironmentBlock({L"A=2", L"C=4"}, res);
-}
-
-}  // namespace sandbox
diff --git a/sandbox/win/src/win_utils.cc b/sandbox/win/src/win_utils.cc
index 0f30bcca..ca38415 100644
--- a/sandbox/win/src/win_utils.cc
+++ b/sandbox/win/src/win_utils.cc
@@ -207,4 +207,24 @@
   CHECK(success);
 }
 
+std::wstring FilterEnvironment(
+    const wchar_t* env,
+    const base::span<const std::wstring_view> to_keep) {
+  std::wstring result;
+
+  std::wstring_view curr(env);
+  while (!curr.empty()) {
+    std::wstring_view key = curr.substr(0, curr.find(L'='));
+    if (std::find(to_keep.begin(), to_keep.end(), key) != to_keep.end()) {
+      result.append(curr).push_back('\0');
+    }
+    UNSAFE_BUFFERS(env += curr.size() + 1);
+    curr = env;
+  }
+
+  // Add the terminating NUL.
+  result.push_back('\0');
+  return result;
+}
+
 }  // namespace sandbox
diff --git a/sandbox/win/src/win_utils.h b/sandbox/win/src/win_utils.h
index 525992b9..dc16be1 100644
--- a/sandbox/win/src/win_utils.h
+++ b/sandbox/win/src/win_utils.h
@@ -84,6 +84,11 @@
 // pre-loaded to support the infrastructure underlying crypto::RandBytes.
 void WarmupRandomnessInfrastructure();
 
+// Filters an environment to only include those that have an entry in `to_keep`.
+std::wstring FilterEnvironment(
+    const wchar_t* env,
+    const base::span<const std::wstring_view> to_keep);
+
 }  // namespace sandbox
 
 #endif  // SANDBOX_WIN_SRC_WIN_UTILS_H_
diff --git a/sandbox/win/src/win_utils_unittest.cc b/sandbox/win/src/win_utils_unittest.cc
index 2b41d32..ba43420d 100644
--- a/sandbox/win/src/win_utils_unittest.cc
+++ b/sandbox/win/src/win_utils_unittest.cc
@@ -91,6 +91,17 @@
       base::EqualsCaseInsensitiveASCII(type_name.value(), expected_type));
 }
 
+void ExpectEnvironmentBlock(const std::vector<std::wstring>& vars,
+                            const std::wstring& block) {
+  std::wstring expected;
+  for (const auto& var : vars) {
+    expected += var;
+    expected.push_back('\0');
+  }
+  expected.push_back('\0');
+  EXPECT_EQ(expected, block);
+}
+
 }  // namespace
 
 TEST(WinUtils, IsPipe) {
@@ -197,4 +208,38 @@
   EXPECT_TRUE(ContainsNulCharacter(str));
 }
 
+TEST(WinUtils, FilterEnvironment) {
+  const wchar_t empty[] = L"";
+  const wchar_t a2b3c4[] = L"A=2\0B=3\0C=4\0";
+  const wchar_t xy1z[] = L"X\0Y=1\0Z\0";
+
+  auto res = FilterEnvironment(empty, {});
+  ExpectEnvironmentBlock({}, res);
+
+  res = FilterEnvironment(a2b3c4, {});
+  ExpectEnvironmentBlock({}, res);
+
+  res = FilterEnvironment(a2b3c4, {L"B"});
+  ExpectEnvironmentBlock({L"B=3"}, res);
+
+  res = FilterEnvironment(empty, {L"B"});
+  ExpectEnvironmentBlock({}, res);
+
+  // D should be ignored, but B should still appear.
+  res = FilterEnvironment(a2b3c4, {L"B", L"D"});
+  ExpectEnvironmentBlock({L"B=3"}, res);
+
+  // D should be ignored.
+  res = FilterEnvironment(a2b3c4, {L"D"});
+  ExpectEnvironmentBlock({}, res);
+
+  // Once again D should be ignored but this time A and C should match.
+  res = FilterEnvironment(a2b3c4, {L"D", L"A", L"C"});
+  ExpectEnvironmentBlock({L"A=2", L"C=4"}, res);
+
+  // Check that the parser works if the '=' character is missing.
+  res = FilterEnvironment(xy1z, {L"X", L"Z"});
+  ExpectEnvironmentBlock({L"X", L"Z"}, res);
+}
+
 }  // namespace sandbox
diff --git a/storage/browser/test/mock_quota_manager.h b/storage/browser/test/mock_quota_manager.h
index 6327e11..db83777e 100644
--- a/storage/browser/test/mock_quota_manager.h
+++ b/storage/browser/test/mock_quota_manager.h
@@ -7,13 +7,15 @@
 
 #include <stdint.h>
 
+#include <limits>
 #include <list>
 #include <map>
 #include <memory>
 #include <set>
-#include <utility>
+#include <string>
 #include <vector>
 
+#include "base/functional/callback_helpers.h"
 #include "base/gtest_prod_util.h"
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
diff --git a/testing/buildbot/filters/trees_in_viz.cc_unittests.filter b/testing/buildbot/filters/trees_in_viz.cc_unittests.filter
index 8d4e1a371..67a0196 100644
--- a/testing/buildbot/filters/trees_in_viz.cc_unittests.filter
+++ b/testing/buildbot/filters/trees_in_viz.cc_unittests.filter
@@ -5,9 +5,6 @@
 -LayerTreeHostImplViewportCoveredTest.ActiveTreeShrinkViewportInvalid
 -LayerTreeHostImplViewportCoveredTest.ViewportCovered
 -LayerTreeHostImplViewportCoveredTest.ViewportCoveredScaled
-# These tests use FakeLayerTreeFrameSink properties that are not set in TreesInViz.
--CommitToPendingTreeLayerTreeHostImplTest.CompositorFrameMetadataFrameIntervalInputs
--CommitToPendingTreeLayerTreeHostImplTest.LatencyInfoPassedToCompositorFrameMetadata
 
 # These tests directly append quads to FrameData, which isn't
 # a meaningful test for TreesInViz mode.
diff --git a/testing/perf/cbb_ref_info/edge/stable/windows.json b/testing/perf/cbb_ref_info/edge/stable/windows.json
index dd94c6d..24ee846 100644
--- a/testing/perf/cbb_ref_info/edge/stable/windows.json
+++ b/testing/perf/cbb_ref_info/edge/stable/windows.json
@@ -2,5 +2,5 @@
   "browser": "edge",
   "channel": "stable",
   "platform": "windows",
-  "version": "142.0.3595.94"
+  "version": "143.0.3650.66"
 }
\ No newline at end of file
diff --git a/testing/perf/cbb_ref_info/safari/technology-preview/mac.json b/testing/perf/cbb_ref_info/safari/technology-preview/mac.json
index b2719a2..2c8ec87 100644
--- a/testing/perf/cbb_ref_info/safari/technology-preview/mac.json
+++ b/testing/perf/cbb_ref_info/safari/technology-preview/mac.json
@@ -2,5 +2,5 @@
   "browser": "safari",
   "channel": "technology-preview",
   "platform": "mac",
-  "version": "26.0 (Release 232, 20624.1.2.19.2)"
+  "version": "26.0 (Release 233, 20624.1.4.19.1)"
 }
\ No newline at end of file
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 59e7e15..78ac6af 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -8998,22 +8998,6 @@
             ]
         }
     ],
-    "DiscardPageWithCrashedSubframePolicy": [
-        {
-            "platforms": [
-                "android"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "DiscardPageWithCrashedSubframePolicy",
-                        "WebContentsDiscard"
-                    ]
-                }
-            ]
-        }
-    ],
     "DiscountAutoPopup": [
         {
             "platforms": [
@@ -13609,6 +13593,25 @@
             ]
         }
     ],
+    "IOSLensTripleCameraWith90Zoom": [
+        {
+            "platforms": [
+                "ios"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "LensCameraNoStillOutputRequired",
+                        "LensCameraUnbinnedCaptureFormatsPreferred",
+                        "LensContinuousZoomEnabled",
+                        "LensInitialLvfZoomLevel90Percent",
+                        "LensTripleCameraEnabled"
+                    ]
+                }
+            ]
+        }
+    ],
     "IOSLogApplicationStorageSizeMetrics": [
         {
             "platforms": [
diff --git a/third_party/android_deps/autorolled/BUILD.gn b/third_party/android_deps/autorolled/BUILD.gn
index 3719fc3..76a05ca 100644
--- a/third_party/android_deps/autorolled/BUILD.gn
+++ b/third_party/android_deps/autorolled/BUILD.gn
@@ -51,7 +51,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/android_deps/autorolled/build.gradle.
+    # //third_party/android_deps/autorolled/build.gradle.template
     visibility = [
       ":*",
       "//third_party/androidx:*",
@@ -879,7 +879,6 @@
       jar_path = "autorolled/cipd/libs/org_jetbrains_kotlinx_atomicfu_jvm/atomicfu-jvm.jar"
       output_name = "org_jetbrains_kotlinx_atomicfu_jvm"
       supports_android = true
-      requires_android = true
       enable_bytecode_checks = false
       deps = [ "//third_party/kotlin_stdlib:kotlin_stdlib_java" ]
     }
@@ -968,7 +967,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -983,7 +982,7 @@
         enable_bytecode_checks = false
 
         # To remove visibility constraint, add this dependency to
-        # //third_party/android_deps/autorolled/build.gradle.
+        # //third_party/android_deps/autorolled/build.gradle.template
         visibility = [
           ":*",
           "//third_party/androidx:*",
@@ -1001,7 +1000,7 @@
         enable_bytecode_checks = false
 
         # To remove visibility constraint, add this dependency to
-        # //third_party/android_deps/autorolled/build.gradle.
+        # //third_party/android_deps/autorolled/build.gradle.template
         visibility = [
           ":*",
           "//third_party/androidx:*",
@@ -1025,7 +1024,7 @@
         enable_bytecode_checks = false
 
         # To remove visibility constraint, add this dependency to
-        # //third_party/android_deps/autorolled/build.gradle.
+        # //third_party/android_deps/autorolled/build.gradle.template
         visibility = [
           ":*",
           "//third_party/androidx:*",
@@ -1048,7 +1047,7 @@
         enable_bytecode_checks = false
 
         # To remove visibility constraint, add this dependency to
-        # //third_party/android_deps/autorolled/build.gradle.
+        # //third_party/android_deps/autorolled/build.gradle.template
         visibility = [
           ":*",
           "//third_party/androidx:*",
@@ -1071,7 +1070,7 @@
         enable_bytecode_checks = false
 
         # To remove visibility constraint, add this dependency to
-        # //third_party/android_deps/autorolled/build.gradle.
+        # //third_party/android_deps/autorolled/build.gradle.template
         visibility = [
           ":*",
           "//third_party/androidx:*",
@@ -1091,7 +1090,7 @@
         enable_bytecode_checks = false
 
         # To remove visibility constraint, add this dependency to
-        # //third_party/android_deps/autorolled/build.gradle.
+        # //third_party/android_deps/autorolled/build.gradle.template
         visibility = [
           ":*",
           "//third_party/androidx:*",
@@ -1111,7 +1110,7 @@
         enable_bytecode_checks = false
 
         # To remove visibility constraint, add this dependency to
-        # //third_party/android_deps/autorolled/build.gradle.
+        # //third_party/android_deps/autorolled/build.gradle.template
         visibility = [
           ":*",
           "//third_party/androidx:*",
@@ -1133,7 +1132,7 @@
         enable_bytecode_checks = false
 
         # To remove visibility constraint, add this dependency to
-        # //third_party/android_deps/autorolled/build.gradle.
+        # //third_party/android_deps/autorolled/build.gradle.template
         visibility = [
           ":*",
           "//third_party/androidx:*",
@@ -1152,7 +1151,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1167,7 +1166,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1185,7 +1184,7 @@
         enable_bytecode_checks = false
 
         # To remove visibility constraint, add this dependency to
-        # //third_party/android_deps/autorolled/build.gradle.
+        # //third_party/android_deps/autorolled/build.gradle.template
         visibility = [
           ":*",
           "//third_party/androidx:*",
@@ -1202,7 +1201,7 @@
         enable_bytecode_checks = false
 
         # To remove visibility constraint, add this dependency to
-        # //third_party/android_deps/autorolled/build.gradle.
+        # //third_party/android_deps/autorolled/build.gradle.template
         visibility = [
           ":*",
           "//third_party/androidx:*",
@@ -1229,7 +1228,7 @@
         enable_bytecode_checks = false
 
         # To remove visibility constraint, add this dependency to
-        # //third_party/android_deps/autorolled/build.gradle.
+        # //third_party/android_deps/autorolled/build.gradle.template
         visibility = [
           ":*",
           "//third_party/androidx:*",
@@ -1250,7 +1249,7 @@
         enable_bytecode_checks = false
 
         # To remove visibility constraint, add this dependency to
-        # //third_party/android_deps/autorolled/build.gradle.
+        # //third_party/android_deps/autorolled/build.gradle.template
         visibility = [
           ":*",
           "//third_party/androidx:*",
@@ -1274,7 +1273,7 @@
         enable_bytecode_checks = false
 
         # To remove visibility constraint, add this dependency to
-        # //third_party/android_deps/autorolled/build.gradle.
+        # //third_party/android_deps/autorolled/build.gradle.template
         visibility = [
           ":*",
           "//third_party/androidx:*",
@@ -1291,7 +1290,7 @@
         enable_bytecode_checks = false
 
         # To remove visibility constraint, add this dependency to
-        # //third_party/android_deps/autorolled/build.gradle.
+        # //third_party/android_deps/autorolled/build.gradle.template
         visibility = [
           ":*",
           "//third_party/androidx:*",
@@ -1313,7 +1312,7 @@
         enable_bytecode_checks = false
 
         # To remove visibility constraint, add this dependency to
-        # //third_party/android_deps/autorolled/build.gradle.
+        # //third_party/android_deps/autorolled/build.gradle.template
         visibility = [
           ":*",
           "//third_party/androidx:*",
@@ -1333,7 +1332,7 @@
         enable_bytecode_checks = false
 
         # To remove visibility constraint, add this dependency to
-        # //third_party/android_deps/autorolled/build.gradle.
+        # //third_party/android_deps/autorolled/build.gradle.template
         visibility = [
           ":*",
           "//third_party/androidx:*",
@@ -1353,7 +1352,7 @@
         enable_bytecode_checks = false
 
         # To remove visibility constraint, add this dependency to
-        # //third_party/android_deps/autorolled/build.gradle.
+        # //third_party/android_deps/autorolled/build.gradle.template
         visibility = [
           ":*",
           "//third_party/androidx:*",
@@ -1378,7 +1377,7 @@
         enable_bytecode_checks = false
 
         # To remove visibility constraint, add this dependency to
-        # //third_party/android_deps/autorolled/build.gradle.
+        # //third_party/android_deps/autorolled/build.gradle.template
         visibility = [
           ":*",
           "//third_party/androidx:*",
@@ -1399,7 +1398,7 @@
         enable_bytecode_checks = false
 
         # To remove visibility constraint, add this dependency to
-        # //third_party/android_deps/autorolled/build.gradle.
+        # //third_party/android_deps/autorolled/build.gradle.template
         visibility = [
           ":*",
           "//third_party/androidx:*",
@@ -1431,7 +1430,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1447,7 +1446,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1463,7 +1462,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1487,7 +1486,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1508,7 +1507,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1530,7 +1529,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1547,7 +1546,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1567,7 +1566,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1586,7 +1585,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1605,7 +1604,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1627,7 +1626,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1648,7 +1647,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1666,7 +1665,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1688,7 +1687,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1710,7 +1709,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1731,7 +1730,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1748,7 +1747,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1763,7 +1762,7 @@
     # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
     java_group("com_squareup_okio_okio_java") {
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1774,7 +1773,7 @@
     # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
     java_group("com_squareup_wire_wire_runtime_java") {
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1794,7 +1793,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1815,7 +1814,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1832,7 +1831,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1865,7 +1864,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1880,7 +1879,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1898,7 +1897,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1914,7 +1913,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1923,9 +1922,22 @@
     }
 
     # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
+    java_group("org_jetbrains_kotlinx_atomicfu_java") {
+      # To remove visibility constraint, add this dependency to
+      # //third_party/android_deps/autorolled/build.gradle.template
+      visibility = [
+        ":*",
+        "//third_party/androidx:*",
+      ]
+      deps = [
+        "//third_party/android_deps:org_jetbrains_kotlinx_atomicfu_jvm_java",
+      ]
+    }
+
+    # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
     java_group("org_jetbrains_kotlinx_kotlinx_coroutines_core_java") {
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1943,7 +1955,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1958,7 +1970,7 @@
     # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
     java_group("org_jetbrains_kotlinx_kotlinx_coroutines_test_java") {
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1976,7 +1988,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -1991,7 +2003,7 @@
     # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
     java_group("org_jetbrains_kotlinx_kotlinx_serialization_core_java") {
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -2008,7 +2020,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -2028,7 +2040,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -2044,7 +2056,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -2065,7 +2077,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -2087,7 +2099,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -2103,7 +2115,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -2123,7 +2135,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -2145,7 +2157,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -2167,7 +2179,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -2194,7 +2206,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -2214,7 +2226,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -2244,7 +2256,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -2265,7 +2277,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
@@ -2286,7 +2298,7 @@
       enable_bytecode_checks = false
 
       # To remove visibility constraint, add this dependency to
-      # //third_party/android_deps/autorolled/build.gradle.
+      # //third_party/android_deps/autorolled/build.gradle.template
       visibility = [
         ":*",
         "//third_party/androidx:*",
diff --git a/third_party/android_deps/autorolled/VERSION.txt b/third_party/android_deps/autorolled/VERSION.txt
index b39a1261..7b20ea3 100644
--- a/third_party/android_deps/autorolled/VERSION.txt
+++ b/third_party/android_deps/autorolled/VERSION.txt
@@ -1 +1 @@
-d4619eb7be1cdee.cffab051f47f383
\ No newline at end of file
+3a503b45fe4f086.fa8ca648e55474c
\ 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 b3130b1..68d6c12 100644
--- a/third_party/android_deps/autorolled/bill_of_materials.json
+++ b/third_party/android_deps/autorolled/bill_of_materials.json
@@ -212,12 +212,12 @@
     {
         "name": "runtime-annotation",
         "group": "androidx.compose.runtime",
-        "version": "1.11.0-SNAPSHOT"
+        "version": "1.11.0-alpha01"
     },
     {
         "name": "runtime-annotation-android",
         "group": "androidx.compose.runtime",
-        "version": "1.11.0-SNAPSHOT"
+        "version": "1.11.0-alpha01"
     },
     {
         "name": "runtime-retain",
@@ -417,62 +417,62 @@
     {
         "name": "datastore",
         "group": "androidx.datastore",
-        "version": "1.3.0-alpha01"
+        "version": "1.3.0-alpha02"
     },
     {
         "name": "datastore-android",
         "group": "androidx.datastore",
-        "version": "1.3.0-alpha01"
+        "version": "1.3.0-alpha02"
     },
     {
         "name": "datastore-core",
         "group": "androidx.datastore",
-        "version": "1.3.0-alpha01"
+        "version": "1.3.0-alpha02"
     },
     {
         "name": "datastore-core-android",
         "group": "androidx.datastore",
-        "version": "1.3.0-alpha01"
+        "version": "1.3.0-alpha02"
     },
     {
         "name": "datastore-core-okio",
         "group": "androidx.datastore",
-        "version": "1.3.0-alpha01"
+        "version": "1.3.0-alpha02"
     },
     {
         "name": "datastore-core-okio-jvm",
         "group": "androidx.datastore",
-        "version": "1.3.0-alpha01"
+        "version": "1.3.0-alpha02"
     },
     {
         "name": "datastore-preferences",
         "group": "androidx.datastore",
-        "version": "1.3.0-alpha01"
+        "version": "1.3.0-alpha02"
     },
     {
         "name": "datastore-preferences-android",
         "group": "androidx.datastore",
-        "version": "1.3.0-alpha01"
+        "version": "1.3.0-alpha02"
     },
     {
         "name": "datastore-preferences-core",
         "group": "androidx.datastore",
-        "version": "1.3.0-alpha01"
+        "version": "1.3.0-alpha02"
     },
     {
         "name": "datastore-preferences-core-android",
         "group": "androidx.datastore",
-        "version": "1.3.0-alpha01"
+        "version": "1.3.0-alpha02"
     },
     {
         "name": "datastore-preferences-external-protobuf",
         "group": "androidx.datastore",
-        "version": "1.3.0-alpha01"
+        "version": "1.3.0-alpha02"
     },
     {
         "name": "datastore-preferences-proto",
         "group": "androidx.datastore",
-        "version": "1.3.0-alpha01"
+        "version": "1.3.0-alpha02"
     },
     {
         "name": "documentfile",
@@ -507,7 +507,7 @@
     {
         "name": "exifinterface",
         "group": "androidx.exifinterface",
-        "version": "1.4.1"
+        "version": "1.4.2"
     },
     {
         "name": "fragment",
@@ -957,22 +957,22 @@
     {
         "name": "sqlite",
         "group": "androidx.sqlite",
-        "version": "2.6.2"
+        "version": "2.7.0-SNAPSHOT"
     },
     {
         "name": "sqlite-android",
         "group": "androidx.sqlite",
-        "version": "2.6.2"
+        "version": "2.7.0-SNAPSHOT"
     },
     {
         "name": "sqlite-framework",
         "group": "androidx.sqlite",
-        "version": "2.6.2"
+        "version": "2.7.0-SNAPSHOT"
     },
     {
         "name": "sqlite-framework-android",
         "group": "androidx.sqlite",
-        "version": "2.6.2"
+        "version": "2.7.0-SNAPSHOT"
     },
     {
         "name": "startup-runtime",
@@ -982,7 +982,7 @@
     {
         "name": "swiperefreshlayout",
         "group": "androidx.swiperefreshlayout",
-        "version": "1.2.0-SNAPSHOT"
+        "version": "1.2.0"
     },
     {
         "name": "espresso-contrib",
@@ -1027,12 +1027,12 @@
     {
         "name": "uiautomator-shell",
         "group": "androidx.test.uiautomator",
-        "version": "1.0.0-SNAPSHOT"
+        "version": "2.4.0-SNAPSHOT"
     },
     {
         "name": "uiautomator-shell-android",
         "group": "androidx.test.uiautomator",
-        "version": "1.0.0-SNAPSHOT"
+        "version": "2.4.0-SNAPSHOT"
     },
     {
         "name": "annotation",
@@ -1092,7 +1092,7 @@
     {
         "name": "transition",
         "group": "androidx.transition",
-        "version": "1.7.0-alpha01"
+        "version": "1.7.0-beta01"
     },
     {
         "name": "tvprovider",
@@ -1382,7 +1382,7 @@
     {
         "name": "impress",
         "group": "com.google.ar",
-        "version": "0.0.8"
+        "version": "0.0.9"
     },
     {
         "name": "auto-service-annotations",
@@ -1497,7 +1497,7 @@
     {
         "name": "protobuf-javalite",
         "group": "com.google.protobuf",
-        "version": "4.33.1"
+        "version": "4.33.2"
     },
     {
         "name": "protobuf-lite",
@@ -1845,9 +1845,14 @@
         "version": "1.8.21"
     },
     {
+        "name": "atomicfu",
+        "group": "org.jetbrains.kotlinx",
+        "version": "0.28.0"
+    },
+    {
         "name": "atomicfu-jvm",
         "group": "org.jetbrains.kotlinx",
-        "version": "0.23.2"
+        "version": "0.30.0-beta"
     },
     {
         "name": "kotlinx-coroutines-android",
diff --git a/third_party/android_deps/autorolled/build.gradle b/third_party/android_deps/autorolled/build.gradle
index 70c28a7..177473c 100644
--- a/third_party/android_deps/autorolled/build.gradle
+++ b/third_party/android_deps/autorolled/build.gradle
@@ -56,8 +56,8 @@
 versionCache['androidx.compose.material:material-ripple-android'] = '1.11.0-SNAPSHOT'
 versionCache['androidx.compose.runtime:runtime'] = '1.11.0-SNAPSHOT'
 versionCache['androidx.compose.runtime:runtime-android'] = '1.11.0-SNAPSHOT'
-versionCache['androidx.compose.runtime:runtime-annotation'] = '1.11.0-SNAPSHOT'
-versionCache['androidx.compose.runtime:runtime-annotation-android'] = '1.11.0-SNAPSHOT'
+versionCache['androidx.compose.runtime:runtime-annotation'] = '1.11.0-alpha01'
+versionCache['androidx.compose.runtime:runtime-annotation-android'] = '1.11.0-alpha01'
 versionCache['androidx.compose.runtime:runtime-retain'] = '1.11.0-SNAPSHOT'
 versionCache['androidx.compose.runtime:runtime-retain-android'] = '1.11.0-SNAPSHOT'
 versionCache['androidx.compose.runtime:runtime-saveable'] = '1.11.0-SNAPSHOT'
@@ -97,25 +97,25 @@
 versionCache['androidx.cursoradapter:cursoradapter'] = '1.1.0-SNAPSHOT'
 versionCache['androidx.customview:customview'] = '1.2.0'
 versionCache['androidx.customview:customview-poolingcontainer'] = '1.1.0'
-versionCache['androidx.datastore:datastore'] = '1.3.0-alpha01'
-versionCache['androidx.datastore:datastore-android'] = '1.3.0-alpha01'
-versionCache['androidx.datastore:datastore-core'] = '1.3.0-alpha01'
-versionCache['androidx.datastore:datastore-core-android'] = '1.3.0-alpha01'
-versionCache['androidx.datastore:datastore-core-okio'] = '1.3.0-alpha01'
-versionCache['androidx.datastore:datastore-core-okio-jvm'] = '1.3.0-alpha01'
-versionCache['androidx.datastore:datastore-preferences'] = '1.3.0-alpha01'
-versionCache['androidx.datastore:datastore-preferences-android'] = '1.3.0-alpha01'
-versionCache['androidx.datastore:datastore-preferences-core'] = '1.3.0-alpha01'
-versionCache['androidx.datastore:datastore-preferences-core-android'] = '1.3.0-alpha01'
-versionCache['androidx.datastore:datastore-preferences-external-protobuf'] = '1.3.0-alpha01'
-versionCache['androidx.datastore:datastore-preferences-proto'] = '1.3.0-alpha01'
+versionCache['androidx.datastore:datastore'] = '1.3.0-alpha02'
+versionCache['androidx.datastore:datastore-android'] = '1.3.0-alpha02'
+versionCache['androidx.datastore:datastore-core'] = '1.3.0-alpha02'
+versionCache['androidx.datastore:datastore-core-android'] = '1.3.0-alpha02'
+versionCache['androidx.datastore:datastore-core-okio'] = '1.3.0-alpha02'
+versionCache['androidx.datastore:datastore-core-okio-jvm'] = '1.3.0-alpha02'
+versionCache['androidx.datastore:datastore-preferences'] = '1.3.0-alpha02'
+versionCache['androidx.datastore:datastore-preferences-android'] = '1.3.0-alpha02'
+versionCache['androidx.datastore:datastore-preferences-core'] = '1.3.0-alpha02'
+versionCache['androidx.datastore:datastore-preferences-core-android'] = '1.3.0-alpha02'
+versionCache['androidx.datastore:datastore-preferences-external-protobuf'] = '1.3.0-alpha02'
+versionCache['androidx.datastore:datastore-preferences-proto'] = '1.3.0-alpha02'
 versionCache['androidx.documentfile:documentfile'] = '1.1.0'
 versionCache['androidx.drawerlayout:drawerlayout'] = '1.3.0-SNAPSHOT'
 versionCache['androidx.dynamicanimation:dynamicanimation'] = '1.1.0'
 versionCache['androidx.emoji2:emoji2'] = '1.6.0'
 versionCache['androidx.emoji2:emoji2-views-helper'] = '1.6.0'
 versionCache['androidx.emoji:emoji'] = '1.2.0-SNAPSHOT'
-versionCache['androidx.exifinterface:exifinterface'] = '1.4.1'
+versionCache['androidx.exifinterface:exifinterface'] = '1.4.2'
 versionCache['androidx.fragment:fragment'] = '1.9.0-SNAPSHOT'
 versionCache['androidx.fragment:fragment-compose'] = '1.9.0-SNAPSHOT'
 versionCache['androidx.fragment:fragment-ktx'] = '1.9.0-SNAPSHOT'
@@ -205,12 +205,12 @@
 versionCache['androidx.savedstate:savedstate-compose-android'] = '1.5.0-SNAPSHOT'
 versionCache['androidx.savedstate:savedstate-ktx'] = '1.5.0-SNAPSHOT'
 versionCache['androidx.slidingpanelayout:slidingpanelayout'] = '1.3.0-SNAPSHOT'
-versionCache['androidx.sqlite:sqlite'] = '2.6.2'
-versionCache['androidx.sqlite:sqlite-android'] = '2.6.2'
-versionCache['androidx.sqlite:sqlite-framework'] = '2.6.2'
-versionCache['androidx.sqlite:sqlite-framework-android'] = '2.6.2'
+versionCache['androidx.sqlite:sqlite'] = '2.7.0-SNAPSHOT'
+versionCache['androidx.sqlite:sqlite-android'] = '2.7.0-SNAPSHOT'
+versionCache['androidx.sqlite:sqlite-framework'] = '2.7.0-SNAPSHOT'
+versionCache['androidx.sqlite:sqlite-framework-android'] = '2.7.0-SNAPSHOT'
 versionCache['androidx.startup:startup-runtime'] = '1.2.0'
-versionCache['androidx.swiperefreshlayout:swiperefreshlayout'] = '1.2.0-SNAPSHOT'
+versionCache['androidx.swiperefreshlayout:swiperefreshlayout'] = '1.2.0'
 versionCache['androidx.test.espresso:espresso-contrib'] = '3.5.1'
 versionCache['androidx.test.espresso:espresso-core'] = '3.7.0'
 versionCache['androidx.test.espresso:espresso-idling-resource'] = '3.7.0'
@@ -219,8 +219,8 @@
 versionCache['androidx.test.ext:junit'] = '1.3.0'
 versionCache['androidx.test.services:storage'] = '1.6.0'
 versionCache['androidx.test.uiautomator:uiautomator'] = '2.4.0-SNAPSHOT'
-versionCache['androidx.test.uiautomator:uiautomator-shell'] = '1.0.0-SNAPSHOT'
-versionCache['androidx.test.uiautomator:uiautomator-shell-android'] = '1.0.0-SNAPSHOT'
+versionCache['androidx.test.uiautomator:uiautomator-shell'] = '2.4.0-SNAPSHOT'
+versionCache['androidx.test.uiautomator:uiautomator-shell-android'] = '2.4.0-SNAPSHOT'
 versionCache['androidx.test:annotation'] = '1.0.1'
 versionCache['androidx.test:core'] = '1.7.0'
 versionCache['androidx.test:monitor'] = '1.8.0'
@@ -232,7 +232,7 @@
 versionCache['androidx.tracing:tracing-perfetto'] = '1.0.1'
 versionCache['androidx.tracing:tracing-perfetto-binary'] = '1.0.1'
 versionCache['androidx.tracing:tracing-perfetto-handshake'] = '1.0.1'
-versionCache['androidx.transition:transition'] = '1.7.0-alpha01'
+versionCache['androidx.transition:transition'] = '1.7.0-beta01'
 versionCache['androidx.tvprovider:tvprovider'] = '1.1.0'
 versionCache['androidx.vectordrawable:vectordrawable'] = '1.2.0'
 versionCache['androidx.vectordrawable:vectordrawable-animated'] = '1.2.0'
@@ -290,7 +290,7 @@
 versionCache['com.google.android.play:core-common'] = '2.0.3'
 versionCache['com.google.android.play:feature-delivery'] = '2.1.0'
 versionCache['com.google.android:annotations'] = '4.1.1.4'
-versionCache['com.google.ar:impress'] = '0.0.8'
+versionCache['com.google.ar:impress'] = '0.0.9'
 versionCache['com.google.auto.service:auto-service-annotations'] = '1.1.1'
 versionCache['com.google.auto.value:auto-value-annotations'] = '1.11.0'
 versionCache['com.google.code.findbugs:jsr305'] = '3.0.2'
@@ -313,7 +313,7 @@
 versionCache['com.google.guava:guava'] = '33.5.0-jre'
 versionCache['com.google.guava:listenablefuture'] = '9999.0-empty-to-avoid-conflict-with-guava'
 versionCache['com.google.j2objc:j2objc-annotations'] = '3.1'
-versionCache['com.google.protobuf:protobuf-javalite'] = '4.33.1'
+versionCache['com.google.protobuf:protobuf-javalite'] = '4.33.2'
 versionCache['com.google.protobuf:protobuf-lite'] = '3.0.1'
 versionCache['com.google.testparameterinjector:test-parameter-injector'] = '1.18'
 versionCache['com.googlecode.java-diff-utils:diffutils'] = '1.3.0'
@@ -383,7 +383,8 @@
 versionCache['org.jetbrains.kotlin:kotlin-stdlib-common'] = '2.0.20'
 versionCache['org.jetbrains.kotlin:kotlin-stdlib-jdk7'] = '1.9.0'
 versionCache['org.jetbrains.kotlin:kotlin-stdlib-jdk8'] = '1.8.21'
-versionCache['org.jetbrains.kotlinx:atomicfu-jvm'] = '0.23.2'
+versionCache['org.jetbrains.kotlinx:atomicfu'] = '0.28.0'
+versionCache['org.jetbrains.kotlinx:atomicfu-jvm'] = '0.30.0-beta'
 versionCache['org.jetbrains.kotlinx:kotlinx-coroutines-android'] = '1.10.2'
 versionCache['org.jetbrains.kotlinx:kotlinx-coroutines-bom'] = '1.10.2'
 versionCache['org.jetbrains.kotlinx:kotlinx-coroutines-core'] = '1.10.2'
@@ -501,6 +502,7 @@
     supportsAndroidCompileLatest 'org.checkerframework:checker-qual:+'
     supportsAndroidCompileLatest 'org.checkerframework:checker-util:+'
     supportsAndroidCompileLatest 'org.codehaus.mojo:animal-sniffer-annotations:+'
+    supportsAndroidCompileLatest 'org.jetbrains.kotlinx:atomicfu-jvm:+'
     supportsAndroidCompileLatest 'org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:+'
     supportsAndroidCompileLatest 'org.reactivestreams:reactive-streams:+'
     compileLatest 'org.jetbrains.kotlinx:kotlinx-coroutines-android:+'
diff --git a/third_party/android_deps/autorolled/committed/libs/com_google_ar_impress/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_ar_impress/README.chromium
index b844b702..c9f54a2 100644
--- a/third_party/android_deps/autorolled/committed/libs/com_google_ar_impress/README.chromium
+++ b/third_party/android_deps/autorolled/committed/libs/com_google_ar_impress/README.chromium
@@ -1,7 +1,7 @@
 Name: impress
 Short Name: impress
-URL: https://dl.google.com/dl/android/maven2/com/google/ar/impress/0.0.8/impress-0.0.8.aar
-Version: 0.0.8
+URL: https://dl.google.com/dl/android/maven2/com/google/ar/impress/0.0.9/impress-0.0.9.aar
+Version: 0.0.9
 Update Mechanism: Autoroll
 License: Apache-2.0
 License File: LICENSE
diff --git a/third_party/android_deps/autorolled/committed/libs/com_google_protobuf_protobuf_javalite/README.chromium b/third_party/android_deps/autorolled/committed/libs/com_google_protobuf_protobuf_javalite/README.chromium
index a743d8f9..69354060 100644
--- a/third_party/android_deps/autorolled/committed/libs/com_google_protobuf_protobuf_javalite/README.chromium
+++ b/third_party/android_deps/autorolled/committed/libs/com_google_protobuf_protobuf_javalite/README.chromium
@@ -1,7 +1,7 @@
 Name: Protocol Buffers [Lite]
 Short Name: protobuf-javalite
-URL: https://repo.maven.apache.org/maven2/com/google/protobuf/protobuf-javalite/4.33.1/protobuf-javalite-4.33.1.jar
-Version: 4.33.1
+URL: https://repo.maven.apache.org/maven2/com/google/protobuf/protobuf-javalite/4.33.2/protobuf-javalite-4.33.2.jar
+Version: 4.33.2
 Update Mechanism: Autoroll
 License: BSD-3-Clause
 License File: LICENSE
diff --git a/third_party/android_deps/autorolled/committed/libs/org_jetbrains_kotlinx_atomicfu_jvm/README.chromium b/third_party/android_deps/autorolled/committed/libs/org_jetbrains_kotlinx_atomicfu_jvm/README.chromium
index 6e0dbfb9..f5bf027 100644
--- a/third_party/android_deps/autorolled/committed/libs/org_jetbrains_kotlinx_atomicfu_jvm/README.chromium
+++ b/third_party/android_deps/autorolled/committed/libs/org_jetbrains_kotlinx_atomicfu_jvm/README.chromium
@@ -1,7 +1,7 @@
 Name: atomicfu
 Short Name: atomicfu-jvm
-URL: https://repo.maven.apache.org/maven2/org/jetbrains/kotlinx/atomicfu-jvm/0.23.2/atomicfu-jvm-0.23.2.jar
-Version: 0.23.2
+URL: https://repo.maven.apache.org/maven2/org/jetbrains/kotlinx/atomicfu-jvm/0.30.0-beta/atomicfu-jvm-0.30.0-beta.jar
+Version: 0.30.0-beta
 Update Mechanism: Autoroll
 License: Apache-2.0
 License File: LICENSE
diff --git a/third_party/androidx/BUILD.gn b/third_party/androidx/BUILD.gn
index 0dd989b2..ace5ad6 100644
--- a/third_party/androidx/BUILD.gn
+++ b/third_party/androidx/BUILD.gn
@@ -1360,7 +1360,6 @@
       ":androidx_core_core_java",
       ":androidx_interpolator_interpolator_java",
       "//third_party/android_deps:org_jspecify_jspecify_java",
-      "//third_party/kotlin_stdlib:kotlin_stdlib_java",
     ]
   }
 
@@ -1749,7 +1748,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -1771,7 +1770,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -1791,7 +1790,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -1815,7 +1814,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_benchmark_benchmark_traceprocessor_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -1832,7 +1831,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -1854,7 +1853,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -1869,7 +1868,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_compose_animation_animation_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -1885,7 +1884,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -1908,7 +1907,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_compose_animation_animation_core_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -1924,7 +1923,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -1945,7 +1944,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_compose_foundation_foundation_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -1961,7 +1960,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -1985,7 +1984,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_compose_foundation_foundation_layout_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2001,7 +2000,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2028,7 +2027,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2055,7 +2054,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_compose_material_material_ripple_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2071,7 +2070,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2089,7 +2088,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_compose_runtime_runtime_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2100,7 +2099,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_compose_runtime_runtime_annotation_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2116,7 +2115,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2127,7 +2126,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_compose_runtime_runtime_retain_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2143,7 +2142,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2159,7 +2158,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_compose_runtime_runtime_saveable_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2175,7 +2174,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2198,7 +2197,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2237,7 +2236,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_compose_ui_ui_geometry_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2253,7 +2252,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2269,7 +2268,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_compose_ui_ui_graphics_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2285,7 +2284,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2306,7 +2305,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_compose_ui_ui_test_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2323,7 +2322,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2350,7 +2349,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_compose_ui_ui_text_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2365,7 +2364,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2389,7 +2388,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_compose_ui_ui_unit_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2404,7 +2403,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2424,7 +2423,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_compose_ui_ui_util_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2439,7 +2438,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2462,7 +2461,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2480,7 +2479,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2500,7 +2499,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2515,7 +2514,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2535,7 +2534,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2549,7 +2548,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_datastore_datastore_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2565,7 +2564,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2580,7 +2579,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_datastore_datastore_core_okio_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2597,7 +2596,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2619,7 +2618,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2635,7 +2634,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_datastore_datastore_preferences_core_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2651,7 +2650,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2661,6 +2660,7 @@
       ":androidx_datastore_datastore_core_okio_java",
       ":androidx_datastore_datastore_preferences_proto_java",
       "//third_party/android_deps:com_squareup_okio_okio_java",
+      "//third_party/android_deps:org_jetbrains_kotlinx_atomicfu_java",
       "//third_party/kotlin_stdlib:kotlin_stdlib_java",
     ]
   }
@@ -2675,7 +2675,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2692,7 +2692,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2710,7 +2710,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2732,7 +2732,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2753,7 +2753,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2776,7 +2776,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2798,7 +2798,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2813,7 +2813,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_graphics_graphics_shapes_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2829,7 +2829,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2850,7 +2850,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2871,7 +2871,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2901,7 +2901,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2922,7 +2922,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2941,7 +2941,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2961,7 +2961,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -2982,7 +2982,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3002,7 +3002,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_lifecycle_lifecycle_runtime_compose_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3018,7 +3018,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3040,7 +3040,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3061,7 +3061,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3083,7 +3083,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3091,6 +3091,7 @@
     deps = [
       ":androidx_annotation_annotation_java",
       ":androidx_compose_runtime_runtime_java",
+      ":androidx_compose_runtime_runtime_saveable_java",
       ":androidx_compose_ui_ui_java",
       ":androidx_lifecycle_lifecycle_common_java",
       ":androidx_lifecycle_lifecycle_viewmodel_java",
@@ -3108,7 +3109,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3128,7 +3129,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3154,7 +3155,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3177,7 +3178,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3191,7 +3192,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_navigation_navigation_common_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3207,7 +3208,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3235,7 +3236,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3274,7 +3275,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3299,7 +3300,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_navigationevent_navigationevent_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3315,7 +3316,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3333,7 +3334,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_navigationevent_navigationevent_compose_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3349,7 +3350,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3366,7 +3367,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_paging_paging_common_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3381,7 +3382,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3403,7 +3404,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3421,7 +3422,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3441,7 +3442,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3462,7 +3463,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3487,7 +3488,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3501,7 +3502,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_room_room_common_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3518,7 +3519,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3532,7 +3533,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_savedstate_savedstate_compose_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3548,7 +3549,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3569,7 +3570,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3583,7 +3584,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_sqlite_sqlite_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3594,7 +3595,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_sqlite_sqlite_framework_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3610,7 +3611,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3629,7 +3630,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3648,7 +3649,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3668,7 +3669,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3679,7 +3680,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_test_uiautomator_uiautomator_shell_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3696,7 +3697,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3715,13 +3716,15 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
     ]
     deps = [
       ":androidx_annotation_annotation_java",
+      ":androidx_collection_collection_java",
+      "//third_party/android_deps:org_jetbrains_kotlinx_kotlinx_coroutines_core_java",
       "//third_party/kotlin_stdlib:kotlin_stdlib_java",
     ]
   }
@@ -3734,7 +3737,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3752,7 +3755,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3773,7 +3776,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3791,7 +3794,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3811,7 +3814,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3826,7 +3829,7 @@
   # This is generated, do not edit. Update BuildConfigGenerator.groovy instead.
   androidx_java_group("androidx_window_window_core_java") {
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3841,7 +3844,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3859,7 +3862,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3880,7 +3883,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
@@ -3895,7 +3898,7 @@
     enable_bytecode_checks = false
 
     # To remove visibility constraint, add this dependency to
-    # //third_party/androidx/build.gradle.
+    # //third_party/androidx/build.gradle.template
     visibility = [
       ":*",
       "//third_party/android_deps:*",
diff --git a/third_party/androidx/bill_of_materials.json b/third_party/androidx/bill_of_materials.json
index c9d7cd8..8176565 100644
--- a/third_party/androidx/bill_of_materials.json
+++ b/third_party/androidx/bill_of_materials.json
@@ -507,7 +507,7 @@
     {
         "name": "exifinterface",
         "group": "androidx.exifinterface",
-        "version": "1.4.1"
+        "version": "1.4.2"
     },
     {
         "name": "fragment",
@@ -967,22 +967,22 @@
     {
         "name": "sqlite",
         "group": "androidx.sqlite",
-        "version": "2.6.2"
+        "version": "2.7.0-SNAPSHOT"
     },
     {
         "name": "sqlite-android",
         "group": "androidx.sqlite",
-        "version": "2.6.2"
+        "version": "2.7.0-SNAPSHOT"
     },
     {
         "name": "sqlite-framework",
         "group": "androidx.sqlite",
-        "version": "2.6.2"
+        "version": "2.7.0-SNAPSHOT"
     },
     {
         "name": "sqlite-framework-android",
         "group": "androidx.sqlite",
-        "version": "2.6.2"
+        "version": "2.7.0-SNAPSHOT"
     },
     {
         "name": "startup-runtime",
@@ -992,7 +992,7 @@
     {
         "name": "swiperefreshlayout",
         "group": "androidx.swiperefreshlayout",
-        "version": "1.2.0-SNAPSHOT"
+        "version": "1.2.0"
     },
     {
         "name": "espresso-contrib",
@@ -1037,12 +1037,12 @@
     {
         "name": "uiautomator-shell",
         "group": "androidx.test.uiautomator",
-        "version": "1.0.0-SNAPSHOT"
+        "version": "2.4.0-SNAPSHOT"
     },
     {
         "name": "uiautomator-shell-android",
         "group": "androidx.test.uiautomator",
-        "version": "1.0.0-SNAPSHOT"
+        "version": "2.4.0-SNAPSHOT"
     },
     {
         "name": "annotation",
@@ -1387,7 +1387,7 @@
     {
         "name": "kotlin-stdlib",
         "group": "org.jetbrains.kotlin",
-        "version": "2.1.20"
+        "version": "2.2.20"
     },
     {
         "name": "kotlin-stdlib-jdk7",
@@ -1400,6 +1400,16 @@
         "version": "1.8.0"
     },
     {
+        "name": "atomicfu",
+        "group": "org.jetbrains.kotlinx",
+        "version": "0.28.0"
+    },
+    {
+        "name": "atomicfu-jvm",
+        "group": "org.jetbrains.kotlinx",
+        "version": "0.28.0"
+    },
+    {
         "name": "kotlinx-coroutines-android",
         "group": "org.jetbrains.kotlinx",
         "version": "1.9.0"
diff --git a/third_party/androidx/build.gradle b/third_party/androidx/build.gradle
index 9ab21f8f..cfd8f86a 100644
--- a/third_party/androidx/build.gradle
+++ b/third_party/androidx/build.gradle
@@ -116,7 +116,7 @@
 versionCache['androidx.emoji2:emoji2'] = '1.6.0'
 versionCache['androidx.emoji2:emoji2-views-helper'] = '1.6.0'
 versionCache['androidx.emoji:emoji'] = '1.2.0-SNAPSHOT'
-versionCache['androidx.exifinterface:exifinterface'] = '1.4.1'
+versionCache['androidx.exifinterface:exifinterface'] = '1.4.2'
 versionCache['androidx.fragment:fragment'] = '1.9.0-SNAPSHOT'
 versionCache['androidx.fragment:fragment-compose'] = '1.9.0-SNAPSHOT'
 versionCache['androidx.fragment:fragment-ktx'] = '1.9.0-SNAPSHOT'
@@ -208,12 +208,12 @@
 versionCache['androidx.savedstate:savedstate-compose-android'] = '1.5.0-SNAPSHOT'
 versionCache['androidx.savedstate:savedstate-ktx'] = '1.5.0-SNAPSHOT'
 versionCache['androidx.slidingpanelayout:slidingpanelayout'] = '1.3.0-SNAPSHOT'
-versionCache['androidx.sqlite:sqlite'] = '2.6.2'
-versionCache['androidx.sqlite:sqlite-android'] = '2.6.2'
-versionCache['androidx.sqlite:sqlite-framework'] = '2.6.2'
-versionCache['androidx.sqlite:sqlite-framework-android'] = '2.6.2'
+versionCache['androidx.sqlite:sqlite'] = '2.7.0-SNAPSHOT'
+versionCache['androidx.sqlite:sqlite-android'] = '2.7.0-SNAPSHOT'
+versionCache['androidx.sqlite:sqlite-framework'] = '2.7.0-SNAPSHOT'
+versionCache['androidx.sqlite:sqlite-framework-android'] = '2.7.0-SNAPSHOT'
 versionCache['androidx.startup:startup-runtime'] = '1.2.0'
-versionCache['androidx.swiperefreshlayout:swiperefreshlayout'] = '1.2.0-SNAPSHOT'
+versionCache['androidx.swiperefreshlayout:swiperefreshlayout'] = '1.2.0'
 versionCache['androidx.test.espresso:espresso-contrib'] = '3.5.1'
 versionCache['androidx.test.espresso:espresso-core'] = '3.7.0'
 versionCache['androidx.test.espresso:espresso-idling-resource'] = '3.7.0'
@@ -222,8 +222,8 @@
 versionCache['androidx.test.ext:junit'] = '1.3.0'
 versionCache['androidx.test.services:storage'] = '1.6.0'
 versionCache['androidx.test.uiautomator:uiautomator'] = '2.4.0-SNAPSHOT'
-versionCache['androidx.test.uiautomator:uiautomator-shell'] = '1.0.0-SNAPSHOT'
-versionCache['androidx.test.uiautomator:uiautomator-shell-android'] = '1.0.0-SNAPSHOT'
+versionCache['androidx.test.uiautomator:uiautomator-shell'] = '2.4.0-SNAPSHOT'
+versionCache['androidx.test.uiautomator:uiautomator-shell-android'] = '2.4.0-SNAPSHOT'
 versionCache['androidx.test:annotation'] = '1.0.1'
 versionCache['androidx.test:core'] = '1.7.0'
 versionCache['androidx.test:monitor'] = '1.8.0'
@@ -292,9 +292,11 @@
 versionCache['org.hamcrest:hamcrest-integration'] = '1.3'
 versionCache['org.hamcrest:hamcrest-library'] = '2.2'
 versionCache['org.jetbrains.kotlin:kotlin-bom'] = '1.8.22'
-versionCache['org.jetbrains.kotlin:kotlin-stdlib'] = '2.1.20'
+versionCache['org.jetbrains.kotlin:kotlin-stdlib'] = '2.2.20'
 versionCache['org.jetbrains.kotlin:kotlin-stdlib-jdk7'] = '1.9.0'
 versionCache['org.jetbrains.kotlin:kotlin-stdlib-jdk8'] = '1.8.0'
+versionCache['org.jetbrains.kotlinx:atomicfu'] = '0.28.0'
+versionCache['org.jetbrains.kotlinx:atomicfu-jvm'] = '0.28.0'
 versionCache['org.jetbrains.kotlinx:kotlinx-coroutines-android'] = '1.9.0'
 versionCache['org.jetbrains.kotlinx:kotlinx-coroutines-bom'] = '1.9.0'
 versionCache['org.jetbrains.kotlinx:kotlinx-coroutines-core'] = '1.9.0'
@@ -316,7 +318,7 @@
     google()
     maven {
         // This URL is generated by the fetch_all_androidx.py script.
-        url 'https://androidx.dev/snapshots/builds/14500233/artifacts/repository'
+        url 'https://androidx.dev/snapshots/builds/14561852/artifacts/repository'
     }
     mavenCentral()
 }
diff --git a/third_party/androidx/committed/libs/androidx_activity_activity/README.chromium b/third_party/androidx/committed/libs/androidx_activity_activity/README.chromium
index 3206784..e913a0a 100644
--- a/third_party/androidx/committed/libs/androidx_activity_activity/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_activity_activity/README.chromium
@@ -1,6 +1,6 @@
 Name: Activity
 Short Name: activity
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/activity/activity/1.13.0-SNAPSHOT/activity-1.13.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/activity/activity/1.13.0-SNAPSHOT/activity-1.13.0-20251209.213522-1.aar
 Version: 1.13.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_activity_activity_compose/README.chromium b/third_party/androidx/committed/libs/androidx_activity_activity_compose/README.chromium
index bcd5933..abccc23 100644
--- a/third_party/androidx/committed/libs/androidx_activity_activity_compose/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_activity_activity_compose/README.chromium
@@ -1,6 +1,6 @@
 Name: Activity Compose
 Short Name: activity-compose
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/activity/activity-compose/1.13.0-SNAPSHOT/activity-compose-1.13.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/activity/activity-compose/1.13.0-SNAPSHOT/activity-compose-1.13.0-20251209.213522-1.aar
 Version: 1.13.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_activity_activity_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_activity_activity_ktx/README.chromium
index a565637..f60f059 100644
--- a/third_party/androidx/committed/libs/androidx_activity_activity_ktx/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_activity_activity_ktx/README.chromium
@@ -1,6 +1,6 @@
 Name: Activity Kotlin Extensions
 Short Name: activity-ktx
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/activity/activity-ktx/1.13.0-SNAPSHOT/activity-ktx-1.13.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/activity/activity-ktx/1.13.0-SNAPSHOT/activity-ktx-1.13.0-20251209.213522-1.aar
 Version: 1.13.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_annotation_annotation_experimental/README.chromium b/third_party/androidx/committed/libs/androidx_annotation_annotation_experimental/README.chromium
index 306c979..a6e9e60 100644
--- a/third_party/androidx/committed/libs/androidx_annotation_annotation_experimental/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_annotation_annotation_experimental/README.chromium
@@ -1,6 +1,6 @@
 Name: Experimental annotation
 Short Name: annotation-experimental
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/annotation/annotation-experimental/1.6.0-SNAPSHOT/annotation-experimental-1.6.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/annotation/annotation-experimental/1.6.0-SNAPSHOT/annotation-experimental-1.6.0-20251209.213522-1.aar
 Version: 1.6.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_annotation_annotation_jvm/README.chromium b/third_party/androidx/committed/libs/androidx_annotation_annotation_jvm/README.chromium
index ba8bdf8..926a3dc0 100644
--- a/third_party/androidx/committed/libs/androidx_annotation_annotation_jvm/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_annotation_annotation_jvm/README.chromium
@@ -1,6 +1,6 @@
 Name: Annotation
 Short Name: annotation-jvm
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/annotation/annotation-jvm/1.10.0-SNAPSHOT/annotation-jvm-1.10.0-20251126.133552-1.jar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/annotation/annotation-jvm/1.10.0-SNAPSHOT/annotation-jvm-1.10.0-20251209.213522-1.jar
 Version: 1.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_appcompat_appcompat/README.chromium b/third_party/androidx/committed/libs/androidx_appcompat_appcompat/README.chromium
index d5fc0680..02a372d 100644
--- a/third_party/androidx/committed/libs/androidx_appcompat_appcompat/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_appcompat_appcompat/README.chromium
@@ -1,6 +1,6 @@
 Name: AppCompat
 Short Name: appcompat
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/appcompat/appcompat/1.8.0-SNAPSHOT/appcompat-1.8.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/appcompat/appcompat/1.8.0-SNAPSHOT/appcompat-1.8.0-20251209.213522-1.aar
 Version: 1.8.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_appcompat_appcompat_resources/README.chromium b/third_party/androidx/committed/libs/androidx_appcompat_appcompat_resources/README.chromium
index 8b9d396..97ac1b7f 100644
--- a/third_party/androidx/committed/libs/androidx_appcompat_appcompat_resources/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_appcompat_appcompat_resources/README.chromium
@@ -1,6 +1,6 @@
 Name: AppCompat Resources
 Short Name: appcompat-resources
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/appcompat/appcompat-resources/1.8.0-SNAPSHOT/appcompat-resources-1.8.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/appcompat/appcompat-resources/1.8.0-SNAPSHOT/appcompat-resources-1.8.0-20251209.213522-1.aar
 Version: 1.8.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_appsearch_appsearch/README.chromium b/third_party/androidx/committed/libs/androidx_appsearch_appsearch/README.chromium
index cb6584ca..0c58c5e0 100644
--- a/third_party/androidx/committed/libs/androidx_appsearch_appsearch/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_appsearch_appsearch/README.chromium
@@ -1,6 +1,6 @@
 Name: AppSearch
 Short Name: appsearch
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/appsearch/appsearch/1.2.0-SNAPSHOT/appsearch-1.2.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/appsearch/appsearch/1.2.0-SNAPSHOT/appsearch-1.2.0-20251209.213522-1.aar
 Version: 1.2.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_appsearch_appsearch_builtin_types/README.chromium b/third_party/androidx/committed/libs/androidx_appsearch_appsearch_builtin_types/README.chromium
index 85f53c9..7bc4732 100644
--- a/third_party/androidx/committed/libs/androidx_appsearch_appsearch_builtin_types/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_appsearch_appsearch_builtin_types/README.chromium
@@ -1,6 +1,6 @@
 Name: AppSearch Builtin Types
 Short Name: appsearch-builtin-types
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/appsearch/appsearch-builtin-types/1.2.0-SNAPSHOT/appsearch-builtin-types-1.2.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/appsearch/appsearch-builtin-types/1.2.0-SNAPSHOT/appsearch-builtin-types-1.2.0-20251209.213522-1.aar
 Version: 1.2.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_appsearch_appsearch_platform_storage/README.chromium b/third_party/androidx/committed/libs/androidx_appsearch_appsearch_platform_storage/README.chromium
index fc24ece..37ed321 100644
--- a/third_party/androidx/committed/libs/androidx_appsearch_appsearch_platform_storage/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_appsearch_appsearch_platform_storage/README.chromium
@@ -1,6 +1,6 @@
 Name: AppSearch Platform Storage
 Short Name: appsearch-platform-storage
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/appsearch/appsearch-platform-storage/1.2.0-SNAPSHOT/appsearch-platform-storage-1.2.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/appsearch/appsearch-platform-storage/1.2.0-SNAPSHOT/appsearch-platform-storage-1.2.0-20251209.213522-1.aar
 Version: 1.2.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_arch_core_core_common/README.chromium b/third_party/androidx/committed/libs/androidx_arch_core_core_common/README.chromium
index 11effe2..1f78681 100644
--- a/third_party/androidx/committed/libs/androidx_arch_core_core_common/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_arch_core_core_common/README.chromium
@@ -1,6 +1,6 @@
 Name: Arch-Common
 Short Name: core-common
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/arch/core/core-common/2.3.0-SNAPSHOT/core-common-2.3.0-20251126.133552-1.jar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/arch/core/core-common/2.3.0-SNAPSHOT/core-common-2.3.0-20251209.213522-1.jar
 Version: 2.3.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_arch_core_core_runtime/README.chromium b/third_party/androidx/committed/libs/androidx_arch_core_core_runtime/README.chromium
index f601ced4..24f10c83 100644
--- a/third_party/androidx/committed/libs/androidx_arch_core_core_runtime/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_arch_core_core_runtime/README.chromium
@@ -1,6 +1,6 @@
 Name: Arch-Runtime
 Short Name: core-runtime
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/arch/core/core-runtime/2.3.0-SNAPSHOT/core-runtime-2.3.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/arch/core/core-runtime/2.3.0-SNAPSHOT/core-runtime-2.3.0-20251209.213522-1.aar
 Version: 2.3.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_autofill_autofill/README.chromium b/third_party/androidx/committed/libs/androidx_autofill_autofill/README.chromium
index a7b598a1..693952a1 100644
--- a/third_party/androidx/committed/libs/androidx_autofill_autofill/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_autofill_autofill/README.chromium
@@ -1,6 +1,6 @@
 Name: Autofill
 Short Name: autofill
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/autofill/autofill/1.4.0-SNAPSHOT/autofill-1.4.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/autofill/autofill/1.4.0-SNAPSHOT/autofill-1.4.0-20251209.213522-1.aar
 Version: 1.4.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_common/README.chromium b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_common/README.chromium
index c3adf89..ede001f8 100644
--- a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_common/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_common/README.chromium
@@ -1,6 +1,6 @@
 Name: Benchmark - Common
 Short Name: benchmark-common
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/benchmark/benchmark-common/1.5.0-SNAPSHOT/benchmark-common-1.5.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/benchmark/benchmark-common/1.5.0-SNAPSHOT/benchmark-common-1.5.0-20251209.213522-1.aar
 Version: 1.5.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_junit4/README.chromium b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_junit4/README.chromium
index 4cf3d1e..70638dc7a 100644
--- a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_junit4/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_junit4/README.chromium
@@ -1,6 +1,6 @@
 Name: Benchmark - JUnit4
 Short Name: benchmark-junit4
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/benchmark/benchmark-junit4/1.5.0-SNAPSHOT/benchmark-junit4-1.5.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/benchmark/benchmark-junit4/1.5.0-SNAPSHOT/benchmark-junit4-1.5.0-20251209.213522-1.aar
 Version: 1.5.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro/README.chromium b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro/README.chromium
index 30ecc9da..429de9e3 100644
--- a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro/README.chromium
@@ -1,6 +1,6 @@
 Name: Benchmark - Macrobenchmark
 Short Name: benchmark-macro
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/benchmark/benchmark-macro/1.5.0-SNAPSHOT/benchmark-macro-1.5.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/benchmark/benchmark-macro/1.5.0-SNAPSHOT/benchmark-macro-1.5.0-20251209.213522-1.aar
 Version: 1.5.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro_junit4/README.chromium b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro_junit4/README.chromium
index 0163294..21b87c1 100644
--- a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro_junit4/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_macro_junit4/README.chromium
@@ -1,6 +1,6 @@
 Name: Benchmark - Macrobenchmark JUnit4
 Short Name: benchmark-macro-junit4
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/benchmark/benchmark-macro-junit4/1.5.0-SNAPSHOT/benchmark-macro-junit4-1.5.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/benchmark/benchmark-macro-junit4/1.5.0-SNAPSHOT/benchmark-macro-junit4-1.5.0-20251209.213522-1.aar
 Version: 1.5.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_traceprocessor_android/README.chromium b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_traceprocessor_android/README.chromium
index 26b6781..955b762 100644
--- a/third_party/androidx/committed/libs/androidx_benchmark_benchmark_traceprocessor_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_benchmark_benchmark_traceprocessor_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Benchmark TraceProcessor
 Short Name: benchmark-traceprocessor-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/benchmark/benchmark-traceprocessor-android/1.5.0-SNAPSHOT/benchmark-traceprocessor-android-1.5.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/benchmark/benchmark-traceprocessor-android/1.5.0-SNAPSHOT/benchmark-traceprocessor-android-1.5.0-20251209.213522-1.aar
 Version: 1.5.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_biometric_biometric/README.chromium b/third_party/androidx/committed/libs/androidx_biometric_biometric/README.chromium
index 57921dc..e200d24 100644
--- a/third_party/androidx/committed/libs/androidx_biometric_biometric/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_biometric_biometric/README.chromium
@@ -1,6 +1,6 @@
 Name: Biometric
 Short Name: biometric
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/biometric/biometric/1.4.0-SNAPSHOT/biometric-1.4.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/biometric/biometric/1.4.0-SNAPSHOT/biometric-1.4.0-20251209.213522-1.aar
 Version: 1.4.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_browser_browser/README.chromium b/third_party/androidx/committed/libs/androidx_browser_browser/README.chromium
index e149223..591b9a17 100644
--- a/third_party/androidx/committed/libs/androidx_browser_browser/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_browser_browser/README.chromium
@@ -1,6 +1,6 @@
 Name: Browser
 Short Name: browser
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/browser/browser/1.10.0-SNAPSHOT/browser-1.10.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/browser/browser/1.10.0-SNAPSHOT/browser-1.10.0-20251209.213522-1.aar
 Version: 1.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_cardview_cardview/README.chromium b/third_party/androidx/committed/libs/androidx_cardview_cardview/README.chromium
index d752f83..079ab642 100644
--- a/third_party/androidx/committed/libs/androidx_cardview_cardview/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_cardview_cardview/README.chromium
@@ -1,6 +1,6 @@
 Name: CardView
 Short Name: cardview
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/cardview/cardview/1.1.0-SNAPSHOT/cardview-1.1.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/cardview/cardview/1.1.0-SNAPSHOT/cardview-1.1.0-20251209.213522-1.aar
 Version: 1.1.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_collection_collection_jvm/README.chromium b/third_party/androidx/committed/libs/androidx_collection_collection_jvm/README.chromium
index 88a1b0f..9c5fcce 100644
--- a/third_party/androidx/committed/libs/androidx_collection_collection_jvm/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_collection_collection_jvm/README.chromium
@@ -1,6 +1,6 @@
 Name: collections
 Short Name: collection-jvm
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/collection/collection-jvm/1.6.0-SNAPSHOT/collection-jvm-1.6.0-20251126.133552-1.jar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/collection/collection-jvm/1.6.0-SNAPSHOT/collection-jvm-1.6.0-20251209.213522-1.jar
 Version: 1.6.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_collection_collection_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_collection_collection_ktx/README.chromium
index d5b04f12..ee133f32 100644
--- a/third_party/androidx/committed/libs/androidx_collection_collection_ktx/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_collection_collection_ktx/README.chromium
@@ -1,6 +1,6 @@
 Name: Collections Kotlin Extensions
 Short Name: collection-ktx
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/collection/collection-ktx/1.6.0-SNAPSHOT/collection-ktx-1.6.0-20251126.133552-1.jar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/collection/collection-ktx/1.6.0-SNAPSHOT/collection-ktx-1.6.0-20251209.213522-1.jar
 Version: 1.6.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_animation_animation_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_animation_animation_android/README.chromium
index 81d945a..f83880f0 100644
--- a/third_party/androidx/committed/libs/androidx_compose_animation_animation_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_animation_animation_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Animation
 Short Name: animation-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/compose/animation/animation-android/1.11.0-SNAPSHOT/animation-android-1.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/compose/animation/animation-android/1.11.0-SNAPSHOT/animation-android-1.11.0-20251209.213522-1.aar
 Version: 1.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_animation_animation_core_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_animation_animation_core_android/README.chromium
index f069ffb..9aa063d 100644
--- a/third_party/androidx/committed/libs/androidx_compose_animation_animation_core_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_animation_animation_core_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Animation Core
 Short Name: animation-core-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/compose/animation/animation-core-android/1.11.0-SNAPSHOT/animation-core-android-1.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/compose/animation/animation-core-android/1.11.0-SNAPSHOT/animation-core-android-1.11.0-20251209.213522-1.aar
 Version: 1.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_android/README.chromium
index fd080737..4920251 100644
--- a/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Foundation
 Short Name: foundation-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/compose/foundation/foundation-android/1.11.0-SNAPSHOT/foundation-android-1.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/compose/foundation/foundation-android/1.11.0-SNAPSHOT/foundation-android-1.11.0-20251209.213522-1.aar
 Version: 1.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_layout_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_layout_android/README.chromium
index 37b893b..5e980c0 100644
--- a/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_layout_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_layout_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Layouts
 Short Name: foundation-layout-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/compose/foundation/foundation-layout-android/1.11.0-SNAPSHOT/foundation-layout-android-1.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/compose/foundation/foundation-layout-android/1.11.0-SNAPSHOT/foundation-layout-android-1.11.0-20251209.213522-1.aar
 Version: 1.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_material3_material3_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_material3_material3_android/README.chromium
index 0251352c..5960bd1 100644
--- a/third_party/androidx/committed/libs/androidx_compose_material3_material3_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_material3_material3_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Material3 Components
 Short Name: material3-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/compose/material3/material3-android/1.5.0-SNAPSHOT/material3-android-1.5.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/compose/material3/material3-android/1.5.0-SNAPSHOT/material3-android-1.5.0-20251209.213522-1.aar
 Version: 1.5.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_material_material_ripple_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_material_material_ripple_android/README.chromium
index 400d34f7..aa0a7e0 100644
--- a/third_party/androidx/committed/libs/androidx_compose_material_material_ripple_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_material_material_ripple_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Material Ripple
 Short Name: material-ripple-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/compose/material/material-ripple-android/1.11.0-SNAPSHOT/material-ripple-android-1.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/compose/material/material-ripple-android/1.11.0-SNAPSHOT/material-ripple-android-1.11.0-20251209.213522-1.aar
 Version: 1.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_android/README.chromium
index 657478a..c8a844f 100644
--- a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Runtime
 Short Name: runtime-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/compose/runtime/runtime-android/1.11.0-SNAPSHOT/runtime-android-1.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/compose/runtime/runtime-android/1.11.0-SNAPSHOT/runtime-android-1.11.0-20251209.213522-1.aar
 Version: 1.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_annotation_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_annotation_android/README.chromium
index 80b5b8ca..880aba9 100644
--- a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_annotation_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_annotation_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Runtime Annotation
 Short Name: runtime-annotation-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/compose/runtime/runtime-annotation-android/1.11.0-SNAPSHOT/runtime-annotation-android-1.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/compose/runtime/runtime-annotation-android/1.11.0-SNAPSHOT/runtime-annotation-android-1.11.0-20251209.213522-1.aar
 Version: 1.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_retain_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_retain_android/README.chromium
index aa08ba4..44caa11 100644
--- a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_retain_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_retain_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Runtime Retain
 Short Name: runtime-retain-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/compose/runtime/runtime-retain-android/1.11.0-SNAPSHOT/runtime-retain-android-1.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/compose/runtime/runtime-retain-android/1.11.0-SNAPSHOT/runtime-retain-android-1.11.0-20251209.213522-1.aar
 Version: 1.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_saveable_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_saveable_android/README.chromium
index 2ae65ef..9e9503e6 100644
--- a/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_saveable_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_saveable_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Saveable
 Short Name: runtime-saveable-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/compose/runtime/runtime-saveable-android/1.11.0-SNAPSHOT/runtime-saveable-android-1.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/compose/runtime/runtime-saveable-android/1.11.0-SNAPSHOT/runtime-saveable-android-1.11.0-20251209.213522-1.aar
 Version: 1.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_android/README.chromium
index cb5ea87..2195a34 100644
--- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose UI
 Short Name: ui-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/compose/ui/ui-android/1.11.0-SNAPSHOT/ui-android-1.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/compose/ui/ui-android/1.11.0-SNAPSHOT/ui-android-1.11.0-20251209.213522-1.aar
 Version: 1.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_geometry_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_geometry_android/README.chromium
index a7ddd66..689a21c9 100644
--- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_geometry_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_geometry_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Geometry
 Short Name: ui-geometry-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/compose/ui/ui-geometry-android/1.11.0-SNAPSHOT/ui-geometry-android-1.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/compose/ui/ui-geometry-android/1.11.0-SNAPSHOT/ui-geometry-android-1.11.0-20251209.213522-1.aar
 Version: 1.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_graphics_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_graphics_android/README.chromium
index 1ced5c61..1845a09 100644
--- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_graphics_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_graphics_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Graphics
 Short Name: ui-graphics-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/compose/ui/ui-graphics-android/1.11.0-SNAPSHOT/ui-graphics-android-1.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/compose/ui/ui-graphics-android/1.11.0-SNAPSHOT/ui-graphics-android-1.11.0-20251209.213522-1.aar
 Version: 1.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_android/README.chromium
index 570842c..ce8c6d7 100644
--- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Testing
 Short Name: ui-test-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/compose/ui/ui-test-android/1.11.0-SNAPSHOT/ui-test-android-1.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/compose/ui/ui-test-android/1.11.0-SNAPSHOT/ui-test-android-1.11.0-20251209.213522-1.aar
 Version: 1.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_junit4_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_junit4_android/README.chromium
index de13008..90672ea 100644
--- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_junit4_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_junit4_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Testing for JUnit4
 Short Name: ui-test-junit4-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/compose/ui/ui-test-junit4-android/1.11.0-SNAPSHOT/ui-test-junit4-android-1.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/compose/ui/ui-test-junit4-android/1.11.0-SNAPSHOT/ui-test-junit4-android-1.11.0-20251209.213522-1.aar
 Version: 1.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_manifest/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_manifest/README.chromium
index 5920172c..889770e6 100644
--- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_manifest/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_test_manifest/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Testing manifest dependency
 Short Name: ui-test-manifest
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/compose/ui/ui-test-manifest/1.11.0-SNAPSHOT/ui-test-manifest-1.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/compose/ui/ui-test-manifest/1.11.0-SNAPSHOT/ui-test-manifest-1.11.0-20251209.213522-1.aar
 Version: 1.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_android/README.chromium
index 6098b6d..520a136 100644
--- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose UI Text
 Short Name: ui-text-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/compose/ui/ui-text-android/1.11.0-SNAPSHOT/ui-text-android-1.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/compose/ui/ui-text-android/1.11.0-SNAPSHOT/ui-text-android-1.11.0-20251209.213522-1.aar
 Version: 1.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_google_fonts/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_google_fonts/README.chromium
index 0d0ce3d..6cd0a47 100644
--- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_google_fonts/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_google_fonts/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Google Fonts integration
 Short Name: ui-text-google-fonts
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/compose/ui/ui-text-google-fonts/1.11.0-SNAPSHOT/ui-text-google-fonts-1.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/compose/ui/ui-text-google-fonts/1.11.0-SNAPSHOT/ui-text-google-fonts-1.11.0-20251209.213522-1.aar
 Version: 1.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_unit_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_unit_android/README.chromium
index 95adbdc..adff4f87 100644
--- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_unit_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_unit_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Unit
 Short Name: ui-unit-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/compose/ui/ui-unit-android/1.11.0-SNAPSHOT/ui-unit-android-1.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/compose/ui/ui-unit-android/1.11.0-SNAPSHOT/ui-unit-android-1.11.0-20251209.213522-1.aar
 Version: 1.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_compose_ui_ui_util_android/README.chromium b/third_party/androidx/committed/libs/androidx_compose_ui_ui_util_android/README.chromium
index 10544de7e..78163aa 100644
--- a/third_party/androidx/committed/libs/androidx_compose_ui_ui_util_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_compose_ui_ui_util_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Util
 Short Name: ui-util-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/compose/ui/ui-util-android/1.11.0-SNAPSHOT/ui-util-android-1.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/compose/ui/ui-util-android/1.11.0-SNAPSHOT/ui-util-android-1.11.0-20251209.213522-1.aar
 Version: 1.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout/README.chromium b/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout/README.chromium
index b4455070..0aa6029 100644
--- a/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout/README.chromium
@@ -1,6 +1,6 @@
 Name: ConstraintLayout
 Short Name: constraintlayout
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/constraintlayout/constraintlayout/2.3.0-SNAPSHOT/constraintlayout-2.3.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/constraintlayout/constraintlayout/2.3.0-SNAPSHOT/constraintlayout-2.3.0-20251209.213522-1.aar
 Version: 2.3.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout_core/README.chromium b/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout_core/README.chromium
index 68ea2378..b7a2cf2 100644
--- a/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout_core/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout_core/README.chromium
@@ -1,6 +1,6 @@
 Name: ConstraintLayout Core
 Short Name: constraintlayout-core
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/constraintlayout/constraintlayout-core/1.2.0-SNAPSHOT/constraintlayout-core-1.2.0-20251126.133552-1.jar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/constraintlayout/constraintlayout-core/1.2.0-SNAPSHOT/constraintlayout-core-1.2.0-20251209.213522-1.jar
 Version: 1.2.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_core_core/README.chromium b/third_party/androidx/committed/libs/androidx_core_core/README.chromium
index b6a5e7e2..cb8a463 100644
--- a/third_party/androidx/committed/libs/androidx_core_core/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_core_core/README.chromium
@@ -1,6 +1,6 @@
 Name: Core
 Short Name: core
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/core/core/1.18.0-SNAPSHOT/core-1.18.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/core/core/1.18.0-SNAPSHOT/core-1.18.0-20251209.213522-1.aar
 Version: 1.18.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_core_core_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_core_core_ktx/README.chromium
index 139ce3d..db80191 100644
--- a/third_party/androidx/committed/libs/androidx_core_core_ktx/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_core_core_ktx/README.chromium
@@ -1,6 +1,6 @@
 Name: Core Kotlin Extensions
 Short Name: core-ktx
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/core/core-ktx/1.18.0-SNAPSHOT/core-ktx-1.18.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/core/core-ktx/1.18.0-SNAPSHOT/core-ktx-1.18.0-20251209.213522-1.aar
 Version: 1.18.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_core_core_viewtree/README.chromium b/third_party/androidx/committed/libs/androidx_core_core_viewtree/README.chromium
index 61ba08f9..cc260812 100644
--- a/third_party/androidx/committed/libs/androidx_core_core_viewtree/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_core_core_viewtree/README.chromium
@@ -1,6 +1,6 @@
 Name: androidx.core:core-viewtree
 Short Name: core-viewtree
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/core/core-viewtree/1.1.0-SNAPSHOT/core-viewtree-1.1.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/core/core-viewtree/1.1.0-SNAPSHOT/core-viewtree-1.1.0-20251209.213522-1.aar
 Version: 1.1.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_credentials_credentials/README.chromium b/third_party/androidx/committed/libs/androidx_credentials_credentials/README.chromium
index bbd1d48..fc055ab 100644
--- a/third_party/androidx/committed/libs/androidx_credentials_credentials/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_credentials_credentials/README.chromium
@@ -1,6 +1,6 @@
 Name: Credentials
 Short Name: credentials
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/credentials/credentials/1.6.0-SNAPSHOT/credentials-1.6.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/credentials/credentials/1.6.0-SNAPSHOT/credentials-1.6.0-20251209.213522-1.aar
 Version: 1.6.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_credentials_credentials_play_services_auth/README.chromium b/third_party/androidx/committed/libs/androidx_credentials_credentials_play_services_auth/README.chromium
index 7fc5726..1f570a3 100644
--- a/third_party/androidx/committed/libs/androidx_credentials_credentials_play_services_auth/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_credentials_credentials_play_services_auth/README.chromium
@@ -1,6 +1,6 @@
 Name: Credentials Play Services Auth
 Short Name: credentials-play-services-auth
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/credentials/credentials-play-services-auth/1.6.0-SNAPSHOT/credentials-play-services-auth-1.6.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/credentials/credentials-play-services-auth/1.6.0-SNAPSHOT/credentials-play-services-auth-1.6.0-20251209.213522-1.aar
 Version: 1.6.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider/README.chromium b/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider/README.chromium
index 6d568ea..339311f 100644
--- a/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider/README.chromium
@@ -1,6 +1,6 @@
 Name: androidx.credentials.registry:registry-provider
 Short Name: registry-provider
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/credentials/registry/registry-provider/1.0.0-SNAPSHOT/registry-provider-1.0.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/credentials/registry/registry-provider/1.0.0-SNAPSHOT/registry-provider-1.0.0-20251209.213522-1.aar
 Version: 1.0.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider_play_services/README.chromium b/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider_play_services/README.chromium
index bbfe09e..0bedf99 100644
--- a/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider_play_services/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider_play_services/README.chromium
@@ -1,6 +1,6 @@
 Name: androidx.credentials.registry:registry-provider-play-services
 Short Name: registry-provider-play-services
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/credentials/registry/registry-provider-play-services/1.0.0-SNAPSHOT/registry-provider-play-services-1.0.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/credentials/registry/registry-provider-play-services/1.0.0-SNAPSHOT/registry-provider-play-services-1.0.0-20251209.213522-1.aar
 Version: 1.0.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_cursoradapter_cursoradapter/README.chromium b/third_party/androidx/committed/libs/androidx_cursoradapter_cursoradapter/README.chromium
index ce27b4c..e7f3168f 100644
--- a/third_party/androidx/committed/libs/androidx_cursoradapter_cursoradapter/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_cursoradapter_cursoradapter/README.chromium
@@ -1,6 +1,6 @@
 Name: Cursor Adapter
 Short Name: cursoradapter
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/cursoradapter/cursoradapter/1.1.0-SNAPSHOT/cursoradapter-1.1.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/cursoradapter/cursoradapter/1.1.0-SNAPSHOT/cursoradapter-1.1.0-20251209.213522-1.aar
 Version: 1.1.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_android/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_android/README.chromium
index 098dc79..e9f8720a 100644
--- a/third_party/androidx/committed/libs/androidx_datastore_datastore_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_android/README.chromium
@@ -1,6 +1,6 @@
 Name: DataStore
 Short Name: datastore-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/datastore/datastore-android/1.3.0-SNAPSHOT/datastore-android-1.3.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/datastore/datastore-android/1.3.0-SNAPSHOT/datastore-android-1.3.0-20251209.213522-1.aar
 Version: 1.3.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_core_android/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_core_android/README.chromium
index e348102..7f7956e7 100644
--- a/third_party/androidx/committed/libs/androidx_datastore_datastore_core_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_core_android/README.chromium
@@ -1,6 +1,6 @@
 Name: DataStore Core
 Short Name: datastore-core-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/datastore/datastore-core-android/1.3.0-SNAPSHOT/datastore-core-android-1.3.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/datastore/datastore-core-android/1.3.0-SNAPSHOT/datastore-core-android-1.3.0-20251209.213522-1.aar
 Version: 1.3.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_core_okio_jvm/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_core_okio_jvm/README.chromium
index 006e982..9232f45 100644
--- a/third_party/androidx/committed/libs/androidx_datastore_datastore_core_okio_jvm/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_core_okio_jvm/README.chromium
@@ -1,6 +1,6 @@
 Name: DataStore Core Okio
 Short Name: datastore-core-okio-jvm
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/datastore/datastore-core-okio-jvm/1.3.0-SNAPSHOT/datastore-core-okio-jvm-1.3.0-20251126.133552-1.jar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/datastore/datastore-core-okio-jvm/1.3.0-SNAPSHOT/datastore-core-okio-jvm-1.3.0-20251209.213522-1.jar
 Version: 1.3.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_android/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_android/README.chromium
index 6a12458..a661bab4 100644
--- a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Preferences DataStore
 Short Name: datastore-preferences-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/datastore/datastore-preferences-android/1.3.0-SNAPSHOT/datastore-preferences-android-1.3.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/datastore/datastore-preferences-android/1.3.0-SNAPSHOT/datastore-preferences-android-1.3.0-20251209.213522-1.aar
 Version: 1.3.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_core_android/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_core_android/README.chromium
index 136f5df..7310936f 100644
--- a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_core_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_core_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Preferences DataStore Core
 Short Name: datastore-preferences-core-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/datastore/datastore-preferences-core-android/1.3.0-SNAPSHOT/datastore-preferences-core-android-1.3.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/datastore/datastore-preferences-core-android/1.3.0-SNAPSHOT/datastore-preferences-core-android-1.3.0-20251209.213522-1.aar
 Version: 1.3.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_external_protobuf/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_external_protobuf/README.chromium
index 4ed51ed..aa84ec2 100644
--- a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_external_protobuf/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_external_protobuf/README.chromium
@@ -1,6 +1,6 @@
 Name: Preferences External Protobuf
 Short Name: datastore-preferences-external-protobuf
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/datastore/datastore-preferences-external-protobuf/1.3.0-SNAPSHOT/datastore-preferences-external-protobuf-1.3.0-20251126.133552-1.jar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/datastore/datastore-preferences-external-protobuf/1.3.0-SNAPSHOT/datastore-preferences-external-protobuf-1.3.0-20251209.213522-1.jar
 Version: 1.3.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: BSD-3-Clause
diff --git a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_proto/README.chromium b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_proto/README.chromium
index 0960104..141f2c7 100644
--- a/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_proto/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_datastore_datastore_preferences_proto/README.chromium
@@ -1,6 +1,6 @@
 Name: Preferences DataStore Proto
 Short Name: datastore-preferences-proto
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/datastore/datastore-preferences-proto/1.3.0-SNAPSHOT/datastore-preferences-proto-1.3.0-20251126.133552-1.jar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/datastore/datastore-preferences-proto/1.3.0-SNAPSHOT/datastore-preferences-proto-1.3.0-20251209.213522-1.jar
 Version: 1.3.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_drawerlayout_drawerlayout/README.chromium b/third_party/androidx/committed/libs/androidx_drawerlayout_drawerlayout/README.chromium
index 941bf07..66cdabb 100644
--- a/third_party/androidx/committed/libs/androidx_drawerlayout_drawerlayout/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_drawerlayout_drawerlayout/README.chromium
@@ -1,6 +1,6 @@
 Name: Drawer Layout
 Short Name: drawerlayout
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/drawerlayout/drawerlayout/1.3.0-SNAPSHOT/drawerlayout-1.3.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/drawerlayout/drawerlayout/1.3.0-SNAPSHOT/drawerlayout-1.3.0-20251209.213522-1.aar
 Version: 1.3.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_emoji_emoji/README.chromium b/third_party/androidx/committed/libs/androidx_emoji_emoji/README.chromium
index 48cb51d5..ddab5e6 100644
--- a/third_party/androidx/committed/libs/androidx_emoji_emoji/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_emoji_emoji/README.chromium
@@ -1,6 +1,6 @@
 Name: Emoji
 Short Name: emoji
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/emoji/emoji/1.2.0-SNAPSHOT/emoji-1.2.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/emoji/emoji/1.2.0-SNAPSHOT/emoji-1.2.0-20251209.213522-1.aar
 Version: 1.2.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0, SIL Open Font License, Version 1.1, Unicode, Inc. License
diff --git a/third_party/androidx/committed/libs/androidx_exifinterface_exifinterface/README.chromium b/third_party/androidx/committed/libs/androidx_exifinterface_exifinterface/README.chromium
index fbcd7d0..ea2dedc 100644
--- a/third_party/androidx/committed/libs/androidx_exifinterface_exifinterface/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_exifinterface_exifinterface/README.chromium
@@ -1,7 +1,7 @@
 Name: ExifInterface
 Short Name: exifinterface
-URL: https://dl.google.com/dl/android/maven2/androidx/exifinterface/exifinterface/1.4.1/exifinterface-1.4.1.aar
-Version: 1.4.1
+URL: https://dl.google.com/dl/android/maven2/androidx/exifinterface/exifinterface/1.4.2/exifinterface-1.4.2.aar
+Version: 1.4.2
 Update Mechanism: Autoroll
 License: Apache-2.0
 License File: LICENSE
@@ -13,7 +13,7 @@
 Description:
 Android Support ExifInterface
 
-See also: https://developer.android.com/jetpack/androidx/releases/exifinterface#1.4.1
+See also: https://developer.android.com/jetpack/androidx/releases/exifinterface#1.4.2
 
 
 Local Modifications:
diff --git a/third_party/androidx/committed/libs/androidx_fragment_fragment/README.chromium b/third_party/androidx/committed/libs/androidx_fragment_fragment/README.chromium
index 9c0ddf7..16713be 100644
--- a/third_party/androidx/committed/libs/androidx_fragment_fragment/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_fragment_fragment/README.chromium
@@ -1,6 +1,6 @@
 Name: fragment
 Short Name: fragment
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/fragment/fragment/1.9.0-SNAPSHOT/fragment-1.9.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/fragment/fragment/1.9.0-SNAPSHOT/fragment-1.9.0-20251209.213522-1.aar
 Version: 1.9.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_fragment_fragment_compose/README.chromium b/third_party/androidx/committed/libs/androidx_fragment_fragment_compose/README.chromium
index 9f4ac18..74b612c 100644
--- a/third_party/androidx/committed/libs/androidx_fragment_fragment_compose/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_fragment_fragment_compose/README.chromium
@@ -1,6 +1,6 @@
 Name: Fragment Compose
 Short Name: fragment-compose
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/fragment/fragment-compose/1.9.0-SNAPSHOT/fragment-compose-1.9.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/fragment/fragment-compose/1.9.0-SNAPSHOT/fragment-compose-1.9.0-20251209.213522-1.aar
 Version: 1.9.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_fragment_fragment_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_fragment_fragment_ktx/README.chromium
index b1191f0..f9ff695 100644
--- a/third_party/androidx/committed/libs/androidx_fragment_fragment_ktx/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_fragment_fragment_ktx/README.chromium
@@ -1,6 +1,6 @@
 Name: Fragment Kotlin Extensions
 Short Name: fragment-ktx
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/fragment/fragment-ktx/1.9.0-SNAPSHOT/fragment-ktx-1.9.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/fragment/fragment-ktx/1.9.0-SNAPSHOT/fragment-ktx-1.9.0-20251209.213522-1.aar
 Version: 1.9.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_fragment_fragment_testing/README.chromium b/third_party/androidx/committed/libs/androidx_fragment_fragment_testing/README.chromium
index 652ba898..611973d 100644
--- a/third_party/androidx/committed/libs/androidx_fragment_fragment_testing/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_fragment_fragment_testing/README.chromium
@@ -1,6 +1,6 @@
 Name: Fragment Testing Extensions
 Short Name: fragment-testing
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/fragment/fragment-testing/1.9.0-SNAPSHOT/fragment-testing-1.9.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/fragment/fragment-testing/1.9.0-SNAPSHOT/fragment-testing-1.9.0-20251209.213522-1.aar
 Version: 1.9.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_fragment_fragment_testing_manifest/README.chromium b/third_party/androidx/committed/libs/androidx_fragment_fragment_testing_manifest/README.chromium
index 403a177..5343653 100644
--- a/third_party/androidx/committed/libs/androidx_fragment_fragment_testing_manifest/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_fragment_fragment_testing_manifest/README.chromium
@@ -1,6 +1,6 @@
 Name: Fragment Testing Manifest dependency
 Short Name: fragment-testing-manifest
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/fragment/fragment-testing-manifest/1.9.0-SNAPSHOT/fragment-testing-manifest-1.9.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/fragment/fragment-testing-manifest/1.9.0-SNAPSHOT/fragment-testing-manifest-1.9.0-20251209.213522-1.aar
 Version: 1.9.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_graphics_graphics_path/README.chromium b/third_party/androidx/committed/libs/androidx_graphics_graphics_path/README.chromium
index b59c0f4..022b07c 100644
--- a/third_party/androidx/committed/libs/androidx_graphics_graphics_path/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_graphics_graphics_path/README.chromium
@@ -1,6 +1,6 @@
 Name: Android Graphics Path
 Short Name: graphics-path
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/graphics/graphics-path/1.1.0-SNAPSHOT/graphics-path-1.1.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/graphics/graphics-path/1.1.0-SNAPSHOT/graphics-path-1.1.0-20251209.213522-1.aar
 Version: 1.1.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_interpolator_interpolator/README.chromium b/third_party/androidx/committed/libs/androidx_interpolator_interpolator/README.chromium
index 790af45..0563189 100644
--- a/third_party/androidx/committed/libs/androidx_interpolator_interpolator/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_interpolator_interpolator/README.chromium
@@ -1,6 +1,6 @@
 Name: Interpolators
 Short Name: interpolator
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/interpolator/interpolator/1.1.0-SNAPSHOT/interpolator-1.1.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/interpolator/interpolator/1.1.0-SNAPSHOT/interpolator-1.1.0-20251209.213522-1.aar
 Version: 1.1.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_java8/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_java8/README.chromium
index c551340..1c363f6 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_java8/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_java8/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle-Common for Java 8
 Short Name: lifecycle-common-java8
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/lifecycle/lifecycle-common-java8/2.11.0-SNAPSHOT/lifecycle-common-java8-2.11.0-20251126.133552-1.jar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/lifecycle/lifecycle-common-java8/2.11.0-SNAPSHOT/lifecycle-common-java8-2.11.0-20251209.213522-1.jar
 Version: 2.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_jvm/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_jvm/README.chromium
index 1c2ac6b..2b1ce19 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_jvm/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_jvm/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle-Common
 Short Name: lifecycle-common-jvm
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/lifecycle/lifecycle-common-jvm/2.11.0-SNAPSHOT/lifecycle-common-jvm-2.11.0-20251126.133552-1.jar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/lifecycle/lifecycle-common-jvm/2.11.0-SNAPSHOT/lifecycle-common-jvm-2.11.0-20251209.213522-1.jar
 Version: 2.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata/README.chromium
index e3c2f25..51a5ec3 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle LiveData
 Short Name: lifecycle-livedata
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/lifecycle/lifecycle-livedata/2.11.0-SNAPSHOT/lifecycle-livedata-2.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/lifecycle/lifecycle-livedata/2.11.0-SNAPSHOT/lifecycle-livedata-2.11.0-20251209.213522-1.aar
 Version: 2.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core/README.chromium
index d695068c..f71f5ee 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle LiveData Core
 Short Name: lifecycle-livedata-core
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/lifecycle/lifecycle-livedata-core/2.11.0-SNAPSHOT/lifecycle-livedata-core-2.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/lifecycle/lifecycle-livedata-core/2.11.0-SNAPSHOT/lifecycle-livedata-core-2.11.0-20251209.213522-1.aar
 Version: 2.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core_ktx/README.chromium
index 94f20d2..b019ccc 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core_ktx/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core_ktx/README.chromium
@@ -1,6 +1,6 @@
 Name: LiveData Core Kotlin Extensions
 Short Name: lifecycle-livedata-core-ktx
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/lifecycle/lifecycle-livedata-core-ktx/2.11.0-SNAPSHOT/lifecycle-livedata-core-ktx-2.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/lifecycle/lifecycle-livedata-core-ktx/2.11.0-SNAPSHOT/lifecycle-livedata-core-ktx-2.11.0-20251209.213522-1.aar
 Version: 2.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_ktx/README.chromium
index 281e69f3..4536a0e 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_ktx/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_ktx/README.chromium
@@ -1,6 +1,6 @@
 Name: LiveData Kotlin Extensions
 Short Name: lifecycle-livedata-ktx
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/lifecycle/lifecycle-livedata-ktx/2.11.0-SNAPSHOT/lifecycle-livedata-ktx-2.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/lifecycle/lifecycle-livedata-ktx/2.11.0-SNAPSHOT/lifecycle-livedata-ktx-2.11.0-20251209.213522-1.aar
 Version: 2.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_process/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_process/README.chromium
index b290902..496e6de 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_process/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_process/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle Process
 Short Name: lifecycle-process
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/lifecycle/lifecycle-process/2.11.0-SNAPSHOT/lifecycle-process-2.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/lifecycle/lifecycle-process/2.11.0-SNAPSHOT/lifecycle-process-2.11.0-20251209.213522-1.aar
 Version: 2.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_android/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_android/README.chromium
index 9666a8f450..2b936095 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle Runtime
 Short Name: lifecycle-runtime-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/lifecycle/lifecycle-runtime-android/2.11.0-SNAPSHOT/lifecycle-runtime-android-2.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/lifecycle/lifecycle-runtime-android/2.11.0-SNAPSHOT/lifecycle-runtime-android-2.11.0-20251209.213522-1.aar
 Version: 2.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_compose_android/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_compose_android/README.chromium
index 022f797e..22fe46b2a 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_compose_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_compose_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle Runtime Compose
 Short Name: lifecycle-runtime-compose-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/lifecycle/lifecycle-runtime-compose-android/2.11.0-SNAPSHOT/lifecycle-runtime-compose-android-2.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/lifecycle/lifecycle-runtime-compose-android/2.11.0-SNAPSHOT/lifecycle-runtime-compose-android-2.11.0-20251209.213522-1.aar
 Version: 2.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_ktx_android/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_ktx_android/README.chromium
index 142949c..9b7b420 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_ktx_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_ktx_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle Kotlin Extensions
 Short Name: lifecycle-runtime-ktx-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/lifecycle/lifecycle-runtime-ktx-android/2.11.0-SNAPSHOT/lifecycle-runtime-ktx-android-2.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/lifecycle/lifecycle-runtime-ktx-android/2.11.0-SNAPSHOT/lifecycle-runtime-ktx-android-2.11.0-20251209.213522-1.aar
 Version: 2.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_service/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_service/README.chromium
index 54511a08..d6c9d9f 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_service/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_service/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle Service
 Short Name: lifecycle-service
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/lifecycle/lifecycle-service/2.11.0-SNAPSHOT/lifecycle-service-2.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/lifecycle/lifecycle-service/2.11.0-SNAPSHOT/lifecycle-service-2.11.0-20251209.213522-1.aar
 Version: 2.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_android/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_android/README.chromium
index 65941b18..a4f7f144 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle ViewModel
 Short Name: lifecycle-viewmodel-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-android/2.11.0-SNAPSHOT/lifecycle-viewmodel-android-2.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-android/2.11.0-SNAPSHOT/lifecycle-viewmodel-android-2.11.0-20251209.213522-1.aar
 Version: 2.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_compose_android/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_compose_android/README.chromium
index 3b13f6f..61faf1f 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_compose_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_compose_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle ViewModel Compose
 Short Name: lifecycle-viewmodel-compose-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-compose-android/2.11.0-SNAPSHOT/lifecycle-viewmodel-compose-android-2.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-compose-android/2.11.0-SNAPSHOT/lifecycle-viewmodel-compose-android-2.11.0-20251209.213522-1.aar
 Version: 2.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_ktx/README.chromium
index 7042f7d..e1c9ba8 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_ktx/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_ktx/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle ViewModel Kotlin Extensions
 Short Name: lifecycle-viewmodel-ktx
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-ktx/2.11.0-SNAPSHOT/lifecycle-viewmodel-ktx-2.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-ktx/2.11.0-SNAPSHOT/lifecycle-viewmodel-ktx-2.11.0-20251209.213522-1.aar
 Version: 2.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_savedstate_android/README.chromium b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_savedstate_android/README.chromium
index a72951a..b4670c3 100644
--- a/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_savedstate_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_savedstate_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Lifecycle ViewModel with SavedState
 Short Name: lifecycle-viewmodel-savedstate-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-savedstate-android/2.11.0-SNAPSHOT/lifecycle-viewmodel-savedstate-android-2.11.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/lifecycle/lifecycle-viewmodel-savedstate-android/2.11.0-SNAPSHOT/lifecycle-viewmodel-savedstate-android-2.11.0-20251209.213522-1.aar
 Version: 2.11.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_loader_loader/README.chromium b/third_party/androidx/committed/libs/androidx_loader_loader/README.chromium
index 50b57a1e..2f68171 100644
--- a/third_party/androidx/committed/libs/androidx_loader_loader/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_loader_loader/README.chromium
@@ -1,6 +1,6 @@
 Name: loader
 Short Name: loader
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/loader/loader/1.2.0-SNAPSHOT/loader-1.2.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/loader/loader/1.2.0-SNAPSHOT/loader-1.2.0-20251209.213522-1.aar
 Version: 1.2.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_media_media/README.chromium b/third_party/androidx/committed/libs/androidx_media_media/README.chromium
index cdaca20..c93b2c8 100644
--- a/third_party/androidx/committed/libs/androidx_media_media/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_media_media/README.chromium
@@ -1,6 +1,6 @@
 Name: Media
 Short Name: media
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/media/media/1.8.0-SNAPSHOT/media-1.8.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/media/media/1.8.0-SNAPSHOT/media-1.8.0-20251209.213522-1.aar
 Version: 1.8.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_mediarouter_mediarouter/README.chromium b/third_party/androidx/committed/libs/androidx_mediarouter_mediarouter/README.chromium
index e62d8dd..a1280aa 100644
--- a/third_party/androidx/committed/libs/androidx_mediarouter_mediarouter/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_mediarouter_mediarouter/README.chromium
@@ -1,6 +1,6 @@
 Name: MediaRouter
 Short Name: mediarouter
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/mediarouter/mediarouter/1.9.0-SNAPSHOT/mediarouter-1.9.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/mediarouter/mediarouter/1.9.0-SNAPSHOT/mediarouter-1.9.0-20251209.213522-1.aar
 Version: 1.9.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_mediarouter_mediarouter/androidx_mediarouter_mediarouter.info b/third_party/androidx/committed/libs/androidx_mediarouter_mediarouter/androidx_mediarouter_mediarouter.info
index baeef99..77a438b0 100644
--- a/third_party/androidx/committed/libs/androidx_mediarouter_mediarouter/androidx_mediarouter_mediarouter.info
+++ b/third_party/androidx/committed/libs/androidx_mediarouter_mediarouter/androidx_mediarouter_mediarouter.info
@@ -19,7 +19,11 @@
   "res/drawable/ic_unchecked_checkbox.xml",
   "res/drawable/ic_vol_mute.xml",
   "res/drawable/ic_vol_type_speaker_dark.xml",
+  "res/drawable/ic_vol_type_speaker_group_dark.xml",
+  "res/drawable/ic_vol_type_speaker_group_light.xml",
   "res/drawable/ic_vol_type_speaker_light.xml",
+  "res/drawable/ic_vol_type_tv_dark.xml",
+  "res/drawable/ic_vol_type_tv_light.xml",
   "res/drawable/ic_vol_unmute.xml",
   "res/drawable/mr_button_connected_dark.xml",
   "res/drawable/mr_button_connected_light.xml",
@@ -52,15 +56,7 @@
   "res/drawable/mr_wifi_icon_dark.xml",
   "res/drawable/mr_wifi_icon_light.xml",
   "res/drawable-hdpi-v4/ic_mr_button_connected_30_dark.png",
-  "res/drawable-hdpi-v4/ic_vol_type_speaker_group_dark.png",
-  "res/drawable-hdpi-v4/ic_vol_type_speaker_group_light.png",
-  "res/drawable-hdpi-v4/ic_vol_type_tv_dark.png",
-  "res/drawable-hdpi-v4/ic_vol_type_tv_light.png",
   "res/drawable-mdpi-v4/ic_mr_button_connected_30_dark.png",
-  "res/drawable-mdpi-v4/ic_vol_type_speaker_group_dark.png",
-  "res/drawable-mdpi-v4/ic_vol_type_speaker_group_light.png",
-  "res/drawable-mdpi-v4/ic_vol_type_tv_dark.png",
-  "res/drawable-mdpi-v4/ic_vol_type_tv_light.png",
   "res/drawable-xhdpi-v4/ic_mr_button_connected_00_dark.png",
   "res/drawable-xhdpi-v4/ic_mr_button_connected_00_light.png",
   "res/drawable-xhdpi-v4/ic_mr_button_connected_01_dark.png",
@@ -185,10 +181,6 @@
   "res/drawable-xhdpi-v4/ic_mr_button_connecting_29_light.png",
   "res/drawable-xhdpi-v4/ic_mr_button_connecting_30_dark.png",
   "res/drawable-xhdpi-v4/ic_mr_button_connecting_30_light.png",
-  "res/drawable-xhdpi-v4/ic_vol_type_speaker_group_dark.png",
-  "res/drawable-xhdpi-v4/ic_vol_type_speaker_group_light.png",
-  "res/drawable-xhdpi-v4/ic_vol_type_tv_dark.png",
-  "res/drawable-xhdpi-v4/ic_vol_type_tv_light.png",
   "res/drawable-xxhdpi-v4/ic_mr_button_connected_00_dark.png",
   "res/drawable-xxhdpi-v4/ic_mr_button_connected_00_light.png",
   "res/drawable-xxhdpi-v4/ic_mr_button_connected_01_dark.png",
@@ -313,10 +305,6 @@
   "res/drawable-xxhdpi-v4/ic_mr_button_connecting_29_light.png",
   "res/drawable-xxhdpi-v4/ic_mr_button_connecting_30_dark.png",
   "res/drawable-xxhdpi-v4/ic_mr_button_connecting_30_light.png",
-  "res/drawable-xxhdpi-v4/ic_vol_type_speaker_group_dark.png",
-  "res/drawable-xxhdpi-v4/ic_vol_type_speaker_group_light.png",
-  "res/drawable-xxhdpi-v4/ic_vol_type_tv_dark.png",
-  "res/drawable-xxhdpi-v4/ic_vol_type_tv_light.png",
   "res/drawable-xxxhdpi-v4/ic_group_collapse_00.png",
   "res/drawable-xxxhdpi-v4/ic_group_collapse_01.png",
   "res/drawable-xxxhdpi-v4/ic_group_collapse_02.png",
diff --git a/third_party/androidx/committed/libs/androidx_navigation_navigation_common_android/README.chromium b/third_party/androidx/committed/libs/androidx_navigation_navigation_common_android/README.chromium
index 02650099..af2bae33 100644
--- a/third_party/androidx/committed/libs/androidx_navigation_navigation_common_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_navigation_navigation_common_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Navigation Common
 Short Name: navigation-common-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/navigation/navigation-common-android/2.10.0-SNAPSHOT/navigation-common-android-2.10.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/navigation/navigation-common-android/2.10.0-SNAPSHOT/navigation-common-android-2.10.0-20251209.213522-1.aar
 Version: 2.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_navigation_navigation_compose_android/README.chromium b/third_party/androidx/committed/libs/androidx_navigation_navigation_compose_android/README.chromium
index 55c767b..9448969 100644
--- a/third_party/androidx/committed/libs/androidx_navigation_navigation_compose_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_navigation_navigation_compose_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Compose Navigation
 Short Name: navigation-compose-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/navigation/navigation-compose-android/2.10.0-SNAPSHOT/navigation-compose-android-2.10.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/navigation/navigation-compose-android/2.10.0-SNAPSHOT/navigation-compose-android-2.10.0-20251209.213522-1.aar
 Version: 2.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_navigation_navigation_runtime_android/README.chromium b/third_party/androidx/committed/libs/androidx_navigation_navigation_runtime_android/README.chromium
index 87a59f1..4a31fd8 100644
--- a/third_party/androidx/committed/libs/androidx_navigation_navigation_runtime_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_navigation_navigation_runtime_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Navigation Runtime
 Short Name: navigation-runtime-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/navigation/navigation-runtime-android/2.10.0-SNAPSHOT/navigation-runtime-android-2.10.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/navigation/navigation-runtime-android/2.10.0-SNAPSHOT/navigation-runtime-android-2.10.0-20251209.213522-1.aar
 Version: 2.10.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/README.chromium b/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/README.chromium
index 2ff7a969..73208bb4 100644
--- a/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Navigation Event
 Short Name: navigationevent-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/navigationevent/navigationevent-android/1.1.0-SNAPSHOT/navigationevent-android-1.1.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/navigationevent/navigationevent-android/1.1.0-SNAPSHOT/navigationevent-android-1.1.0-20251209.213522-1.aar
 Version: 1.1.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_compose_android/README.chromium b/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_compose_android/README.chromium
index d5539028..90ce5a7e 100644
--- a/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_compose_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_navigationevent_navigationevent_compose_android/README.chromium
@@ -1,6 +1,6 @@
 Name: NavigationEvent Compose
 Short Name: navigationevent-compose-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/navigationevent/navigationevent-compose-android/1.1.0-SNAPSHOT/navigationevent-compose-android-1.1.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/navigationevent/navigationevent-compose-android/1.1.0-SNAPSHOT/navigationevent-compose-android-1.1.0-20251209.213522-1.aar
 Version: 1.1.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_paging_paging_common_android/README.chromium b/third_party/androidx/committed/libs/androidx_paging_paging_common_android/README.chromium
index fb89746f..36317beb 100644
--- a/third_party/androidx/committed/libs/androidx_paging_paging_common_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_paging_paging_common_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Paging-Common
 Short Name: paging-common-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/paging/paging-common-android/3.4.0-SNAPSHOT/paging-common-android-3.4.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/paging/paging-common-android/3.4.0-SNAPSHOT/paging-common-android-3.4.0-20251209.213522-1.aar
 Version: 3.4.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_paging_paging_common_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_paging_paging_common_ktx/README.chromium
index 789d0168..7d7d73b 100644
--- a/third_party/androidx/committed/libs/androidx_paging_paging_common_ktx/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_paging_paging_common_ktx/README.chromium
@@ -1,6 +1,6 @@
 Name: Paging-Common Kotlin Extensions
 Short Name: paging-common-ktx
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/paging/paging-common-ktx/3.4.0-SNAPSHOT/paging-common-ktx-3.4.0-20251126.133552-1.jar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/paging/paging-common-ktx/3.4.0-SNAPSHOT/paging-common-ktx-3.4.0-20251209.213522-1.jar
 Version: 3.4.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_paging_paging_compose_android/README.chromium b/third_party/androidx/committed/libs/androidx_paging_paging_compose_android/README.chromium
index cc4f9b5..9a10944 100644
--- a/third_party/androidx/committed/libs/androidx_paging_paging_compose_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_paging_paging_compose_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Paging-Compose
 Short Name: paging-compose-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/paging/paging-compose-android/3.4.0-SNAPSHOT/paging-compose-android-3.4.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/paging/paging-compose-android/3.4.0-SNAPSHOT/paging-compose-android-3.4.0-20251209.213522-1.aar
 Version: 3.4.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_paging_paging_runtime/README.chromium b/third_party/androidx/committed/libs/androidx_paging_paging_runtime/README.chromium
index 220137f..c2d968a8 100644
--- a/third_party/androidx/committed/libs/androidx_paging_paging_runtime/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_paging_paging_runtime/README.chromium
@@ -1,6 +1,6 @@
 Name: Paging-Runtime
 Short Name: paging-runtime
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/paging/paging-runtime/3.4.0-SNAPSHOT/paging-runtime-3.4.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/paging/paging-runtime/3.4.0-SNAPSHOT/paging-runtime-3.4.0-20251209.213522-1.aar
 Version: 3.4.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_palette_palette/README.chromium b/third_party/androidx/committed/libs/androidx_palette_palette/README.chromium
index b8ec0b3..7273030f 100644
--- a/third_party/androidx/committed/libs/androidx_palette_palette/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_palette_palette/README.chromium
@@ -1,6 +1,6 @@
 Name: Palette
 Short Name: palette
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/palette/palette/1.1.0-SNAPSHOT/palette-1.1.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/palette/palette/1.1.0-SNAPSHOT/palette-1.1.0-20251209.213522-1.aar
 Version: 1.1.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_pdf_pdf_document_service/README.chromium b/third_party/androidx/committed/libs/androidx_pdf_pdf_document_service/README.chromium
index 28c9fa9..f49b52bc 100644
--- a/third_party/androidx/committed/libs/androidx_pdf_pdf_document_service/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_pdf_pdf_document_service/README.chromium
@@ -1,6 +1,6 @@
 Name: androidx.pdf:pdf-document-service
 Short Name: pdf-document-service
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/pdf/pdf-document-service/1.0.0-SNAPSHOT/pdf-document-service-1.0.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/pdf/pdf-document-service/1.0.0-SNAPSHOT/pdf-document-service-1.0.0-20251209.213522-1.aar
 Version: 1.0.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer/README.chromium b/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer/README.chromium
index d1335df..13d772fe 100644
--- a/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer/README.chromium
@@ -1,6 +1,6 @@
 Name: androidx.pdf:pdf-viewer
 Short Name: pdf-viewer
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/pdf/pdf-viewer/1.0.0-SNAPSHOT/pdf-viewer-1.0.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/pdf/pdf-viewer/1.0.0-SNAPSHOT/pdf-viewer-1.0.0-20251209.213522-1.aar
 Version: 1.0.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer_fragment/README.chromium b/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer_fragment/README.chromium
index aa50ea6..9fc8a12 100644
--- a/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer_fragment/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer_fragment/README.chromium
@@ -1,6 +1,6 @@
 Name: androidx.pdf:pdf-viewer-fragment
 Short Name: pdf-viewer-fragment
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/pdf/pdf-viewer-fragment/1.0.0-SNAPSHOT/pdf-viewer-fragment-1.0.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/pdf/pdf-viewer-fragment/1.0.0-SNAPSHOT/pdf-viewer-fragment-1.0.0-20251209.213522-1.aar
 Version: 1.0.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_preference_preference/README.chromium b/third_party/androidx/committed/libs/androidx_preference_preference/README.chromium
index d0af1e9..9986e2a 100644
--- a/third_party/androidx/committed/libs/androidx_preference_preference/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_preference_preference/README.chromium
@@ -1,6 +1,6 @@
 Name: Preference
 Short Name: preference
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/preference/preference/1.3.0-SNAPSHOT/preference-1.3.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/preference/preference/1.3.0-SNAPSHOT/preference-1.3.0-20251209.213522-1.aar
 Version: 1.3.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_profileinstaller_profileinstaller/README.chromium b/third_party/androidx/committed/libs/androidx_profileinstaller_profileinstaller/README.chromium
index 674d08f..f1fb86ab 100644
--- a/third_party/androidx/committed/libs/androidx_profileinstaller_profileinstaller/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_profileinstaller_profileinstaller/README.chromium
@@ -1,6 +1,6 @@
 Name: Profile Installer
 Short Name: profileinstaller
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/profileinstaller/profileinstaller/1.5.0-SNAPSHOT/profileinstaller-1.5.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/profileinstaller/profileinstaller/1.5.0-SNAPSHOT/profileinstaller-1.5.0-20251209.213522-1.aar
 Version: 1.5.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_recyclerview_recyclerview/README.chromium b/third_party/androidx/committed/libs/androidx_recyclerview_recyclerview/README.chromium
index 3aabeb6..1161771 100644
--- a/third_party/androidx/committed/libs/androidx_recyclerview_recyclerview/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_recyclerview_recyclerview/README.chromium
@@ -1,6 +1,6 @@
 Name: RecyclerView
 Short Name: recyclerview
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/recyclerview/recyclerview/1.5.0-SNAPSHOT/recyclerview-1.5.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/recyclerview/recyclerview/1.5.0-SNAPSHOT/recyclerview-1.5.0-20251209.213522-1.aar
 Version: 1.5.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_resourceinspection_resourceinspection_annotation/README.chromium b/third_party/androidx/committed/libs/androidx_resourceinspection_resourceinspection_annotation/README.chromium
index b15af13..69fda0bf 100644
--- a/third_party/androidx/committed/libs/androidx_resourceinspection_resourceinspection_annotation/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_resourceinspection_resourceinspection_annotation/README.chromium
@@ -1,6 +1,6 @@
 Name: Resource Inspection - Annotations
 Short Name: resourceinspection-annotation
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/resourceinspection/resourceinspection-annotation/1.1.0-SNAPSHOT/resourceinspection-annotation-1.1.0-20251126.133552-1.jar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/resourceinspection/resourceinspection-annotation/1.1.0-SNAPSHOT/resourceinspection-annotation-1.1.0-20251209.213522-1.jar
 Version: 1.1.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_savedstate_savedstate_android/README.chromium b/third_party/androidx/committed/libs/androidx_savedstate_savedstate_android/README.chromium
index cf9fdee..fb8cc0c 100644
--- a/third_party/androidx/committed/libs/androidx_savedstate_savedstate_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_savedstate_savedstate_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Saved State
 Short Name: savedstate-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/savedstate/savedstate-android/1.5.0-SNAPSHOT/savedstate-android-1.5.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/savedstate/savedstate-android/1.5.0-SNAPSHOT/savedstate-android-1.5.0-20251209.213522-1.aar
 Version: 1.5.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_savedstate_savedstate_compose_android/README.chromium b/third_party/androidx/committed/libs/androidx_savedstate_savedstate_compose_android/README.chromium
index ef632f02..db448a1 100644
--- a/third_party/androidx/committed/libs/androidx_savedstate_savedstate_compose_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_savedstate_savedstate_compose_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Saved State Compose
 Short Name: savedstate-compose-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/savedstate/savedstate-compose-android/1.5.0-SNAPSHOT/savedstate-compose-android-1.5.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/savedstate/savedstate-compose-android/1.5.0-SNAPSHOT/savedstate-compose-android-1.5.0-20251209.213522-1.aar
 Version: 1.5.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_savedstate_savedstate_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_savedstate_savedstate_ktx/README.chromium
index 74622cec..48c6f5d 100644
--- a/third_party/androidx/committed/libs/androidx_savedstate_savedstate_ktx/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_savedstate_savedstate_ktx/README.chromium
@@ -1,6 +1,6 @@
 Name: SavedState Kotlin Extensions
 Short Name: savedstate-ktx
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/savedstate/savedstate-ktx/1.5.0-SNAPSHOT/savedstate-ktx-1.5.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/savedstate/savedstate-ktx/1.5.0-SNAPSHOT/savedstate-ktx-1.5.0-20251209.213522-1.aar
 Version: 1.5.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_slidingpanelayout_slidingpanelayout/README.chromium b/third_party/androidx/committed/libs/androidx_slidingpanelayout_slidingpanelayout/README.chromium
index a44a7d9e..610eb5a 100644
--- a/third_party/androidx/committed/libs/androidx_slidingpanelayout_slidingpanelayout/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_slidingpanelayout_slidingpanelayout/README.chromium
@@ -1,6 +1,6 @@
 Name: Sliding Pane Layout
 Short Name: slidingpanelayout
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/slidingpanelayout/slidingpanelayout/1.3.0-SNAPSHOT/slidingpanelayout-1.3.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/slidingpanelayout/slidingpanelayout/1.3.0-SNAPSHOT/slidingpanelayout-1.3.0-20251209.213522-1.aar
 Version: 1.3.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_sqlite_sqlite_android/README.chromium b/third_party/androidx/committed/libs/androidx_sqlite_sqlite_android/README.chromium
index 58c04bf..2e6a41717 100644
--- a/third_party/androidx/committed/libs/androidx_sqlite_sqlite_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_sqlite_sqlite_android/README.chromium
@@ -1,7 +1,7 @@
 Name: SQLite
 Short Name: sqlite-android
-URL: https://dl.google.com/dl/android/maven2/androidx/sqlite/sqlite-android/2.6.2/sqlite-android-2.6.2.aar
-Version: 2.6.2
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/sqlite/sqlite-android/2.7.0-SNAPSHOT/sqlite-android-2.7.0-20251209.213522-1.aar
+Version: 2.7.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
 License File: LICENSE
@@ -13,7 +13,7 @@
 Description:
 SQLite API
 
-See also: https://developer.android.com/jetpack/androidx/releases/sqlite#2.6.2
+See also: https://developer.android.com/jetpack/androidx/releases/sqlite#2.7.0-SNAPSHOT
 
 
 Local Modifications:
diff --git a/third_party/androidx/committed/libs/androidx_sqlite_sqlite_framework_android/README.chromium b/third_party/androidx/committed/libs/androidx_sqlite_sqlite_framework_android/README.chromium
index bd15d6f..ecee87c 100644
--- a/third_party/androidx/committed/libs/androidx_sqlite_sqlite_framework_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_sqlite_sqlite_framework_android/README.chromium
@@ -1,7 +1,7 @@
 Name: SQLite Framework Integration
 Short Name: sqlite-framework-android
-URL: https://dl.google.com/dl/android/maven2/androidx/sqlite/sqlite-framework-android/2.6.2/sqlite-framework-android-2.6.2.aar
-Version: 2.6.2
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/sqlite/sqlite-framework-android/2.7.0-SNAPSHOT/sqlite-framework-android-2.7.0-20251209.213522-1.aar
+Version: 2.7.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
 License File: LICENSE
@@ -13,7 +13,7 @@
 Description:
 The implementation of SQLite library using the framework code.
 
-See also: https://developer.android.com/jetpack/androidx/releases/sqlite#2.6.2
+See also: https://developer.android.com/jetpack/androidx/releases/sqlite#2.7.0-SNAPSHOT
 
 
 Local Modifications:
diff --git a/third_party/androidx/committed/libs/androidx_swiperefreshlayout_swiperefreshlayout/README.chromium b/third_party/androidx/committed/libs/androidx_swiperefreshlayout_swiperefreshlayout/README.chromium
index 1f01da1..a58e735 100644
--- a/third_party/androidx/committed/libs/androidx_swiperefreshlayout_swiperefreshlayout/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_swiperefreshlayout_swiperefreshlayout/README.chromium
@@ -1,7 +1,7 @@
 Name: Swipe Refresh Layout
 Short Name: swiperefreshlayout
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/swiperefreshlayout/swiperefreshlayout/1.2.0-SNAPSHOT/swiperefreshlayout-1.2.0-20251126.133552-1.aar
-Version: 1.2.0-SNAPSHOT
+URL: https://dl.google.com/dl/android/maven2/androidx/swiperefreshlayout/swiperefreshlayout/1.2.0/swiperefreshlayout-1.2.0.aar
+Version: 1.2.0
 Update Mechanism: Autoroll
 License: Apache-2.0
 License File: LICENSE
@@ -13,7 +13,7 @@
 Description:
 The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.
 
-See also: https://developer.android.com/jetpack/androidx/releases/swiperefreshlayout#1.2.0-SNAPSHOT
+See also: https://developer.android.com/jetpack/androidx/releases/swiperefreshlayout#1.2.0
 
 
 Local Modifications:
diff --git a/third_party/androidx/committed/libs/androidx_test_uiautomator_uiautomator/README.chromium b/third_party/androidx/committed/libs/androidx_test_uiautomator_uiautomator/README.chromium
index 35766d7..51fe272 100644
--- a/third_party/androidx/committed/libs/androidx_test_uiautomator_uiautomator/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_test_uiautomator_uiautomator/README.chromium
@@ -1,6 +1,6 @@
 Name: UIAutomator
 Short Name: uiautomator
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/test/uiautomator/uiautomator/2.4.0-SNAPSHOT/uiautomator-2.4.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/test/uiautomator/uiautomator/2.4.0-SNAPSHOT/uiautomator-2.4.0-20251209.213522-1.aar
 Version: 2.4.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_test_uiautomator_uiautomator_shell_android/README.chromium b/third_party/androidx/committed/libs/androidx_test_uiautomator_uiautomator_shell_android/README.chromium
index d177ab1..667e6e5 100644
--- a/third_party/androidx/committed/libs/androidx_test_uiautomator_uiautomator_shell_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_test_uiautomator_uiautomator_shell_android/README.chromium
@@ -1,7 +1,7 @@
 Name: Shell
 Short Name: uiautomator-shell-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/test/uiautomator/uiautomator-shell-android/1.0.0-SNAPSHOT/uiautomator-shell-android-1.0.0-20251126.133552-1.aar
-Version: 1.0.0-SNAPSHOT
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/test/uiautomator/uiautomator-shell-android/2.4.0-SNAPSHOT/uiautomator-shell-android-2.4.0-20251209.213522-1.aar
+Version: 2.4.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
 License File: LICENSE
@@ -13,7 +13,7 @@
 Description:
 Allows executing shell command as shell user for testing purposes.
 
-See also: https://developer.android.com/jetpack/androidx/releases/test-uiautomator#1.0.0-SNAPSHOT
+See also: https://developer.android.com/jetpack/androidx/releases/test-uiautomator#2.4.0-SNAPSHOT
 
 
 Local Modifications:
diff --git a/third_party/androidx/committed/libs/androidx_tracing_tracing_android/README.chromium b/third_party/androidx/committed/libs/androidx_tracing_tracing_android/README.chromium
index cbd6d88..6d12e38a2 100644
--- a/third_party/androidx/committed/libs/androidx_tracing_tracing_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_tracing_tracing_android/README.chromium
@@ -1,6 +1,6 @@
 Name: Tracing
 Short Name: tracing-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/tracing/tracing-android/2.0.0-SNAPSHOT/tracing-android-2.0.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/tracing/tracing-android/2.0.0-SNAPSHOT/tracing-android-2.0.0-20251209.213522-1.aar
 Version: 2.0.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_tracing_tracing_ktx/README.chromium b/third_party/androidx/committed/libs/androidx_tracing_tracing_ktx/README.chromium
index af0c246..9e532c17 100644
--- a/third_party/androidx/committed/libs/androidx_tracing_tracing_ktx/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_tracing_tracing_ktx/README.chromium
@@ -1,6 +1,6 @@
 Name: Tracing Kotlin Extensions
 Short Name: tracing-ktx
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/tracing/tracing-ktx/2.0.0-SNAPSHOT/tracing-ktx-2.0.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/tracing/tracing-ktx/2.0.0-SNAPSHOT/tracing-ktx-2.0.0-20251209.213522-1.aar
 Version: 2.0.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_transition_transition/README.chromium b/third_party/androidx/committed/libs/androidx_transition_transition/README.chromium
index 27ede369..5efa771 100644
--- a/third_party/androidx/committed/libs/androidx_transition_transition/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_transition_transition/README.chromium
@@ -1,6 +1,6 @@
 Name: Transition
 Short Name: transition
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/transition/transition/1.7.0-SNAPSHOT/transition-1.7.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/transition/transition/1.7.0-SNAPSHOT/transition-1.7.0-20251209.213522-1.aar
 Version: 1.7.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_viewpager2_viewpager2/README.chromium b/third_party/androidx/committed/libs/androidx_viewpager2_viewpager2/README.chromium
index ab91cd3..7f7eac3d 100644
--- a/third_party/androidx/committed/libs/androidx_viewpager2_viewpager2/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_viewpager2_viewpager2/README.chromium
@@ -1,6 +1,6 @@
 Name: ViewPager2
 Short Name: viewpager2
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/viewpager2/viewpager2/1.2.0-SNAPSHOT/viewpager2-1.2.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/viewpager2/viewpager2/1.2.0-SNAPSHOT/viewpager2-1.2.0-20251209.213522-1.aar
 Version: 1.2.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_webkit_webkit/README.chromium b/third_party/androidx/committed/libs/androidx_webkit_webkit/README.chromium
index af47ae4..dc1dd03 100644
--- a/third_party/androidx/committed/libs/androidx_webkit_webkit/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_webkit_webkit/README.chromium
@@ -1,6 +1,6 @@
 Name: Webkit
 Short Name: webkit
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/webkit/webkit/1.16.0-SNAPSHOT/webkit-1.16.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/webkit/webkit/1.16.0-SNAPSHOT/webkit-1.16.0-20251209.213522-1.aar
 Version: 1.16.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_window_sidecar_sidecar/README.chromium b/third_party/androidx/committed/libs/androidx_window_sidecar_sidecar/README.chromium
index 1c76277..5be27c6c 100644
--- a/third_party/androidx/committed/libs/androidx_window_sidecar_sidecar/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_window_sidecar_sidecar/README.chromium
@@ -1,6 +1,6 @@
 Name: WindowManager Sidecar
 Short Name: sidecar
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/window/sidecar/sidecar/1.0.0-SNAPSHOT/sidecar-1.0.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/window/sidecar/sidecar/1.0.0-SNAPSHOT/sidecar-1.0.0-20251209.213522-1.aar
 Version: 1.0.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_window_window/README.chromium b/third_party/androidx/committed/libs/androidx_window_window/README.chromium
index 72f2db0a..3d2d66ad 100644
--- a/third_party/androidx/committed/libs/androidx_window_window/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_window_window/README.chromium
@@ -1,6 +1,6 @@
 Name: WindowManager
 Short Name: window
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/window/window/1.6.0-SNAPSHOT/window-1.6.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/window/window/1.6.0-SNAPSHOT/window-1.6.0-20251209.213522-1.aar
 Version: 1.6.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_window_window_core_android/README.chromium b/third_party/androidx/committed/libs/androidx_window_window_core_android/README.chromium
index 51bbb84a..c020a01 100644
--- a/third_party/androidx/committed/libs/androidx_window_window_core_android/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_window_window_core_android/README.chromium
@@ -1,6 +1,6 @@
 Name: WindowManager Core
 Short Name: window-core-android
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/window/window-core-android/1.6.0-SNAPSHOT/window-core-android-1.6.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/window/window-core-android/1.6.0-SNAPSHOT/window-core-android-1.6.0-20251209.213522-1.aar
 Version: 1.6.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_work_work_multiprocess/README.chromium b/third_party/androidx/committed/libs/androidx_work_work_multiprocess/README.chromium
index 9de7431..442eac6 100644
--- a/third_party/androidx/committed/libs/androidx_work_work_multiprocess/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_work_work_multiprocess/README.chromium
@@ -1,6 +1,6 @@
 Name: WorkManager Multiprocess
 Short Name: work-multiprocess
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/work/work-multiprocess/2.12.0-SNAPSHOT/work-multiprocess-2.12.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/work/work-multiprocess/2.12.0-SNAPSHOT/work-multiprocess-2.12.0-20251209.213522-1.aar
 Version: 2.12.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/androidx/committed/libs/androidx_work_work_runtime/README.chromium b/third_party/androidx/committed/libs/androidx_work_work_runtime/README.chromium
index cfea427..35b4a7a 100644
--- a/third_party/androidx/committed/libs/androidx_work_work_runtime/README.chromium
+++ b/third_party/androidx/committed/libs/androidx_work_work_runtime/README.chromium
@@ -1,6 +1,6 @@
 Name: WorkManager Runtime
 Short Name: work-runtime
-URL: https://androidx.dev/snapshots/builds/14500233/artifacts/repository/androidx/work/work-runtime/2.12.0-SNAPSHOT/work-runtime-2.12.0-20251126.133552-1.aar
+URL: https://androidx.dev/snapshots/builds/14561852/artifacts/repository/androidx/work/work-runtime/2.12.0-SNAPSHOT/work-runtime-2.12.0-20251209.213522-1.aar
 Version: 2.12.0-SNAPSHOT
 Update Mechanism: Autoroll
 License: Apache-2.0
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 70561a5..311a725 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -979,12 +979,6 @@
 
 BASE_FEATURE(kInputPredictorTypeChoice, base::FEATURE_DISABLED_BY_DEFAULT);
 
-BASE_FEATURE(kInputScenarioPriorityBoost, base::FEATURE_DISABLED_BY_DEFAULT);
-
-constexpr base::FeatureParam<bool> kInputScenarioPriorityBoostIncludesLoading{
-    &features::kInputScenarioPriorityBoost,
-    "input_scenario_priority_boost_includes_loading", false};
-
 // When enabled, wake ups from throttleable TaskQueues are limited to 1 per
 // minute in a page that has been backgrounded for 5 minutes.
 //
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index 23f7fcc1..d3f5e38 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -694,15 +694,6 @@
 // enabled.
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kInputPredictorTypeChoice);
 
-// Boosts the priority of the renderer main thread if an input scenario is
-// detected.
-BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kInputScenarioPriorityBoost);
-
-// Other times that kInputScenarioPriorityBoost should boost the priority, to
-// compensate for the lower default main thread priority.
-BLINK_COMMON_EXPORT extern const base::FeatureParam<bool>
-    kInputScenarioPriorityBoostIncludesLoading;
-
 BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kIntensiveWakeUpThrottling);
 BLINK_COMMON_EXPORT extern const char
     kIntensiveWakeUpThrottling_GracePeriodSeconds_Name[];
diff --git a/third_party/blink/renderer/build/scripts/core/css/properties/templates/style_builder_functions.tmpl b/third_party/blink/renderer/build/scripts/core/css/properties/templates/style_builder_functions.tmpl
index 20a9d0a..e470d14 100644
--- a/third_party/blink/renderer/build/scripts/core/css/properties/templates/style_builder_functions.tmpl
+++ b/third_party/blink/renderer/build/scripts/core/css/properties/templates/style_builder_functions.tmpl
@@ -352,13 +352,15 @@
     AtomicString identifier(To<CSSCustomIdentValue>(counter_data.Identifier())->Value());
     CounterDirectives& directives =
         map.insert(identifier, CounterDirectives()).stored_value->value;
+        {% if action == 'Reset' %}
+    if (counter_data.IsReversed()) {
+      directives.SetIsResetReversed();
+    }
+        {% endif %}
     if (const CSSPrimitiveValue* counter_data_value = counter_data.Value()) {
       int counter_value = counter_data_value->ComputeInteger(state.CssToLengthConversionData());
           {% if action == 'Reset' %}
       directives.SetResetValue(counter_value);
-      if (counter_data.IsReversed()) {
-        directives.SetIsResetReversed();
-      }
           {% elif action == 'Increment' %}
       directives.AddIncrementValue(counter_value);
           {% else %}
diff --git a/third_party/blink/renderer/controller/crash_memory_metrics_reporter_impl.cc b/third_party/blink/renderer/controller/crash_memory_metrics_reporter_impl.cc
index 43a7afa..a2c79850 100644
--- a/third_party/blink/renderer/controller/crash_memory_metrics_reporter_impl.cc
+++ b/third_party/blink/renderer/controller/crash_memory_metrics_reporter_impl.cc
@@ -7,6 +7,8 @@
 #include <utility>
 
 #include "base/atomicops.h"
+#include "base/byte_count.h"
+#include "base/byte_size.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/process/memory.h"
 #include "base/process/process_metrics.h"
@@ -70,8 +72,10 @@
   base::SystemMemoryInfo meminfo;
   base::GetSystemMemoryInfo(&meminfo);
   OomInterventionMetrics metrics;
-  metrics.current_available_memory = meminfo.available;
-  metrics.current_swap_free = meminfo.swap_free;
+  metrics.current_available_memory =
+      base::ByteCount::FromUnsigned(meminfo.available.InBytes());
+  metrics.current_swap_free =
+      base::ByteCount::FromUnsigned(meminfo.swap_free.InBytes());
   last_reported_metrics_ = metrics;
   WriteIntoSharedMemory();
 }
diff --git a/third_party/blink/renderer/core/dom/events/event_target.h b/third_party/blink/renderer/core/dom/events/event_target.h
index acd6db9..2fb4b367 100644
--- a/third_party/blink/renderer/core/dom/events/event_target.h
+++ b/third_party/blink/renderer/core/dom/events/event_target.h
@@ -230,6 +230,7 @@
   // but they will only actually be web-exposed for interfaces that include
   // GlobalEventHandlers as a mixin in the idl.
   DEFINE_ATTRIBUTE_EVENT_LISTENER(abort, kAbort)
+  DEFINE_ATTRIBUTE_EVENT_LISTENER(animationcancel, kAnimationcancel)
   DEFINE_ATTRIBUTE_EVENT_LISTENER(animationend, kAnimationend)
   DEFINE_ATTRIBUTE_EVENT_LISTENER(animationiteration, kAnimationiteration)
   DEFINE_ATTRIBUTE_EVENT_LISTENER(animationstart, kAnimationstart)
diff --git a/third_party/blink/renderer/core/dom/global_event_handlers.idl b/third_party/blink/renderer/core/dom/global_event_handlers.idl
index fbc97b3b..53adf9ad 100644
--- a/third_party/blink/renderer/core/dom/global_event_handlers.idl
+++ b/third_party/blink/renderer/core/dom/global_event_handlers.idl
@@ -142,6 +142,7 @@
 
   // CSS Animations
   // https://drafts.csswg.org/css-animations/#interface-globaleventhandlers-idl
+  attribute EventHandler onanimationcancel;
   attribute EventHandler onanimationend;
   attribute EventHandler onanimationiteration;
   attribute EventHandler onanimationstart;
diff --git a/third_party/blink/renderer/core/html/html_attribute_names.json5 b/third_party/blink/renderer/core/html/html_attribute_names.json5
index 5aa6b7a0..73869ae9 100644
--- a/third_party/blink/renderer/core/html/html_attribute_names.json5
+++ b/third_party/blink/renderer/core/html/html_attribute_names.json5
@@ -175,6 +175,7 @@
     "onanimationstart",
     "onanimationiteration",
     "onanimationend",
+    "onanimationcancel",
     "onautofill",
     "onauxclick",
     "onbeforecopy",
diff --git a/third_party/blink/renderer/core/html/html_element.cc b/third_party/blink/renderer/core/html/html_element.cc
index ecb29e4..385283f 100644
--- a/third_party/blink/renderer/core/html/html_element.cc
+++ b/third_party/blink/renderer/core/html/html_element.cc
@@ -463,6 +463,8 @@
 
       {html_names::kOnabortAttr, kNoWebFeature, event_type_names::kAbort,
        nullptr},
+      {html_names::kOnanimationcancelAttr, kNoWebFeature,
+       event_type_names::kAnimationcancel, nullptr},
       {html_names::kOnanimationendAttr, kNoWebFeature,
        event_type_names::kAnimationend, nullptr},
       {html_names::kOnanimationiterationAttr, kNoWebFeature,
diff --git a/third_party/blink/renderer/core/sanitizer/builtins_baseline_config.json b/third_party/blink/renderer/core/sanitizer/builtins_baseline_config.json
index 53acd6f5..c703ded 100644
--- a/third_party/blink/renderer/core/sanitizer/builtins_baseline_config.json
+++ b/third_party/blink/renderer/core/sanitizer/builtins_baseline_config.json
@@ -33,6 +33,7 @@
     "onabort",
     "onactivate",
     "onafterprint",
+    "onanimationcancel",
     "onanimationend",
     "onanimationiteration",
     "onanimationstart",
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index b6809fc..8e4e1fa 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -4869,7 +4869,7 @@
     },
     {
       name: "SmallerViewportUnits",
-      status: "experimental",
+      status: "stable",
     },
     {
       name: "SmartCard",
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/DEPS b/third_party/blink/renderer/platform/scheduler/main_thread/DEPS
index ae04a5a..9bf2eb7d 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/DEPS
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/DEPS
@@ -28,7 +28,4 @@
   "main_thread_unittest.cc": [
     "+base/message_loop/message_pump_type.h",
   ],
-  "main_thread_scheduler_impl.h": [
-    "+base/threading/scoped_thread_priority.h",
-  ],
 }
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
index 628b46a..aa7241f3 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
@@ -485,11 +485,7 @@
           base::FeatureList::IsEnabled(features::kDeferRendererTasksAfterInput)
               ? std::optional<features::TaskDeferralPolicy>(
                     features::kTaskDeferralPolicyParam.Get())
-              : std::nullopt),
-      input_scenario_priority_boost_enabled(
-          base::FeatureList::IsEnabled(features::kInputScenarioPriorityBoost)),
-      input_scenario_priority_boost_includes_loading(
-          features::kInputScenarioPriorityBoostIncludesLoading.Get()) {}
+              : std::nullopt) {}
 
 MainThreadSchedulerImpl::AnyThread::~AnyThread() = default;
 
@@ -2359,28 +2355,6 @@
   // tasks to notify observers if there's been a change.
   performance_scenarios::PerformanceScenarioObserverList::NotifyAllScopes(
       FROM_HERE);
-
-  // TODO(crbug.com/406587000): Convert this to a PerformanceScenario observer
-  // instead of hard-coding it.
-  if (scheduling_settings().input_scenario_priority_boost_enabled) {
-    // Check if the input scenario has changed and update the main thread
-    // priority boost accordingly.
-    performance_scenarios::ScenarioPattern idle_pattern{
-        .input = {performance_scenarios::InputScenario::kNoInput},
-    };
-    if (scheduling_settings().input_scenario_priority_boost_includes_loading) {
-      idle_pattern.loading = {
-          performance_scenarios::LoadingScenario::kNoPageLoading};
-    }
-    if (performance_scenarios::CurrentScenariosMatch(
-            performance_scenarios::ScenarioScope::kCurrentProcess,
-            idle_pattern)) {
-      main_thread_only().main_thread_priority_boost.reset();
-    } else if (!main_thread_only().main_thread_priority_boost.has_value()) {
-      main_thread_only().main_thread_priority_boost.emplace(
-          base::ThreadType::kDisplayCritical);
-    }
-  }
 }
 
 void MainThreadSchedulerImpl::OnTaskCompleted(
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
index b015f8e..ed76f4f 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
@@ -25,7 +25,6 @@
 #include "base/task/sequence_manager/task_time_observer.h"
 #include "base/task/sequenced_task_runner.h"
 #include "base/task/single_thread_task_runner.h"
-#include "base/threading/scoped_thread_priority.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_log.h"
 #include "build/build_config.h"
@@ -154,9 +153,6 @@
     // std::nullopt.
     std::optional<features::TaskDeferralPolicy>
         discrete_input_task_deferral_policy;
-
-    bool input_scenario_priority_boost_enabled;
-    bool input_scenario_priority_boost_includes_loading;
   };
 
   static const char* RAILModeToString(RAILMode rail_mode);
@@ -782,10 +778,6 @@
     // pending tasks that need to run.
     HashSet<scoped_refptr<MainThreadTaskQueue>> detached_task_queues;
 
-    // Temporarily boosts the main thread priority. Only used if
-    // kInputScenarioPriorityBoost is enabled.
-    std::optional<base::ScopedBoostPriority> main_thread_priority_boost;
-
     // `WidgetScheduler`s that have not been shut down.
     HashSet<scoped_refptr<WidgetSchedulerImpl>> widget_schedulers;
     raw_ptr<base::MessagePump> message_pump;
diff --git a/third_party/blink/renderer/platform/text/justification_opportunity.cc b/third_party/blink/renderer/platform/text/justification_opportunity.cc
index 16e31aa..c20425d 100644
--- a/third_party/blink/renderer/platform/text/justification_opportunity.cc
+++ b/third_party/blink/renderer/platform/text/justification_opportunity.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/platform/text/justification_opportunity.h"
 
 #include "third_party/blink/renderer/platform/text/character.h"
+#include "third_party/blink/renderer/platform/wtf/text/character_names.h"
 
 namespace blink {
 
@@ -24,12 +25,20 @@
       return {false, false};
 
     // https://drafts.csswg.org/css-text-4/#valdef-text-justify-inter-character
-    case TextJustify::kInterCharacter:
+    case TextJustify::kInterCharacter: {
       if (Character::IsDefaultIgnorable(ch)) {
         return {false, false};
       }
+      if (ch == uchar::kObjectReplacementCharacter) {
+        is_after_opportunity = false;
+        return {false, false};
+      }
+      // We should expand before this glyph if the glyph is placed after an
+      // atomic inline.
+      bool expand_before = !is_after_opportunity;
       is_after_opportunity = true;
-      return {false, true};
+      return {expand_before, true};
+    }
 
     // https://drafts.csswg.org/css-text-4/#valdef-text-justify-inter-word
     case TextJustify::kInterWord:
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index e1e9027..ce9adb7 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1203,7 +1203,6 @@
 crbug.com/1066577 external/wpt/css/css-lists/li-value-reversed-008b.html [ Failure ]
 crbug.com/1066577 external/wpt/css/css-lists/li-value-reversed-009a.html [ Failure ]
 crbug.com/1066577 external/wpt/css/css-lists/li-value-reversed-009b.html [ Failure ]
-crbug.com/1066577 external/wpt/css/css-lists/counter-reset-reversed-not-list-item-start.html [ Failure ]
 crbug.com/1066577 external/wpt/css/css-lists/counter-reset-reversed-list-item.html [ Failure ]
 crbug.com/1066577 external/wpt/css/css-lists/counter-reset-reversed-list-item-start.html [ Failure ]
 crbug.com/1066577 external/wpt/css/css-lists/counter-reset-reversed-not-list-item.html [ Failure ]
@@ -3174,6 +3173,7 @@
 crbug.com/440811029 [ Win ] external/wpt/bluetooth/bidi/server/getPrimaryServices/gen-disconnect-called-before.https.window.html [ Failure Timeout ]
 
 # ====== New tests from wpt-importer added here ======
+[ Win ] external/wpt/html/browsers/origin/api/origin-from-messageevent.window.html [ Crash Pass ]
 crbug.com/467185802 external/wpt/css/css-anchor-position/grid-position-area-basic.html [ Failure ]
 crbug.com/467194617 external/wpt/css/mediaqueries/at-custom-media-basic.html [ Failure ]
 crbug.com/467185802 virtual/fragmented-oof-in-cb/external/wpt/css/css-anchor-position/grid-position-area-basic.html [ Failure ]
@@ -6597,6 +6597,7 @@
 
 # Sheriff 2021-06-03
 crbug.com/1185121 fast/scroll-snap/animate-fling-to-snap-points-1.html [ Failure Pass ]
+crbug.com/40747768 http/tests/devtools/screen-orientation-override.js [ Failure Pass ]
 crbug.com/1215949 external/wpt/pointerevents/pointerevent_iframe-touch-action-none_touch.html [ Pass Timeout ]
 crbug.com/40770317 http/tests/devtools/bfcache/bfcache-elements-update.js [ Failure Pass ]
 
@@ -8626,7 +8627,7 @@
 crbug.com/356930166 [ Mac15 ] external/wpt/webrtc-encoded-transform/tentative/RTCPeerConnection-insertable-streams-errors.https.html [ Timeout ]
 crbug.com/356930166 [ Mac15 ] external/wpt/webrtc-extensions/RTCRtpSynchronizationSource-captureTimestamp.html [ Skip Timeout ]
 crbug.com/356930166 [ Mac15 ] external/wpt/webrtc-extensions/RTCRtpSynchronizationSource-senderCaptureTimeOffset.html [ Skip Timeout ]
-crbug.com/356930166 [ Mac15 ] external/wpt/webrtc-stats/getStats-remote-candidate-address.html [ Timeout ]
+crbug.com/356930166 [ Mac15 ] external/wpt/webrtc-stats/getStats-remote-candidate-address.html [ Skip Timeout ]
 crbug.com/356930166 [ Mac15 ] external/wpt/webrtc-stats/hardware-capability-stats.https.html [ Skip Timeout ]
 crbug.com/356930166 [ Mac15 ] external/wpt/webrtc-stats/supported-stats.https.html [ Skip Timeout ]
 crbug.com/356930166 [ Mac15 ] external/wpt/webrtc-svc/RTCRtpParameters-scalability-av1.html [ Skip Timeout ]
@@ -8690,7 +8691,7 @@
 crbug.com/356930166 [ Mac15-arm64 ] external/wpt/webrtc-encoded-transform/tentative/RTCPeerConnection-insertable-streams-errors.https.html [ Timeout ]
 crbug.com/356930166 [ Mac15-arm64 ] external/wpt/webrtc-extensions/RTCRtpSynchronizationSource-captureTimestamp.html [ Skip Timeout ]
 crbug.com/356930166 [ Mac15-arm64 ] external/wpt/webrtc-extensions/RTCRtpSynchronizationSource-senderCaptureTimeOffset.html [ Skip Timeout ]
-crbug.com/356930166 [ Mac15-arm64 ] external/wpt/webrtc-stats/getStats-remote-candidate-address.html [ Timeout ]
+crbug.com/356930166 [ Mac15-arm64 ] external/wpt/webrtc-stats/getStats-remote-candidate-address.html [ Skip Timeout ]
 crbug.com/356930166 [ Mac15-arm64 ] external/wpt/webrtc-stats/hardware-capability-stats.https.html [ Skip Timeout ]
 crbug.com/356930166 [ Mac15-arm64 ] external/wpt/webrtc-stats/supported-stats.https.html [ Skip Timeout ]
 crbug.com/356930166 [ Mac15-arm64 ] external/wpt/webrtc-svc/RTCRtpParameters-scalability-av1.html [ Skip Timeout ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index cd160dc..b070f11 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
@@ -3633,6 +3633,13 @@
         {}
        ]
       ],
+      "block-in-inline-with-abspos-after-spanner.html": [
+       "e5bcb4e71e444013a27e000c02a4c19a918d15ad",
+       [
+        null,
+        {}
+       ]
+      ],
       "block-in-inline-with-spanner-in-overflowed-parent-nested-multicol.html": [
        "b75aad5bfc05fe6ffbb3e525d0907b5c348d1e94",
        [
@@ -139491,6 +139498,110 @@
          ],
          {}
         ]
+       ],
+       "grid-gap-decorations-fragmentation-020.html": [
+        "46fe020bb3cf82e18f948006ca1568062042ea37",
+        [
+         null,
+         [
+          [
+           "/css/css-gaps/grid/fragmentation/grid-gap-decorations-fragmentation-020-ref.html",
+           "=="
+          ]
+         ],
+         {}
+        ]
+       ],
+       "grid-gap-decorations-fragmentation-021.html": [
+        "b81b7379658ad19b74b70de490d724d480f8f4e6",
+        [
+         null,
+         [
+          [
+           "/css/css-gaps/grid/fragmentation/grid-gap-decorations-fragmentation-021-ref.html",
+           "=="
+          ]
+         ],
+         {}
+        ]
+       ],
+       "grid-gap-decorations-fragmentation-022.html": [
+        "8ae56ea9752075b48ac83daf6b2447d150513236",
+        [
+         null,
+         [
+          [
+           "/css/css-gaps/grid/fragmentation/grid-gap-decorations-fragmentation-022-ref.html",
+           "=="
+          ]
+         ],
+         {}
+        ]
+       ],
+       "grid-gap-decorations-fragmentation-023.html": [
+        "ca1f97991712bbb20d84342f43190f8c46758dd0",
+        [
+         null,
+         [
+          [
+           "/css/css-gaps/grid/fragmentation/grid-gap-decorations-fragmentation-023-ref.html",
+           "=="
+          ]
+         ],
+         {}
+        ]
+       ],
+       "grid-gap-decorations-fragmentation-024.html": [
+        "747e6bf2fb755a312976203ea717846f857ff98b",
+        [
+         null,
+         [
+          [
+           "/css/css-gaps/grid/fragmentation/grid-gap-decorations-fragmentation-024-ref.html",
+           "=="
+          ]
+         ],
+         {}
+        ]
+       ],
+       "grid-gap-decorations-fragmentation-025.html": [
+        "261e090b41fddd33e842d31f563e526efa837877",
+        [
+         null,
+         [
+          [
+           "/css/css-gaps/grid/fragmentation/grid-gap-decorations-fragmentation-025-ref.html",
+           "=="
+          ]
+         ],
+         {}
+        ]
+       ],
+       "grid-gap-decorations-fragmentation-026.html": [
+        "2eefae856d080f36e516c1494145e0360c863c7f",
+        [
+         null,
+         [
+          [
+           "/css/css-gaps/grid/fragmentation/grid-gap-decorations-fragmentation-026-ref.html",
+           "=="
+          ]
+         ],
+         {}
+        ]
+       ],
+       "grid-gap-decorations-fragmentation-027.html": [
+        "ac386c2d49bcb986f4b44caffd767e589c0411c9",
+        [
+         null,
+         [
+          [
+           "/css/css-gaps/grid/fragmentation/grid-gap-decorations-fragmentation-027-ref.html",
+           "=="
+          ]
+         ],
+         {}
+        ]
        ]
       },
       "grid-gap-decorations-001.html": [
@@ -140341,7 +140452,7 @@
          ]
         ],
         "subgrid-gap-decorations-fragmentation-012.html": [
-         "a65e72d9b11e4b842927f71c7f0c01056311ac37",
+         "9edc0887f85cb06b74b5dedab82272fe2026a8ef",
          [
           null,
           [
@@ -140365,6 +140476,71 @@
           ],
           {}
          ]
+        ],
+        "subgrid-gap-decorations-fragmentation-014.html": [
+         "dddc1f2c859cbb87674fb206e2549b5870ec1767",
+         [
+          null,
+          [
+           [
+            "/css/css-gaps/grid/subgrid/fragmentation/subgrid-gap-decorations-fragmentation-014-ref.html",
+            "=="
+           ]
+          ],
+          {}
+         ]
+        ],
+        "subgrid-gap-decorations-fragmentation-015.html": [
+         "bfcd458a4c1102f657d63f14ef556622d2b4ab4b",
+         [
+          null,
+          [
+           [
+            "/css/css-gaps/grid/subgrid/fragmentation/subgrid-gap-decorations-fragmentation-015-ref.html",
+            "=="
+           ]
+          ],
+          {}
+         ]
+        ],
+        "subgrid-gap-decorations-fragmentation-016.html": [
+         "b5a6cdd7d7435afd083c4d0411f60ac0b5f48d46",
+         [
+          null,
+          [
+           [
+            "/css/css-gaps/grid/subgrid/fragmentation/subgrid-gap-decorations-fragmentation-016-ref.html",
+            "=="
+           ]
+          ],
+          {}
+         ]
+        ],
+        "subgrid-gap-decorations-fragmentation-017.html": [
+         "e4a8482666940fb024ad8a8a221e40699aa41f1c",
+         [
+          null,
+          [
+           [
+            "/css/css-gaps/grid/subgrid/fragmentation/subgrid-gap-decorations-fragmentation-017-ref.html",
+            "=="
+           ]
+          ],
+          {}
+         ]
+        ],
+        "subgrid-gap-decorations-fragmentation-018.html": [
+         "abda0ac8df36157fe1ad4bf2f38461d7edf4d735",
+         [
+          null,
+          [
+           [
+            "/css/css-gaps/grid/subgrid/fragmentation/subgrid-gap-decorations-fragmentation-018-ref.html",
+            "=="
+           ]
+          ],
+          {}
+         ]
         ]
        },
        "subgrid-gap-decorations-001.html": [
@@ -170740,7 +170916,7 @@
         ]
        ],
        "clip-path-animation-retarget.html": [
-        "1e3624e73742ac29ed35d04b1750fcb71fad3ab3",
+        "5204c9c201b02255cb848cdf70b3143ee4d3f982",
         [
          null,
          [
@@ -170749,7 +170925,23 @@
            "=="
           ]
          ],
-         {}
+         {
+          "fuzzy": [
+           [
+            null,
+            [
+             [
+              0,
+              10
+             ],
+             [
+              0,
+              30
+             ]
+            ]
+           ]
+          ]
+         }
         ]
        ],
        "clip-path-animation-revert-layer.html": [
@@ -170831,7 +171023,7 @@
         ]
        ],
        "clip-path-animation-start-time.html": [
-        "56ed807f4d05913ed6247dfed0c07187a0645b5e",
+        "116fddb258672c8bb17e1e5b0c17775aef6a5d18",
         [
          null,
          [
@@ -170840,7 +171032,23 @@
            "=="
           ]
          ],
-         {}
+         {
+          "fuzzy": [
+           [
+            null,
+            [
+             [
+              0,
+              10
+             ],
+             [
+              0,
+              30
+             ]
+            ]
+           ]
+          ]
+         }
         ]
        ],
        "clip-path-animation-svg-zoom.html": [
@@ -370534,6 +370742,38 @@
        "grid-gap-decorations-fragmentation-017-ref.html": [
         "8f6172a89e80a747325b0155cca8f904e84078fb",
         []
+       ],
+       "grid-gap-decorations-fragmentation-020-ref.html": [
+        "2fb4fc899cbb58f53fa46900da99586545ccc31c",
+        []
+       ],
+       "grid-gap-decorations-fragmentation-021-ref.html": [
+        "59d4d2d6a30f5b7b413474fb735f15645f589d13",
+        []
+       ],
+       "grid-gap-decorations-fragmentation-022-ref.html": [
+        "9697d046828eacf05f837a8d39d8d0c4beb86823",
+        []
+       ],
+       "grid-gap-decorations-fragmentation-023-ref.html": [
+        "9a95d1de87c6422574e4687af5ddbdf7b0996d0e",
+        []
+       ],
+       "grid-gap-decorations-fragmentation-024-ref.html": [
+        "3f6acc00b952b6fae64064edb72d7d5278c59b80",
+        []
+       ],
+       "grid-gap-decorations-fragmentation-025-ref.html": [
+        "bc463a11cbf3d597b035eb417266e1f0250bfc3c",
+        []
+       ],
+       "grid-gap-decorations-fragmentation-026-ref.html": [
+        "424962f626b2777a836af68c24f903656603bcab",
+        []
+       ],
+       "grid-gap-decorations-fragmentation-027-ref.html": [
+        "973c49a5d29e506aae1041c7f319dccd3e3dc334",
+        []
        ]
       },
       "grid-gap-decorations-003-ref.html": [
@@ -370757,6 +370997,26 @@
         "subgrid-gap-decorations-fragmentation-013-ref.html": [
          "a6893986a1462c038091565efb90716d4d29c942",
          []
+        ],
+        "subgrid-gap-decorations-fragmentation-014-ref.html": [
+         "fa4d2e946a721e4b0d4d57b032b2bdd59dc86cdb",
+         []
+        ],
+        "subgrid-gap-decorations-fragmentation-015-ref.html": [
+         "a7f51df03f51c9a1431a972cbefa6fd563e5ce1b",
+         []
+        ],
+        "subgrid-gap-decorations-fragmentation-016-ref.html": [
+         "79faac8117ec8ec30ac5dff0f327c0332a26a405",
+         []
+        ],
+        "subgrid-gap-decorations-fragmentation-017-ref.html": [
+         "6174269c6cd9f30aba89ea390f2c0b9dd3932c5c",
+         []
+        ],
+        "subgrid-gap-decorations-fragmentation-018-ref.html": [
+         "bf17b8f8c32d86d17c47da7346b9266c0f6d04e3",
+         []
         ]
        },
        "subgrid-gap-decorations-012-ref.html": [
@@ -393209,7 +393469,7 @@
      ],
      "resources": {
       "testhelper.js": [
-       "4c9ed78c78cb905c95fc98a6d07b53beb0bccca1",
+       "4007a1f094830b1193289786da150e4c8f31a08d",
        []
       ]
      },
@@ -415557,6 +415817,14 @@
         "4268f94f989bad188183f3e408015b5186886e0b",
         []
        ],
+       "origin-from-extendablemessageevent.any.serviceworker-expected.txt": [
+        "a6cf7e024c67e1770f89e751f174e9446ba8c8d4",
+        []
+       ],
+       "origin-from-messageevent.window-expected.txt": [
+        "493c84db2f616d09283d61bdf99a993cc89c3de1",
+        []
+       ],
        "resources": {
         "serializations.js": [
          "dec7fbdd1da7fee8422aa67e4bed073f4d362302",
@@ -425305,6 +425573,10 @@
         "a7142360eb190ab0466fca43bfeb7a068c043b1d",
         []
        ],
+       "WEB_FEATURES.yml": [
+        "b69cf9245fc74f09b1fd1f720ef6b21a66983e14",
+        []
+       ],
        "align-ref.html": [
         "9e4283e208e17e4f2cfed05882bb1aff276028ad",
         []
@@ -426287,6 +426559,20 @@
        ]
       }
      },
+     "edits": {
+      "the-del-element": {
+       "WEB_FEATURES.yml": [
+        "6497c9da752f31783cba6d844f38657545ce0039",
+        []
+       ]
+      },
+      "the-ins-element": {
+       "WEB_FEATURES.yml": [
+        "9ab8483913082a4695f267532f91f291fd130143",
+        []
+       ]
+      }
+     },
      "embedded-content": {
       "META.yml": [
        "c1dd8dddf9eec3ab3fb58df01c549c251f3a3fdf",
@@ -428484,6 +428770,12 @@
         []
        ]
       },
+      "the-hr-element": {
+       "WEB_FEATURES.yml": [
+        "b69cf9245fc74f09b1fd1f720ef6b21a66983e14",
+        []
+       ]
+      },
       "the-li-element": {
        "grouping-li-reftest-001-ref.html": [
         "23b6cdabe8054051356450636e910a636da87a41",
@@ -429184,6 +429476,10 @@
        "c1175ff23c5d322f7dec1a7794ffafa5b95f6db6",
        []
       ],
+      "light-dismiss-event-ordering-expected.txt": [
+       "81bdb7e87105f0a8095560bf5642631242697da7",
+       []
+      ],
       "popover-alignment-001-ref.html": [
        "8bf4a0ac9a739f33f0afaf52a30f6b9ebf968033",
        []
@@ -445131,6 +445427,10 @@
       "support.js": [
        "5467317cd01312968a4f5375e85c0b2b6de3b691",
        []
+      ],
+      "trigger-scope-support.js": [
+       "ca8723415ab8167b5d2aea63426fe20a4172f857",
+       []
       ]
      }
     },
@@ -450592,18 +450892,14 @@
       []
      ],
      "storage-access-beyond-cookies-iframe-iframe.html": [
-      "61d04834def4e5e66a6ba6e2a94dcaa03e7836cd",
+      "08edcf2d42b63ea237b8ad10aacd98e1c8ad8bc0",
       []
      ],
      "storage-access-beyond-cookies-iframe.sub.html": [
-      "775aaa3d7a699958afefc9a0ef4d037505d973ef",
+      "b50463a3b2ec8a47bdf64bc3f6cb34da6ea1a864",
       []
      ]
     },
-    "storage-access-beyond-cookies.unpartitioned.sub.https.window-expected.txt": [
-     "3efdb8f865284878c7452851b88079d4ce886b28",
-     []
-    ],
     "storageAccess.testdriver.sub-expected.txt": [
      "f2751aa9537c0eae2ee03c17422dde060cd2ab46",
      []
@@ -460875,7 +461171,7 @@
      []
     ],
     "getStats-remote-candidate-address-expected.txt": [
-     "f73ad23fc53014c79fb1d0aa11ece0ab1c2f8ff1",
+     "2142d322389d22fc393beaa11d6a71a798ee7259",
      []
     ],
     "supported-stats.https-expected.txt": [
@@ -575230,6 +575526,19 @@
     },
     "observable": {
      "tentative": {
+      "crashtests": {
+       "observable-takeUntil-toArray.any.js": [
+        "df877d944456967365b754de2487167294325ff9",
+        [
+         "dom/observable/tentative/crashtests/observable-takeUntil-toArray.any.html",
+         {}
+        ],
+        [
+         "dom/observable/tentative/crashtests/observable-takeUntil-toArray.any.worker.html",
+         {}
+        ]
+       ]
+      },
       "idlharness.html": [
        "ea8743528f67ac0bc9154f82b3c391bbc96eb20f",
        [
@@ -595084,6 +595393,24 @@
       }
      ]
     ],
+    "gap-keydown-keyup.html": [
+     "b2daa0278763772537c76f7d3c22fe818608b27d",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
+    "gap-pointerdown-pointerup.html": [
+     "46723b4b01fb500d2a015ba64b54382ec06da9a4",
+     [
+      null,
+      {
+       "testdriver": true
+      }
+     ]
+    ],
     "idlharness.any.js": [
      "4750111a505d1f51ed241ffc873bfe3d2c030179",
      [
@@ -637609,7 +637936,7 @@
         ]
        ],
        "origin-from-extendablemessageevent.any.js": [
-        "48fff278131fd84cc8e9019bdd413e768432d81b",
+        "8ddd1b817c86d614dd9348763cc4b8bcbcca7139",
         [
          "html/browsers/origin/api/origin-from-extendablemessageevent.any.serviceworker.html",
          {
@@ -637764,7 +638091,7 @@
         ]
        ],
        "origin-from-messageevent.window.js": [
-        "c2e225b48cfa674def301d943204a1f095652101",
+        "d44828f0f4e10a387de185082d3d8e0d828d5cd2",
         [
          "html/browsers/origin/api/origin-from-messageevent.window.html",
          {
@@ -669263,6 +669590,13 @@
          {}
         ]
        ],
+       "stream-html-unsafe.html": [
+        "2c7052f1cd772b1dc3dbb56d1d756d024011073c",
+        [
+         null,
+         {}
+        ]
+       ],
        "template-contentmethod-append-elements.html": [
         "cf8e3d4c2b9c4c3bde003632cdc3a32d63d0a23d",
         [
@@ -683182,6 +683516,15 @@
           }
          ]
         ],
+        "select-click-picker-light-dismiss.tentative.html": [
+         "120e5c5f9af6811d6ada8a9006b9c5b4b6dbb70d",
+         [
+          null,
+          {
+           "testdriver": true
+          }
+         ]
+        ],
         "select-dialog-mode-focus.optional.html": [
          "cc739150f4a1a665470dbc2fa6c99f3a96383dd0",
          [
@@ -684397,6 +684740,33 @@
          }
         ]
        ],
+       "dialog-light-dismiss-drag.html": [
+        "2b9f9b5793cee68910e5fbf4351264565647e7f6",
+        [
+         null,
+         {
+          "testdriver": true
+         }
+        ]
+       ],
+       "dialog-light-dismiss-pointer-capture.html": [
+        "4b6b1f3261a8cb8d811ba82d655feee38670a5cd",
+        [
+         null,
+         {
+          "testdriver": true
+         }
+        ]
+       ],
+       "dialog-light-dismiss-touch.html": [
+        "43fd9490aec48d97048dfb16cc42ce8e763332e5",
+        [
+         null,
+         {
+          "testdriver": true
+         }
+        ]
+       ],
        "dialog-no-throw-requested-state.html": [
         "c86cbe84a62294b2d4ce949bd3e9d6af6623c8dc",
         [
@@ -685645,6 +686015,24 @@
         }
        ]
       ],
+      "light-dismiss-event-ordering.tentative.html": [
+       "e1d9c66997d15d266851cd221a359453bb31fe44",
+       [
+        null,
+        {
+         "testdriver": true
+        }
+       ]
+      ],
+      "light-dismiss-remove-target.html": [
+       "38ec238c96fd52ed45e1500f4a73cde20157b08d",
+       [
+        null,
+        {
+         "testdriver": true
+        }
+       ]
+      ],
       "popover-active-document.html": [
        "f5ce266759771d1de153ad3752933b542918cd35",
        [
@@ -685940,6 +686328,15 @@
         }
        ]
       ],
+      "popover-light-dismiss-contextmenu.html": [
+       "12da92947fdf631f59b0bdbb467bee02997c5303",
+       [
+        null,
+        {
+         "testdriver": true
+        }
+       ]
+      ],
       "popover-light-dismiss-flat-tree-nested.html": [
        "ef3b35aea408e9c59f6d371ca83576268c34141c",
        [
@@ -685984,6 +686381,15 @@
         }
        ]
       ],
+      "popover-light-dismiss-touch-scroll.html": [
+       "b71985bae72432eda5c0bfaade759a85f0430884",
+       [
+        null,
+        {
+         "testdriver": true
+        }
+       ]
+      ],
       "popover-light-dismiss-with-anchor.tentative.html": [
        "c4e545c4fb97133cf6ad74ed73e2ade827c3721b",
        [
@@ -738204,7 +738610,49 @@
         {}
        ]
       ]
-     }
+     },
+     "trigger-scope-in-scope-source.tentative.html": [
+      "2a76efaf242c677a1e5f04f48eed9b6b40b920ac",
+      [
+       null,
+       {}
+      ]
+     ],
+     "trigger-scope-named.tentative.html": [
+      "adaa3c5b31df444a09008e6ac3764a70821ab7c7",
+      [
+       null,
+       {}
+      ]
+     ],
+     "trigger-scope-oof.tentative.html": [
+      "bfae371e2fdba494870a1a1dcbdbd65308a3a3f7",
+      [
+       null,
+       {}
+      ]
+     ],
+     "trigger-scope-out-of-scope-source.tentative.html": [
+      "08071fd5216059d110520128a2290d0b59382658",
+      [
+       null,
+       {}
+      ]
+     ],
+     "trigger-scope-scoped-tree-order.tentative.html": [
+      "0263ea562aa6fd335dfbad11c26c51971f5cacbd",
+      [
+       null,
+       {}
+      ]
+     ],
+     "trigger-scope-unscoped-tree-order.tentative.html": [
+      "62af3f9a81a97f76e36d790a21dca067b49bf9f7",
+      [
+       null,
+       {}
+      ]
+     ]
     },
     "css": {
      "animation-duration-auto.tentative.html": [
@@ -753057,24 +753505,6 @@
       }
      ]
     ],
-    "storage-access-beyond-cookies.unpartitioned.sub.https.window.js": [
-     "ddc5b49f4819fc127a99d30ebc2792244cae3570",
-     [
-      "storage-access-api/storage-access-beyond-cookies.unpartitioned.sub.https.window.html",
-      {
-       "script_metadata": [
-        [
-         "script",
-         "/resources/testdriver.js"
-        ],
-        [
-         "script",
-         "/resources/testdriver-vendor.js"
-        ]
-       ]
-      }
-     ]
-    ],
     "storage-access-headers.tentative.https.sub.window.js": [
      "d965118fba24bfcc46bea4c42b7939de5cd31071",
      [
@@ -839044,10 +839474,12 @@
    },
    "webrtc-stats": {
     "getStats-remote-candidate-address.html": [
-     "add679044c7499806e1da9a3dce1b75c56822fb1",
+     "93d42845cc5ab6a7ce15c9b670376f134bbeffed",
      [
       null,
-      {}
+      {
+       "timeout": "long"
+      }
      ]
     ],
     "getStats-remote-candidate-ufrag.html": [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/idlharness-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-animations/idlharness-expected.txt
deleted file mode 100644
index 0f1b4fec..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-animations/idlharness-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-This is a testharness.js-based test.
-Found 3 FAIL, 0 TIMEOUT, 0 NOTRUN.
-[FAIL] HTMLElement interface: attribute onanimationcancel
-  assert_true: The prototype object must have a property "onanimationcancel" expected true got false
-[FAIL] Window interface: attribute onanimationcancel
-  assert_own_property: The global object must have a property "onanimationcancel" expected property "onanimationcancel" missing
-[FAIL] Document interface: attribute onanimationcancel
-  assert_true: The prototype object must have a property "onanimationcancel" expected true got false
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/block-in-inline-with-abspos-after-spanner.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/block-in-inline-with-abspos-after-spanner.html
new file mode 100644
index 0000000..e5bcb4e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/crashtests/block-in-inline-with-abspos-after-spanner.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+<link rel="author" title="Mozilla" href="https://www.mozilla.org/">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=2004166">
+
+<div style="columns:2">
+<span id="span">
+<div style="column-span:all"></div><div>
+<div style="position:absolute"></div>
+<script>
+span.style.position = "relative"
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-justify/text-justify-inter-character-atomic-inline-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-justify/text-justify-inter-character-atomic-inline-ref.html
new file mode 100644
index 0000000..a2d0af9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-justify/text-justify-inter-character-atomic-inline-ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="/fonts/ahem.css">
+<style>
+p {
+  font: 20px/1 Ahem;
+  border: 1px solid black;
+  padding: 10px;
+  width: 100px;
+}
+.test {
+}
+.test img {
+  width: 20px;
+  height: 20px;
+  vertical-align: top;
+}
+</style>
+</head>
+<body>
+<p class="test">X<img src="/images/blue.png" style="padding-left:10px;"><img src="/images/blue.png" style="padding-right:10px;">X</p>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-justify/text-justify-inter-character-atomic-inline.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-justify/text-justify-inter-character-atomic-inline.html
new file mode 100644
index 0000000..a0d7ae3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-justify/text-justify-inter-character-atomic-inline.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Justification Method: text-justify: inter-character</title>
+<link rel="author" title="Kent Tamura" href="mailto:tkent@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-text-4/#valdef-text-justify-inter-character">
+<link rel='match' href='text-justify-inter-character-atomic-inline-ref.html'>
+<meta name="assert" content="text-justify:inter-character should handle a consecutive run of atomic inlines as a single typographic unit.">
+<link rel="stylesheet" href="/fonts/ahem.css">
+<style>
+p {
+  font: 20px/1 Ahem;
+  border: 1px solid black;
+  padding: 10px;
+  width: 100px;
+}
+.test {
+  text-align-last: justify;
+  text-justify: inter-character;
+}
+.test img {
+  width: 20px;
+  height: 20px;
+  vertical-align: top;
+}
+</style>
+</head>
+<body>
+<p class="test">X<img src="/images/blue.png"><img src="/images/blue.png">X</p>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-typed-om/resources/testhelper.js b/third_party/blink/web_tests/external/wpt/css/css-typed-om/resources/testhelper.js
index 4c9ed78c..4007a1f 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-typed-om/resources/testhelper.js
+++ b/third_party/blink/web_tests/external/wpt/css/css-typed-om/resources/testhelper.js
@@ -63,6 +63,8 @@
       break;
     case 'CSSMathSum':
     case 'CSSMathProduct':
+      assert_style_value_array_unordered_equals(a.values, b.values);
+      break;
     case 'CSSMathMin':
     case 'CSSMathMax':
       assert_style_value_array_equals(a.values, b.values);
@@ -126,6 +128,34 @@
   }
 }
 
+// Compares two arrays of CSSStyleValues, ignoring element order.
+//
+// Used for CSSMathSum and CSSMathProduct, where browsers currently differ
+// in how values are ordered. The ordering behavior is under discussion in
+// https://github.com/w3c/csswg-drafts/issues/9451.
+//
+// This is a temporary relaxation: for now, the test accepts any order
+// to avoid interop failures across engines. Once the spec is clarified,
+// tests should assert that the order matches the canonical (sorted) form
+// used for both CSS values and CSS Typed OM.
+function assert_style_value_array_unordered_equals(a, b) {
+  assert_equals(a.length, b.length);
+
+  const remaining = [...b];
+  a.forEach((valueA) => {
+    const matched = remaining.some((valueB, i) => {
+      try {
+        assert_style_value_equals(valueA, valueB);
+        remaining.splice(i, 1);
+        return true;
+      } catch {
+        return false;
+      }
+    });
+    assert_true(matched);
+  });
+}
+
 const gValidUnits = [
   'number', 'percent', 'em', 'ex', 'ch',
   'ic', 'rem', 'lh', 'rlh', 'vw',
diff --git a/third_party/blink/web_tests/external/wpt/event-timing/gap-keydown-keyup.html b/third_party/blink/web_tests/external/wpt/event-timing/gap-keydown-keyup.html
new file mode 100644
index 0000000..b2daa027
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/event-timing/gap-keydown-keyup.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+<meta charset=utf-8 />
+<title>Event Timing: keydown/up gap.</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/resources/testdriver.js></script>
+<script src=/resources/testdriver-actions.js></script>
+<script src=/resources/testdriver-vendor.js></script>
+<script src=resources/event-timing-test-utils.js></script>
+<div id='target'>Click me</div>
+<script>
+  promise_test(async t => {
+    const keyDowns = []
+    const keyUps = []
+    blockNextEventListener(window, 'keydown', 30)
+    blockNextEventListener(window, 'keyup', 30)
+
+    // A pointerdown is used as an interleaving event, to make sure the keydown's
+    // timing entry had it's duration set before triggering the keyup. Using
+    // only `await afterNextPaint()` after the first event is not enough to
+    // guarantee this in all browsers. See discussion in
+    // https://github.com/web-platform-tests/wpt/pull/55577#discussion_r2466579023
+    blockNextEventListener(window, 'pointerdown', 30)
+    const {promise: interleavingEventTimingEntryObserved, resolve: resolveInterleaving } = Promise.withResolvers();
+    new PerformanceObserver( (entries) => {
+      entries.getEntries().forEach(  (e) => {
+        if (e.name == 'keydown')
+          keyDowns.push(e)
+        if (e.name =='keyup')
+          keyUps.push(e)
+        if (e.name == 'pointerdown')
+          resolveInterleaving()
+      })
+    }).observe({type: 'event', durationThreshold: 16})
+    const keyDownHandled = new Promise( resolve => window.addEventListener('keydown', e => resolve(), true) )
+    const keyUpHandled = new Promise( resolve => window.addEventListener('keyup', e => resolve(), true) )
+
+    await new test_driver.Actions()
+      .keyDown('a')
+      .send()
+    await keyDownHandled
+    await afterNextPaint()
+    await new test_driver.Actions()
+      .pointerMove(0, 0)
+      .pointerDown()
+      .pointerUp()
+      .send()
+    await interleavingEventTimingEntryObserved
+    const waitStart = performance.now()
+    await t.step_wait(() => (performance.now() - waitStart > 50))
+    await new test_driver.Actions()
+      .keyUp('a')
+      .send()
+    await keyUpHandled
+    await t.step_wait(() => (keyDowns.length != 0 && keyUps.length != 0), 'Wait for the event timing entries to be processed.')
+    assert_equals(keyDowns.length, 1)
+    assert_equals(keyUps.length, 1)
+    assert_greater_than(keyUps[0].startTime, keyDowns[0].startTime + keyDowns[0].duration)
+  }, "keydown duration shouldn't wait for keyup.")
+</script>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/event-timing/gap-pointerdown-pointerup.html b/third_party/blink/web_tests/external/wpt/event-timing/gap-pointerdown-pointerup.html
new file mode 100644
index 0000000..46723b4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/event-timing/gap-pointerdown-pointerup.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+<meta charset=utf-8 />
+<title>Event Timing: pointerdown/up gap.</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/resources/testdriver.js></script>
+<script src=/resources/testdriver-actions.js></script>
+<script src=/resources/testdriver-vendor.js></script>
+<script src=resources/event-timing-test-utils.js></script>
+<div id='target'>Click me</div>
+<script>
+  promise_test(async t => {
+    const pointerDowns = []
+    const pointerUps = []
+    blockNextEventListener(window, 'pointerdown', 30)
+    blockNextEventListener(window, 'pointerup', 30)
+
+    // A keydown is used as an interleaving event, to make sure the pointerdown's
+    // timing entry had it's duration set before triggering the pointerup. Using
+    // only `await afterNextPaint()` after the first event is not enough to
+    // guarantee this in all browsers. See discussion in
+    // https://github.com/web-platform-tests/wpt/pull/55577#discussion_r2466579023
+    blockNextEventListener(window, 'keydown', 30)
+    const {promise: interleavingEventTimingEntryObserved, resolve: resolveInterleaving } = Promise.withResolvers();
+    new PerformanceObserver( (entries) => {
+      entries.getEntries().forEach(  (e) => {
+        if (e.name == 'pointerdown')
+          pointerDowns.push(e)
+        if (e.name =='pointerup')
+          pointerUps.push(e)
+        if (e.name == 'keydown')
+          resolveInterleaving()
+      })
+    }).observe({type: 'event', durationThreshold: 16})
+    const pointerDownHandled = new Promise( resolve => window.addEventListener('pointerdown', e => resolve(), true) )
+    const pointerUpHandled = new Promise( resolve => window.addEventListener('pointerup', e => resolve(), true) )
+
+    await new test_driver.Actions()
+      .pointerMove(0, 0)
+      .pointerDown()
+      .send()
+    await pointerDownHandled
+    await afterNextPaint()
+    await new test_driver.Actions()
+      .keyDown('k')
+      .keyUp('k')
+      .send()
+    await interleavingEventTimingEntryObserved
+    const waitStart = performance.now()
+    await t.step_wait(() => (performance.now() - waitStart > 50))
+    await new test_driver.Actions()
+      .pointerUp()
+      .send()
+    await pointerUpHandled
+    await t.step_wait(() => (pointerDowns.length != 0 && pointerUps.length != 0), 'Wait for the event timing entries to be processed.')
+    assert_equals(pointerDowns.length, 1)
+    assert_equals(pointerUps.length, 1)
+    assert_greater_than(pointerUps[0].startTime, pointerDowns[0].startTime + pointerDowns[0].duration)
+  }, "pointerdown duration shouldn't wait for pointerup.")
+</script>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/api/origin-from-extendablemessageevent.any.js b/third_party/blink/web_tests/external/wpt/html/browsers/origin/api/origin-from-extendablemessageevent.any.js
index 48fff27..8ddd1b8 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/api/origin-from-extendablemessageevent.any.js
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/origin/api/origin-from-extendablemessageevent.any.js
@@ -14,12 +14,8 @@
 
 test(t => {
   const e = new ExtendableMessageEvent("message", { origin: get_host_info().ORIGIN });
-  const origin = Origin.from(e);
-  assert_true(!!origin, "It's not null!");
-  assert_false(origin.opaque, "It's not opaque!");
-  assert_true(origin.isSameOrigin(Origin.from(self)), "It's same-origin with an Origin!");
-}, "Constructed `ExtendableMessageEvent` objects have origins.");
-
+  assert_throws_js(TypeError, _ => Origin.from(e));
+}, "Constructed `ExtendableMessageEvent` objects have no real origins.");
 
 promise_test(async t => {
   await WorkerActivationPromise();
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/api/origin-from-extendablemessageevent.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/html/browsers/origin/api/origin-from-extendablemessageevent.any.serviceworker-expected.txt
new file mode 100644
index 0000000..a6cf7e0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/origin/api/origin-from-extendablemessageevent.any.serviceworker-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] Constructed `ExtendableMessageEvent` objects have no real origins.
+  assert_throws_js: function "_ => Origin.from(e)" did not throw
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/api/origin-from-messageevent.window-expected.txt b/third_party/blink/web_tests/external/wpt/html/browsers/origin/api/origin-from-messageevent.window-expected.txt
new file mode 100644
index 0000000..493c84d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/origin/api/origin-from-messageevent.window-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+[FAIL] Constructed `MessageEvent` objects have no real origins.
+  assert_throws_js: function "_ => Origin.from(e)" did not throw
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/origin/api/origin-from-messageevent.window.js b/third_party/blink/web_tests/external/wpt/html/browsers/origin/api/origin-from-messageevent.window.js
index c2e225b..d44828f0 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/origin/api/origin-from-messageevent.window.js
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/origin/api/origin-from-messageevent.window.js
@@ -1,6 +1,11 @@
 // META: title=`Origin.from(MessageEvent)`
 // META: script=/common/get-host-info.sub.js
 
+test(t => {
+  const e = new MessageEvent("message", { origin: get_host_info().ORIGIN });
+  assert_throws_js(TypeError, _ => Origin.from(e));
+}, "Constructed `MessageEvent` objects have no real origins.");
+
 async_test(t => {
   const el = document.createElement('iframe');
   el.src = "/html/browsers/windows/resources/message-parent.html"
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/lists/lists-styles-expected.txt b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/lists/lists-styles-expected.txt
index 37a26920..81b6a35 100644
--- a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/lists/lists-styles-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/lists/lists-styles-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 80 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 82 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] <menu>\n   <li> - counter-reset
   assert_equals: expected "list-item 0" but got "none"
 [FAIL] <ol>\n   <li> - counter-reset
@@ -154,11 +154,15 @@
   assert_equals: expected "list-item 9" but got "none"
 [FAIL] <ol start="xyz"><li> - counter-reset
   assert_equals: expected "list-item 0" but got "none"
+[FAIL] <ol reversed=""><li> - counter-reset
+  assert_equals: expected "reversed(list-item)" but got "none"
 [FAIL] <ol reversed="" start="20"><li> - counter-reset
   assert_equals: expected "reversed(list-item) 21" but got "none"
 [FAIL] <ol reversed="" start="20xyz"><li> - counter-reset
   assert_equals: expected "reversed(list-item) 21" but got "none"
 [FAIL] <ol reversed="" start="20e10"><li> - counter-reset
   assert_equals: expected "reversed(list-item) 21" but got "none"
+[FAIL] <ol reversed="" start="xyz"><li> - counter-reset
+  assert_equals: expected "reversed(list-item)" but got "none"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/lists/lists-styles-quirks-expected.txt b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/lists/lists-styles-quirks-expected.txt
index 37a26920..81b6a35 100644
--- a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/lists/lists-styles-quirks-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/lists/lists-styles-quirks-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 80 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 82 FAIL, 0 TIMEOUT, 0 NOTRUN.
 [FAIL] <menu>\n   <li> - counter-reset
   assert_equals: expected "list-item 0" but got "none"
 [FAIL] <ol>\n   <li> - counter-reset
@@ -154,11 +154,15 @@
   assert_equals: expected "list-item 9" but got "none"
 [FAIL] <ol start="xyz"><li> - counter-reset
   assert_equals: expected "list-item 0" but got "none"
+[FAIL] <ol reversed=""><li> - counter-reset
+  assert_equals: expected "reversed(list-item)" but got "none"
 [FAIL] <ol reversed="" start="20"><li> - counter-reset
   assert_equals: expected "reversed(list-item) 21" but got "none"
 [FAIL] <ol reversed="" start="20xyz"><li> - counter-reset
   assert_equals: expected "reversed(list-item) 21" but got "none"
 [FAIL] <ol reversed="" start="20e10"><li> - counter-reset
   assert_equals: expected "reversed(list-item) 21" but got "none"
+[FAIL] <ol reversed="" start="xyz"><li> - counter-reset
+  assert_equals: expected "reversed(list-item)" but got "none"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-hr-element-0/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-hr-element-0/WEB_FEATURES.yml
new file mode 100644
index 0000000..b69cf92
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/the-hr-element-0/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: hr
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/edits/the-del-element/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/html/semantics/edits/the-del-element/WEB_FEATURES.yml
new file mode 100644
index 0000000..6497c9d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/edits/the-del-element/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: del
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/edits/the-ins-element/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/html/semantics/edits/the-ins-element/WEB_FEATURES.yml
new file mode 100644
index 0000000..9ab8483
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/edits/the-ins-element/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: ins
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/grouping-content/the-hr-element/WEB_FEATURES.yml b/third_party/blink/web_tests/external/wpt/html/semantics/grouping-content/the-hr-element/WEB_FEATURES.yml
new file mode 100644
index 0000000..b69cf92
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/grouping-content/the-hr-element/WEB_FEATURES.yml
@@ -0,0 +1,3 @@
+features:
+- name: hr
+  files: "**"
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-stats/getStats-remote-candidate-address-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc-stats/getStats-remote-candidate-address-expected.txt
index f73ad23f..2142d322 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc-stats/getStats-remote-candidate-address-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc-stats/getStats-remote-candidate-address-expected.txt
@@ -1,5 +1,7 @@
 This is a testharness.js-based test.
 [FAIL] Do not expose in stats remote addresses that are not known to be already exposed to JS
-  assert_equals: address should be null expected (object) null but got (string) ""
+  promise_test: Unhandled rejection with value: object "ReferenceError: openChannelPair is not defined"
+[FAIL] Expose in stats remote addresses that are already exposed to JS
+  promise_test: Unhandled rejection with value: object "ReferenceError: openChannelPair is not defined"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-stats/getStats-remote-candidate-address.html b/third_party/blink/web_tests/external/wpt/webrtc-stats/getStats-remote-candidate-address.html
index add6790..93d4284 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc-stats/getStats-remote-candidate-address.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc-stats/getStats-remote-candidate-address.html
@@ -1,9 +1,11 @@
 <!doctype html>
 <meta charset=utf-8>
+<meta name="timeout" content="long">
 <title>Exposure or remote candidate address on stats</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="../webrtc/RTCPeerConnection-helper.js"></script>
+<script src="../webrtc/RTCDataChannel-helper.js"></script>
 <script>
 promise_test(async (test) => {
     const localPc = new RTCPeerConnection();
@@ -11,26 +13,19 @@
     const remotePc = new RTCPeerConnection();
     test.add_cleanup(() => remotePc.close());
 
-    const promiseDataChannel = new Promise(resolve => {
-        remotePc.addEventListener('datachannel', (event) => {
-            resolve(event.channel);
-        });
-    });
-
-    const localDataChannel = localPc.createDataChannel('test');
-
+    const pairPromise = openChannelPair(localPc, remotePc, 'prflx_obfuscate');
     localPc.addEventListener('icecandidate', event => {
         if (event.candidate)
             remotePc.addIceCandidate(event.candidate);
     });
     exchangeOfferAnswer(localPc, remotePc);
 
-    const remoteDataChannel = await promiseDataChannel;
+    const [localChannel, remoteChannel] = await pairPromise;
 
-    localDataChannel.send("test");
+    localChannel.send("test");
 
     await new Promise(resolve => {
-        remoteDataChannel.onmessage = resolve;
+        remoteChannel.onmessage = resolve;
     });
 
     const remoteCandidateStats = [...(await localPc.getStats()).values()].find(({type}) => type === 'remote-candidate');
@@ -43,30 +38,19 @@
     const remotePc = new RTCPeerConnection();
     test.add_cleanup(() => remotePc.close());
 
-    const promiseDataChannel = new Promise(resolve => {
-        remotePc.addEventListener('datachannel', (event) => {
-            resolve(event.channel);
-        });
-    });
-
-    const localDataChannel = localPc.createDataChannel('test');
-
+    const pairPromise = openChannelPair(localPc, remotePc, 'prflx_obfuscate');
     localPc.addEventListener('icecandidate', event => {
         if (event.candidate)
             remotePc.addIceCandidate(event.candidate);
     });
-    remotePc.addEventListener('icecandidate', event => {
-        if (event.candidate)
-            localPc.addIceCandidate(event.candidate);
-    });
     exchangeOfferAnswer(localPc, remotePc);
 
-    const remoteDataChannel = await promiseDataChannel;
+    const [localChannel, remoteChannel] = await pairPromise;
 
-    localDataChannel.send("test");
+    localChannel.send("test");
 
     await new Promise(resolve => {
-        remoteDataChannel.onmessage = resolve;
+        remoteChannel.onmessage = resolve;
     });
 
     const remoteCandidateStats = [...(await localPc.getStats()).values()].find(({type}) => type === 'remote-candidate');
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
index 99f20fb..1caa1354 100644
--- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
+++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
@@ -120,6 +120,7 @@
 PASS oldChildWindow.navigator.xr.ondevicechange is newChildWindow.navigator.xr.ondevicechange
 PASS oldChildWindow.onabort is newChildWindow.onabort
 PASS oldChildWindow.onafterprint is newChildWindow.onafterprint
+PASS oldChildWindow.onanimationcancel is newChildWindow.onanimationcancel
 PASS oldChildWindow.onanimationend is newChildWindow.onanimationend
 PASS oldChildWindow.onanimationiteration is newChildWindow.onanimationiteration
 PASS oldChildWindow.onanimationstart is newChildWindow.onanimationstart
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
index 6253908..9f226c2b 100644
--- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
+++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
@@ -59,6 +59,7 @@
 PASS childWindow.navigator.windowControlsOverlay.visible is false
 PASS childWindow.onabort is null
 PASS childWindow.onafterprint is null
+PASS childWindow.onanimationcancel is null
 PASS childWindow.onanimationend is null
 PASS childWindow.onanimationiteration is null
 PASS childWindow.onanimationstart is null
diff --git a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
index 8313909..caa32baa 100644
--- a/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
+++ b/third_party/blink/web_tests/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
@@ -59,6 +59,7 @@
 PASS childWindow.navigator.windowControlsOverlay.visible is false
 PASS childWindow.onabort is null
 PASS childWindow.onafterprint is null
+PASS childWindow.onanimationcancel is null
 PASS childWindow.onanimationend is null
 PASS childWindow.onanimationiteration is null
 PASS childWindow.onanimationstart is null
diff --git a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
index 235bd0aa..325657c 100644
--- a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
@@ -99,6 +99,7 @@
 PASS oldChildWindow.navigator.xr.ondevicechange is newChildWindow.navigator.xr.ondevicechange
 PASS oldChildWindow.onabort is newChildWindow.onabort
 PASS oldChildWindow.onafterprint is newChildWindow.onafterprint
+PASS oldChildWindow.onanimationcancel is newChildWindow.onanimationcancel
 PASS oldChildWindow.onanimationend is newChildWindow.onanimationend
 PASS oldChildWindow.onanimationiteration is newChildWindow.onanimationiteration
 PASS oldChildWindow.onanimationstart is newChildWindow.onanimationstart
diff --git a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
index 224e58a7..16dc2c0f 100644
--- a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced-expected.txt
@@ -58,6 +58,7 @@
 PASS childWindow.navigator.windowControlsOverlay.visible is false
 PASS childWindow.onabort is null
 PASS childWindow.onafterprint is null
+PASS childWindow.onanimationcancel is null
 PASS childWindow.onanimationend is null
 PASS childWindow.onanimationiteration is null
 PASS childWindow.onanimationstart is null
diff --git a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
index 1d61d2a..dbb8eb1 100644
--- a/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/fast/dom/Window/property-access-on-cached-window-after-frame-removed-expected.txt
@@ -58,6 +58,7 @@
 PASS childWindow.navigator.windowControlsOverlay.visible is false
 PASS childWindow.onabort is null
 PASS childWindow.onafterprint is null
+PASS childWindow.onanimationcancel is null
 PASS childWindow.onanimationend is null
 PASS childWindow.onanimationiteration is null
 PASS childWindow.onanimationstart is null
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/element-instance-property-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/element-instance-property-listing-expected.txt
index 35a8a352..dd275c0cc 100644
--- a/third_party/blink/web_tests/virtual/stable/webexposed/element-instance-property-listing-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/webexposed/element-instance-property-listing-expected.txt
@@ -174,6 +174,7 @@
     property offsetTop
     property offsetWidth
     property onabort
+    property onanimationcancel
     property onanimationend
     property onanimationiteration
     property onanimationstart
@@ -1417,6 +1418,7 @@
     property nonce
     property normalize
     property onabort
+    property onanimationcancel
     property onanimationend
     property onanimationiteration
     property onanimationstart
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
index 81853f08..3f272af 100644
--- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -1757,6 +1757,7 @@
     getter linkColor
     getter links
     getter onabort
+    getter onanimationcancel
     getter onanimationend
     getter onanimationiteration
     getter onanimationstart
@@ -1979,6 +1980,7 @@
     setter fullscreenEnabled
     setter linkColor
     setter onabort
+    setter onanimationcancel
     setter onanimationend
     setter onanimationiteration
     setter onanimationstart
@@ -3534,6 +3536,7 @@
     getter offsetTop
     getter offsetWidth
     getter onabort
+    getter onanimationcancel
     getter onanimationend
     getter onanimationiteration
     getter onanimationstart
@@ -3670,6 +3673,7 @@
     setter lang
     setter nonce
     setter onabort
+    setter onanimationcancel
     setter onanimationend
     setter onanimationiteration
     setter onanimationstart
@@ -5523,6 +5527,7 @@
     getter dataset
     getter nonce
     getter onabort
+    getter onanimationcancel
     getter onanimationend
     getter onanimationiteration
     getter onanimationstart
@@ -5635,6 +5640,7 @@
     setter autofocus
     setter nonce
     setter onabort
+    setter onanimationcancel
     setter onanimationend
     setter onanimationiteration
     setter onanimationstart
@@ -7807,6 +7813,7 @@
     getter dataset
     getter nonce
     getter onabort
+    getter onanimationcancel
     getter onanimationend
     getter onanimationiteration
     getter onanimationstart
@@ -7921,6 +7928,7 @@
     setter autofocus
     setter nonce
     setter onabort
+    setter onanimationcancel
     setter onanimationend
     setter onanimationiteration
     setter onanimationstart
@@ -12284,6 +12292,7 @@
     getter offscreenBuffering
     getter onabort
     getter onafterprint
+    getter onanimationcancel
     getter onanimationend
     getter onanimationiteration
     getter onanimationstart
@@ -12508,6 +12517,7 @@
     setter offscreenBuffering
     setter onabort
     setter onafterprint
+    setter onanimationcancel
     setter onanimationend
     setter onanimationiteration
     setter onanimationstart
diff --git a/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt b/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
index 9275004..8942e8a2 100644
--- a/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
@@ -186,6 +186,7 @@
     property offsetTop
     property offsetWidth
     property onabort
+    property onanimationcancel
     property onanimationend
     property onanimationiteration
     property onanimationstart
@@ -1507,6 +1508,7 @@
     property nonce
     property normalize
     property onabort
+    property onanimationcancel
     property onanimationend
     property onanimationiteration
     property onanimationstart
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index 09aa58d..cf62e53 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -1993,6 +1993,7 @@
     getter linkColor
     getter links
     getter onabort
+    getter onanimationcancel
     getter onanimationend
     getter onanimationiteration
     getter onanimationstart
@@ -2225,6 +2226,7 @@
     setter fullscreenEnabled
     setter linkColor
     setter onabort
+    setter onanimationcancel
     setter onanimationend
     setter onanimationiteration
     setter onanimationstart
@@ -3902,6 +3904,7 @@
     getter offsetTop
     getter offsetWidth
     getter onabort
+    getter onanimationcancel
     getter onanimationend
     getter onanimationiteration
     getter onanimationstart
@@ -4041,6 +4044,7 @@
     setter lang
     setter nonce
     setter onabort
+    setter onanimationcancel
     setter onanimationend
     setter onanimationiteration
     setter onanimationstart
@@ -6027,6 +6031,7 @@
     getter focusgroup
     getter nonce
     getter onabort
+    getter onanimationcancel
     getter onanimationend
     getter onanimationiteration
     getter onanimationstart
@@ -6141,6 +6146,7 @@
     setter focusgroup
     setter nonce
     setter onabort
+    setter onanimationcancel
     setter onanimationend
     setter onanimationiteration
     setter onanimationstart
@@ -8607,6 +8613,7 @@
     getter focusgroup
     getter nonce
     getter onabort
+    getter onanimationcancel
     getter onanimationend
     getter onanimationiteration
     getter onanimationstart
@@ -8723,6 +8730,7 @@
     setter focusgroup
     setter nonce
     setter onabort
+    setter onanimationcancel
     setter onanimationend
     setter onanimationiteration
     setter onanimationstart
@@ -13428,6 +13436,7 @@
     getter offscreenBuffering
     getter onabort
     getter onafterprint
+    getter onanimationcancel
     getter onanimationend
     getter onanimationiteration
     getter onanimationstart
@@ -13662,6 +13671,7 @@
     setter offscreenBuffering
     setter onabort
     setter onafterprint
+    setter onanimationcancel
     setter onanimationend
     setter onanimationiteration
     setter onanimationstart
diff --git a/third_party/boringssl/src b/third_party/boringssl/src
index 8c7d129..1524d7b 160000
--- a/third_party/boringssl/src
+++ b/third_party/boringssl/src
@@ -1 +1 @@
-Subproject commit 8c7d12999b5bcce52f6e47f06906173fdc56d6a1
+Subproject commit 1524d7be010cf0949d5d55d809a1a411de407c88
diff --git a/third_party/cpuinfo/src b/third_party/cpuinfo/src
index 161a9ec..ff24ffe 160000
--- a/third_party/cpuinfo/src
+++ b/third_party/cpuinfo/src
@@ -1 +1 @@
-Subproject commit 161a9ec374884f4b3e85725cb22e05f9458fdc93
+Subproject commit ff24ffee8340fbd9001cce6a9ef41cdd16aa2bd3
diff --git a/third_party/dawn b/third_party/dawn
index 04dab81..7546172 160000
--- a/third_party/dawn
+++ b/third_party/dawn
@@ -1 +1 @@
-Subproject commit 04dab8177931725bd88271eb4d2de43d8e1b6601
+Subproject commit 75461721fdeecd4db2654fcedaa22b20acdbfc36
diff --git a/third_party/depot_tools b/third_party/depot_tools
index b48cbb3..7c09ebf 160000
--- a/third_party/depot_tools
+++ b/third_party/depot_tools
@@ -1 +1 @@
-Subproject commit b48cbb3e60a0f96597657c7b66738ead6b50a229
+Subproject commit 7c09ebfd12c9470ec2ff6c02685c3a157a9290b7
diff --git a/third_party/devtools-frontend/src b/third_party/devtools-frontend/src
index bee4830..7116806 160000
--- a/third_party/devtools-frontend/src
+++ b/third_party/devtools-frontend/src
@@ -1 +1 @@
-Subproject commit bee483082d01ffc91dd4dd192bda7d9267c45ddd
+Subproject commit 7116806a8572358c8424600a0111972d925f48aa
diff --git a/third_party/perfetto b/third_party/perfetto
index 7307480..43be17d 160000
--- a/third_party/perfetto
+++ b/third_party/perfetto
@@ -1 +1 @@
-Subproject commit 7307480b25c072cc68e359067e1d09aae90111d0
+Subproject commit 43be17dba6e57a47f1f71d0b6ff072f3179e54a6
diff --git a/third_party/robolectric/custom_asynctask/java/src/org/chromium/base/task/test/ShadowAsyncTask.java b/third_party/robolectric/custom_asynctask/java/src/org/chromium/base/task/test/ShadowAsyncTask.java
index 857dacf9..bac4e80 100644
--- a/third_party/robolectric/custom_asynctask/java/src/org/chromium/base/task/test/ShadowAsyncTask.java
+++ b/third_party/robolectric/custom_asynctask/java/src/org/chromium/base/task/test/ShadowAsyncTask.java
@@ -136,13 +136,13 @@
 
     @Implementation
     public AsyncTask<Result> executeOnExecutor(LocationAwareExecutor executor) {
-        return executeOnExecutor((Executor) executor);
+        return executeOnExecutor(executor, null);
     }
 
     @Implementation
     public AsyncTask<Result> executeOnExecutor(
             LocationAwareExecutor executor, @Nullable Location location) {
-        return executeOnExecutor(executor);
+        return executeOnExecutor((Executor) executor);
     }
 
     @Implementation
diff --git a/third_party/rust/array_init/v2/BUILD.gn b/third_party/rust/array_init/v2/BUILD.gn
new file mode 100644
index 0000000..e760e44
--- /dev/null
+++ b/third_party/rust/array_init/v2/BUILD.gn
@@ -0,0 +1,66 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# @generated from third_party/rust/chromium_crates_io/BUILD.gn.hbs by
+# tools/crates/gnrt.
+# Do not edit!
+
+import("//build/rust/cargo_crate.gni")
+
+cargo_crate("lib") {
+  crate_name = "array_init"
+  epoch = "2"
+  crate_type = "rlib"
+  crate_root =
+      "//third_party/rust/chromium_crates_io/vendor/array-init-v2/src/lib.rs"
+  sources = [
+    "//third_party/rust/chromium_crates_io/vendor/array-init-v2/src/lib.rs",
+  ]
+  inputs = []
+
+  build_native_rust_unit_tests = false
+  edition = "2018"
+  cargo_pkg_authors = "Manish Goregaokar <manishsmail@gmail.com>, Michal 'vorner' Vaner <vorner@vorner.cz>"
+  cargo_pkg_name = "array-init"
+  cargo_pkg_description = "Safe wrapper for initializing fixed-size arrays"
+  cargo_pkg_repository = "https://github.com/Manishearth/array-init/"
+  cargo_pkg_version = "2.1.0"
+
+  allow_unsafe = true
+
+  # Only for usage from third-party crates. Add the crate to
+  # //third_party/rust/chromium_crates_io/Cargo.toml to use
+  # it from first-party code.
+  visibility = [ "//third_party/rust/*" ]
+
+  #####################################################################
+  # Tweaking which GN `config`s apply to this target.
+
+  # Config changes that apply to all `//third_party/rust` crates.
+  _configs_to_remove = [
+    # We don't need code coverage data for any `chromium_crates_io` crates.
+    "//build/config/coverage:default_coverage",
+
+    # This is third-party code, so remove `chromium_code` config.  We are not
+    # at the same time adding `//build/config/compiler:no_chromium_code`,
+    # because 1) we don't want to pull how warnings are handled by that config
+    # and 2) that config doesn't have any non-warnings-related stuff.
+    "//build/config/compiler:chromium_code",
+  ]
+  _configs_to_add = []
+
+  # Changing (if needed) which configs apply to this specific crate (based on
+  # `extra_kv.configs_to_remove` and `extra_kv.configs_to_add` from
+  # `gnrt_config.toml`).
+  _configs_to_remove += []
+  _configs_to_add += []
+
+  # Applying config changes.
+  library_configs -= _configs_to_remove
+  library_configs += _configs_to_add
+  executable_configs -= _configs_to_remove
+  executable_configs += _configs_to_add
+  proc_macro_configs -= _configs_to_remove
+  proc_macro_configs += _configs_to_add
+}
diff --git a/third_party/rust/array_init/v2/README.chromium b/third_party/rust/array_init/v2/README.chromium
new file mode 100644
index 0000000..4cd37ae
--- /dev/null
+++ b/third_party/rust/array_init/v2/README.chromium
@@ -0,0 +1,11 @@
+Name: array-init
+URL: https://crates.io/crates/array-init
+Version: 2.1.0
+Revision: 60635047ab2800832319829840c68df03c39945b
+Update Mechanism: Manual (https://crbug.com/449898466)
+License: Apache-2.0
+License File: //third_party/rust/chromium_crates_io/vendor/array-init-v2/LICENSE-APACHE
+Shipped: yes
+Security Critical: yes
+
+Description: Safe wrapper for initializing fixed-size arrays
diff --git a/third_party/rust/byteorder/v1/BUILD.gn b/third_party/rust/byteorder/v1/BUILD.gn
new file mode 100644
index 0000000..d6431d3
--- /dev/null
+++ b/third_party/rust/byteorder/v1/BUILD.gn
@@ -0,0 +1,73 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# @generated from third_party/rust/chromium_crates_io/BUILD.gn.hbs by
+# tools/crates/gnrt.
+# Do not edit!
+
+import("//build/rust/cargo_crate.gni")
+
+cargo_crate("lib") {
+  crate_name = "byteorder"
+  epoch = "1"
+  crate_type = "rlib"
+  crate_root =
+      "//third_party/rust/chromium_crates_io/vendor/byteorder-v1/src/lib.rs"
+  sources = [
+    "//third_party/rust/chromium_crates_io/vendor/byteorder-v1/src/io.rs",
+    "//third_party/rust/chromium_crates_io/vendor/byteorder-v1/src/lib.rs",
+  ]
+  inputs = []
+
+  build_native_rust_unit_tests = false
+  edition = "2021"
+  cargo_pkg_authors = "Andrew Gallant <jamslam@gmail.com>"
+  cargo_pkg_name = "byteorder"
+  cargo_pkg_description =
+      "Library for reading/writing numbers in big-endian and little-endian."
+  cargo_pkg_repository = "https://github.com/BurntSushi/byteorder"
+  cargo_pkg_version = "1.5.0"
+
+  allow_unsafe = true
+
+  features = [
+    "default",
+    "std",
+  ]
+
+  # Only for usage from third-party crates. Add the crate to
+  # //third_party/rust/chromium_crates_io/Cargo.toml to use
+  # it from first-party code.
+  visibility = [ "//third_party/rust/*" ]
+
+  #####################################################################
+  # Tweaking which GN `config`s apply to this target.
+
+  # Config changes that apply to all `//third_party/rust` crates.
+  _configs_to_remove = [
+    # We don't need code coverage data for any `chromium_crates_io` crates.
+    "//build/config/coverage:default_coverage",
+
+    # This is third-party code, so remove `chromium_code` config.  We are not
+    # at the same time adding `//build/config/compiler:no_chromium_code`,
+    # because 1) we don't want to pull how warnings are handled by that config
+    # and 2) that config doesn't have any non-warnings-related stuff.
+    "//build/config/compiler:chromium_code",
+  ]
+  _configs_to_add = []
+
+  # Changing (if needed) which configs apply to this specific crate (based on
+  # `extra_kv.configs_to_remove` and `extra_kv.configs_to_add` from
+  # `gnrt_config.toml`).
+  _configs_to_remove += []
+  _configs_to_add += []
+
+  # Applying config changes.
+  library_configs -= _configs_to_remove
+  library_configs += _configs_to_add
+  executable_configs -= _configs_to_remove
+  executable_configs += _configs_to_add
+  proc_macro_configs -= _configs_to_remove
+  proc_macro_configs += _configs_to_add
+}
diff --git a/third_party/rust/byteorder/v1/README.chromium b/third_party/rust/byteorder/v1/README.chromium
new file mode 100644
index 0000000..5694419
--- /dev/null
+++ b/third_party/rust/byteorder/v1/README.chromium
@@ -0,0 +1,11 @@
+Name: byteorder
+URL: https://crates.io/crates/byteorder
+Version: 1.5.0
+Revision: ec068eefa042d494475db125c4b034bd8e9e34dd
+Update Mechanism: Manual (https://crbug.com/449898466)
+License: MIT
+License File: //third_party/rust/chromium_crates_io/vendor/byteorder-v1/LICENSE-MIT
+Shipped: yes
+Security Critical: yes
+
+Description: Library for reading/writing numbers in big-endian and little-endian.
diff --git a/third_party/rust/chromium_crates_io/Cargo.lock b/third_party/rust/chromium_crates_io/Cargo.lock
index 0df8f57..a35f89b 100644
--- a/third_party/rust/chromium_crates_io/Cargo.lock
+++ b/third_party/rust/chromium_crates_io/Cargo.lock
@@ -26,6 +26,11 @@
 ]
 
 [[package]]
+name = "array-init"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "arrayvec"
 version = "0.7.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -69,6 +74,11 @@
 ]
 
 [[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "bytes"
 version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -117,6 +127,7 @@
  "icu_normalizer",
  "icu_properties",
  "icu_provider",
+ "jxl",
  "lazy_static",
  "libc",
  "llguidance",
@@ -668,6 +679,45 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "jxl"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "array-init",
+ "byteorder",
+ "jxl_macros",
+ "jxl_simd",
+ "jxl_transforms",
+ "num-derive",
+ "num-traits",
+ "thiserror",
+]
+
+[[package]]
+name = "jxl_macros"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro-error2",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "jxl_simd"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "jxl_transforms"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "jxl_simd",
+]
+
+[[package]]
 name = "lazy_static"
 version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -738,6 +788,16 @@
 ]
 
 [[package]]
+name = "num-derive"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
 name = "num-integer"
 version = "0.1.46"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -786,6 +846,26 @@
 ]
 
 [[package]]
+name = "proc-macro-error-attr2"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2",
+ "quote",
+]
+
+[[package]]
+name = "proc-macro-error2"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro-error-attr2",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
 name = "proc-macro2"
 version = "1.0.103"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1119,6 +1199,24 @@
 ]
 
 [[package]]
+name = "thiserror"
+version = "2.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
 name = "timezone_provider"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/third_party/rust/chromium_crates_io/Cargo.toml b/third_party/rust/chromium_crates_io/Cargo.toml
index b32a09d..44cbaf89 100644
--- a/third_party/rust/chromium_crates_io/Cargo.toml
+++ b/third_party/rust/chromium_crates_io/Cargo.toml
@@ -24,6 +24,7 @@
 fend-core = "1"
 font-types = "0.10"
 hex = "0.4"
+jxl = "0.1.4"
 lazy_static = "1"
 libc = "0.2"
 png = "=0.18.0-rc"
diff --git a/third_party/rust/chromium_crates_io/gnrt_config.toml b/third_party/rust/chromium_crates_io/gnrt_config.toml
index 746c410..38749b56 100644
--- a/third_party/rust/chromium_crates_io/gnrt_config.toml
+++ b/third_party/rust/chromium_crates_io/gnrt_config.toml
@@ -108,6 +108,9 @@
 [crate.anyhow.extra_kv]
 allow_unsafe = true
 
+[crate.array-init]
+extra_kv = { allow_unsafe = true }
+
 [crate.arrayvec.extra_kv]
 allow_unsafe = true
 
@@ -129,6 +132,9 @@
 [crate.bytemuck_derive.extra_kv]
 allow_unsafe = false
 
+[crate.byteorder]
+extra_kv = { allow_unsafe = true }
+
 [crate.bytes.extra_kv]
 allow_unsafe = true
 
@@ -355,6 +361,18 @@
 [crate.ixdtf.extra_kv]
 allow_unsafe = false
 
+[crate.jxl]
+extra_kv = { allow_unsafe = true }
+
+[crate.jxl_macros]
+extra_kv = { allow_unsafe = false }
+
+[crate.jxl_simd]
+extra_kv = { allow_unsafe = true }
+
+[crate.jxl_transforms]
+extra_kv = { allow_unsafe = true }
+
 [crate.lazy_static.extra_kv]
 allow_unsafe = true
 
@@ -394,6 +412,9 @@
 [crate.num-bigint.extra_kv]
 allow_unsafe = true
 
+[crate.num-derive]
+extra_kv = { allow_unsafe = false }
+
 [crate.num-integer.extra_kv]
 allow_unsafe = false
 
@@ -416,6 +437,12 @@
 [crate.potential_utf.extra_kv]
 allow_unsafe = true
 
+[crate.proc-macro-error-attr2]
+extra_kv = { allow_unsafe = false }
+
+[crate.proc-macro-error2]
+extra_kv = { allow_unsafe = false }
+
 [crate.proc-macro2.extra_kv]
 allow_unsafe = true
 
@@ -540,6 +567,13 @@
 [crate.termcolor.extra_kv]
 allow_unsafe = false
 
+[crate.thiserror]
+build_script_outputs = [ "private.rs" ]
+extra_kv = { allow_unsafe = false }
+
+[crate.thiserror-impl]
+extra_kv = { allow_unsafe = false }
+
 [crate.timezone_provider.extra_kv]
 allow_unsafe = true
 
diff --git a/third_party/rust/chromium_crates_io/vendor/array-init-v2/.cargo-checksum.json b/third_party/rust/chromium_crates_io/vendor/array-init-v2/.cargo-checksum.json
new file mode 100644
index 0000000..697c9ce
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/array-init-v2/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{}}
diff --git a/third_party/rust/chromium_crates_io/vendor/array-init-v2/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/array-init-v2/.cargo_vcs_info.json
new file mode 100644
index 0000000..7b5ef41b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/array-init-v2/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+  "git": {
+    "sha1": "60635047ab2800832319829840c68df03c39945b"
+  },
+  "path_in_vcs": ""
+}
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/array-init-v2/.github/workflows/rust.yml b/third_party/rust/chromium_crates_io/vendor/array-init-v2/.github/workflows/rust.yml
new file mode 100644
index 0000000..b90b04ef
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/array-init-v2/.github/workflows/rust.yml
@@ -0,0 +1,31 @@
+name: Rust
+
+on:
+  push:
+    branches: [ master ]
+  pull_request:
+    branches: [ master ]
+
+env:
+  CARGO_TERM_COLOR: always
+
+jobs:
+  build:
+
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        rust_version:
+          - stable
+          - 1.51  # MSRV (Minimum Supported Rust Version)
+
+    steps:
+    - uses: actions/checkout@v3
+    - uses: dtolnay/rust-toolchain@master
+      with:
+        toolchain: ${{matrix.rust_version}}
+    - name: Build
+      run: cargo build --verbose
+    - name: Run tests
+      run: cargo test --verbose
diff --git a/third_party/rust/chromium_crates_io/vendor/array-init-v2/.gitignore b/third_party/rust/chromium_crates_io/vendor/array-init-v2/.gitignore
new file mode 100644
index 0000000..4308d82
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/array-init-v2/.gitignore
@@ -0,0 +1,3 @@
+target/
+**/*.rs.bk
+Cargo.lock
diff --git a/third_party/rust/chromium_crates_io/vendor/array-init-v2/CHANGELOG.md b/third_party/rust/chromium_crates_io/vendor/array-init-v2/CHANGELOG.md
new file mode 100644
index 0000000..1c0f6af
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/array-init-v2/CHANGELOG.md
@@ -0,0 +1,30 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+
+## 2.1.0
+### Added
+- Introduced an MSRV: Rust 1.51
+- Added `map_array_init` function ([#38](https://github.com/Manishearth/array-init/pull/38))
+
+## v2.0.1 (2022-06-24)
+### Added
+- Added `from_iter_reversed` function ([#30](https://github.com/Manishearth/array-init/issues/30))
+
+## v2.0.0 (2021-03-29)
+### Breaking
+- Removed `IsArray` trait (not necessary anymore with const generics)
+
+## v1.1.0 (yanked)
+### Breaking
+- Removed `const-generics` feature flag. The MSRV is now rust 1.51
+
+## v1.0.0 (2020-10-14)
+### Added
+  - Added a `try_array_init` function which initializes an array with a callable that may fail.
+  - Added a `const-generics` feature which uses rust (unstable) `const-generics` feature to implement the initializer functions for all array sizes.
+  - Added documentation
diff --git a/third_party/rust/chromium_crates_io/vendor/array-init-v2/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/array-init-v2/Cargo.toml
new file mode 100644
index 0000000..be8d26a
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/array-init-v2/Cargo.toml
@@ -0,0 +1,37 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2018"
+name = "array-init"
+version = "2.1.0"
+authors = [
+    "Manish Goregaokar <manishsmail@gmail.com>",
+    "Michal 'vorner' Vaner <vorner@vorner.cz>",
+]
+exclude = [".travis.yml"]
+description = "Safe wrapper for initializing fixed-size arrays"
+documentation = "https://docs.rs/crate/array-init"
+readme = "README.md"
+keywords = [
+    "abstraction",
+    "initialization",
+    "no_std",
+]
+categories = [
+    "data-structures",
+    "no-std",
+]
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/Manishearth/array-init/"
+
+[package.metadata]
+msrv = "1.51"
diff --git a/third_party/rust/chromium_crates_io/vendor/array-init-v2/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/array-init-v2/Cargo.toml.orig
new file mode 100644
index 0000000..da9129e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/array-init-v2/Cargo.toml.orig
@@ -0,0 +1,21 @@
+[package]
+authors = [
+  "Manish Goregaokar <manishsmail@gmail.com>",
+  "Michal 'vorner' Vaner <vorner@vorner.cz>",
+]
+name = "array-init"
+version = "2.1.0"
+license = "MIT OR Apache-2.0"
+edition = "2018"
+description = "Safe wrapper for initializing fixed-size arrays"
+readme = "README.md"
+repository = "https://github.com/Manishearth/array-init/"
+documentation = "https://docs.rs/crate/array-init"
+
+keywords = ["abstraction", "initialization", "no_std"]
+categories = ["data-structures", "no-std"]
+exclude = [".travis.yml"]
+
+[package.metadata]
+# to be replaced by `package.rust-version` once we increase the msrv beyond 1.56
+msrv = "1.51"
diff --git a/third_party/rust/chromium_crates_io/vendor/array-init-v2/LICENSE-APACHE b/third_party/rust/chromium_crates_io/vendor/array-init-v2/LICENSE-APACHE
new file mode 100644
index 0000000..c1179ae
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/array-init-v2/LICENSE-APACHE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright 2017-2020 The array-init developers
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/third_party/rust/chromium_crates_io/vendor/array-init-v2/LICENSE-MIT b/third_party/rust/chromium_crates_io/vendor/array-init-v2/LICENSE-MIT
new file mode 100644
index 0000000..6c7d88b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/array-init-v2/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2017-2020 The array-init developers
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/third_party/rust/chromium_crates_io/vendor/array-init-v2/README.md b/third_party/rust/chromium_crates_io/vendor/array-init-v2/README.md
new file mode 100644
index 0000000..91d9a2e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/array-init-v2/README.md
@@ -0,0 +1,62 @@
+# array-init
+
+[![Crates.io](https://img.shields.io/crates/v/array-init?style=flat-square)](https://crates.io/crates/array-init)
+[![Docs](https://img.shields.io/badge/docs-doc.rs-blue?style=flat-square)](https://docs.rs/array-init)
+
+The `array-init` crate allows you to initialize arrays
+with an initializer closure that will be called
+once for each element until the array is filled.
+
+This way you do not need to default-fill an array
+before running initializers. Rust currently only
+lets you either specify all initializers at once,
+individually (`[a(), b(), c(), ...]`), or specify
+one initializer for a `Copy` type (`[a(); N]`),
+which will be called once with the result copied over.
+
+Care is taken not to leak memory shall the initialization
+fail.
+
+## Examples:
+
+```rust
+// Initialize an array of length 50 containing
+// successive squares
+
+let arr: [usize; 50] = array_init::array_init(|i| i * i);
+
+// Initialize an array from an iterator
+// producing an array of [1,2,3,4] repeated
+
+let four = [1,2,3,4];
+let mut iter = four.iter().copied().cycle();
+let arr: [u32; 50] = array_init::from_iter(iter).unwrap();
+
+// Closures can also mutate state. We guarantee that they will be called
+// in order from lower to higher indices.
+
+let mut last = 1u64;
+let mut secondlast = 0;
+let fibonacci: [u64; 50] = array_init::array_init(|_| {
+    let this = last + secondlast;
+    secondlast = last;
+    last = this;
+    this
+});
+```
+
+## Minimum Supported Rust Version (MSRV)
+
+`array-init` will only increase the MSRV on a new major
+or minor release, but not for patch releases.
+Any changes of the MSRV will be announced in the changelog.
+When increasing the MSRV, the new Rust version must have been
+released at least six months ago. The current MSRV is 1.51.0.
+MSRV changes can be expected to happen conservatively.
+
+## Licensing
+
+Licensed under either of Apache License, Version 2.0 or MIT license at your option.
+
+Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
+
diff --git a/third_party/rust/chromium_crates_io/vendor/array-init-v2/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/array-init-v2/src/lib.rs
new file mode 100644
index 0000000..6a0f50f
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/array-init-v2/src/lib.rs
@@ -0,0 +1,490 @@
+#![no_std]
+
+//! The `array-init` crate allows you to initialize arrays
+//! with an initializer closure that will be called
+//! once for each element until the array is filled.
+//!
+//! This way you do not need to default-fill an array
+//! before running initializers. Rust currently only
+//! lets you either specify all initializers at once,
+//! individually (`[a(), b(), c(), ...]`), or specify
+//! one initializer for a `Copy` type (`[a(); N]`),
+//! which will be called once with the result copied over.
+//!
+//! Care is taken not to leak memory shall the initialization
+//! fail.
+//!
+//! # Examples:
+//! ```rust
+//! # #![allow(unused)]
+//! # extern crate array_init;
+//! #
+//! // Initialize an array of length 50 containing
+//! // successive squares
+//!
+//! let arr: [u32; 50] = array_init::array_init(|i: usize| (i * i) as u32);
+//!
+//! // Initialize an array from an iterator
+//! // producing an array of [1,2,3,4] repeated
+//!
+//! let four = [1,2,3,4];
+//! let mut iter = four.iter().copied().cycle();
+//! let arr: [u32; 50] = array_init::from_iter(iter).unwrap();
+//!
+//! // Closures can also mutate state. We guarantee that they will be called
+//! // in order from lower to higher indices.
+//!
+//! let mut last = 1u64;
+//! let mut secondlast = 0;
+//! let fibonacci: [u64; 50] = array_init::array_init(|_| {
+//!     let this = last + secondlast;
+//!     secondlast = last;
+//!     last = this;
+//!     this
+//! });
+//! ```
+
+use ::core::{
+    mem::{self, MaybeUninit},
+    ptr, slice,
+};
+
+#[inline]
+/// Initialize an array given an initializer expression.
+///
+/// The initializer is given the index of the element. It is allowed
+/// to mutate external state; we will always initialize the elements in order.
+///
+/// # Examples
+///
+/// ```rust
+/// # #![allow(unused)]
+/// # extern crate array_init;
+/// #
+/// // Initialize an array of length 50 containing
+/// // successive squares
+/// let arr: [usize; 50] = array_init::array_init(|i| i * i);
+///
+/// assert!(arr.iter().enumerate().all(|(i, &x)| x == i * i));
+/// ```
+pub fn array_init<F, T, const N: usize>(mut initializer: F) -> [T; N]
+where
+    F: FnMut(usize) -> T,
+{
+    enum Unreachable {}
+
+    try_array_init(
+        // monomorphise into an infallible version
+        move |i| -> Result<T, Unreachable> { Ok(initializer(i)) },
+    )
+    .unwrap_or_else(
+        // zero-cost unwrap
+        |unreachable| match unreachable { /* ! */ },
+    )
+}
+
+#[inline]
+/// Initialize an array given an iterator
+///
+/// We will iterate until the array is full or the iterator is exhausted. Returns
+/// `None` if the iterator is exhausted before we can fill the array.
+///
+///   - Once the array is full, extra elements from the iterator (if any)
+///     won't be consumed.
+///
+/// # Examples
+///
+/// ```rust
+/// # #![allow(unused)]
+/// # extern crate array_init;
+/// #
+/// // Initialize an array from an iterator
+/// // producing an array of [1,2,3,4] repeated
+///
+/// let four = [1,2,3,4];
+/// let mut iter = four.iter().copied().cycle();
+/// let arr: [u32; 10] = array_init::from_iter(iter).unwrap();
+/// assert_eq!(arr, [1, 2, 3, 4, 1, 2, 3, 4, 1, 2]);
+/// ```
+pub fn from_iter<Iterable, T, const N: usize>(iterable: Iterable) -> Option<[T; N]>
+where
+    Iterable: IntoIterator<Item = T>,
+{
+    try_array_init_impl::<_, _, T, N, 1>({
+        let mut iterator = iterable.into_iter();
+        move |_| iterator.next().ok_or(())
+    })
+    .ok()
+}
+
+#[inline]
+/// Initialize an array in reverse given an iterator
+///
+/// We will iterate until the array is full or the iterator is exhausted. Returns
+/// `None` if the iterator is exhausted before we can fill the array.
+///
+///   - Once the array is full, extra elements from the iterator (if any)
+///     won't be consumed.
+///
+/// # Examples
+///
+/// ```rust
+/// # #![allow(unused)]
+/// # extern crate array_init;
+/// #
+/// // Initialize an array from an iterator
+/// // producing an array of [4,3,2,1] repeated, finishing with 1.
+///
+/// let four = [1,2,3,4];
+/// let mut iter = four.iter().copied().cycle();
+/// let arr: [u32; 10] = array_init::from_iter_reversed(iter).unwrap();
+/// assert_eq!(arr, [2, 1, 4, 3, 2, 1, 4, 3, 2, 1]);
+/// ```
+pub fn from_iter_reversed<Iterable, T, const N: usize>(iterable: Iterable) -> Option<[T; N]>
+where
+    Iterable: IntoIterator<Item = T>,
+{
+    try_array_init_impl::<_, _, T, N, -1>({
+        let mut iterator = iterable.into_iter();
+        move |_| iterator.next().ok_or(())
+    })
+    .ok()
+}
+
+#[inline]
+/// Initialize an array given an initializer expression that may fail.
+///
+/// The initializer is given the index (between 0 and `N - 1` included) of the element, and returns a `Result<T, Err>,`. It is allowed
+/// to mutate external state; we will always initialize from lower to higher indices.
+///
+/// # Examples
+///
+/// ```rust
+/// # #![allow(unused)]
+/// # extern crate array_init;
+/// #
+/// #[derive(PartialEq,Eq,Debug)]
+/// struct DivideByZero;
+///
+/// fn inv(i : usize) -> Result<f64,DivideByZero> {
+///     if i == 0 {
+///         Err(DivideByZero)
+///     } else {
+///         Ok(1./(i as f64))
+///     }
+/// }
+///
+/// // If the initializer does not fail, we get an initialized array
+/// let arr: [f64; 3] = array_init::try_array_init(|i| inv(3-i)).unwrap();
+/// assert_eq!(arr,[1./3., 1./2., 1./1.]);
+///
+/// // The initializer fails
+/// let res : Result<[f64;4], DivideByZero> = array_init::try_array_init(|i| inv(3-i));
+/// assert_eq!(res,Err(DivideByZero));
+/// ```
+pub fn try_array_init<Err, F, T, const N: usize>(initializer: F) -> Result<[T; N], Err>
+where
+    F: FnMut(usize) -> Result<T, Err>,
+{
+    try_array_init_impl::<Err, F, T, N, 1>(initializer)
+}
+
+#[inline]
+/// Initialize an array given a source array and a mapping expression. The size of the source array
+/// is the same as the size of the returned array.
+///
+/// The mapper is given an element from the source array and maps it to an element in the
+/// destination.
+///
+/// # Examples
+///
+/// ```rust
+/// # #![allow(unused)]
+/// # extern crate array_init;
+/// #
+/// // Initialize an array of length 50 containing successive squares
+/// let arr: [usize; 50] = array_init::array_init(|i| i * i);
+///
+/// // Map each usize element to a u64 element.
+/// let u64_arr: [u64; 50] = array_init::map_array_init(&arr, |element| *element as u64);
+///
+/// assert!(u64_arr.iter().enumerate().all(|(i, &x)| x == (i * i) as u64));
+/// ```
+pub fn map_array_init<M, T, U, const N: usize>(source: &[U; N], mut mapper: M) -> [T; N]
+where
+    M: FnMut(&U) -> T,
+{
+    // # Safety
+    //   - The array size is known at compile time so we are certain that both the source and
+    //     desitination have the same size. If the two arrays are of the same size we know that a
+    //     valid index for one would be a valid index for the other.
+    array_init(|index| unsafe { mapper(source.get_unchecked(index)) })
+}
+
+#[inline]
+fn try_array_init_impl<Err, F, T, const N: usize, const D: i8>(
+    mut initializer: F,
+) -> Result<[T; N], Err>
+where
+    F: FnMut(usize) -> Result<T, Err>,
+{
+    // The implementation differentiates two cases:
+    //   A) `T` does not need to be dropped. Even if the initializer panics
+    //      or returns `Err` we will not leak memory.
+    //   B) `T` needs to be dropped. We must keep track of which elements have
+    //      been initialized so far, and drop them if we encounter a panic or `Err` midway.
+    if !mem::needs_drop::<T>() {
+        let mut array: MaybeUninit<[T; N]> = MaybeUninit::uninit();
+        // pointer to array = *mut [T; N] <-> *mut T = pointer to first element
+        let mut ptr_i = array.as_mut_ptr() as *mut T;
+
+        // # Safety
+        //
+        //   - for D > 0, we are within the array since we start from the
+        //     beginning of the array, and we have `0 <= i < N`.
+        //   - for D < 0, we start at the end of the array and go back one
+        //     place before writing, going back N times in total, finishing
+        //     at the start of the array.
+        unsafe {
+            if D < 0 {
+                ptr_i = ptr_i.add(N);
+            }
+            for i in 0..N {
+                let value_i = initializer(i)?;
+                // We overwrite *ptr_i previously undefined value without reading or dropping it.
+                if D < 0 {
+                    ptr_i = ptr_i.sub(1);
+                }
+                ptr_i.write(value_i);
+                if D > 0 {
+                    ptr_i = ptr_i.add(1);
+                }
+            }
+            Ok(array.assume_init())
+        }
+    } else {
+        // else: `mem::needs_drop::<T>()`
+
+        /// # Safety
+        ///
+        ///   - `base_ptr[.. initialized_count]` must be a slice of init elements...
+        ///
+        ///   - ... that must be sound to `ptr::drop_in_place` if/when
+        ///     `UnsafeDropSliceGuard` is dropped: "symbolic ownership"
+        struct UnsafeDropSliceGuard<Item> {
+            base_ptr: *mut Item,
+            initialized_count: usize,
+        }
+
+        impl<Item> Drop for UnsafeDropSliceGuard<Item> {
+            fn drop(self: &'_ mut Self) {
+                unsafe {
+                    // # Safety
+                    //
+                    //   - the contract of the struct guarantees that this is sound
+                    ptr::drop_in_place(slice::from_raw_parts_mut(
+                        self.base_ptr,
+                        self.initialized_count,
+                    ));
+                }
+            }
+        }
+
+        //  If the `initializer(i)` call panics, `panic_guard` is dropped,
+        //  dropping `array[.. initialized_count]` => no memory leak!
+        //
+        // # Safety
+        //
+        //  1. - For D > 0, by construction, array[.. initiliazed_count] only
+        //       contains init elements, thus there is no risk of dropping
+        //       uninit data;
+        //     - For D < 0, by construction, array[N - initialized_count..] only
+        //       contains init elements.
+        //
+        //  2. - for D > 0, we are within the array since we start from the
+        //       beginning of the array, and we have `0 <= i < N`.
+        //     - for D < 0, we start at the end of the array and go back one
+        //       place before writing, going back N times in total, finishing
+        //       at the start of the array.
+        //
+        unsafe {
+            let mut array: MaybeUninit<[T; N]> = MaybeUninit::uninit();
+            // pointer to array = *mut [T; N] <-> *mut T = pointer to first element
+            let mut ptr_i = array.as_mut_ptr() as *mut T;
+            if D < 0 {
+                ptr_i = ptr_i.add(N);
+            }
+            let mut panic_guard = UnsafeDropSliceGuard {
+                base_ptr: ptr_i,
+                initialized_count: 0,
+            };
+
+            for i in 0..N {
+                // Invariant: `i` elements have already been initialized
+                panic_guard.initialized_count = i;
+                // If this panics or fails, `panic_guard` is dropped, thus
+                // dropping the elements in `base_ptr[.. i]` for D > 0 or
+                // `base_ptr[N - i..]` for D < 0.
+                let value_i = initializer(i)?;
+                // this cannot panic
+                // the previously uninit value is overwritten without being read or dropped
+                if D < 0 {
+                    ptr_i = ptr_i.sub(1);
+                    panic_guard.base_ptr = ptr_i;
+                }
+                ptr_i.write(value_i);
+                if D > 0 {
+                    ptr_i = ptr_i.add(1);
+                }
+            }
+            // From now on, the code can no longer `panic!`, let's take the
+            // symbolic ownership back
+            mem::forget(panic_guard);
+
+            Ok(array.assume_init())
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn seq() {
+        let seq: [usize; 5] = array_init(|i| i);
+        assert_eq!(&[0, 1, 2, 3, 4], &seq);
+    }
+
+    #[test]
+    fn array_from_iter() {
+        let array = [0, 1, 2, 3, 4];
+        let seq: [usize; 5] = from_iter(array.iter().copied()).unwrap();
+        assert_eq!(array, seq,);
+    }
+
+    #[test]
+    fn array_init_no_drop() {
+        DropChecker::with(|drop_checker| {
+            let result: Result<[_; 5], ()> = try_array_init(|i| {
+                if i < 3 {
+                    Ok(drop_checker.new_element())
+                } else {
+                    Err(())
+                }
+            });
+            assert!(result.is_err());
+        });
+    }
+
+    #[test]
+    fn from_iter_no_drop() {
+        DropChecker::with(|drop_checker| {
+            let iterator = (0..3).map(|_| drop_checker.new_element());
+            let result: Option<[_; 5]> = from_iter(iterator);
+            assert!(result.is_none());
+        });
+    }
+
+    #[test]
+    fn from_iter_reversed_no_drop() {
+        DropChecker::with(|drop_checker| {
+            let iterator = (0..3).map(|_| drop_checker.new_element());
+            let result: Option<[_; 5]> = from_iter_reversed(iterator);
+            assert!(result.is_none());
+        });
+    }
+
+    #[test]
+    fn test_513_seq() {
+        let seq: [usize; 513] = array_init(|i| i);
+        assert_eq!(
+            [
+                0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+                23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+                44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+                65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
+                86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
+                105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
+                121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136,
+                137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152,
+                153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168,
+                169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184,
+                185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200,
+                201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216,
+                217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
+                233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248,
+                249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+                265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280,
+                281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296,
+                297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312,
+                313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328,
+                329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344,
+                345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360,
+                361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376,
+                377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392,
+                393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408,
+                409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424,
+                425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440,
+                441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456,
+                457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472,
+                473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488,
+                489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504,
+                505, 506, 507, 508, 509, 510, 511, 512
+            ],
+            seq
+        );
+    }
+
+    use self::drop_checker::DropChecker;
+    mod drop_checker {
+        use ::core::cell::Cell;
+
+        pub(super) struct DropChecker {
+            slots: [Cell<bool>; 512],
+            next_uninit_slot: Cell<usize>,
+        }
+
+        pub(super) struct Element<'drop_checker> {
+            slot: &'drop_checker Cell<bool>,
+        }
+
+        impl Drop for Element<'_> {
+            fn drop(self: &'_ mut Self) {
+                assert!(self.slot.replace(false), "Double free!");
+            }
+        }
+
+        impl DropChecker {
+            pub(super) fn with(f: impl FnOnce(&Self)) {
+                let drop_checker = Self::new();
+                f(&drop_checker);
+                drop_checker.assert_no_leaks();
+            }
+
+            pub(super) fn new_element(self: &'_ Self) -> Element<'_> {
+                let i = self.next_uninit_slot.get();
+                self.next_uninit_slot.set(i + 1);
+                self.slots[i].set(true);
+                Element {
+                    slot: &self.slots[i],
+                }
+            }
+
+            fn new() -> Self {
+                Self {
+                    slots: crate::array_init(|_| Cell::new(false)),
+                    next_uninit_slot: Cell::new(0),
+                }
+            }
+
+            fn assert_no_leaks(self: Self) {
+                let leak_count: usize = self.slots[..self.next_uninit_slot.get()]
+                    .iter()
+                    .map(|slot| usize::from(slot.get() as u8))
+                    .sum();
+                assert_eq!(leak_count, 0, "{} elements leaked", leak_count);
+            }
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/byteorder-v1/.cargo-checksum.json b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/.cargo-checksum.json
new file mode 100644
index 0000000..697c9ce
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{}}
diff --git a/third_party/rust/chromium_crates_io/vendor/byteorder-v1/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/.cargo_vcs_info.json
new file mode 100644
index 0000000..39b39eff
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+  "git": {
+    "sha1": "ec068eefa042d494475db125c4b034bd8e9e34dd"
+  },
+  "path_in_vcs": ""
+}
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/byteorder-v1/.github/workflows/ci.yml b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/.github/workflows/ci.yml
new file mode 100644
index 0000000..1aa3c3b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/.github/workflows/ci.yml
@@ -0,0 +1,183 @@
+name: ci
+on:
+  pull_request:
+    branches:
+    - master
+  push:
+    branches:
+    - master
+  schedule:
+  - cron: '00 01 * * *'
+
+# The section is needed to drop write-all permissions that are granted on
+# `schedule` event. By specifying any permission explicitly all others are set
+# to none. By using the principle of least privilege the damage a compromised
+# workflow can do (because of an injection or compromised third party tool or
+# action) is restricted. Currently the worklow doesn't need any additional
+# permission except for pulling the code. Adding labels to issues, commenting
+# on pull-requests, etc. may need additional permissions:
+#
+# Syntax for this section:
+# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
+#
+# Reference for how to assign permissions on a job-by-job basis:
+# https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
+#
+# Reference for available permissions that we can enable if needed:
+# https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token
+permissions:
+  # to fetch code (actions/checkout)
+  contents: read
+
+jobs:
+  test:
+    name: test
+    env:
+      # For some builds, we use cross to test on 32-bit and big-endian
+      # systems.
+      CARGO: cargo
+      # When CARGO is set to CROSS, TARGET is set to `--target matrix.target`.
+      # Note that we only use cross on Linux, so setting a target on a
+      # different OS will just use normal cargo.
+      TARGET:
+      # Bump this as appropriate. We pin to a version to make sure CI
+      # continues to work as cross releases in the past have broken things
+      # in subtle ways.
+      CROSS_VERSION: v0.2.5
+    runs-on: ${{ matrix.os }}
+    strategy:
+      fail-fast: false
+      matrix:
+        include:
+        - build: pinned
+          os: ubuntu-latest
+          rust: 1.60.0
+        - build: stable
+          os: ubuntu-latest
+          rust: stable
+        - build: beta
+          os: ubuntu-latest
+          rust: beta
+        - build: nightly
+          os: ubuntu-latest
+          rust: nightly
+        - build: macos
+          os: macos-latest
+          rust: stable
+        - build: win-msvc
+          os: windows-latest
+          rust: stable
+        - build: win-gnu
+          os: windows-latest
+          rust: stable-x86_64-gnu
+        - build: stable-x86
+          os: ubuntu-latest
+          rust: stable
+          target: i686-unknown-linux-gnu
+        - build: stable-aarch64
+          os: ubuntu-latest
+          rust: stable
+          target: aarch64-unknown-linux-gnu
+        - build: stable-powerpc64
+          os: ubuntu-latest
+          rust: stable
+          target: powerpc64-unknown-linux-gnu
+        - build: stable-s390x
+          os: ubuntu-latest
+          rust: stable
+          target: s390x-unknown-linux-gnu
+    steps:
+    - name: Checkout repository
+      uses: actions/checkout@v4
+    - name: Install Rust
+      uses: dtolnay/rust-toolchain@master
+      with:
+        toolchain: ${{ matrix.rust }}
+    - name: Use Cross
+      if: matrix.os == 'ubuntu-latest' && matrix.target != ''
+      run: |
+        # In the past, new releases of 'cross' have broken CI. So for now, we
+        # pin it. We also use their pre-compiled binary releases because cross
+        # has over 100 dependencies and takes a bit to compile.
+        dir="$RUNNER_TEMP/cross-download"
+        mkdir "$dir"
+        echo "$dir" >> $GITHUB_PATH
+        cd "$dir"
+        curl -LO "https://github.com/cross-rs/cross/releases/download/$CROSS_VERSION/cross-x86_64-unknown-linux-musl.tar.gz"
+        tar xf cross-x86_64-unknown-linux-musl.tar.gz
+        echo "CARGO=cross" >> $GITHUB_ENV
+        echo "TARGET=--target ${{ matrix.target }}" >> $GITHUB_ENV
+    - name: Show command used for Cargo
+      run: |
+        echo "cargo command is: ${{ env.CARGO }}"
+        echo "target flag is: ${{ env.TARGET }}"
+    - name: Show CPU info for debugging
+      if: matrix.os == 'ubuntu-latest'
+      run: lscpu
+    - name: Build
+      run: ${{ env.CARGO }} build --verbose $TARGET
+    - name: Build (no default)
+      run: ${{ env.CARGO }} build --verbose $TARGET --no-default-features
+    - name: Build docs
+      run: ${{ env.CARGO }} doc --verbose $TARGET
+
+    # Our dev dependencies evolve more rapidly than we'd like, so only run
+    # tests when we aren't pinning the Rust version.
+    - name: Tests
+      if: matrix.build != 'pinned'
+      run: ${{ env.CARGO }} test --verbose $TARGET
+
+    - name: Tests (no default, lib only)
+      if: matrix.build != 'pinned'
+      run: ${{ env.CARGO }} test --verbose --no-default-features --lib $TARGET
+
+    - name: Tests (i128)
+      if: matrix.build != 'pinned'
+      run: ${{ env.CARGO }} test --verbose --features i128 $TARGET
+
+    - name: Tests (no default, lib only, i128)
+      if: matrix.build != 'pinned'
+      run: ${{ env.CARGO }} test --verbose --no-default-features --features i128 --lib $TARGET
+
+    - name: Compile benchmarks
+      if: matrix.build == 'nightly'
+      run: cargo bench --verbose --no-run $TARGET
+
+    - name: Compile benchmarks (no default)
+      if: matrix.build == 'nightly'
+      run: cargo bench --verbose --no-run --no-default-features $TARGET
+
+    - name: Compile benchmarks (i128)
+      if: matrix.build == 'nightly'
+      run: cargo bench --verbose --no-run --features i128 $TARGET
+
+    - name: Compile benchmarks (no default, i128)
+      if: matrix.build == 'nightly'
+      run: cargo bench --verbose --no-run --no-default-features --features i128 $TARGET
+
+  miri:
+    runs-on: ubuntu-latest
+    steps:
+    - name: Checkout repository
+      uses: actions/checkout@v4
+    - name: Install Rust
+      uses: dtolnay/rust-toolchain@master
+      with:
+        # We use nightly here so that we can use miri I guess?
+        toolchain: nightly
+        components: miri
+    - name: Run full test suite
+      run: cargo miri test --verbose
+
+  rustfmt:
+    runs-on: ubuntu-latest
+    steps:
+    - name: Checkout repository
+      uses: actions/checkout@v4
+    - name: Install Rust
+      uses: dtolnay/rust-toolchain@master
+      with:
+        toolchain: stable
+        components: rustfmt
+    - name: Check formatting
+      run: cargo fmt -- --check
diff --git a/third_party/rust/chromium_crates_io/vendor/byteorder-v1/.gitignore b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/.gitignore
new file mode 100644
index 0000000..1fec0efb8
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/.gitignore
@@ -0,0 +1,6 @@
+.*.swp
+doc
+tags
+build
+target
+Cargo.lock
diff --git a/third_party/rust/chromium_crates_io/vendor/byteorder-v1/CHANGELOG.md b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/CHANGELOG.md
new file mode 100644
index 0000000..9efb7ed2
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/CHANGELOG.md
@@ -0,0 +1,143 @@
+**WARNING:** This CHANGELOG is no longer updated. The activity for this project
+is sparse enough that you should refer to the commit log instead.
+
+
+1.3.4
+=====
+This patch release squashes deprecation warnings for the `try!` macro, in
+accordance with byteorder's minimum supported Rust version (currently at Rust
+1.12.0).
+
+
+1.3.3
+=====
+This patch release adds `ByteOrder::write_i8_into()` as a simple, safe interface
+for ordinarily unsafe or tedious code.
+
+
+1.3.2
+=====
+This patch release adds `ReadBytesExt::read_i8_into()` as a simple, safe interface
+for ordinarily unsafe or tedious code.
+
+
+1.3.1
+=====
+This minor release performs mostly small internal changes. Going forward, these
+are not going to be incorporated into the changelog.
+
+
+1.3.0
+=====
+This new minor release now enables `i128` support automatically on Rust
+compilers that support 128-bit integers. The `i128` feature is now a no-op, but
+continues to exist for backward compatibility purposes. The crate continues to
+maintain compatibility with Rust 1.12.0.
+
+This release also deprecates the `ByteOrder` trait methods
+`read_f32_into_unchecked` and `read_f64_into_unchecked` in favor of
+`read_f32_into` and `read_f64_into`. This was an oversight from the 1.2 release
+where the corresponding methods on `ReadBytesExt` were deprecated.
+
+`quickcheck` and `rand` were bumped to `0.8` and `0.6`, respectively.
+
+A few small documentation related bugs have been fixed.
+
+
+1.2.7
+=====
+This patch release excludes some CI files from the crate release and updates
+the license field to use `OR` instead of `/`.
+
+
+1.2.6
+=====
+This patch release fixes some test compilation errors introduced by an
+over-eager release of 1.2.5.
+
+
+1.2.5
+=====
+This patch release fixes some typos in the docs, adds doc tests to methods on
+`WriteByteExt` and bumps the quickcheck dependency to `0.7`.
+
+
+1.2.4
+=====
+This patch release adds support for 48-bit integers by adding the following
+methods to the `ByteOrder` trait: `read_u48`, `read_i48`, `write_u48` and
+`write_i48`. Corresponding methods have been added to the `ReadBytesExt` and
+`WriteBytesExt` traits as well.
+
+
+1.2.3
+=====
+This patch release removes the use of `feature(i128_type)` from byteorder,
+since it has been stabilized. We leave byteorder's `i128` feature in place
+in order to continue supporting compilation on older versions of Rust.
+
+
+1.2.2
+=====
+This patch release only consists of internal improvements and refactorings.
+Notably, this removes all uses of `transmute` and instead uses pointer casts.
+
+
+1.2.1
+=====
+This patch release removes more unnecessary uses of `unsafe` that
+were overlooked in the prior `1.2.0` release. In particular, the
+`ReadBytesExt::read_{f32,f64}_into_checked` methods have been deprecated and
+replaced by more appropriately named `read_{f32,f64}_into` methods.
+
+
+1.2.0
+=====
+The most prominent change in this release of `byteorder` is the removal of
+unnecessary signaling NaN masking, and in turn, the `unsafe` annotations
+associated with methods that didn't do masking. See
+[#103](https://github.com/BurntSushi/byteorder/issues/103)
+for more details.
+
+* [BUG #102](https://github.com/BurntSushi/byteorder/issues/102):
+  Fix big endian tests.
+* [BUG #103](https://github.com/BurntSushi/byteorder/issues/103):
+  Remove sNaN masking.
+
+
+1.1.0
+=====
+This release of `byteorder` features a number of fixes and improvements, mostly
+as a result of the
+[Litz Blitz evaluation](https://public.etherpad-mozilla.org/p/rust-crate-eval-byteorder).
+
+Feature enhancements:
+
+* [FEATURE #63](https://github.com/BurntSushi/byteorder/issues/63):
+  Add methods for reading/writing slices of numbers for a specific
+  endianness.
+* [FEATURE #65](https://github.com/BurntSushi/byteorder/issues/65):
+  Add support for `u128`/`i128` types. (Behind the nightly only `i128`
+  feature.)
+* [FEATURE #72](https://github.com/BurntSushi/byteorder/issues/72):
+  Add "panics" and "errors" sections for each relevant public API item.
+* [FEATURE #74](https://github.com/BurntSushi/byteorder/issues/74):
+  Add CI badges to Cargo.toml.
+* [FEATURE #75](https://github.com/BurntSushi/byteorder/issues/75):
+  Add more examples to public API items.
+* Add 24-bit read/write methods.
+* Add `BE` and `LE` type aliases for `BigEndian` and `LittleEndian`,
+  respectively.
+
+Bug fixes:
+
+* [BUG #68](https://github.com/BurntSushi/byteorder/issues/68):
+  Panic in {BigEndian,LittleEndian}::default.
+* [BUG #69](https://github.com/BurntSushi/byteorder/issues/69):
+  Seal the `ByteOrder` trait to prevent out-of-crate implementations.
+* [BUG #71](https://github.com/BurntSushi/byteorder/issues/71):
+  Guarantee that the results of `read_f32`/`read_f64` are always defined.
+* [BUG #73](https://github.com/BurntSushi/byteorder/issues/73):
+  Add crates.io categories.
+* [BUG #77](https://github.com/BurntSushi/byteorder/issues/77):
+  Add `html_root` doc attribute.
diff --git a/third_party/rust/chromium_crates_io/vendor/byteorder-v1/COPYING b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/COPYING
new file mode 100644
index 0000000..bb9c20a0
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/COPYING
@@ -0,0 +1,3 @@
+This project is dual-licensed under the Unlicense and MIT licenses.
+
+You may use this code under the terms of either license.
diff --git a/third_party/rust/chromium_crates_io/vendor/byteorder-v1/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/Cargo.toml
new file mode 100644
index 0000000..da515d9d
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/Cargo.toml
@@ -0,0 +1,54 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2021"
+rust-version = "1.60"
+name = "byteorder"
+version = "1.5.0"
+authors = ["Andrew Gallant <jamslam@gmail.com>"]
+description = "Library for reading/writing numbers in big-endian and little-endian."
+homepage = "https://github.com/BurntSushi/byteorder"
+documentation = "https://docs.rs/byteorder"
+readme = "README.md"
+keywords = [
+    "byte",
+    "endian",
+    "big-endian",
+    "little-endian",
+    "binary",
+]
+categories = [
+    "encoding",
+    "parsing",
+    "no-std",
+]
+license = "Unlicense OR MIT"
+repository = "https://github.com/BurntSushi/byteorder"
+
+[profile.bench]
+opt-level = 3
+
+[lib]
+name = "byteorder"
+bench = false
+
+[dev-dependencies.quickcheck]
+version = "0.9.2"
+default-features = false
+
+[dev-dependencies.rand]
+version = "0.7"
+
+[features]
+default = ["std"]
+i128 = []
+std = []
diff --git a/third_party/rust/chromium_crates_io/vendor/byteorder-v1/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/Cargo.toml.orig
new file mode 100644
index 0000000..91e6ab1
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/Cargo.toml.orig
@@ -0,0 +1,34 @@
+[package]
+name = "byteorder"
+version = "1.5.0"  #:version
+authors = ["Andrew Gallant <jamslam@gmail.com>"]
+description = "Library for reading/writing numbers in big-endian and little-endian."
+documentation = "https://docs.rs/byteorder"
+homepage = "https://github.com/BurntSushi/byteorder"
+repository = "https://github.com/BurntSushi/byteorder"
+readme = "README.md"
+categories = ["encoding", "parsing", "no-std"]
+keywords = ["byte", "endian", "big-endian", "little-endian", "binary"]
+license = "Unlicense OR MIT"
+edition = "2021"
+rust-version = "1.60"
+
+[lib]
+name = "byteorder"
+bench = false
+
+[dev-dependencies]
+quickcheck = { version = "0.9.2", default-features = false }
+rand = "0.7"
+
+[features]
+default = ["std"]
+std = []
+
+# This feature is no longer used and is DEPRECATED. This crate now
+# automatically enables i128 support for Rust compilers that support it. The
+# feature will be removed if and when a new major version is released.
+i128 = []
+
+[profile.bench]
+opt-level = 3
diff --git a/third_party/rust/chromium_crates_io/vendor/byteorder-v1/LICENSE-MIT b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/LICENSE-MIT
new file mode 100644
index 0000000..3b0a5dc
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/LICENSE-MIT
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Andrew Gallant
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/third_party/rust/chromium_crates_io/vendor/byteorder-v1/README.md b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/README.md
new file mode 100644
index 0000000..7c46019
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/README.md
@@ -0,0 +1,77 @@
+byteorder
+=========
+This crate provides convenience methods for encoding and decoding
+numbers in either big-endian or little-endian order.
+
+[![Build status](https://github.com/BurntSushi/byteorder/workflows/ci/badge.svg)](https://github.com/BurntSushi/byteorder/actions)
+[![crates.io](https://img.shields.io/crates/v/byteorder.svg)](https://crates.io/crates/byteorder)
+
+Dual-licensed under MIT or the [UNLICENSE](https://unlicense.org/).
+
+
+### Documentation
+
+https://docs.rs/byteorder
+
+
+### Installation
+
+This crate works with Cargo and is on
+[crates.io](https://crates.io/crates/byteorder). Add it to your `Cargo.toml`
+like so:
+
+```toml
+[dependencies]
+byteorder = "1"
+```
+
+If you want to augment existing `Read` and `Write` traits, then import the
+extension methods like so:
+
+```rust
+use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian, LittleEndian};
+```
+
+For example:
+
+```rust
+use std::io::Cursor;
+use byteorder::{BigEndian, ReadBytesExt};
+
+let mut rdr = Cursor::new(vec![2, 5, 3, 0]);
+// Note that we use type parameters to indicate which kind of byte order
+// we want!
+assert_eq!(517, rdr.read_u16::<BigEndian>().unwrap());
+assert_eq!(768, rdr.read_u16::<BigEndian>().unwrap());
+```
+
+### `no_std` crates
+
+This crate has a feature, `std`, that is enabled by default. To use this crate
+in a `no_std` context, add the following to your `Cargo.toml`:
+
+```toml
+[dependencies]
+byteorder = { version = "1", default-features = false }
+```
+
+
+### Minimum Rust version policy
+
+This crate's minimum supported `rustc` version is `1.60.0`.
+
+The current policy is that the minimum Rust version required to use this crate
+can be increased in minor version updates. For example, if `crate 1.0` requires
+Rust 1.20.0, then `crate 1.0.z` for all values of `z` will also require Rust
+1.20.0 or newer. However, `crate 1.y` for `y > 0` may require a newer minimum
+version of Rust.
+
+In general, this crate will be conservative with respect to the minimum
+supported version of Rust.
+
+
+### Alternatives
+
+Note that as of Rust 1.32, the standard numeric types provide built-in methods
+like `to_le_bytes` and `from_le_bytes`, which support some of the same use
+cases.
diff --git a/third_party/rust/chromium_crates_io/vendor/byteorder-v1/UNLICENSE b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/UNLICENSE
new file mode 100644
index 0000000..68a49da
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/UNLICENSE
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org/>
diff --git a/third_party/rust/chromium_crates_io/vendor/byteorder-v1/benches/bench.rs b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/benches/bench.rs
new file mode 100644
index 0000000..963251ce
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/benches/bench.rs
@@ -0,0 +1,326 @@
+#![feature(test)]
+
+extern crate test;
+
+macro_rules! bench_num {
+    ($name:ident, $read:ident, $bytes:expr, $data:expr) => {
+        mod $name {
+            use byteorder::{
+                BigEndian, ByteOrder, LittleEndian, NativeEndian,
+            };
+            use test::black_box as bb;
+            use test::Bencher;
+
+            const NITER: usize = 100_000;
+
+            #[bench]
+            fn read_big_endian(b: &mut Bencher) {
+                let buf = $data;
+                b.iter(|| {
+                    for _ in 0..NITER {
+                        bb(BigEndian::$read(&buf, $bytes));
+                    }
+                });
+            }
+
+            #[bench]
+            fn read_little_endian(b: &mut Bencher) {
+                let buf = $data;
+                b.iter(|| {
+                    for _ in 0..NITER {
+                        bb(LittleEndian::$read(&buf, $bytes));
+                    }
+                });
+            }
+
+            #[bench]
+            fn read_native_endian(b: &mut Bencher) {
+                let buf = $data;
+                b.iter(|| {
+                    for _ in 0..NITER {
+                        bb(NativeEndian::$read(&buf, $bytes));
+                    }
+                });
+            }
+        }
+    };
+    ($ty:ident, $max:ident,
+     $read:ident, $write:ident, $size:expr, $data:expr) => {
+        mod $ty {
+            use byteorder::{
+                BigEndian, ByteOrder, LittleEndian, NativeEndian,
+            };
+            use std::$ty;
+            use test::black_box as bb;
+            use test::Bencher;
+
+            const NITER: usize = 100_000;
+
+            #[bench]
+            fn read_big_endian(b: &mut Bencher) {
+                let buf = $data;
+                b.iter(|| {
+                    for _ in 0..NITER {
+                        bb(BigEndian::$read(&buf));
+                    }
+                });
+            }
+
+            #[bench]
+            fn read_little_endian(b: &mut Bencher) {
+                let buf = $data;
+                b.iter(|| {
+                    for _ in 0..NITER {
+                        bb(LittleEndian::$read(&buf));
+                    }
+                });
+            }
+
+            #[bench]
+            fn read_native_endian(b: &mut Bencher) {
+                let buf = $data;
+                b.iter(|| {
+                    for _ in 0..NITER {
+                        bb(NativeEndian::$read(&buf));
+                    }
+                });
+            }
+
+            #[bench]
+            fn write_big_endian(b: &mut Bencher) {
+                let mut buf = $data;
+                let n = $ty::$max;
+                b.iter(|| {
+                    for _ in 0..NITER {
+                        bb(BigEndian::$write(&mut buf, n));
+                    }
+                });
+            }
+
+            #[bench]
+            fn write_little_endian(b: &mut Bencher) {
+                let mut buf = $data;
+                let n = $ty::$max;
+                b.iter(|| {
+                    for _ in 0..NITER {
+                        bb(LittleEndian::$write(&mut buf, n));
+                    }
+                });
+            }
+
+            #[bench]
+            fn write_native_endian(b: &mut Bencher) {
+                let mut buf = $data;
+                let n = $ty::$max;
+                b.iter(|| {
+                    for _ in 0..NITER {
+                        bb(NativeEndian::$write(&mut buf, n));
+                    }
+                });
+            }
+        }
+    };
+}
+
+bench_num!(u16, MAX, read_u16, write_u16, 2, [1, 2]);
+bench_num!(i16, MAX, read_i16, write_i16, 2, [1, 2]);
+bench_num!(u32, MAX, read_u32, write_u32, 4, [1, 2, 3, 4]);
+bench_num!(i32, MAX, read_i32, write_i32, 4, [1, 2, 3, 4]);
+bench_num!(u64, MAX, read_u64, write_u64, 8, [1, 2, 3, 4, 5, 6, 7, 8]);
+bench_num!(i64, MAX, read_i64, write_i64, 8, [1, 2, 3, 4, 5, 6, 7, 8]);
+bench_num!(f32, MAX, read_f32, write_f32, 4, [1, 2, 3, 4]);
+bench_num!(f64, MAX, read_f64, write_f64, 8, [1, 2, 3, 4, 5, 6, 7, 8]);
+
+bench_num!(uint_1, read_uint, 1, [1]);
+bench_num!(uint_2, read_uint, 2, [1, 2]);
+bench_num!(uint_3, read_uint, 3, [1, 2, 3]);
+bench_num!(uint_4, read_uint, 4, [1, 2, 3, 4]);
+bench_num!(uint_5, read_uint, 5, [1, 2, 3, 4, 5]);
+bench_num!(uint_6, read_uint, 6, [1, 2, 3, 4, 5, 6]);
+bench_num!(uint_7, read_uint, 7, [1, 2, 3, 4, 5, 6, 7]);
+bench_num!(uint_8, read_uint, 8, [1, 2, 3, 4, 5, 6, 7, 8]);
+
+bench_num!(int_1, read_int, 1, [1]);
+bench_num!(int_2, read_int, 2, [1, 2]);
+bench_num!(int_3, read_int, 3, [1, 2, 3]);
+bench_num!(int_4, read_int, 4, [1, 2, 3, 4]);
+bench_num!(int_5, read_int, 5, [1, 2, 3, 4, 5]);
+bench_num!(int_6, read_int, 6, [1, 2, 3, 4, 5, 6]);
+bench_num!(int_7, read_int, 7, [1, 2, 3, 4, 5, 6, 7]);
+bench_num!(int_8, read_int, 8, [1, 2, 3, 4, 5, 6, 7, 8]);
+
+bench_num!(
+    u128,
+    MAX,
+    read_u128,
+    write_u128,
+    16,
+    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
+);
+bench_num!(
+    i128,
+    MAX,
+    read_i128,
+    write_i128,
+    16,
+    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
+);
+
+bench_num!(uint128_1, read_uint128, 1, [1]);
+bench_num!(uint128_2, read_uint128, 2, [1, 2]);
+bench_num!(uint128_3, read_uint128, 3, [1, 2, 3]);
+bench_num!(uint128_4, read_uint128, 4, [1, 2, 3, 4]);
+bench_num!(uint128_5, read_uint128, 5, [1, 2, 3, 4, 5]);
+bench_num!(uint128_6, read_uint128, 6, [1, 2, 3, 4, 5, 6]);
+bench_num!(uint128_7, read_uint128, 7, [1, 2, 3, 4, 5, 6, 7]);
+bench_num!(uint128_8, read_uint128, 8, [1, 2, 3, 4, 5, 6, 7, 8]);
+bench_num!(uint128_9, read_uint128, 9, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
+bench_num!(uint128_10, read_uint128, 10, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+bench_num!(uint128_11, read_uint128, 11, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
+bench_num!(
+    uint128_12,
+    read_uint128,
+    12,
+    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+);
+bench_num!(
+    uint128_13,
+    read_uint128,
+    13,
+    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
+);
+bench_num!(
+    uint128_14,
+    read_uint128,
+    14,
+    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
+);
+bench_num!(
+    uint128_15,
+    read_uint128,
+    15,
+    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
+);
+bench_num!(
+    uint128_16,
+    read_uint128,
+    16,
+    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
+);
+
+bench_num!(int128_1, read_int128, 1, [1]);
+bench_num!(int128_2, read_int128, 2, [1, 2]);
+bench_num!(int128_3, read_int128, 3, [1, 2, 3]);
+bench_num!(int128_4, read_int128, 4, [1, 2, 3, 4]);
+bench_num!(int128_5, read_int128, 5, [1, 2, 3, 4, 5]);
+bench_num!(int128_6, read_int128, 6, [1, 2, 3, 4, 5, 6]);
+bench_num!(int128_7, read_int128, 7, [1, 2, 3, 4, 5, 6, 7]);
+bench_num!(int128_8, read_int128, 8, [1, 2, 3, 4, 5, 6, 7, 8]);
+bench_num!(int128_9, read_int128, 9, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
+bench_num!(int128_10, read_int128, 10, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+bench_num!(int128_11, read_int128, 11, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
+bench_num!(
+    int128_12,
+    read_int128,
+    12,
+    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+);
+bench_num!(
+    int128_13,
+    read_int128,
+    13,
+    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
+);
+bench_num!(
+    int128_14,
+    read_int128,
+    14,
+    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
+);
+bench_num!(
+    int128_15,
+    read_int128,
+    15,
+    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
+);
+bench_num!(
+    int128_16,
+    read_int128,
+    16,
+    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
+);
+
+macro_rules! bench_slice {
+    ($name:ident, $numty:ty, $read:ident, $write:ident) => {
+        mod $name {
+            use std::mem::size_of;
+
+            use byteorder::{BigEndian, ByteOrder, LittleEndian};
+            use rand::distributions;
+            use rand::{self, Rng};
+            use test::Bencher;
+
+            #[bench]
+            fn read_big_endian(b: &mut Bencher) {
+                let mut numbers: Vec<$numty> = rand::thread_rng()
+                    .sample_iter(&distributions::Standard)
+                    .take(100000)
+                    .collect();
+                let mut bytes = vec![0; numbers.len() * size_of::<$numty>()];
+                BigEndian::$write(&numbers, &mut bytes);
+
+                b.bytes = bytes.len() as u64;
+                b.iter(|| {
+                    BigEndian::$read(&bytes, &mut numbers);
+                });
+            }
+
+            #[bench]
+            fn read_little_endian(b: &mut Bencher) {
+                let mut numbers: Vec<$numty> = rand::thread_rng()
+                    .sample_iter(&distributions::Standard)
+                    .take(100000)
+                    .collect();
+                let mut bytes = vec![0; numbers.len() * size_of::<$numty>()];
+                LittleEndian::$write(&numbers, &mut bytes);
+
+                b.bytes = bytes.len() as u64;
+                b.iter(|| {
+                    LittleEndian::$read(&bytes, &mut numbers);
+                });
+            }
+
+            #[bench]
+            fn write_big_endian(b: &mut Bencher) {
+                let numbers: Vec<$numty> = rand::thread_rng()
+                    .sample_iter(&distributions::Standard)
+                    .take(100000)
+                    .collect();
+                let mut bytes = vec![0; numbers.len() * size_of::<$numty>()];
+
+                b.bytes = bytes.len() as u64;
+                b.iter(|| {
+                    BigEndian::$write(&numbers, &mut bytes);
+                });
+            }
+
+            #[bench]
+            fn write_little_endian(b: &mut Bencher) {
+                let numbers: Vec<$numty> = rand::thread_rng()
+                    .sample_iter(&distributions::Standard)
+                    .take(100000)
+                    .collect();
+                let mut bytes = vec![0; numbers.len() * size_of::<$numty>()];
+
+                b.bytes = bytes.len() as u64;
+                b.iter(|| {
+                    LittleEndian::$write(&numbers, &mut bytes);
+                });
+            }
+        }
+    };
+}
+
+bench_slice!(slice_u16, u16, read_u16_into, write_u16_into);
+bench_slice!(slice_u64, u64, read_u64_into, write_u64_into);
+bench_slice!(slice_i64, i64, read_i64_into, write_i64_into);
diff --git a/third_party/rust/chromium_crates_io/vendor/byteorder-v1/rustfmt.toml b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/rustfmt.toml
new file mode 100644
index 0000000..aa37a218
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/rustfmt.toml
@@ -0,0 +1,2 @@
+max_width = 79
+use_small_heuristics = "max"
diff --git a/third_party/rust/chromium_crates_io/vendor/byteorder-v1/src/io.rs b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/src/io.rs
new file mode 100644
index 0000000..dfad2ca
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/src/io.rs
@@ -0,0 +1,1592 @@
+use std::{
+    io::{self, Result},
+    slice,
+};
+
+use crate::ByteOrder;
+
+/// Extends [`Read`] with methods for reading numbers. (For `std::io`.)
+///
+/// Most of the methods defined here have an unconstrained type parameter that
+/// must be explicitly instantiated. Typically, it is instantiated with either
+/// the [`BigEndian`] or [`LittleEndian`] types defined in this crate.
+///
+/// # Examples
+///
+/// Read unsigned 16 bit big-endian integers from a [`Read`]:
+///
+/// ```rust
+/// use std::io::Cursor;
+/// use byteorder::{BigEndian, ReadBytesExt};
+///
+/// let mut rdr = Cursor::new(vec![2, 5, 3, 0]);
+/// assert_eq!(517, rdr.read_u16::<BigEndian>().unwrap());
+/// assert_eq!(768, rdr.read_u16::<BigEndian>().unwrap());
+/// ```
+///
+/// [`BigEndian`]: enum.BigEndian.html
+/// [`LittleEndian`]: enum.LittleEndian.html
+/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
+pub trait ReadBytesExt: io::Read {
+    /// Reads an unsigned 8 bit integer from the underlying reader.
+    ///
+    /// Note that since this reads a single byte, no byte order conversions
+    /// are used. It is included for completeness.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read unsigned 8 bit integers from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::ReadBytesExt;
+    ///
+    /// let mut rdr = Cursor::new(vec![2, 5]);
+    /// assert_eq!(2, rdr.read_u8().unwrap());
+    /// assert_eq!(5, rdr.read_u8().unwrap());
+    /// ```
+    #[inline]
+    fn read_u8(&mut self) -> Result<u8> {
+        let mut buf = [0; 1];
+        self.read_exact(&mut buf)?;
+        Ok(buf[0])
+    }
+
+    /// Reads a signed 8 bit integer from the underlying reader.
+    ///
+    /// Note that since this reads a single byte, no byte order conversions
+    /// are used. It is included for completeness.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read signed 8 bit integers from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::ReadBytesExt;
+    ///
+    /// let mut rdr = Cursor::new(vec![0x02, 0xfb]);
+    /// assert_eq!(2, rdr.read_i8().unwrap());
+    /// assert_eq!(-5, rdr.read_i8().unwrap());
+    /// ```
+    #[inline]
+    fn read_i8(&mut self) -> Result<i8> {
+        let mut buf = [0; 1];
+        self.read_exact(&mut buf)?;
+        Ok(buf[0] as i8)
+    }
+
+    /// Reads an unsigned 16 bit integer from the underlying reader.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read unsigned 16 bit big-endian integers from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![2, 5, 3, 0]);
+    /// assert_eq!(517, rdr.read_u16::<BigEndian>().unwrap());
+    /// assert_eq!(768, rdr.read_u16::<BigEndian>().unwrap());
+    /// ```
+    #[inline]
+    fn read_u16<T: ByteOrder>(&mut self) -> Result<u16> {
+        let mut buf = [0; 2];
+        self.read_exact(&mut buf)?;
+        Ok(T::read_u16(&buf))
+    }
+
+    /// Reads a signed 16 bit integer from the underlying reader.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read signed 16 bit big-endian integers from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![0x00, 0xc1, 0xff, 0x7c]);
+    /// assert_eq!(193, rdr.read_i16::<BigEndian>().unwrap());
+    /// assert_eq!(-132, rdr.read_i16::<BigEndian>().unwrap());
+    /// ```
+    #[inline]
+    fn read_i16<T: ByteOrder>(&mut self) -> Result<i16> {
+        let mut buf = [0; 2];
+        self.read_exact(&mut buf)?;
+        Ok(T::read_i16(&buf))
+    }
+
+    /// Reads an unsigned 24 bit integer from the underlying reader.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read unsigned 24 bit big-endian integers from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![0x00, 0x01, 0x0b]);
+    /// assert_eq!(267, rdr.read_u24::<BigEndian>().unwrap());
+    /// ```
+    #[inline]
+    fn read_u24<T: ByteOrder>(&mut self) -> Result<u32> {
+        let mut buf = [0; 3];
+        self.read_exact(&mut buf)?;
+        Ok(T::read_u24(&buf))
+    }
+
+    /// Reads a signed 24 bit integer from the underlying reader.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read signed 24 bit big-endian integers from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![0xff, 0x7a, 0x33]);
+    /// assert_eq!(-34253, rdr.read_i24::<BigEndian>().unwrap());
+    /// ```
+    #[inline]
+    fn read_i24<T: ByteOrder>(&mut self) -> Result<i32> {
+        let mut buf = [0; 3];
+        self.read_exact(&mut buf)?;
+        Ok(T::read_i24(&buf))
+    }
+
+    /// Reads an unsigned 32 bit integer from the underlying reader.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read unsigned 32 bit big-endian integers from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![0x00, 0x00, 0x01, 0x0b]);
+    /// assert_eq!(267, rdr.read_u32::<BigEndian>().unwrap());
+    /// ```
+    #[inline]
+    fn read_u32<T: ByteOrder>(&mut self) -> Result<u32> {
+        let mut buf = [0; 4];
+        self.read_exact(&mut buf)?;
+        Ok(T::read_u32(&buf))
+    }
+
+    /// Reads a signed 32 bit integer from the underlying reader.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read signed 32 bit big-endian integers from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![0xff, 0xff, 0x7a, 0x33]);
+    /// assert_eq!(-34253, rdr.read_i32::<BigEndian>().unwrap());
+    /// ```
+    #[inline]
+    fn read_i32<T: ByteOrder>(&mut self) -> Result<i32> {
+        let mut buf = [0; 4];
+        self.read_exact(&mut buf)?;
+        Ok(T::read_i32(&buf))
+    }
+
+    /// Reads an unsigned 48 bit integer from the underlying reader.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read unsigned 48 bit big-endian integers from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![0xb6, 0x71, 0x6b, 0xdc, 0x2b, 0x31]);
+    /// assert_eq!(200598257150769, rdr.read_u48::<BigEndian>().unwrap());
+    /// ```
+    #[inline]
+    fn read_u48<T: ByteOrder>(&mut self) -> Result<u64> {
+        let mut buf = [0; 6];
+        self.read_exact(&mut buf)?;
+        Ok(T::read_u48(&buf))
+    }
+
+    /// Reads a signed 48 bit integer from the underlying reader.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read signed 48 bit big-endian integers from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![0x9d, 0x71, 0xab, 0xe7, 0x97, 0x8f]);
+    /// assert_eq!(-108363435763825, rdr.read_i48::<BigEndian>().unwrap());
+    /// ```
+    #[inline]
+    fn read_i48<T: ByteOrder>(&mut self) -> Result<i64> {
+        let mut buf = [0; 6];
+        self.read_exact(&mut buf)?;
+        Ok(T::read_i48(&buf))
+    }
+
+    /// Reads an unsigned 64 bit integer from the underlying reader.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read an unsigned 64 bit big-endian integer from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![0x00, 0x03, 0x43, 0x95, 0x4d, 0x60, 0x86, 0x83]);
+    /// assert_eq!(918733457491587, rdr.read_u64::<BigEndian>().unwrap());
+    /// ```
+    #[inline]
+    fn read_u64<T: ByteOrder>(&mut self) -> Result<u64> {
+        let mut buf = [0; 8];
+        self.read_exact(&mut buf)?;
+        Ok(T::read_u64(&buf))
+    }
+
+    /// Reads a signed 64 bit integer from the underlying reader.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read a signed 64 bit big-endian integer from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![0x80, 0, 0, 0, 0, 0, 0, 0]);
+    /// assert_eq!(i64::min_value(), rdr.read_i64::<BigEndian>().unwrap());
+    /// ```
+    #[inline]
+    fn read_i64<T: ByteOrder>(&mut self) -> Result<i64> {
+        let mut buf = [0; 8];
+        self.read_exact(&mut buf)?;
+        Ok(T::read_i64(&buf))
+    }
+
+    /// Reads an unsigned 128 bit integer from the underlying reader.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read an unsigned 128 bit big-endian integer from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![
+    ///     0x00, 0x03, 0x43, 0x95, 0x4d, 0x60, 0x86, 0x83,
+    ///     0x00, 0x03, 0x43, 0x95, 0x4d, 0x60, 0x86, 0x83
+    /// ]);
+    /// assert_eq!(16947640962301618749969007319746179, rdr.read_u128::<BigEndian>().unwrap());
+    /// ```
+    #[inline]
+    fn read_u128<T: ByteOrder>(&mut self) -> Result<u128> {
+        let mut buf = [0; 16];
+        self.read_exact(&mut buf)?;
+        Ok(T::read_u128(&buf))
+    }
+
+    /// Reads a signed 128 bit integer from the underlying reader.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read a signed 128 bit big-endian integer from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
+    /// assert_eq!(i128::min_value(), rdr.read_i128::<BigEndian>().unwrap());
+    /// ```
+    #[inline]
+    fn read_i128<T: ByteOrder>(&mut self) -> Result<i128> {
+        let mut buf = [0; 16];
+        self.read_exact(&mut buf)?;
+        Ok(T::read_i128(&buf))
+    }
+
+    /// Reads an unsigned n-bytes integer from the underlying reader.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read an unsigned n-byte big-endian integer from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![0x80, 0x74, 0xfa]);
+    /// assert_eq!(8418554, rdr.read_uint::<BigEndian>(3).unwrap());
+    #[inline]
+    fn read_uint<T: ByteOrder>(&mut self, nbytes: usize) -> Result<u64> {
+        let mut buf = [0; 8];
+        self.read_exact(&mut buf[..nbytes])?;
+        Ok(T::read_uint(&buf[..nbytes], nbytes))
+    }
+
+    /// Reads a signed n-bytes integer from the underlying reader.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read an unsigned n-byte big-endian integer from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![0xc1, 0xff, 0x7c]);
+    /// assert_eq!(-4063364, rdr.read_int::<BigEndian>(3).unwrap());
+    #[inline]
+    fn read_int<T: ByteOrder>(&mut self, nbytes: usize) -> Result<i64> {
+        let mut buf = [0; 8];
+        self.read_exact(&mut buf[..nbytes])?;
+        Ok(T::read_int(&buf[..nbytes], nbytes))
+    }
+
+    /// Reads an unsigned n-bytes integer from the underlying reader.
+    #[inline]
+    fn read_uint128<T: ByteOrder>(&mut self, nbytes: usize) -> Result<u128> {
+        let mut buf = [0; 16];
+        self.read_exact(&mut buf[..nbytes])?;
+        Ok(T::read_uint128(&buf[..nbytes], nbytes))
+    }
+
+    /// Reads a signed n-bytes integer from the underlying reader.
+    #[inline]
+    fn read_int128<T: ByteOrder>(&mut self, nbytes: usize) -> Result<i128> {
+        let mut buf = [0; 16];
+        self.read_exact(&mut buf[..nbytes])?;
+        Ok(T::read_int128(&buf[..nbytes], nbytes))
+    }
+
+    /// Reads a IEEE754 single-precision (4 bytes) floating point number from
+    /// the underlying reader.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read a big-endian single-precision floating point number from a `Read`:
+    ///
+    /// ```rust
+    /// use std::f32;
+    /// use std::io::Cursor;
+    ///
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![
+    ///     0x40, 0x49, 0x0f, 0xdb,
+    /// ]);
+    /// assert_eq!(f32::consts::PI, rdr.read_f32::<BigEndian>().unwrap());
+    /// ```
+    #[inline]
+    fn read_f32<T: ByteOrder>(&mut self) -> Result<f32> {
+        let mut buf = [0; 4];
+        self.read_exact(&mut buf)?;
+        Ok(T::read_f32(&buf))
+    }
+
+    /// Reads a IEEE754 double-precision (8 bytes) floating point number from
+    /// the underlying reader.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read a big-endian double-precision floating point number from a `Read`:
+    ///
+    /// ```rust
+    /// use std::f64;
+    /// use std::io::Cursor;
+    ///
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![
+    ///     0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18,
+    /// ]);
+    /// assert_eq!(f64::consts::PI, rdr.read_f64::<BigEndian>().unwrap());
+    /// ```
+    #[inline]
+    fn read_f64<T: ByteOrder>(&mut self) -> Result<f64> {
+        let mut buf = [0; 8];
+        self.read_exact(&mut buf)?;
+        Ok(T::read_f64(&buf))
+    }
+
+    /// Reads a sequence of unsigned 16 bit integers from the underlying
+    /// reader.
+    ///
+    /// The given buffer is either filled completely or an error is returned.
+    /// If an error is returned, the contents of `dst` are unspecified.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read a sequence of unsigned 16 bit big-endian integers from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![2, 5, 3, 0]);
+    /// let mut dst = [0; 2];
+    /// rdr.read_u16_into::<BigEndian>(&mut dst).unwrap();
+    /// assert_eq!([517, 768], dst);
+    /// ```
+    #[inline]
+    fn read_u16_into<T: ByteOrder>(&mut self, dst: &mut [u16]) -> Result<()> {
+        {
+            let buf = unsafe { slice_to_u8_mut(dst) };
+            self.read_exact(buf)?;
+        }
+        T::from_slice_u16(dst);
+        Ok(())
+    }
+
+    /// Reads a sequence of unsigned 32 bit integers from the underlying
+    /// reader.
+    ///
+    /// The given buffer is either filled completely or an error is returned.
+    /// If an error is returned, the contents of `dst` are unspecified.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read a sequence of unsigned 32 bit big-endian integers from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![0, 0, 2, 5, 0, 0, 3, 0]);
+    /// let mut dst = [0; 2];
+    /// rdr.read_u32_into::<BigEndian>(&mut dst).unwrap();
+    /// assert_eq!([517, 768], dst);
+    /// ```
+    #[inline]
+    fn read_u32_into<T: ByteOrder>(&mut self, dst: &mut [u32]) -> Result<()> {
+        {
+            let buf = unsafe { slice_to_u8_mut(dst) };
+            self.read_exact(buf)?;
+        }
+        T::from_slice_u32(dst);
+        Ok(())
+    }
+
+    /// Reads a sequence of unsigned 64 bit integers from the underlying
+    /// reader.
+    ///
+    /// The given buffer is either filled completely or an error is returned.
+    /// If an error is returned, the contents of `dst` are unspecified.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read a sequence of unsigned 64 bit big-endian integers from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![
+    ///     0, 0, 0, 0, 0, 0, 2, 5,
+    ///     0, 0, 0, 0, 0, 0, 3, 0,
+    /// ]);
+    /// let mut dst = [0; 2];
+    /// rdr.read_u64_into::<BigEndian>(&mut dst).unwrap();
+    /// assert_eq!([517, 768], dst);
+    /// ```
+    #[inline]
+    fn read_u64_into<T: ByteOrder>(&mut self, dst: &mut [u64]) -> Result<()> {
+        {
+            let buf = unsafe { slice_to_u8_mut(dst) };
+            self.read_exact(buf)?;
+        }
+        T::from_slice_u64(dst);
+        Ok(())
+    }
+
+    /// Reads a sequence of unsigned 128 bit integers from the underlying
+    /// reader.
+    ///
+    /// The given buffer is either filled completely or an error is returned.
+    /// If an error is returned, the contents of `dst` are unspecified.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read a sequence of unsigned 128 bit big-endian integers from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![
+    ///     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5,
+    ///     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0,
+    /// ]);
+    /// let mut dst = [0; 2];
+    /// rdr.read_u128_into::<BigEndian>(&mut dst).unwrap();
+    /// assert_eq!([517, 768], dst);
+    /// ```
+    #[inline]
+    fn read_u128_into<T: ByteOrder>(
+        &mut self,
+        dst: &mut [u128],
+    ) -> Result<()> {
+        {
+            let buf = unsafe { slice_to_u8_mut(dst) };
+            self.read_exact(buf)?;
+        }
+        T::from_slice_u128(dst);
+        Ok(())
+    }
+
+    /// Reads a sequence of signed 8 bit integers from the underlying reader.
+    ///
+    /// The given buffer is either filled completely or an error is returned.
+    /// If an error is returned, the contents of `dst` are unspecified.
+    ///
+    /// Note that since each `i8` is a single byte, no byte order conversions
+    /// are used. This method is included because it provides a safe, simple
+    /// way for the caller to read into a `&mut [i8]` buffer. (Without this
+    /// method, the caller would have to either use `unsafe` code or convert
+    /// each byte to `i8` individually.)
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read a sequence of signed 8 bit integers from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![2, 251, 3]);
+    /// let mut dst = [0; 3];
+    /// rdr.read_i8_into(&mut dst).unwrap();
+    /// assert_eq!([2, -5, 3], dst);
+    /// ```
+    #[inline]
+    fn read_i8_into(&mut self, dst: &mut [i8]) -> Result<()> {
+        let buf = unsafe { slice_to_u8_mut(dst) };
+        self.read_exact(buf)
+    }
+
+    /// Reads a sequence of signed 16 bit integers from the underlying
+    /// reader.
+    ///
+    /// The given buffer is either filled completely or an error is returned.
+    /// If an error is returned, the contents of `dst` are unspecified.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read a sequence of signed 16 bit big-endian integers from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![2, 5, 3, 0]);
+    /// let mut dst = [0; 2];
+    /// rdr.read_i16_into::<BigEndian>(&mut dst).unwrap();
+    /// assert_eq!([517, 768], dst);
+    /// ```
+    #[inline]
+    fn read_i16_into<T: ByteOrder>(&mut self, dst: &mut [i16]) -> Result<()> {
+        {
+            let buf = unsafe { slice_to_u8_mut(dst) };
+            self.read_exact(buf)?;
+        }
+        T::from_slice_i16(dst);
+        Ok(())
+    }
+
+    /// Reads a sequence of signed 32 bit integers from the underlying
+    /// reader.
+    ///
+    /// The given buffer is either filled completely or an error is returned.
+    /// If an error is returned, the contents of `dst` are unspecified.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read a sequence of signed 32 bit big-endian integers from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![0, 0, 2, 5, 0, 0, 3, 0]);
+    /// let mut dst = [0; 2];
+    /// rdr.read_i32_into::<BigEndian>(&mut dst).unwrap();
+    /// assert_eq!([517, 768], dst);
+    /// ```
+    #[inline]
+    fn read_i32_into<T: ByteOrder>(&mut self, dst: &mut [i32]) -> Result<()> {
+        {
+            let buf = unsafe { slice_to_u8_mut(dst) };
+            self.read_exact(buf)?;
+        }
+        T::from_slice_i32(dst);
+        Ok(())
+    }
+
+    /// Reads a sequence of signed 64 bit integers from the underlying
+    /// reader.
+    ///
+    /// The given buffer is either filled completely or an error is returned.
+    /// If an error is returned, the contents of `dst` are unspecified.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read a sequence of signed 64 bit big-endian integers from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![
+    ///     0, 0, 0, 0, 0, 0, 2, 5,
+    ///     0, 0, 0, 0, 0, 0, 3, 0,
+    /// ]);
+    /// let mut dst = [0; 2];
+    /// rdr.read_i64_into::<BigEndian>(&mut dst).unwrap();
+    /// assert_eq!([517, 768], dst);
+    /// ```
+    #[inline]
+    fn read_i64_into<T: ByteOrder>(&mut self, dst: &mut [i64]) -> Result<()> {
+        {
+            let buf = unsafe { slice_to_u8_mut(dst) };
+            self.read_exact(buf)?;
+        }
+        T::from_slice_i64(dst);
+        Ok(())
+    }
+
+    /// Reads a sequence of signed 128 bit integers from the underlying
+    /// reader.
+    ///
+    /// The given buffer is either filled completely or an error is returned.
+    /// If an error is returned, the contents of `dst` are unspecified.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read a sequence of signed 128 bit big-endian integers from a `Read`:
+    ///
+    /// ```rust
+    /// use std::io::Cursor;
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![
+    ///     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5,
+    ///     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0,
+    /// ]);
+    /// let mut dst = [0; 2];
+    /// rdr.read_i128_into::<BigEndian>(&mut dst).unwrap();
+    /// assert_eq!([517, 768], dst);
+    /// ```
+    #[inline]
+    fn read_i128_into<T: ByteOrder>(
+        &mut self,
+        dst: &mut [i128],
+    ) -> Result<()> {
+        {
+            let buf = unsafe { slice_to_u8_mut(dst) };
+            self.read_exact(buf)?;
+        }
+        T::from_slice_i128(dst);
+        Ok(())
+    }
+
+    /// Reads a sequence of IEEE754 single-precision (4 bytes) floating
+    /// point numbers from the underlying reader.
+    ///
+    /// The given buffer is either filled completely or an error is returned.
+    /// If an error is returned, the contents of `dst` are unspecified.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read a sequence of big-endian single-precision floating point number
+    /// from a `Read`:
+    ///
+    /// ```rust
+    /// use std::f32;
+    /// use std::io::Cursor;
+    ///
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![
+    ///     0x40, 0x49, 0x0f, 0xdb,
+    ///     0x3f, 0x80, 0x00, 0x00,
+    /// ]);
+    /// let mut dst = [0.0; 2];
+    /// rdr.read_f32_into::<BigEndian>(&mut dst).unwrap();
+    /// assert_eq!([f32::consts::PI, 1.0], dst);
+    /// ```
+    #[inline]
+    fn read_f32_into<T: ByteOrder>(&mut self, dst: &mut [f32]) -> Result<()> {
+        {
+            let buf = unsafe { slice_to_u8_mut(dst) };
+            self.read_exact(buf)?;
+        }
+        T::from_slice_f32(dst);
+        Ok(())
+    }
+
+    /// **DEPRECATED**.
+    ///
+    /// This method is deprecated. Use `read_f32_into` instead.
+    ///
+    /// Reads a sequence of IEEE754 single-precision (4 bytes) floating
+    /// point numbers from the underlying reader.
+    ///
+    /// The given buffer is either filled completely or an error is returned.
+    /// If an error is returned, the contents of `dst` are unspecified.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read a sequence of big-endian single-precision floating point number
+    /// from a `Read`:
+    ///
+    /// ```rust
+    /// use std::f32;
+    /// use std::io::Cursor;
+    ///
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![
+    ///     0x40, 0x49, 0x0f, 0xdb,
+    ///     0x3f, 0x80, 0x00, 0x00,
+    /// ]);
+    /// let mut dst = [0.0; 2];
+    /// rdr.read_f32_into_unchecked::<BigEndian>(&mut dst).unwrap();
+    /// assert_eq!([f32::consts::PI, 1.0], dst);
+    /// ```
+    #[inline]
+    #[deprecated(since = "1.2.0", note = "please use `read_f32_into` instead")]
+    fn read_f32_into_unchecked<T: ByteOrder>(
+        &mut self,
+        dst: &mut [f32],
+    ) -> Result<()> {
+        self.read_f32_into::<T>(dst)
+    }
+
+    /// Reads a sequence of IEEE754 double-precision (8 bytes) floating
+    /// point numbers from the underlying reader.
+    ///
+    /// The given buffer is either filled completely or an error is returned.
+    /// If an error is returned, the contents of `dst` are unspecified.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read a sequence of big-endian single-precision floating point number
+    /// from a `Read`:
+    ///
+    /// ```rust
+    /// use std::f64;
+    /// use std::io::Cursor;
+    ///
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![
+    ///     0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18,
+    ///     0x3f, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    /// ]);
+    /// let mut dst = [0.0; 2];
+    /// rdr.read_f64_into::<BigEndian>(&mut dst).unwrap();
+    /// assert_eq!([f64::consts::PI, 1.0], dst);
+    /// ```
+    #[inline]
+    fn read_f64_into<T: ByteOrder>(&mut self, dst: &mut [f64]) -> Result<()> {
+        {
+            let buf = unsafe { slice_to_u8_mut(dst) };
+            self.read_exact(buf)?;
+        }
+        T::from_slice_f64(dst);
+        Ok(())
+    }
+
+    /// **DEPRECATED**.
+    ///
+    /// This method is deprecated. Use `read_f64_into` instead.
+    ///
+    /// Reads a sequence of IEEE754 double-precision (8 bytes) floating
+    /// point numbers from the underlying reader.
+    ///
+    /// The given buffer is either filled completely or an error is returned.
+    /// If an error is returned, the contents of `dst` are unspecified.
+    ///
+    /// # Safety
+    ///
+    /// This method is unsafe because there are no guarantees made about the
+    /// floating point values. In particular, this method does not check for
+    /// signaling NaNs, which may result in undefined behavior.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Read::read_exact`].
+    ///
+    /// [`Read::read_exact`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_exact
+    ///
+    /// # Examples
+    ///
+    /// Read a sequence of big-endian single-precision floating point number
+    /// from a `Read`:
+    ///
+    /// ```rust
+    /// use std::f64;
+    /// use std::io::Cursor;
+    ///
+    /// use byteorder::{BigEndian, ReadBytesExt};
+    ///
+    /// let mut rdr = Cursor::new(vec![
+    ///     0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18,
+    ///     0x3f, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    /// ]);
+    /// let mut dst = [0.0; 2];
+    /// rdr.read_f64_into_unchecked::<BigEndian>(&mut dst).unwrap();
+    /// assert_eq!([f64::consts::PI, 1.0], dst);
+    /// ```
+    #[inline]
+    #[deprecated(since = "1.2.0", note = "please use `read_f64_into` instead")]
+    fn read_f64_into_unchecked<T: ByteOrder>(
+        &mut self,
+        dst: &mut [f64],
+    ) -> Result<()> {
+        self.read_f64_into::<T>(dst)
+    }
+}
+
+/// All types that implement `Read` get methods defined in `ReadBytesExt`
+/// for free.
+impl<R: io::Read + ?Sized> ReadBytesExt for R {}
+
+/// Extends [`Write`] with methods for writing numbers. (For `std::io`.)
+///
+/// Most of the methods defined here have an unconstrained type parameter that
+/// must be explicitly instantiated. Typically, it is instantiated with either
+/// the [`BigEndian`] or [`LittleEndian`] types defined in this crate.
+///
+/// # Examples
+///
+/// Write unsigned 16 bit big-endian integers to a [`Write`]:
+///
+/// ```rust
+/// use byteorder::{BigEndian, WriteBytesExt};
+///
+/// let mut wtr = vec![];
+/// wtr.write_u16::<BigEndian>(517).unwrap();
+/// wtr.write_u16::<BigEndian>(768).unwrap();
+/// assert_eq!(wtr, vec![2, 5, 3, 0]);
+/// ```
+///
+/// [`BigEndian`]: enum.BigEndian.html
+/// [`LittleEndian`]: enum.LittleEndian.html
+/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
+pub trait WriteBytesExt: io::Write {
+    /// Writes an unsigned 8 bit integer to the underlying writer.
+    ///
+    /// Note that since this writes a single byte, no byte order conversions
+    /// are used. It is included for completeness.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Write::write_all`].
+    ///
+    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
+    ///
+    /// # Examples
+    ///
+    /// Write unsigned 8 bit integers to a `Write`:
+    ///
+    /// ```rust
+    /// use byteorder::WriteBytesExt;
+    ///
+    /// let mut wtr = Vec::new();
+    /// wtr.write_u8(2).unwrap();
+    /// wtr.write_u8(5).unwrap();
+    /// assert_eq!(wtr, b"\x02\x05");
+    /// ```
+    #[inline]
+    fn write_u8(&mut self, n: u8) -> Result<()> {
+        self.write_all(&[n])
+    }
+
+    /// Writes a signed 8 bit integer to the underlying writer.
+    ///
+    /// Note that since this writes a single byte, no byte order conversions
+    /// are used. It is included for completeness.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Write::write_all`].
+    ///
+    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
+    ///
+    /// # Examples
+    ///
+    /// Write signed 8 bit integers to a `Write`:
+    ///
+    /// ```rust
+    /// use byteorder::WriteBytesExt;
+    ///
+    /// let mut wtr = Vec::new();
+    /// wtr.write_i8(2).unwrap();
+    /// wtr.write_i8(-5).unwrap();
+    /// assert_eq!(wtr, b"\x02\xfb");
+    /// ```
+    #[inline]
+    fn write_i8(&mut self, n: i8) -> Result<()> {
+        self.write_all(&[n as u8])
+    }
+
+    /// Writes an unsigned 16 bit integer to the underlying writer.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Write::write_all`].
+    ///
+    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
+    ///
+    /// # Examples
+    ///
+    /// Write unsigned 16 bit big-endian integers to a `Write`:
+    ///
+    /// ```rust
+    /// use byteorder::{BigEndian, WriteBytesExt};
+    ///
+    /// let mut wtr = Vec::new();
+    /// wtr.write_u16::<BigEndian>(517).unwrap();
+    /// wtr.write_u16::<BigEndian>(768).unwrap();
+    /// assert_eq!(wtr, b"\x02\x05\x03\x00");
+    /// ```
+    #[inline]
+    fn write_u16<T: ByteOrder>(&mut self, n: u16) -> Result<()> {
+        let mut buf = [0; 2];
+        T::write_u16(&mut buf, n);
+        self.write_all(&buf)
+    }
+
+    /// Writes a signed 16 bit integer to the underlying writer.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Write::write_all`].
+    ///
+    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
+    ///
+    /// # Examples
+    ///
+    /// Write signed 16 bit big-endian integers to a `Write`:
+    ///
+    /// ```rust
+    /// use byteorder::{BigEndian, WriteBytesExt};
+    ///
+    /// let mut wtr = Vec::new();
+    /// wtr.write_i16::<BigEndian>(193).unwrap();
+    /// wtr.write_i16::<BigEndian>(-132).unwrap();
+    /// assert_eq!(wtr, b"\x00\xc1\xff\x7c");
+    /// ```
+    #[inline]
+    fn write_i16<T: ByteOrder>(&mut self, n: i16) -> Result<()> {
+        let mut buf = [0; 2];
+        T::write_i16(&mut buf, n);
+        self.write_all(&buf)
+    }
+
+    /// Writes an unsigned 24 bit integer to the underlying writer.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Write::write_all`].
+    ///
+    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
+    ///
+    /// # Examples
+    ///
+    /// Write unsigned 24 bit big-endian integers to a `Write`:
+    ///
+    /// ```rust
+    /// use byteorder::{BigEndian, WriteBytesExt};
+    ///
+    /// let mut wtr = Vec::new();
+    /// wtr.write_u24::<BigEndian>(267).unwrap();
+    /// wtr.write_u24::<BigEndian>(120111).unwrap();
+    /// assert_eq!(wtr, b"\x00\x01\x0b\x01\xd5\x2f");
+    /// ```
+    #[inline]
+    fn write_u24<T: ByteOrder>(&mut self, n: u32) -> Result<()> {
+        let mut buf = [0; 3];
+        T::write_u24(&mut buf, n);
+        self.write_all(&buf)
+    }
+
+    /// Writes a signed 24 bit integer to the underlying writer.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Write::write_all`].
+    ///
+    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
+    ///
+    /// # Examples
+    ///
+    /// Write signed 24 bit big-endian integers to a `Write`:
+    ///
+    /// ```rust
+    /// use byteorder::{BigEndian, WriteBytesExt};
+    ///
+    /// let mut wtr = Vec::new();
+    /// wtr.write_i24::<BigEndian>(-34253).unwrap();
+    /// wtr.write_i24::<BigEndian>(120111).unwrap();
+    /// assert_eq!(wtr, b"\xff\x7a\x33\x01\xd5\x2f");
+    /// ```
+    #[inline]
+    fn write_i24<T: ByteOrder>(&mut self, n: i32) -> Result<()> {
+        let mut buf = [0; 3];
+        T::write_i24(&mut buf, n);
+        self.write_all(&buf)
+    }
+
+    /// Writes an unsigned 32 bit integer to the underlying writer.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Write::write_all`].
+    ///
+    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
+    ///
+    /// # Examples
+    ///
+    /// Write unsigned 32 bit big-endian integers to a `Write`:
+    ///
+    /// ```rust
+    /// use byteorder::{BigEndian, WriteBytesExt};
+    ///
+    /// let mut wtr = Vec::new();
+    /// wtr.write_u32::<BigEndian>(267).unwrap();
+    /// wtr.write_u32::<BigEndian>(1205419366).unwrap();
+    /// assert_eq!(wtr, b"\x00\x00\x01\x0b\x47\xd9\x3d\x66");
+    /// ```
+    #[inline]
+    fn write_u32<T: ByteOrder>(&mut self, n: u32) -> Result<()> {
+        let mut buf = [0; 4];
+        T::write_u32(&mut buf, n);
+        self.write_all(&buf)
+    }
+
+    /// Writes a signed 32 bit integer to the underlying writer.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Write::write_all`].
+    ///
+    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
+    ///
+    /// # Examples
+    ///
+    /// Write signed 32 bit big-endian integers to a `Write`:
+    ///
+    /// ```rust
+    /// use byteorder::{BigEndian, WriteBytesExt};
+    ///
+    /// let mut wtr = Vec::new();
+    /// wtr.write_i32::<BigEndian>(-34253).unwrap();
+    /// wtr.write_i32::<BigEndian>(1205419366).unwrap();
+    /// assert_eq!(wtr, b"\xff\xff\x7a\x33\x47\xd9\x3d\x66");
+    /// ```
+    #[inline]
+    fn write_i32<T: ByteOrder>(&mut self, n: i32) -> Result<()> {
+        let mut buf = [0; 4];
+        T::write_i32(&mut buf, n);
+        self.write_all(&buf)
+    }
+
+    /// Writes an unsigned 48 bit integer to the underlying writer.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Write::write_all`].
+    ///
+    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
+    ///
+    /// # Examples
+    ///
+    /// Write unsigned 48 bit big-endian integers to a `Write`:
+    ///
+    /// ```rust
+    /// use byteorder::{BigEndian, WriteBytesExt};
+    ///
+    /// let mut wtr = Vec::new();
+    /// wtr.write_u48::<BigEndian>(52360336390828).unwrap();
+    /// wtr.write_u48::<BigEndian>(541).unwrap();
+    /// assert_eq!(wtr, b"\x2f\x9f\x17\x40\x3a\xac\x00\x00\x00\x00\x02\x1d");
+    /// ```
+    #[inline]
+    fn write_u48<T: ByteOrder>(&mut self, n: u64) -> Result<()> {
+        let mut buf = [0; 6];
+        T::write_u48(&mut buf, n);
+        self.write_all(&buf)
+    }
+
+    /// Writes a signed 48 bit integer to the underlying writer.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Write::write_all`].
+    ///
+    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
+    ///
+    /// # Examples
+    ///
+    /// Write signed 48 bit big-endian integers to a `Write`:
+    ///
+    /// ```rust
+    /// use byteorder::{BigEndian, WriteBytesExt};
+    ///
+    /// let mut wtr = Vec::new();
+    /// wtr.write_i48::<BigEndian>(-108363435763825).unwrap();
+    /// wtr.write_i48::<BigEndian>(77).unwrap();
+    /// assert_eq!(wtr, b"\x9d\x71\xab\xe7\x97\x8f\x00\x00\x00\x00\x00\x4d");
+    /// ```
+    #[inline]
+    fn write_i48<T: ByteOrder>(&mut self, n: i64) -> Result<()> {
+        let mut buf = [0; 6];
+        T::write_i48(&mut buf, n);
+        self.write_all(&buf)
+    }
+
+    /// Writes an unsigned 64 bit integer to the underlying writer.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Write::write_all`].
+    ///
+    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
+    ///
+    /// # Examples
+    ///
+    /// Write unsigned 64 bit big-endian integers to a `Write`:
+    ///
+    /// ```rust
+    /// use byteorder::{BigEndian, WriteBytesExt};
+    ///
+    /// let mut wtr = Vec::new();
+    /// wtr.write_u64::<BigEndian>(918733457491587).unwrap();
+    /// wtr.write_u64::<BigEndian>(143).unwrap();
+    /// assert_eq!(wtr, b"\x00\x03\x43\x95\x4d\x60\x86\x83\x00\x00\x00\x00\x00\x00\x00\x8f");
+    /// ```
+    #[inline]
+    fn write_u64<T: ByteOrder>(&mut self, n: u64) -> Result<()> {
+        let mut buf = [0; 8];
+        T::write_u64(&mut buf, n);
+        self.write_all(&buf)
+    }
+
+    /// Writes a signed 64 bit integer to the underlying writer.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Write::write_all`].
+    ///
+    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
+    ///
+    /// # Examples
+    ///
+    /// Write signed 64 bit big-endian integers to a `Write`:
+    ///
+    /// ```rust
+    /// use byteorder::{BigEndian, WriteBytesExt};
+    ///
+    /// let mut wtr = Vec::new();
+    /// wtr.write_i64::<BigEndian>(i64::min_value()).unwrap();
+    /// wtr.write_i64::<BigEndian>(i64::max_value()).unwrap();
+    /// assert_eq!(wtr, b"\x80\x00\x00\x00\x00\x00\x00\x00\x7f\xff\xff\xff\xff\xff\xff\xff");
+    /// ```
+    #[inline]
+    fn write_i64<T: ByteOrder>(&mut self, n: i64) -> Result<()> {
+        let mut buf = [0; 8];
+        T::write_i64(&mut buf, n);
+        self.write_all(&buf)
+    }
+
+    /// Writes an unsigned 128 bit integer to the underlying writer.
+    #[inline]
+    fn write_u128<T: ByteOrder>(&mut self, n: u128) -> Result<()> {
+        let mut buf = [0; 16];
+        T::write_u128(&mut buf, n);
+        self.write_all(&buf)
+    }
+
+    /// Writes a signed 128 bit integer to the underlying writer.
+    #[inline]
+    fn write_i128<T: ByteOrder>(&mut self, n: i128) -> Result<()> {
+        let mut buf = [0; 16];
+        T::write_i128(&mut buf, n);
+        self.write_all(&buf)
+    }
+
+    /// Writes an unsigned n-bytes integer to the underlying writer.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Write::write_all`].
+    ///
+    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
+    ///
+    /// # Panics
+    ///
+    /// If the given integer is not representable in the given number of bytes,
+    /// this method panics. If `nbytes > 8`, this method panics.
+    ///
+    /// # Examples
+    ///
+    /// Write unsigned 40 bit big-endian integers to a `Write`:
+    ///
+    /// ```rust
+    /// use byteorder::{BigEndian, WriteBytesExt};
+    ///
+    /// let mut wtr = Vec::new();
+    /// wtr.write_uint::<BigEndian>(312550384361, 5).unwrap();
+    /// wtr.write_uint::<BigEndian>(43, 5).unwrap();
+    /// assert_eq!(wtr, b"\x48\xc5\x74\x62\xe9\x00\x00\x00\x00\x2b");
+    /// ```
+    #[inline]
+    fn write_uint<T: ByteOrder>(
+        &mut self,
+        n: u64,
+        nbytes: usize,
+    ) -> Result<()> {
+        let mut buf = [0; 8];
+        T::write_uint(&mut buf, n, nbytes);
+        self.write_all(&buf[0..nbytes])
+    }
+
+    /// Writes a signed n-bytes integer to the underlying writer.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Write::write_all`].
+    ///
+    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
+    ///
+    /// # Panics
+    ///
+    /// If the given integer is not representable in the given number of bytes,
+    /// this method panics. If `nbytes > 8`, this method panics.
+    ///
+    /// # Examples
+    ///
+    /// Write signed 56 bit big-endian integers to a `Write`:
+    ///
+    /// ```rust
+    /// use byteorder::{BigEndian, WriteBytesExt};
+    ///
+    /// let mut wtr = Vec::new();
+    /// wtr.write_int::<BigEndian>(-3548172039376767, 7).unwrap();
+    /// wtr.write_int::<BigEndian>(43, 7).unwrap();
+    /// assert_eq!(wtr, b"\xf3\x64\xf4\xd1\xfd\xb0\x81\x00\x00\x00\x00\x00\x00\x2b");
+    /// ```
+    #[inline]
+    fn write_int<T: ByteOrder>(
+        &mut self,
+        n: i64,
+        nbytes: usize,
+    ) -> Result<()> {
+        let mut buf = [0; 8];
+        T::write_int(&mut buf, n, nbytes);
+        self.write_all(&buf[0..nbytes])
+    }
+
+    /// Writes an unsigned n-bytes integer to the underlying writer.
+    ///
+    /// If the given integer is not representable in the given number of bytes,
+    /// this method panics. If `nbytes > 16`, this method panics.
+    #[inline]
+    fn write_uint128<T: ByteOrder>(
+        &mut self,
+        n: u128,
+        nbytes: usize,
+    ) -> Result<()> {
+        let mut buf = [0; 16];
+        T::write_uint128(&mut buf, n, nbytes);
+        self.write_all(&buf[0..nbytes])
+    }
+
+    /// Writes a signed n-bytes integer to the underlying writer.
+    ///
+    /// If the given integer is not representable in the given number of bytes,
+    /// this method panics. If `nbytes > 16`, this method panics.
+    #[inline]
+    fn write_int128<T: ByteOrder>(
+        &mut self,
+        n: i128,
+        nbytes: usize,
+    ) -> Result<()> {
+        let mut buf = [0; 16];
+        T::write_int128(&mut buf, n, nbytes);
+        self.write_all(&buf[0..nbytes])
+    }
+
+    /// Writes a IEEE754 single-precision (4 bytes) floating point number to
+    /// the underlying writer.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Write::write_all`].
+    ///
+    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
+    ///
+    /// # Examples
+    ///
+    /// Write a big-endian single-precision floating point number to a `Write`:
+    ///
+    /// ```rust
+    /// use std::f32;
+    ///
+    /// use byteorder::{BigEndian, WriteBytesExt};
+    ///
+    /// let mut wtr = Vec::new();
+    /// wtr.write_f32::<BigEndian>(f32::consts::PI).unwrap();
+    /// assert_eq!(wtr, b"\x40\x49\x0f\xdb");
+    /// ```
+    #[inline]
+    fn write_f32<T: ByteOrder>(&mut self, n: f32) -> Result<()> {
+        let mut buf = [0; 4];
+        T::write_f32(&mut buf, n);
+        self.write_all(&buf)
+    }
+
+    /// Writes a IEEE754 double-precision (8 bytes) floating point number to
+    /// the underlying writer.
+    ///
+    /// # Errors
+    ///
+    /// This method returns the same errors as [`Write::write_all`].
+    ///
+    /// [`Write::write_all`]: https://doc.rust-lang.org/std/io/trait.Write.html#method.write_all
+    ///
+    /// # Examples
+    ///
+    /// Write a big-endian double-precision floating point number to a `Write`:
+    ///
+    /// ```rust
+    /// use std::f64;
+    ///
+    /// use byteorder::{BigEndian, WriteBytesExt};
+    ///
+    /// let mut wtr = Vec::new();
+    /// wtr.write_f64::<BigEndian>(f64::consts::PI).unwrap();
+    /// assert_eq!(wtr, b"\x40\x09\x21\xfb\x54\x44\x2d\x18");
+    /// ```
+    #[inline]
+    fn write_f64<T: ByteOrder>(&mut self, n: f64) -> Result<()> {
+        let mut buf = [0; 8];
+        T::write_f64(&mut buf, n);
+        self.write_all(&buf)
+    }
+}
+
+/// All types that implement `Write` get methods defined in `WriteBytesExt`
+/// for free.
+impl<W: io::Write + ?Sized> WriteBytesExt for W {}
+
+/// Convert a slice of T (where T is plain old data) to its mutable binary
+/// representation.
+///
+/// This function is wildly unsafe because it permits arbitrary modification of
+/// the binary representation of any `Copy` type. Use with care. It's intended
+/// to be called only where `T` is a numeric type.
+unsafe fn slice_to_u8_mut<T: Copy>(slice: &mut [T]) -> &mut [u8] {
+    use std::mem::size_of;
+
+    let len = size_of::<T>() * slice.len();
+    slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut u8, len)
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/byteorder-v1/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/src/lib.rs
new file mode 100644
index 0000000..cfd53c3
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/byteorder-v1/src/lib.rs
@@ -0,0 +1,3975 @@
+/*!
+This crate provides convenience methods for encoding and decoding numbers in
+either [big-endian or little-endian order].
+
+The organization of the crate is pretty simple. A trait, [`ByteOrder`], specifies
+byte conversion methods for each type of number in Rust (sans numbers that have
+a platform dependent size like `usize` and `isize`). Two types, [`BigEndian`]
+and [`LittleEndian`] implement these methods. Finally, [`ReadBytesExt`] and
+[`WriteBytesExt`] provide convenience methods available to all types that
+implement [`Read`] and [`Write`].
+
+An alias, [`NetworkEndian`], for [`BigEndian`] is provided to help improve
+code clarity.
+
+An additional alias, [`NativeEndian`], is provided for the endianness of the
+local platform. This is convenient when serializing data for use and
+conversions are not desired.
+
+# Examples
+
+Read unsigned 16 bit big-endian integers from a [`Read`] type:
+
+```rust
+use std::io::Cursor;
+use byteorder::{BigEndian, ReadBytesExt};
+
+let mut rdr = Cursor::new(vec![2, 5, 3, 0]);
+// Note that we use type parameters to indicate which kind of byte order
+// we want!
+assert_eq!(517, rdr.read_u16::<BigEndian>().unwrap());
+assert_eq!(768, rdr.read_u16::<BigEndian>().unwrap());
+```
+
+Write unsigned 16 bit little-endian integers to a [`Write`] type:
+
+```rust
+use byteorder::{LittleEndian, WriteBytesExt};
+
+let mut wtr = vec![];
+wtr.write_u16::<LittleEndian>(517).unwrap();
+wtr.write_u16::<LittleEndian>(768).unwrap();
+assert_eq!(wtr, vec![5, 2, 0, 3]);
+```
+
+# Optional Features
+
+This crate optionally provides support for 128 bit values (`i128` and `u128`)
+when built with the `i128` feature enabled.
+
+This crate can also be used without the standard library.
+
+# Alternatives
+
+Note that as of Rust 1.32, the standard numeric types provide built-in methods
+like `to_le_bytes` and `from_le_bytes`, which support some of the same use
+cases.
+
+[big-endian or little-endian order]: https://en.wikipedia.org/wiki/Endianness
+[`ByteOrder`]: trait.ByteOrder.html
+[`BigEndian`]: enum.BigEndian.html
+[`LittleEndian`]: enum.LittleEndian.html
+[`ReadBytesExt`]: trait.ReadBytesExt.html
+[`WriteBytesExt`]: trait.WriteBytesExt.html
+[`NetworkEndian`]: type.NetworkEndian.html
+[`NativeEndian`]: type.NativeEndian.html
+[`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
+[`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
+*/
+
+#![deny(missing_docs)]
+#![cfg_attr(not(feature = "std"), no_std)]
+// When testing under miri, we disable tests that take too long. But this
+// provokes lots of dead code warnings. So we just squash them.
+#![cfg_attr(miri, allow(dead_code, unused_macros))]
+
+use core::{
+    convert::TryInto, fmt::Debug, hash::Hash, mem::align_of,
+    ptr::copy_nonoverlapping, slice,
+};
+
+#[cfg(feature = "std")]
+pub use crate::io::{ReadBytesExt, WriteBytesExt};
+
+#[cfg(feature = "std")]
+mod io;
+
+#[inline]
+fn extend_sign(val: u64, nbytes: usize) -> i64 {
+    let shift = (8 - nbytes) * 8;
+    (val << shift) as i64 >> shift
+}
+
+#[inline]
+fn extend_sign128(val: u128, nbytes: usize) -> i128 {
+    let shift = (16 - nbytes) * 8;
+    (val << shift) as i128 >> shift
+}
+
+#[inline]
+fn unextend_sign(val: i64, nbytes: usize) -> u64 {
+    let shift = (8 - nbytes) * 8;
+    (val << shift) as u64 >> shift
+}
+
+#[inline]
+fn unextend_sign128(val: i128, nbytes: usize) -> u128 {
+    let shift = (16 - nbytes) * 8;
+    (val << shift) as u128 >> shift
+}
+
+#[inline]
+fn pack_size(n: u64) -> usize {
+    if n < 1 << 8 {
+        1
+    } else if n < 1 << 16 {
+        2
+    } else if n < 1 << 24 {
+        3
+    } else if n < 1 << 32 {
+        4
+    } else if n < 1 << 40 {
+        5
+    } else if n < 1 << 48 {
+        6
+    } else if n < 1 << 56 {
+        7
+    } else {
+        8
+    }
+}
+
+#[inline]
+fn pack_size128(n: u128) -> usize {
+    if n < 1 << 8 {
+        1
+    } else if n < 1 << 16 {
+        2
+    } else if n < 1 << 24 {
+        3
+    } else if n < 1 << 32 {
+        4
+    } else if n < 1 << 40 {
+        5
+    } else if n < 1 << 48 {
+        6
+    } else if n < 1 << 56 {
+        7
+    } else if n < 1 << 64 {
+        8
+    } else if n < 1 << 72 {
+        9
+    } else if n < 1 << 80 {
+        10
+    } else if n < 1 << 88 {
+        11
+    } else if n < 1 << 96 {
+        12
+    } else if n < 1 << 104 {
+        13
+    } else if n < 1 << 112 {
+        14
+    } else if n < 1 << 120 {
+        15
+    } else {
+        16
+    }
+}
+
+mod private {
+    /// Sealed stops crates other than byteorder from implementing any traits
+    /// that use it.
+    pub trait Sealed {}
+    impl Sealed for super::LittleEndian {}
+    impl Sealed for super::BigEndian {}
+}
+
+/// `ByteOrder` describes types that can serialize integers as bytes.
+///
+/// Note that `Self` does not appear anywhere in this trait's definition!
+/// Therefore, in order to use it, you'll need to use syntax like
+/// `T::read_u16(&[0, 1])` where `T` implements `ByteOrder`.
+///
+/// This crate provides two types that implement `ByteOrder`: [`BigEndian`]
+/// and [`LittleEndian`].
+/// This trait is sealed and cannot be implemented for callers to avoid
+/// breaking backwards compatibility when adding new derived traits.
+///
+/// # Examples
+///
+/// Write and read `u32` numbers in little endian order:
+///
+/// ```rust
+/// use byteorder::{ByteOrder, LittleEndian};
+///
+/// let mut buf = [0; 4];
+/// LittleEndian::write_u32(&mut buf, 1_000_000);
+/// assert_eq!(1_000_000, LittleEndian::read_u32(&buf));
+/// ```
+///
+/// Write and read `i16` numbers in big endian order:
+///
+/// ```rust
+/// use byteorder::{ByteOrder, BigEndian};
+///
+/// let mut buf = [0; 2];
+/// BigEndian::write_i16(&mut buf, -5_000);
+/// assert_eq!(-5_000, BigEndian::read_i16(&buf));
+/// ```
+///
+/// [`BigEndian`]: enum.BigEndian.html
+/// [`LittleEndian`]: enum.LittleEndian.html
+pub trait ByteOrder:
+    Clone
+    + Copy
+    + Debug
+    + Default
+    + Eq
+    + Hash
+    + Ord
+    + PartialEq
+    + PartialOrd
+    + private::Sealed
+{
+    /// Reads an unsigned 16 bit integer from `buf`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 2`.
+    fn read_u16(buf: &[u8]) -> u16;
+
+    /// Reads an unsigned 24 bit integer from `buf`, stored in u32.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 3`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read 24 bit `u32` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 3];
+    /// LittleEndian::write_u24(&mut buf, 1_000_000);
+    /// assert_eq!(1_000_000, LittleEndian::read_u24(&buf));
+    /// ```
+    fn read_u24(buf: &[u8]) -> u32 {
+        Self::read_uint(buf, 3) as u32
+    }
+
+    /// Reads an unsigned 32 bit integer from `buf`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 4`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `u32` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 4];
+    /// LittleEndian::write_u32(&mut buf, 1_000_000);
+    /// assert_eq!(1_000_000, LittleEndian::read_u32(&buf));
+    /// ```
+    fn read_u32(buf: &[u8]) -> u32;
+
+    /// Reads an unsigned 48 bit integer from `buf`, stored in u64.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 6`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read 48 bit `u64` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 6];
+    /// LittleEndian::write_u48(&mut buf, 1_000_000_000_000);
+    /// assert_eq!(1_000_000_000_000, LittleEndian::read_u48(&buf));
+    /// ```
+    fn read_u48(buf: &[u8]) -> u64 {
+        Self::read_uint(buf, 6) as u64
+    }
+
+    /// Reads an unsigned 64 bit integer from `buf`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 8`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `u64` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 8];
+    /// LittleEndian::write_u64(&mut buf, 1_000_000);
+    /// assert_eq!(1_000_000, LittleEndian::read_u64(&buf));
+    /// ```
+    fn read_u64(buf: &[u8]) -> u64;
+
+    /// Reads an unsigned 128 bit integer from `buf`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 16`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `u128` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 16];
+    /// LittleEndian::write_u128(&mut buf, 1_000_000);
+    /// assert_eq!(1_000_000, LittleEndian::read_u128(&buf));
+    /// ```
+    fn read_u128(buf: &[u8]) -> u128;
+
+    /// Reads an unsigned n-bytes integer from `buf`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `nbytes < 1` or `nbytes > 8` or
+    /// `buf.len() < nbytes`
+    ///
+    /// # Examples
+    ///
+    /// Write and read an n-byte number in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 3];
+    /// LittleEndian::write_uint(&mut buf, 1_000_000, 3);
+    /// assert_eq!(1_000_000, LittleEndian::read_uint(&buf, 3));
+    /// ```
+    fn read_uint(buf: &[u8], nbytes: usize) -> u64;
+
+    /// Reads an unsigned n-bytes integer from `buf`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `nbytes < 1` or `nbytes > 16` or
+    /// `buf.len() < nbytes`
+    ///
+    /// # Examples
+    ///
+    /// Write and read an n-byte number in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 3];
+    /// LittleEndian::write_uint128(&mut buf, 1_000_000, 3);
+    /// assert_eq!(1_000_000, LittleEndian::read_uint128(&buf, 3));
+    /// ```
+    fn read_uint128(buf: &[u8], nbytes: usize) -> u128;
+
+    /// Writes an unsigned 16 bit integer `n` to `buf`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 2`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `u16` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 2];
+    /// LittleEndian::write_u16(&mut buf, 1_000);
+    /// assert_eq!(1_000, LittleEndian::read_u16(&buf));
+    /// ```
+    fn write_u16(buf: &mut [u8], n: u16);
+
+    /// Writes an unsigned 24 bit integer `n` to `buf`, stored in u32.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 3`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read 24 bit `u32` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 3];
+    /// LittleEndian::write_u24(&mut buf, 1_000_000);
+    /// assert_eq!(1_000_000, LittleEndian::read_u24(&buf));
+    /// ```
+    fn write_u24(buf: &mut [u8], n: u32) {
+        Self::write_uint(buf, n as u64, 3)
+    }
+
+    /// Writes an unsigned 32 bit integer `n` to `buf`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 4`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `u32` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 4];
+    /// LittleEndian::write_u32(&mut buf, 1_000_000);
+    /// assert_eq!(1_000_000, LittleEndian::read_u32(&buf));
+    /// ```
+    fn write_u32(buf: &mut [u8], n: u32);
+
+    /// Writes an unsigned 48 bit integer `n` to `buf`, stored in u64.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 6`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read 48 bit `u64` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 6];
+    /// LittleEndian::write_u48(&mut buf, 1_000_000_000_000);
+    /// assert_eq!(1_000_000_000_000, LittleEndian::read_u48(&buf));
+    /// ```
+    fn write_u48(buf: &mut [u8], n: u64) {
+        Self::write_uint(buf, n as u64, 6)
+    }
+
+    /// Writes an unsigned 64 bit integer `n` to `buf`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 8`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `u64` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 8];
+    /// LittleEndian::write_u64(&mut buf, 1_000_000);
+    /// assert_eq!(1_000_000, LittleEndian::read_u64(&buf));
+    /// ```
+    fn write_u64(buf: &mut [u8], n: u64);
+
+    /// Writes an unsigned 128 bit integer `n` to `buf`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 16`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `u128` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 16];
+    /// LittleEndian::write_u128(&mut buf, 1_000_000);
+    /// assert_eq!(1_000_000, LittleEndian::read_u128(&buf));
+    /// ```
+    fn write_u128(buf: &mut [u8], n: u128);
+
+    /// Writes an unsigned integer `n` to `buf` using only `nbytes`.
+    ///
+    /// # Panics
+    ///
+    /// If `n` is not representable in `nbytes`, or if `nbytes` is `> 8`, then
+    /// this method panics.
+    ///
+    /// # Examples
+    ///
+    /// Write and read an n-byte number in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 3];
+    /// LittleEndian::write_uint(&mut buf, 1_000_000, 3);
+    /// assert_eq!(1_000_000, LittleEndian::read_uint(&buf, 3));
+    /// ```
+    fn write_uint(buf: &mut [u8], n: u64, nbytes: usize);
+
+    /// Writes an unsigned integer `n` to `buf` using only `nbytes`.
+    ///
+    /// # Panics
+    ///
+    /// If `n` is not representable in `nbytes`, or if `nbytes` is `> 16`, then
+    /// this method panics.
+    ///
+    /// # Examples
+    ///
+    /// Write and read an n-byte number in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 3];
+    /// LittleEndian::write_uint128(&mut buf, 1_000_000, 3);
+    /// assert_eq!(1_000_000, LittleEndian::read_uint128(&buf, 3));
+    /// ```
+    fn write_uint128(buf: &mut [u8], n: u128, nbytes: usize);
+
+    /// Reads a signed 16 bit integer from `buf`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 2`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `i16` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 2];
+    /// LittleEndian::write_i16(&mut buf, -1_000);
+    /// assert_eq!(-1_000, LittleEndian::read_i16(&buf));
+    /// ```
+    #[inline]
+    fn read_i16(buf: &[u8]) -> i16 {
+        Self::read_u16(buf) as i16
+    }
+
+    /// Reads a signed 24 bit integer from `buf`, stored in i32.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 3`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read 24 bit `i32` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 3];
+    /// LittleEndian::write_i24(&mut buf, -1_000_000);
+    /// assert_eq!(-1_000_000, LittleEndian::read_i24(&buf));
+    /// ```
+    #[inline]
+    fn read_i24(buf: &[u8]) -> i32 {
+        Self::read_int(buf, 3) as i32
+    }
+
+    /// Reads a signed 32 bit integer from `buf`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 4`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `i32` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 4];
+    /// LittleEndian::write_i32(&mut buf, -1_000_000);
+    /// assert_eq!(-1_000_000, LittleEndian::read_i32(&buf));
+    /// ```
+    #[inline]
+    fn read_i32(buf: &[u8]) -> i32 {
+        Self::read_u32(buf) as i32
+    }
+
+    /// Reads a signed 48 bit integer from `buf`, stored in i64.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 6`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read 48 bit `i64` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 6];
+    /// LittleEndian::write_i48(&mut buf, -1_000_000_000_000);
+    /// assert_eq!(-1_000_000_000_000, LittleEndian::read_i48(&buf));
+    /// ```
+    #[inline]
+    fn read_i48(buf: &[u8]) -> i64 {
+        Self::read_int(buf, 6) as i64
+    }
+
+    /// Reads a signed 64 bit integer from `buf`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 8`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `i64` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 8];
+    /// LittleEndian::write_i64(&mut buf, -1_000_000_000);
+    /// assert_eq!(-1_000_000_000, LittleEndian::read_i64(&buf));
+    /// ```
+    #[inline]
+    fn read_i64(buf: &[u8]) -> i64 {
+        Self::read_u64(buf) as i64
+    }
+
+    /// Reads a signed 128 bit integer from `buf`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 16`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `i128` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 16];
+    /// LittleEndian::write_i128(&mut buf, -1_000_000_000);
+    /// assert_eq!(-1_000_000_000, LittleEndian::read_i128(&buf));
+    /// ```
+    #[inline]
+    fn read_i128(buf: &[u8]) -> i128 {
+        Self::read_u128(buf) as i128
+    }
+
+    /// Reads a signed n-bytes integer from `buf`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `nbytes < 1` or `nbytes > 8` or
+    /// `buf.len() < nbytes`
+    ///
+    /// # Examples
+    ///
+    /// Write and read n-length signed numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 3];
+    /// LittleEndian::write_int(&mut buf, -1_000, 3);
+    /// assert_eq!(-1_000, LittleEndian::read_int(&buf, 3));
+    /// ```
+    #[inline]
+    fn read_int(buf: &[u8], nbytes: usize) -> i64 {
+        extend_sign(Self::read_uint(buf, nbytes), nbytes)
+    }
+
+    /// Reads a signed n-bytes integer from `buf`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `nbytes < 1` or `nbytes > 16` or
+    /// `buf.len() < nbytes`
+    ///
+    /// # Examples
+    ///
+    /// Write and read n-length signed numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 3];
+    /// LittleEndian::write_int128(&mut buf, -1_000, 3);
+    /// assert_eq!(-1_000, LittleEndian::read_int128(&buf, 3));
+    /// ```
+    #[inline]
+    fn read_int128(buf: &[u8], nbytes: usize) -> i128 {
+        extend_sign128(Self::read_uint128(buf, nbytes), nbytes)
+    }
+
+    /// Reads a IEEE754 single-precision (4 bytes) floating point number.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 4`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `f32` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let e = 2.71828;
+    /// let mut buf = [0; 4];
+    /// LittleEndian::write_f32(&mut buf, e);
+    /// assert_eq!(e, LittleEndian::read_f32(&buf));
+    /// ```
+    #[inline]
+    fn read_f32(buf: &[u8]) -> f32 {
+        f32::from_bits(Self::read_u32(buf))
+    }
+
+    /// Reads a IEEE754 double-precision (8 bytes) floating point number.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 8`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `f64` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let phi = 1.6180339887;
+    /// let mut buf = [0; 8];
+    /// LittleEndian::write_f64(&mut buf, phi);
+    /// assert_eq!(phi, LittleEndian::read_f64(&buf));
+    /// ```
+    #[inline]
+    fn read_f64(buf: &[u8]) -> f64 {
+        f64::from_bits(Self::read_u64(buf))
+    }
+
+    /// Writes a signed 16 bit integer `n` to `buf`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 2`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `i16` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 2];
+    /// LittleEndian::write_i16(&mut buf, -1_000);
+    /// assert_eq!(-1_000, LittleEndian::read_i16(&buf));
+    /// ```
+    #[inline]
+    fn write_i16(buf: &mut [u8], n: i16) {
+        Self::write_u16(buf, n as u16)
+    }
+
+    /// Writes a signed 24 bit integer `n` to `buf`, stored in i32.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 3`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read 24 bit `i32` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 3];
+    /// LittleEndian::write_i24(&mut buf, -1_000_000);
+    /// assert_eq!(-1_000_000, LittleEndian::read_i24(&buf));
+    /// ```
+    #[inline]
+    fn write_i24(buf: &mut [u8], n: i32) {
+        Self::write_int(buf, n as i64, 3)
+    }
+
+    /// Writes a signed 32 bit integer `n` to `buf`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 4`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `i32` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 4];
+    /// LittleEndian::write_i32(&mut buf, -1_000_000);
+    /// assert_eq!(-1_000_000, LittleEndian::read_i32(&buf));
+    /// ```
+    #[inline]
+    fn write_i32(buf: &mut [u8], n: i32) {
+        Self::write_u32(buf, n as u32)
+    }
+
+    /// Writes a signed 48 bit integer `n` to `buf`, stored in i64.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 6`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read 48 bit `i64` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 6];
+    /// LittleEndian::write_i48(&mut buf, -1_000_000_000_000);
+    /// assert_eq!(-1_000_000_000_000, LittleEndian::read_i48(&buf));
+    /// ```
+    #[inline]
+    fn write_i48(buf: &mut [u8], n: i64) {
+        Self::write_int(buf, n as i64, 6)
+    }
+
+    /// Writes a signed 64 bit integer `n` to `buf`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 8`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `i64` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 8];
+    /// LittleEndian::write_i64(&mut buf, -1_000_000_000);
+    /// assert_eq!(-1_000_000_000, LittleEndian::read_i64(&buf));
+    /// ```
+    #[inline]
+    fn write_i64(buf: &mut [u8], n: i64) {
+        Self::write_u64(buf, n as u64)
+    }
+
+    /// Writes a signed 128 bit integer `n` to `buf`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 16`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read n-byte `i128` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 16];
+    /// LittleEndian::write_i128(&mut buf, -1_000_000_000);
+    /// assert_eq!(-1_000_000_000, LittleEndian::read_i128(&buf));
+    /// ```
+    #[inline]
+    fn write_i128(buf: &mut [u8], n: i128) {
+        Self::write_u128(buf, n as u128)
+    }
+
+    /// Writes a signed integer `n` to `buf` using only `nbytes`.
+    ///
+    /// # Panics
+    ///
+    /// If `n` is not representable in `nbytes`, or if `nbytes` is `> 8`, then
+    /// this method panics.
+    ///
+    /// # Examples
+    ///
+    /// Write and read an n-byte number in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 3];
+    /// LittleEndian::write_int(&mut buf, -1_000, 3);
+    /// assert_eq!(-1_000, LittleEndian::read_int(&buf, 3));
+    /// ```
+    #[inline]
+    fn write_int(buf: &mut [u8], n: i64, nbytes: usize) {
+        Self::write_uint(buf, unextend_sign(n, nbytes), nbytes)
+    }
+
+    /// Writes a signed integer `n` to `buf` using only `nbytes`.
+    ///
+    /// # Panics
+    ///
+    /// If `n` is not representable in `nbytes`, or if `nbytes` is `> 16`, then
+    /// this method panics.
+    ///
+    /// # Examples
+    ///
+    /// Write and read n-length signed numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut buf = [0; 3];
+    /// LittleEndian::write_int128(&mut buf, -1_000, 3);
+    /// assert_eq!(-1_000, LittleEndian::read_int128(&buf, 3));
+    /// ```
+    #[inline]
+    fn write_int128(buf: &mut [u8], n: i128, nbytes: usize) {
+        Self::write_uint128(buf, unextend_sign128(n, nbytes), nbytes)
+    }
+
+    /// Writes a IEEE754 single-precision (4 bytes) floating point number.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 4`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `f32` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let e = 2.71828;
+    /// let mut buf = [0; 4];
+    /// LittleEndian::write_f32(&mut buf, e);
+    /// assert_eq!(e, LittleEndian::read_f32(&buf));
+    /// ```
+    #[inline]
+    fn write_f32(buf: &mut [u8], n: f32) {
+        Self::write_u32(buf, n.to_bits())
+    }
+
+    /// Writes a IEEE754 double-precision (8 bytes) floating point number.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() < 8`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `f64` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let phi = 1.6180339887;
+    /// let mut buf = [0; 8];
+    /// LittleEndian::write_f64(&mut buf, phi);
+    /// assert_eq!(phi, LittleEndian::read_f64(&buf));
+    /// ```
+    #[inline]
+    fn write_f64(buf: &mut [u8], n: f64) {
+        Self::write_u64(buf, n.to_bits())
+    }
+
+    /// Reads unsigned 16 bit integers from `src` into `dst`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `src.len() != 2*dst.len()`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `u16` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut bytes = [0; 8];
+    /// let numbers_given = [1, 2, 0xf00f, 0xffee];
+    /// LittleEndian::write_u16_into(&numbers_given, &mut bytes);
+    ///
+    /// let mut numbers_got = [0; 4];
+    /// LittleEndian::read_u16_into(&bytes, &mut numbers_got);
+    /// assert_eq!(numbers_given, numbers_got);
+    /// ```
+    fn read_u16_into(src: &[u8], dst: &mut [u16]);
+
+    /// Reads unsigned 32 bit integers from `src` into `dst`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `src.len() != 4*dst.len()`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `u32` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut bytes = [0; 16];
+    /// let numbers_given = [1, 2, 0xf00f, 0xffee];
+    /// LittleEndian::write_u32_into(&numbers_given, &mut bytes);
+    ///
+    /// let mut numbers_got = [0; 4];
+    /// LittleEndian::read_u32_into(&bytes, &mut numbers_got);
+    /// assert_eq!(numbers_given, numbers_got);
+    /// ```
+    fn read_u32_into(src: &[u8], dst: &mut [u32]);
+
+    /// Reads unsigned 64 bit integers from `src` into `dst`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `src.len() != 8*dst.len()`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `u64` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut bytes = [0; 32];
+    /// let numbers_given = [1, 2, 0xf00f, 0xffee];
+    /// LittleEndian::write_u64_into(&numbers_given, &mut bytes);
+    ///
+    /// let mut numbers_got = [0; 4];
+    /// LittleEndian::read_u64_into(&bytes, &mut numbers_got);
+    /// assert_eq!(numbers_given, numbers_got);
+    /// ```
+    fn read_u64_into(src: &[u8], dst: &mut [u64]);
+
+    /// Reads unsigned 128 bit integers from `src` into `dst`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `src.len() != 16*dst.len()`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `u128` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut bytes = [0; 64];
+    /// let numbers_given = [1, 2, 0xf00f, 0xffee];
+    /// LittleEndian::write_u128_into(&numbers_given, &mut bytes);
+    ///
+    /// let mut numbers_got = [0; 4];
+    /// LittleEndian::read_u128_into(&bytes, &mut numbers_got);
+    /// assert_eq!(numbers_given, numbers_got);
+    /// ```
+    fn read_u128_into(src: &[u8], dst: &mut [u128]);
+
+    /// Reads signed 16 bit integers from `src` to `dst`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() != 2*dst.len()`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `i16` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut bytes = [0; 8];
+    /// let numbers_given = [1, 2, 0x0f, 0xee];
+    /// LittleEndian::write_i16_into(&numbers_given, &mut bytes);
+    ///
+    /// let mut numbers_got = [0; 4];
+    /// LittleEndian::read_i16_into(&bytes, &mut numbers_got);
+    /// assert_eq!(numbers_given, numbers_got);
+    /// ```
+    #[inline]
+    fn read_i16_into(src: &[u8], dst: &mut [i16]) {
+        let dst = unsafe {
+            slice::from_raw_parts_mut(dst.as_mut_ptr() as *mut u16, dst.len())
+        };
+        Self::read_u16_into(src, dst)
+    }
+
+    /// Reads signed 32 bit integers from `src` into `dst`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `src.len() != 4*dst.len()`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `i32` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut bytes = [0; 16];
+    /// let numbers_given = [1, 2, 0xf00f, 0xffee];
+    /// LittleEndian::write_i32_into(&numbers_given, &mut bytes);
+    ///
+    /// let mut numbers_got = [0; 4];
+    /// LittleEndian::read_i32_into(&bytes, &mut numbers_got);
+    /// assert_eq!(numbers_given, numbers_got);
+    /// ```
+    #[inline]
+    fn read_i32_into(src: &[u8], dst: &mut [i32]) {
+        let dst = unsafe {
+            slice::from_raw_parts_mut(dst.as_mut_ptr() as *mut u32, dst.len())
+        };
+        Self::read_u32_into(src, dst);
+    }
+
+    /// Reads signed 64 bit integers from `src` into `dst`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `src.len() != 8*dst.len()`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `i64` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut bytes = [0; 32];
+    /// let numbers_given = [1, 2, 0xf00f, 0xffee];
+    /// LittleEndian::write_i64_into(&numbers_given, &mut bytes);
+    ///
+    /// let mut numbers_got = [0; 4];
+    /// LittleEndian::read_i64_into(&bytes, &mut numbers_got);
+    /// assert_eq!(numbers_given, numbers_got);
+    /// ```
+    #[inline]
+    fn read_i64_into(src: &[u8], dst: &mut [i64]) {
+        let dst = unsafe {
+            slice::from_raw_parts_mut(dst.as_mut_ptr() as *mut u64, dst.len())
+        };
+        Self::read_u64_into(src, dst);
+    }
+
+    /// Reads signed 128 bit integers from `src` into `dst`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `src.len() != 16*dst.len()`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `i128` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut bytes = [0; 64];
+    /// let numbers_given = [1, 2, 0xf00f, 0xffee];
+    /// LittleEndian::write_i128_into(&numbers_given, &mut bytes);
+    ///
+    /// let mut numbers_got = [0; 4];
+    /// LittleEndian::read_i128_into(&bytes, &mut numbers_got);
+    /// assert_eq!(numbers_given, numbers_got);
+    /// ```
+    #[inline]
+    fn read_i128_into(src: &[u8], dst: &mut [i128]) {
+        let dst = unsafe {
+            slice::from_raw_parts_mut(dst.as_mut_ptr() as *mut u128, dst.len())
+        };
+        Self::read_u128_into(src, dst);
+    }
+
+    /// Reads IEEE754 single-precision (4 bytes) floating point numbers from
+    /// `src` into `dst`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `src.len() != 4*dst.len()`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `f32` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut bytes = [0; 16];
+    /// let numbers_given = [1.0, 2.0, 31.312e31, -11.32e19];
+    /// LittleEndian::write_f32_into(&numbers_given, &mut bytes);
+    ///
+    /// let mut numbers_got = [0.0; 4];
+    /// LittleEndian::read_f32_into(&bytes, &mut numbers_got);
+    /// assert_eq!(numbers_given, numbers_got);
+    /// ```
+    #[inline]
+    fn read_f32_into(src: &[u8], dst: &mut [f32]) {
+        let dst = unsafe {
+            const _: () = assert!(align_of::<u32>() <= align_of::<f32>());
+            slice::from_raw_parts_mut(dst.as_mut_ptr() as *mut u32, dst.len())
+        };
+        Self::read_u32_into(src, dst);
+    }
+
+    /// **DEPRECATED**.
+    ///
+    /// This method is deprecated. Use `read_f32_into` instead.
+    /// Reads IEEE754 single-precision (4 bytes) floating point numbers from
+    /// `src` into `dst`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `src.len() != 4*dst.len()`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `f32` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut bytes = [0; 16];
+    /// let numbers_given = [1.0, 2.0, 31.312e31, -11.32e19];
+    /// LittleEndian::write_f32_into(&numbers_given, &mut bytes);
+    ///
+    /// let mut numbers_got = [0.0; 4];
+    /// LittleEndian::read_f32_into_unchecked(&bytes, &mut numbers_got);
+    /// assert_eq!(numbers_given, numbers_got);
+    /// ```
+    #[inline]
+    #[deprecated(since = "1.3.0", note = "please use `read_f32_into` instead")]
+    fn read_f32_into_unchecked(src: &[u8], dst: &mut [f32]) {
+        Self::read_f32_into(src, dst);
+    }
+
+    /// Reads IEEE754 single-precision (4 bytes) floating point numbers from
+    /// `src` into `dst`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `src.len() != 8*dst.len()`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `f64` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut bytes = [0; 32];
+    /// let numbers_given = [1.0, 2.0, 31.312e211, -11.32e91];
+    /// LittleEndian::write_f64_into(&numbers_given, &mut bytes);
+    ///
+    /// let mut numbers_got = [0.0; 4];
+    /// LittleEndian::read_f64_into(&bytes, &mut numbers_got);
+    /// assert_eq!(numbers_given, numbers_got);
+    /// ```
+    #[inline]
+    fn read_f64_into(src: &[u8], dst: &mut [f64]) {
+        let dst = unsafe {
+            const _: () = assert!(align_of::<u64>() <= align_of::<f64>());
+            slice::from_raw_parts_mut(dst.as_mut_ptr() as *mut u64, dst.len())
+        };
+        Self::read_u64_into(src, dst);
+    }
+
+    /// **DEPRECATED**.
+    ///
+    /// This method is deprecated. Use `read_f64_into` instead.
+    ///
+    /// Reads IEEE754 single-precision (4 bytes) floating point numbers from
+    /// `src` into `dst`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `src.len() != 8*dst.len()`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `f64` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut bytes = [0; 32];
+    /// let numbers_given = [1.0, 2.0, 31.312e211, -11.32e91];
+    /// LittleEndian::write_f64_into(&numbers_given, &mut bytes);
+    ///
+    /// let mut numbers_got = [0.0; 4];
+    /// LittleEndian::read_f64_into_unchecked(&bytes, &mut numbers_got);
+    /// assert_eq!(numbers_given, numbers_got);
+    /// ```
+    #[inline]
+    #[deprecated(since = "1.3.0", note = "please use `read_f64_into` instead")]
+    fn read_f64_into_unchecked(src: &[u8], dst: &mut [f64]) {
+        Self::read_f64_into(src, dst);
+    }
+
+    /// Writes unsigned 16 bit integers from `src` into `dst`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `dst.len() != 2*src.len()`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `u16` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut bytes = [0; 8];
+    /// let numbers_given = [1, 2, 0xf00f, 0xffee];
+    /// LittleEndian::write_u16_into(&numbers_given, &mut bytes);
+    ///
+    /// let mut numbers_got = [0; 4];
+    /// LittleEndian::read_u16_into(&bytes, &mut numbers_got);
+    /// assert_eq!(numbers_given, numbers_got);
+    /// ```
+    fn write_u16_into(src: &[u16], dst: &mut [u8]);
+
+    /// Writes unsigned 32 bit integers from `src` into `dst`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `dst.len() != 4*src.len()`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `u32` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut bytes = [0; 16];
+    /// let numbers_given = [1, 2, 0xf00f, 0xffee];
+    /// LittleEndian::write_u32_into(&numbers_given, &mut bytes);
+    ///
+    /// let mut numbers_got = [0; 4];
+    /// LittleEndian::read_u32_into(&bytes, &mut numbers_got);
+    /// assert_eq!(numbers_given, numbers_got);
+    /// ```
+    fn write_u32_into(src: &[u32], dst: &mut [u8]);
+
+    /// Writes unsigned 64 bit integers from `src` into `dst`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `dst.len() != 8*src.len()`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `u64` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut bytes = [0; 32];
+    /// let numbers_given = [1, 2, 0xf00f, 0xffee];
+    /// LittleEndian::write_u64_into(&numbers_given, &mut bytes);
+    ///
+    /// let mut numbers_got = [0; 4];
+    /// LittleEndian::read_u64_into(&bytes, &mut numbers_got);
+    /// assert_eq!(numbers_given, numbers_got);
+    /// ```
+    fn write_u64_into(src: &[u64], dst: &mut [u8]);
+
+    /// Writes unsigned 128 bit integers from `src` into `dst`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `dst.len() != 16*src.len()`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `u128` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut bytes = [0; 64];
+    /// let numbers_given = [1, 2, 0xf00f, 0xffee];
+    /// LittleEndian::write_u128_into(&numbers_given, &mut bytes);
+    ///
+    /// let mut numbers_got = [0; 4];
+    /// LittleEndian::read_u128_into(&bytes, &mut numbers_got);
+    /// assert_eq!(numbers_given, numbers_got);
+    /// ```
+    fn write_u128_into(src: &[u128], dst: &mut [u8]);
+
+    /// Writes signed 8 bit integers from `src` into `dst`.
+    ///
+    /// Note that since each `i8` is a single byte, no byte order conversions
+    /// are used. This method is included because it provides a safe, simple
+    /// way for the caller to write from a `&[i8]` buffer. (Without this
+    /// method, the caller would have to either use `unsafe` code or convert
+    /// each byte to `u8` individually.)
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() != src.len()`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `i8` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian, ReadBytesExt};
+    ///
+    /// let mut bytes = [0; 4];
+    /// let numbers_given = [1, 2, 0xf, 0xe];
+    /// LittleEndian::write_i8_into(&numbers_given, &mut bytes);
+    ///
+    /// let mut numbers_got = [0; 4];
+    /// bytes.as_ref().read_i8_into(&mut numbers_got);
+    /// assert_eq!(numbers_given, numbers_got);
+    /// ```
+    fn write_i8_into(src: &[i8], dst: &mut [u8]) {
+        let src = unsafe {
+            slice::from_raw_parts(src.as_ptr() as *const u8, src.len())
+        };
+        dst.copy_from_slice(src);
+    }
+
+    /// Writes signed 16 bit integers from `src` into `dst`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `buf.len() != 2*src.len()`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `i16` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut bytes = [0; 8];
+    /// let numbers_given = [1, 2, 0x0f, 0xee];
+    /// LittleEndian::write_i16_into(&numbers_given, &mut bytes);
+    ///
+    /// let mut numbers_got = [0; 4];
+    /// LittleEndian::read_i16_into(&bytes, &mut numbers_got);
+    /// assert_eq!(numbers_given, numbers_got);
+    /// ```
+    fn write_i16_into(src: &[i16], dst: &mut [u8]) {
+        let src = unsafe {
+            slice::from_raw_parts(src.as_ptr() as *const u16, src.len())
+        };
+        Self::write_u16_into(src, dst);
+    }
+
+    /// Writes signed 32 bit integers from `src` into `dst`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `dst.len() != 4*src.len()`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `i32` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut bytes = [0; 16];
+    /// let numbers_given = [1, 2, 0xf00f, 0xffee];
+    /// LittleEndian::write_i32_into(&numbers_given, &mut bytes);
+    ///
+    /// let mut numbers_got = [0; 4];
+    /// LittleEndian::read_i32_into(&bytes, &mut numbers_got);
+    /// assert_eq!(numbers_given, numbers_got);
+    /// ```
+    fn write_i32_into(src: &[i32], dst: &mut [u8]) {
+        let src = unsafe {
+            slice::from_raw_parts(src.as_ptr() as *const u32, src.len())
+        };
+        Self::write_u32_into(src, dst);
+    }
+
+    /// Writes signed 64 bit integers from `src` into `dst`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `dst.len() != 8*src.len()`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `i64` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut bytes = [0; 32];
+    /// let numbers_given = [1, 2, 0xf00f, 0xffee];
+    /// LittleEndian::write_i64_into(&numbers_given, &mut bytes);
+    ///
+    /// let mut numbers_got = [0; 4];
+    /// LittleEndian::read_i64_into(&bytes, &mut numbers_got);
+    /// assert_eq!(numbers_given, numbers_got);
+    /// ```
+    fn write_i64_into(src: &[i64], dst: &mut [u8]) {
+        let src = unsafe {
+            slice::from_raw_parts(src.as_ptr() as *const u64, src.len())
+        };
+        Self::write_u64_into(src, dst);
+    }
+
+    /// Writes signed 128 bit integers from `src` into `dst`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `dst.len() != 16*src.len()`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `i128` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut bytes = [0; 64];
+    /// let numbers_given = [1, 2, 0xf00f, 0xffee];
+    /// LittleEndian::write_i128_into(&numbers_given, &mut bytes);
+    ///
+    /// let mut numbers_got = [0; 4];
+    /// LittleEndian::read_i128_into(&bytes, &mut numbers_got);
+    /// assert_eq!(numbers_given, numbers_got);
+    /// ```
+    fn write_i128_into(src: &[i128], dst: &mut [u8]) {
+        let src = unsafe {
+            slice::from_raw_parts(src.as_ptr() as *const u128, src.len())
+        };
+        Self::write_u128_into(src, dst);
+    }
+
+    /// Writes IEEE754 single-precision (4 bytes) floating point numbers from
+    /// `src` into `dst`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `src.len() != 4*dst.len()`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `f32` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut bytes = [0; 16];
+    /// let numbers_given = [1.0, 2.0, 31.312e31, -11.32e19];
+    /// LittleEndian::write_f32_into(&numbers_given, &mut bytes);
+    ///
+    /// let mut numbers_got = [0.0; 4];
+    /// LittleEndian::read_f32_into(&bytes, &mut numbers_got);
+    /// assert_eq!(numbers_given, numbers_got);
+    /// ```
+    fn write_f32_into(src: &[f32], dst: &mut [u8]) {
+        let src = unsafe {
+            slice::from_raw_parts(src.as_ptr() as *const u32, src.len())
+        };
+        Self::write_u32_into(src, dst);
+    }
+
+    /// Writes IEEE754 double-precision (8 bytes) floating point numbers from
+    /// `src` into `dst`.
+    ///
+    /// # Panics
+    ///
+    /// Panics when `src.len() != 8*dst.len()`.
+    ///
+    /// # Examples
+    ///
+    /// Write and read `f64` numbers in little endian order:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, LittleEndian};
+    ///
+    /// let mut bytes = [0; 32];
+    /// let numbers_given = [1.0, 2.0, 31.312e211, -11.32e91];
+    /// LittleEndian::write_f64_into(&numbers_given, &mut bytes);
+    ///
+    /// let mut numbers_got = [0.0; 4];
+    /// LittleEndian::read_f64_into(&bytes, &mut numbers_got);
+    /// assert_eq!(numbers_given, numbers_got);
+    /// ```
+    fn write_f64_into(src: &[f64], dst: &mut [u8]) {
+        let src = unsafe {
+            slice::from_raw_parts(src.as_ptr() as *const u64, src.len())
+        };
+        Self::write_u64_into(src, dst);
+    }
+
+    /// Converts the given slice of unsigned 16 bit integers to a particular
+    /// endianness.
+    ///
+    /// If the endianness matches the endianness of the host platform, then
+    /// this is a no-op.
+    ///
+    /// # Examples
+    ///
+    /// Convert the host platform's endianness to big-endian:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, BigEndian};
+    ///
+    /// let mut numbers = [5, 65000];
+    /// BigEndian::from_slice_u16(&mut numbers);
+    /// assert_eq!(numbers, [5u16.to_be(), 65000u16.to_be()]);
+    /// ```
+    fn from_slice_u16(numbers: &mut [u16]);
+
+    /// Converts the given slice of unsigned 32 bit integers to a particular
+    /// endianness.
+    ///
+    /// If the endianness matches the endianness of the host platform, then
+    /// this is a no-op.
+    ///
+    /// # Examples
+    ///
+    /// Convert the host platform's endianness to big-endian:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, BigEndian};
+    ///
+    /// let mut numbers = [5, 65000];
+    /// BigEndian::from_slice_u32(&mut numbers);
+    /// assert_eq!(numbers, [5u32.to_be(), 65000u32.to_be()]);
+    /// ```
+    fn from_slice_u32(numbers: &mut [u32]);
+
+    /// Converts the given slice of unsigned 64 bit integers to a particular
+    /// endianness.
+    ///
+    /// If the endianness matches the endianness of the host platform, then
+    /// this is a no-op.
+    ///
+    /// # Examples
+    ///
+    /// Convert the host platform's endianness to big-endian:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, BigEndian};
+    ///
+    /// let mut numbers = [5, 65000];
+    /// BigEndian::from_slice_u64(&mut numbers);
+    /// assert_eq!(numbers, [5u64.to_be(), 65000u64.to_be()]);
+    /// ```
+    fn from_slice_u64(numbers: &mut [u64]);
+
+    /// Converts the given slice of unsigned 128 bit integers to a particular
+    /// endianness.
+    ///
+    /// If the endianness matches the endianness of the host platform, then
+    /// this is a no-op.
+    ///
+    /// # Examples
+    ///
+    /// Convert the host platform's endianness to big-endian:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, BigEndian};
+    ///
+    /// let mut numbers = [5, 65000];
+    /// BigEndian::from_slice_u128(&mut numbers);
+    /// assert_eq!(numbers, [5u128.to_be(), 65000u128.to_be()]);
+    /// ```
+    fn from_slice_u128(numbers: &mut [u128]);
+
+    /// Converts the given slice of signed 16 bit integers to a particular
+    /// endianness.
+    ///
+    /// If the endianness matches the endianness of the host platform, then
+    /// this is a no-op.
+    ///
+    /// # Examples
+    ///
+    /// Convert the host platform's endianness to big-endian:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, BigEndian};
+    ///
+    /// let mut numbers = [5, 6500];
+    /// BigEndian::from_slice_i16(&mut numbers);
+    /// assert_eq!(numbers, [5i16.to_be(), 6500i16.to_be()]);
+    /// ```
+    #[inline]
+    fn from_slice_i16(src: &mut [i16]) {
+        let src = unsafe {
+            slice::from_raw_parts_mut(src.as_mut_ptr() as *mut u16, src.len())
+        };
+        Self::from_slice_u16(src);
+    }
+
+    /// Converts the given slice of signed 32 bit integers to a particular
+    /// endianness.
+    ///
+    /// If the endianness matches the endianness of the host platform, then
+    /// this is a no-op.
+    ///
+    /// # Examples
+    ///
+    /// Convert the host platform's endianness to big-endian:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, BigEndian};
+    ///
+    /// let mut numbers = [5, 65000];
+    /// BigEndian::from_slice_i32(&mut numbers);
+    /// assert_eq!(numbers, [5i32.to_be(), 65000i32.to_be()]);
+    /// ```
+    #[inline]
+    fn from_slice_i32(src: &mut [i32]) {
+        let src = unsafe {
+            slice::from_raw_parts_mut(src.as_mut_ptr() as *mut u32, src.len())
+        };
+        Self::from_slice_u32(src);
+    }
+
+    /// Converts the given slice of signed 64 bit integers to a particular
+    /// endianness.
+    ///
+    /// If the endianness matches the endianness of the host platform, then
+    /// this is a no-op.
+    ///
+    /// # Examples
+    ///
+    /// Convert the host platform's endianness to big-endian:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, BigEndian};
+    ///
+    /// let mut numbers = [5, 65000];
+    /// BigEndian::from_slice_i64(&mut numbers);
+    /// assert_eq!(numbers, [5i64.to_be(), 65000i64.to_be()]);
+    /// ```
+    #[inline]
+    fn from_slice_i64(src: &mut [i64]) {
+        let src = unsafe {
+            slice::from_raw_parts_mut(src.as_mut_ptr() as *mut u64, src.len())
+        };
+        Self::from_slice_u64(src);
+    }
+
+    /// Converts the given slice of signed 128 bit integers to a particular
+    /// endianness.
+    ///
+    /// If the endianness matches the endianness of the host platform, then
+    /// this is a no-op.
+    ///
+    /// # Examples
+    ///
+    /// Convert the host platform's endianness to big-endian:
+    ///
+    /// ```rust
+    /// use byteorder::{ByteOrder, BigEndian};
+    ///
+    /// let mut numbers = [5, 65000];
+    /// BigEndian::from_slice_i128(&mut numbers);
+    /// assert_eq!(numbers, [5i128.to_be(), 65000i128.to_be()]);
+    /// ```
+    #[inline]
+    fn from_slice_i128(src: &mut [i128]) {
+        let src = unsafe {
+            slice::from_raw_parts_mut(src.as_mut_ptr() as *mut u128, src.len())
+        };
+        Self::from_slice_u128(src);
+    }
+
+    /// Converts the given slice of IEEE754 single-precision (4 bytes) floating
+    /// point numbers to a particular endianness.
+    ///
+    /// If the endianness matches the endianness of the host platform, then
+    /// this is a no-op.
+    fn from_slice_f32(numbers: &mut [f32]);
+
+    /// Converts the given slice of IEEE754 double-precision (8 bytes) floating
+    /// point numbers to a particular endianness.
+    ///
+    /// If the endianness matches the endianness of the host platform, then
+    /// this is a no-op.
+    fn from_slice_f64(numbers: &mut [f64]);
+}
+
+/// Defines big-endian serialization.
+///
+/// Note that this type has no value constructor. It is used purely at the
+/// type level.
+///
+/// # Examples
+///
+/// Write and read `u32` numbers in big endian order:
+///
+/// ```rust
+/// use byteorder::{ByteOrder, BigEndian};
+///
+/// let mut buf = [0; 4];
+/// BigEndian::write_u32(&mut buf, 1_000_000);
+/// assert_eq!(1_000_000, BigEndian::read_u32(&buf));
+/// ```
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub enum BigEndian {}
+
+impl Default for BigEndian {
+    fn default() -> BigEndian {
+        panic!("BigEndian default")
+    }
+}
+
+/// A type alias for [`BigEndian`].
+///
+/// [`BigEndian`]: enum.BigEndian.html
+pub type BE = BigEndian;
+
+/// Defines little-endian serialization.
+///
+/// Note that this type has no value constructor. It is used purely at the
+/// type level.
+///
+/// # Examples
+///
+/// Write and read `u32` numbers in little endian order:
+///
+/// ```rust
+/// use byteorder::{ByteOrder, LittleEndian};
+///
+/// let mut buf = [0; 4];
+/// LittleEndian::write_u32(&mut buf, 1_000_000);
+/// assert_eq!(1_000_000, LittleEndian::read_u32(&buf));
+/// ```
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub enum LittleEndian {}
+
+impl Default for LittleEndian {
+    fn default() -> LittleEndian {
+        panic!("LittleEndian default")
+    }
+}
+
+/// A type alias for [`LittleEndian`].
+///
+/// [`LittleEndian`]: enum.LittleEndian.html
+pub type LE = LittleEndian;
+
+/// Defines network byte order serialization.
+///
+/// Network byte order is defined by [RFC 1700][1] to be big-endian, and is
+/// referred to in several protocol specifications.  This type is an alias of
+/// [`BigEndian`].
+///
+/// [1]: https://tools.ietf.org/html/rfc1700
+///
+/// Note that this type has no value constructor. It is used purely at the
+/// type level.
+///
+/// # Examples
+///
+/// Write and read `i16` numbers in big endian order:
+///
+/// ```rust
+/// use byteorder::{ByteOrder, NetworkEndian, BigEndian};
+///
+/// let mut buf = [0; 2];
+/// BigEndian::write_i16(&mut buf, -5_000);
+/// assert_eq!(-5_000, NetworkEndian::read_i16(&buf));
+/// ```
+///
+/// [`BigEndian`]: enum.BigEndian.html
+pub type NetworkEndian = BigEndian;
+
+/// Defines system native-endian serialization.
+///
+/// Note that this type has no value constructor. It is used purely at the
+/// type level.
+///
+/// On this platform, this is an alias for [`LittleEndian`].
+///
+/// [`LittleEndian`]: enum.LittleEndian.html
+#[cfg(target_endian = "little")]
+pub type NativeEndian = LittleEndian;
+
+/// Defines system native-endian serialization.
+///
+/// Note that this type has no value constructor. It is used purely at the
+/// type level.
+///
+/// On this platform, this is an alias for [`BigEndian`].
+///
+/// [`BigEndian`]: enum.BigEndian.html
+#[cfg(target_endian = "big")]
+pub type NativeEndian = BigEndian;
+
+/// Copies a &[u8] $src into a &mut [$ty] $dst for the endianness given by
+/// $from_bytes (must be either from_be_bytes or from_le_bytes).
+///
+/// Panics if $src.len() != $dst.len() * size_of::<$ty>().
+macro_rules! read_slice {
+    ($src:expr, $dst:expr, $ty:ty, $from_bytes:ident) => {{
+        const SIZE: usize = core::mem::size_of::<$ty>();
+        // Check types:
+        let src: &[u8] = $src;
+        let dst: &mut [$ty] = $dst;
+        assert_eq!(src.len(), dst.len() * SIZE);
+        for (src, dst) in src.chunks_exact(SIZE).zip(dst.iter_mut()) {
+            *dst = <$ty>::$from_bytes(src.try_into().unwrap());
+        }
+    }};
+}
+
+/// Copies a &[$ty] $src into a &mut [u8] $dst for the endianness given by
+/// $from_bytes (must be either from_be_bytes or from_le_bytes).
+///
+/// Panics if $src.len() * size_of::<$ty>() != $dst.len().
+macro_rules! write_slice {
+    ($src:expr, $dst:expr, $ty:ty, $to_bytes:ident) => {{
+        const SIZE: usize = core::mem::size_of::<$ty>();
+        // Check types:
+        let src: &[$ty] = $src;
+        let dst: &mut [u8] = $dst;
+        assert_eq!(src.len() * SIZE, dst.len());
+        for (src, dst) in src.iter().zip(dst.chunks_exact_mut(SIZE)) {
+            dst.copy_from_slice(&src.$to_bytes());
+        }
+    }};
+}
+
+impl ByteOrder for BigEndian {
+    #[inline]
+    fn read_u16(buf: &[u8]) -> u16 {
+        u16::from_be_bytes(buf[..2].try_into().unwrap())
+    }
+
+    #[inline]
+    fn read_u32(buf: &[u8]) -> u32 {
+        u32::from_be_bytes(buf[..4].try_into().unwrap())
+    }
+
+    #[inline]
+    fn read_u64(buf: &[u8]) -> u64 {
+        u64::from_be_bytes(buf[..8].try_into().unwrap())
+    }
+
+    #[inline]
+    fn read_u128(buf: &[u8]) -> u128 {
+        u128::from_be_bytes(buf[..16].try_into().unwrap())
+    }
+
+    #[inline]
+    fn read_uint(buf: &[u8], nbytes: usize) -> u64 {
+        let mut out = [0; 8];
+        assert!(1 <= nbytes && nbytes <= out.len() && nbytes <= buf.len());
+        let start = out.len() - nbytes;
+        out[start..].copy_from_slice(&buf[..nbytes]);
+        u64::from_be_bytes(out)
+    }
+
+    #[inline]
+    fn read_uint128(buf: &[u8], nbytes: usize) -> u128 {
+        let mut out = [0; 16];
+        assert!(1 <= nbytes && nbytes <= out.len() && nbytes <= buf.len());
+        let start = out.len() - nbytes;
+        out[start..].copy_from_slice(&buf[..nbytes]);
+        u128::from_be_bytes(out)
+    }
+
+    #[inline]
+    fn write_u16(buf: &mut [u8], n: u16) {
+        buf[..2].copy_from_slice(&n.to_be_bytes());
+    }
+
+    #[inline]
+    fn write_u32(buf: &mut [u8], n: u32) {
+        buf[..4].copy_from_slice(&n.to_be_bytes());
+    }
+
+    #[inline]
+    fn write_u64(buf: &mut [u8], n: u64) {
+        buf[..8].copy_from_slice(&n.to_be_bytes());
+    }
+
+    #[inline]
+    fn write_u128(buf: &mut [u8], n: u128) {
+        buf[..16].copy_from_slice(&n.to_be_bytes());
+    }
+
+    #[inline]
+    fn write_uint(buf: &mut [u8], n: u64, nbytes: usize) {
+        assert!(pack_size(n) <= nbytes && nbytes <= 8);
+        assert!(nbytes <= buf.len());
+        unsafe {
+            let bytes = *(&n.to_be() as *const u64 as *const [u8; 8]);
+            copy_nonoverlapping(
+                bytes.as_ptr().offset((8 - nbytes) as isize),
+                buf.as_mut_ptr(),
+                nbytes,
+            );
+        }
+    }
+
+    #[inline]
+    fn write_uint128(buf: &mut [u8], n: u128, nbytes: usize) {
+        assert!(pack_size128(n) <= nbytes && nbytes <= 16);
+        assert!(nbytes <= buf.len());
+        unsafe {
+            let bytes = *(&n.to_be() as *const u128 as *const [u8; 16]);
+            copy_nonoverlapping(
+                bytes.as_ptr().offset((16 - nbytes) as isize),
+                buf.as_mut_ptr(),
+                nbytes,
+            );
+        }
+    }
+
+    #[inline]
+    fn read_u16_into(src: &[u8], dst: &mut [u16]) {
+        read_slice!(src, dst, u16, from_be_bytes);
+    }
+
+    #[inline]
+    fn read_u32_into(src: &[u8], dst: &mut [u32]) {
+        read_slice!(src, dst, u32, from_be_bytes);
+    }
+
+    #[inline]
+    fn read_u64_into(src: &[u8], dst: &mut [u64]) {
+        read_slice!(src, dst, u64, from_be_bytes);
+    }
+
+    #[inline]
+    fn read_u128_into(src: &[u8], dst: &mut [u128]) {
+        read_slice!(src, dst, u128, from_be_bytes);
+    }
+
+    #[inline]
+    fn write_u16_into(src: &[u16], dst: &mut [u8]) {
+        write_slice!(src, dst, u16, to_be_bytes);
+    }
+
+    #[inline]
+    fn write_u32_into(src: &[u32], dst: &mut [u8]) {
+        write_slice!(src, dst, u32, to_be_bytes);
+    }
+
+    #[inline]
+    fn write_u64_into(src: &[u64], dst: &mut [u8]) {
+        write_slice!(src, dst, u64, to_be_bytes);
+    }
+
+    #[inline]
+    fn write_u128_into(src: &[u128], dst: &mut [u8]) {
+        write_slice!(src, dst, u128, to_be_bytes);
+    }
+
+    #[inline]
+    fn from_slice_u16(numbers: &mut [u16]) {
+        if cfg!(target_endian = "little") {
+            for n in numbers {
+                *n = n.to_be();
+            }
+        }
+    }
+
+    #[inline]
+    fn from_slice_u32(numbers: &mut [u32]) {
+        if cfg!(target_endian = "little") {
+            for n in numbers {
+                *n = n.to_be();
+            }
+        }
+    }
+
+    #[inline]
+    fn from_slice_u64(numbers: &mut [u64]) {
+        if cfg!(target_endian = "little") {
+            for n in numbers {
+                *n = n.to_be();
+            }
+        }
+    }
+
+    #[inline]
+    fn from_slice_u128(numbers: &mut [u128]) {
+        if cfg!(target_endian = "little") {
+            for n in numbers {
+                *n = n.to_be();
+            }
+        }
+    }
+
+    #[inline]
+    fn from_slice_f32(numbers: &mut [f32]) {
+        if cfg!(target_endian = "little") {
+            for n in numbers {
+                unsafe {
+                    let int = *(n as *const f32 as *const u32);
+                    *n = *(&int.to_be() as *const u32 as *const f32);
+                }
+            }
+        }
+    }
+
+    #[inline]
+    fn from_slice_f64(numbers: &mut [f64]) {
+        if cfg!(target_endian = "little") {
+            for n in numbers {
+                unsafe {
+                    let int = *(n as *const f64 as *const u64);
+                    *n = *(&int.to_be() as *const u64 as *const f64);
+                }
+            }
+        }
+    }
+}
+
+impl ByteOrder for LittleEndian {
+    #[inline]
+    fn read_u16(buf: &[u8]) -> u16 {
+        u16::from_le_bytes(buf[..2].try_into().unwrap())
+    }
+
+    #[inline]
+    fn read_u32(buf: &[u8]) -> u32 {
+        u32::from_le_bytes(buf[..4].try_into().unwrap())
+    }
+
+    #[inline]
+    fn read_u64(buf: &[u8]) -> u64 {
+        u64::from_le_bytes(buf[..8].try_into().unwrap())
+    }
+
+    #[inline]
+    fn read_u128(buf: &[u8]) -> u128 {
+        u128::from_le_bytes(buf[..16].try_into().unwrap())
+    }
+
+    #[inline]
+    fn read_uint(buf: &[u8], nbytes: usize) -> u64 {
+        let mut out = [0; 8];
+        assert!(1 <= nbytes && nbytes <= out.len() && nbytes <= buf.len());
+        out[..nbytes].copy_from_slice(&buf[..nbytes]);
+        u64::from_le_bytes(out)
+    }
+
+    #[inline]
+    fn read_uint128(buf: &[u8], nbytes: usize) -> u128 {
+        let mut out = [0; 16];
+        assert!(1 <= nbytes && nbytes <= out.len() && nbytes <= buf.len());
+        out[..nbytes].copy_from_slice(&buf[..nbytes]);
+        u128::from_le_bytes(out)
+    }
+
+    #[inline]
+    fn write_u16(buf: &mut [u8], n: u16) {
+        buf[..2].copy_from_slice(&n.to_le_bytes());
+    }
+
+    #[inline]
+    fn write_u32(buf: &mut [u8], n: u32) {
+        buf[..4].copy_from_slice(&n.to_le_bytes());
+    }
+
+    #[inline]
+    fn write_u64(buf: &mut [u8], n: u64) {
+        buf[..8].copy_from_slice(&n.to_le_bytes());
+    }
+
+    #[inline]
+    fn write_u128(buf: &mut [u8], n: u128) {
+        buf[..16].copy_from_slice(&n.to_le_bytes());
+    }
+
+    #[inline]
+    fn write_uint(buf: &mut [u8], n: u64, nbytes: usize) {
+        assert!(pack_size(n as u64) <= nbytes && nbytes <= 8);
+        assert!(nbytes <= buf.len());
+        unsafe {
+            let bytes = *(&n.to_le() as *const u64 as *const [u8; 8]);
+            copy_nonoverlapping(bytes.as_ptr(), buf.as_mut_ptr(), nbytes);
+        }
+    }
+
+    #[inline]
+    fn write_uint128(buf: &mut [u8], n: u128, nbytes: usize) {
+        assert!(pack_size128(n as u128) <= nbytes && nbytes <= 16);
+        assert!(nbytes <= buf.len());
+        unsafe {
+            let bytes = *(&n.to_le() as *const u128 as *const [u8; 16]);
+            copy_nonoverlapping(bytes.as_ptr(), buf.as_mut_ptr(), nbytes);
+        }
+    }
+
+    #[inline]
+    fn read_u16_into(src: &[u8], dst: &mut [u16]) {
+        read_slice!(src, dst, u16, from_le_bytes);
+    }
+
+    #[inline]
+    fn read_u32_into(src: &[u8], dst: &mut [u32]) {
+        read_slice!(src, dst, u32, from_le_bytes);
+    }
+
+    #[inline]
+    fn read_u64_into(src: &[u8], dst: &mut [u64]) {
+        read_slice!(src, dst, u64, from_le_bytes);
+    }
+
+    #[inline]
+    fn read_u128_into(src: &[u8], dst: &mut [u128]) {
+        read_slice!(src, dst, u128, from_le_bytes);
+    }
+
+    #[inline]
+    fn write_u16_into(src: &[u16], dst: &mut [u8]) {
+        write_slice!(src, dst, u16, to_le_bytes);
+    }
+
+    #[inline]
+    fn write_u32_into(src: &[u32], dst: &mut [u8]) {
+        write_slice!(src, dst, u32, to_le_bytes);
+    }
+
+    #[inline]
+    fn write_u64_into(src: &[u64], dst: &mut [u8]) {
+        write_slice!(src, dst, u64, to_le_bytes);
+    }
+
+    #[inline]
+    fn write_u128_into(src: &[u128], dst: &mut [u8]) {
+        write_slice!(src, dst, u128, to_le_bytes);
+    }
+
+    #[inline]
+    fn from_slice_u16(numbers: &mut [u16]) {
+        if cfg!(target_endian = "big") {
+            for n in numbers {
+                *n = n.to_le();
+            }
+        }
+    }
+
+    #[inline]
+    fn from_slice_u32(numbers: &mut [u32]) {
+        if cfg!(target_endian = "big") {
+            for n in numbers {
+                *n = n.to_le();
+            }
+        }
+    }
+
+    #[inline]
+    fn from_slice_u64(numbers: &mut [u64]) {
+        if cfg!(target_endian = "big") {
+            for n in numbers {
+                *n = n.to_le();
+            }
+        }
+    }
+
+    #[inline]
+    fn from_slice_u128(numbers: &mut [u128]) {
+        if cfg!(target_endian = "big") {
+            for n in numbers {
+                *n = n.to_le();
+            }
+        }
+    }
+
+    #[inline]
+    fn from_slice_f32(numbers: &mut [f32]) {
+        if cfg!(target_endian = "big") {
+            for n in numbers {
+                unsafe {
+                    let int = *(n as *const f32 as *const u32);
+                    *n = *(&int.to_le() as *const u32 as *const f32);
+                }
+            }
+        }
+    }
+
+    #[inline]
+    fn from_slice_f64(numbers: &mut [f64]) {
+        if cfg!(target_endian = "big") {
+            for n in numbers {
+                unsafe {
+                    let int = *(n as *const f64 as *const u64);
+                    *n = *(&int.to_le() as *const u64 as *const f64);
+                }
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use quickcheck::{Arbitrary, Gen, QuickCheck, StdGen, Testable};
+    use rand::{thread_rng, Rng};
+
+    pub const U24_MAX: u32 = 16_777_215;
+    pub const I24_MAX: i32 = 8_388_607;
+    pub const U48_MAX: u64 = 281_474_976_710_655;
+    pub const I48_MAX: i64 = 140_737_488_355_327;
+
+    pub const U64_MAX: u64 = ::core::u64::MAX;
+    pub const I64_MAX: u64 = ::core::i64::MAX as u64;
+
+    macro_rules! calc_max {
+        ($max:expr, $bytes:expr) => {
+            calc_max!($max, $bytes, 8)
+        };
+        ($max:expr, $bytes:expr, $maxbytes:expr) => {
+            ($max - 1) >> (8 * ($maxbytes - $bytes))
+        };
+    }
+
+    #[derive(Clone, Debug)]
+    pub struct Wi128<T>(pub T);
+
+    impl<T: Clone> Wi128<T> {
+        pub fn clone(&self) -> T {
+            self.0.clone()
+        }
+    }
+
+    impl<T: PartialEq> PartialEq<T> for Wi128<T> {
+        fn eq(&self, other: &T) -> bool {
+            self.0.eq(other)
+        }
+    }
+
+    impl Arbitrary for Wi128<u128> {
+        fn arbitrary<G: Gen>(gen: &mut G) -> Wi128<u128> {
+            let max = calc_max!(::core::u128::MAX, gen.size(), 16);
+            let output = (gen.gen::<u64>() as u128)
+                | ((gen.gen::<u64>() as u128) << 64);
+            Wi128(output & (max - 1))
+        }
+    }
+
+    impl Arbitrary for Wi128<i128> {
+        fn arbitrary<G: Gen>(gen: &mut G) -> Wi128<i128> {
+            let max = calc_max!(::core::i128::MAX, gen.size(), 16);
+            let output = (gen.gen::<i64>() as i128)
+                | ((gen.gen::<i64>() as i128) << 64);
+            Wi128(output & (max - 1))
+        }
+    }
+
+    pub fn qc_sized<A: Testable>(f: A, size: u64) {
+        QuickCheck::new()
+            .gen(StdGen::new(thread_rng(), size as usize))
+            .tests(1_00)
+            .max_tests(10_000)
+            .quickcheck(f);
+    }
+
+    macro_rules! qc_byte_order {
+        ($name:ident, $ty_int:ty, $max:expr,
+         $bytes:expr, $read:ident, $write:ident) => {
+            #[cfg(not(miri))]
+            mod $name {
+                #[allow(unused_imports)]
+                use super::{qc_sized, Wi128};
+                use crate::{
+                    BigEndian, ByteOrder, LittleEndian, NativeEndian,
+                };
+
+                #[test]
+                fn big_endian() {
+                    fn prop(n: $ty_int) -> bool {
+                        let mut buf = [0; 16];
+                        BigEndian::$write(&mut buf, n.clone(), $bytes);
+                        n == BigEndian::$read(&buf[..$bytes], $bytes)
+                    }
+                    qc_sized(prop as fn($ty_int) -> bool, $max);
+                }
+
+                #[test]
+                fn little_endian() {
+                    fn prop(n: $ty_int) -> bool {
+                        let mut buf = [0; 16];
+                        LittleEndian::$write(&mut buf, n.clone(), $bytes);
+                        n == LittleEndian::$read(&buf[..$bytes], $bytes)
+                    }
+                    qc_sized(prop as fn($ty_int) -> bool, $max);
+                }
+
+                #[test]
+                fn native_endian() {
+                    fn prop(n: $ty_int) -> bool {
+                        let mut buf = [0; 16];
+                        NativeEndian::$write(&mut buf, n.clone(), $bytes);
+                        n == NativeEndian::$read(&buf[..$bytes], $bytes)
+                    }
+                    qc_sized(prop as fn($ty_int) -> bool, $max);
+                }
+            }
+        };
+        ($name:ident, $ty_int:ty, $max:expr,
+         $read:ident, $write:ident) => {
+            #[cfg(not(miri))]
+            mod $name {
+                #[allow(unused_imports)]
+                use super::{qc_sized, Wi128};
+                use crate::{
+                    BigEndian, ByteOrder, LittleEndian, NativeEndian,
+                };
+                use core::mem::size_of;
+
+                #[test]
+                fn big_endian() {
+                    fn prop(n: $ty_int) -> bool {
+                        let bytes = size_of::<$ty_int>();
+                        let mut buf = [0; 16];
+                        BigEndian::$write(&mut buf[16 - bytes..], n.clone());
+                        n == BigEndian::$read(&buf[16 - bytes..])
+                    }
+                    qc_sized(prop as fn($ty_int) -> bool, $max - 1);
+                }
+
+                #[test]
+                fn little_endian() {
+                    fn prop(n: $ty_int) -> bool {
+                        let bytes = size_of::<$ty_int>();
+                        let mut buf = [0; 16];
+                        LittleEndian::$write(&mut buf[..bytes], n.clone());
+                        n == LittleEndian::$read(&buf[..bytes])
+                    }
+                    qc_sized(prop as fn($ty_int) -> bool, $max - 1);
+                }
+
+                #[test]
+                fn native_endian() {
+                    fn prop(n: $ty_int) -> bool {
+                        let bytes = size_of::<$ty_int>();
+                        let mut buf = [0; 16];
+                        NativeEndian::$write(&mut buf[..bytes], n.clone());
+                        n == NativeEndian::$read(&buf[..bytes])
+                    }
+                    qc_sized(prop as fn($ty_int) -> bool, $max - 1);
+                }
+            }
+        };
+    }
+
+    qc_byte_order!(
+        prop_u16,
+        u16,
+        ::core::u16::MAX as u64,
+        read_u16,
+        write_u16
+    );
+    qc_byte_order!(
+        prop_i16,
+        i16,
+        ::core::i16::MAX as u64,
+        read_i16,
+        write_i16
+    );
+    qc_byte_order!(
+        prop_u24,
+        u32,
+        crate::test::U24_MAX as u64,
+        read_u24,
+        write_u24
+    );
+    qc_byte_order!(
+        prop_i24,
+        i32,
+        crate::test::I24_MAX as u64,
+        read_i24,
+        write_i24
+    );
+    qc_byte_order!(
+        prop_u32,
+        u32,
+        ::core::u32::MAX as u64,
+        read_u32,
+        write_u32
+    );
+    qc_byte_order!(
+        prop_i32,
+        i32,
+        ::core::i32::MAX as u64,
+        read_i32,
+        write_i32
+    );
+    qc_byte_order!(
+        prop_u48,
+        u64,
+        crate::test::U48_MAX as u64,
+        read_u48,
+        write_u48
+    );
+    qc_byte_order!(
+        prop_i48,
+        i64,
+        crate::test::I48_MAX as u64,
+        read_i48,
+        write_i48
+    );
+    qc_byte_order!(
+        prop_u64,
+        u64,
+        ::core::u64::MAX as u64,
+        read_u64,
+        write_u64
+    );
+    qc_byte_order!(
+        prop_i64,
+        i64,
+        ::core::i64::MAX as u64,
+        read_i64,
+        write_i64
+    );
+    qc_byte_order!(
+        prop_f32,
+        f32,
+        ::core::u64::MAX as u64,
+        read_f32,
+        write_f32
+    );
+    qc_byte_order!(
+        prop_f64,
+        f64,
+        ::core::i64::MAX as u64,
+        read_f64,
+        write_f64
+    );
+
+    qc_byte_order!(prop_u128, Wi128<u128>, 16 + 1, read_u128, write_u128);
+    qc_byte_order!(prop_i128, Wi128<i128>, 16 + 1, read_i128, write_i128);
+
+    qc_byte_order!(
+        prop_uint_1,
+        u64,
+        calc_max!(super::U64_MAX, 1),
+        1,
+        read_uint,
+        write_uint
+    );
+    qc_byte_order!(
+        prop_uint_2,
+        u64,
+        calc_max!(super::U64_MAX, 2),
+        2,
+        read_uint,
+        write_uint
+    );
+    qc_byte_order!(
+        prop_uint_3,
+        u64,
+        calc_max!(super::U64_MAX, 3),
+        3,
+        read_uint,
+        write_uint
+    );
+    qc_byte_order!(
+        prop_uint_4,
+        u64,
+        calc_max!(super::U64_MAX, 4),
+        4,
+        read_uint,
+        write_uint
+    );
+    qc_byte_order!(
+        prop_uint_5,
+        u64,
+        calc_max!(super::U64_MAX, 5),
+        5,
+        read_uint,
+        write_uint
+    );
+    qc_byte_order!(
+        prop_uint_6,
+        u64,
+        calc_max!(super::U64_MAX, 6),
+        6,
+        read_uint,
+        write_uint
+    );
+    qc_byte_order!(
+        prop_uint_7,
+        u64,
+        calc_max!(super::U64_MAX, 7),
+        7,
+        read_uint,
+        write_uint
+    );
+    qc_byte_order!(
+        prop_uint_8,
+        u64,
+        calc_max!(super::U64_MAX, 8),
+        8,
+        read_uint,
+        write_uint
+    );
+
+    qc_byte_order!(
+        prop_uint128_1,
+        Wi128<u128>,
+        1,
+        1,
+        read_uint128,
+        write_uint128
+    );
+    qc_byte_order!(
+        prop_uint128_2,
+        Wi128<u128>,
+        2,
+        2,
+        read_uint128,
+        write_uint128
+    );
+    qc_byte_order!(
+        prop_uint128_3,
+        Wi128<u128>,
+        3,
+        3,
+        read_uint128,
+        write_uint128
+    );
+    qc_byte_order!(
+        prop_uint128_4,
+        Wi128<u128>,
+        4,
+        4,
+        read_uint128,
+        write_uint128
+    );
+    qc_byte_order!(
+        prop_uint128_5,
+        Wi128<u128>,
+        5,
+        5,
+        read_uint128,
+        write_uint128
+    );
+    qc_byte_order!(
+        prop_uint128_6,
+        Wi128<u128>,
+        6,
+        6,
+        read_uint128,
+        write_uint128
+    );
+    qc_byte_order!(
+        prop_uint128_7,
+        Wi128<u128>,
+        7,
+        7,
+        read_uint128,
+        write_uint128
+    );
+    qc_byte_order!(
+        prop_uint128_8,
+        Wi128<u128>,
+        8,
+        8,
+        read_uint128,
+        write_uint128
+    );
+    qc_byte_order!(
+        prop_uint128_9,
+        Wi128<u128>,
+        9,
+        9,
+        read_uint128,
+        write_uint128
+    );
+    qc_byte_order!(
+        prop_uint128_10,
+        Wi128<u128>,
+        10,
+        10,
+        read_uint128,
+        write_uint128
+    );
+    qc_byte_order!(
+        prop_uint128_11,
+        Wi128<u128>,
+        11,
+        11,
+        read_uint128,
+        write_uint128
+    );
+    qc_byte_order!(
+        prop_uint128_12,
+        Wi128<u128>,
+        12,
+        12,
+        read_uint128,
+        write_uint128
+    );
+    qc_byte_order!(
+        prop_uint128_13,
+        Wi128<u128>,
+        13,
+        13,
+        read_uint128,
+        write_uint128
+    );
+    qc_byte_order!(
+        prop_uint128_14,
+        Wi128<u128>,
+        14,
+        14,
+        read_uint128,
+        write_uint128
+    );
+    qc_byte_order!(
+        prop_uint128_15,
+        Wi128<u128>,
+        15,
+        15,
+        read_uint128,
+        write_uint128
+    );
+    qc_byte_order!(
+        prop_uint128_16,
+        Wi128<u128>,
+        16,
+        16,
+        read_uint128,
+        write_uint128
+    );
+
+    qc_byte_order!(
+        prop_int_1,
+        i64,
+        calc_max!(super::I64_MAX, 1),
+        1,
+        read_int,
+        write_int
+    );
+    qc_byte_order!(
+        prop_int_2,
+        i64,
+        calc_max!(super::I64_MAX, 2),
+        2,
+        read_int,
+        write_int
+    );
+    qc_byte_order!(
+        prop_int_3,
+        i64,
+        calc_max!(super::I64_MAX, 3),
+        3,
+        read_int,
+        write_int
+    );
+    qc_byte_order!(
+        prop_int_4,
+        i64,
+        calc_max!(super::I64_MAX, 4),
+        4,
+        read_int,
+        write_int
+    );
+    qc_byte_order!(
+        prop_int_5,
+        i64,
+        calc_max!(super::I64_MAX, 5),
+        5,
+        read_int,
+        write_int
+    );
+    qc_byte_order!(
+        prop_int_6,
+        i64,
+        calc_max!(super::I64_MAX, 6),
+        6,
+        read_int,
+        write_int
+    );
+    qc_byte_order!(
+        prop_int_7,
+        i64,
+        calc_max!(super::I64_MAX, 7),
+        7,
+        read_int,
+        write_int
+    );
+    qc_byte_order!(
+        prop_int_8,
+        i64,
+        calc_max!(super::I64_MAX, 8),
+        8,
+        read_int,
+        write_int
+    );
+
+    qc_byte_order!(
+        prop_int128_1,
+        Wi128<i128>,
+        1,
+        1,
+        read_int128,
+        write_int128
+    );
+    qc_byte_order!(
+        prop_int128_2,
+        Wi128<i128>,
+        2,
+        2,
+        read_int128,
+        write_int128
+    );
+    qc_byte_order!(
+        prop_int128_3,
+        Wi128<i128>,
+        3,
+        3,
+        read_int128,
+        write_int128
+    );
+    qc_byte_order!(
+        prop_int128_4,
+        Wi128<i128>,
+        4,
+        4,
+        read_int128,
+        write_int128
+    );
+    qc_byte_order!(
+        prop_int128_5,
+        Wi128<i128>,
+        5,
+        5,
+        read_int128,
+        write_int128
+    );
+    qc_byte_order!(
+        prop_int128_6,
+        Wi128<i128>,
+        6,
+        6,
+        read_int128,
+        write_int128
+    );
+    qc_byte_order!(
+        prop_int128_7,
+        Wi128<i128>,
+        7,
+        7,
+        read_int128,
+        write_int128
+    );
+    qc_byte_order!(
+        prop_int128_8,
+        Wi128<i128>,
+        8,
+        8,
+        read_int128,
+        write_int128
+    );
+    qc_byte_order!(
+        prop_int128_9,
+        Wi128<i128>,
+        9,
+        9,
+        read_int128,
+        write_int128
+    );
+    qc_byte_order!(
+        prop_int128_10,
+        Wi128<i128>,
+        10,
+        10,
+        read_int128,
+        write_int128
+    );
+    qc_byte_order!(
+        prop_int128_11,
+        Wi128<i128>,
+        11,
+        11,
+        read_int128,
+        write_int128
+    );
+    qc_byte_order!(
+        prop_int128_12,
+        Wi128<i128>,
+        12,
+        12,
+        read_int128,
+        write_int128
+    );
+    qc_byte_order!(
+        prop_int128_13,
+        Wi128<i128>,
+        13,
+        13,
+        read_int128,
+        write_int128
+    );
+    qc_byte_order!(
+        prop_int128_14,
+        Wi128<i128>,
+        14,
+        14,
+        read_int128,
+        write_int128
+    );
+    qc_byte_order!(
+        prop_int128_15,
+        Wi128<i128>,
+        15,
+        15,
+        read_int128,
+        write_int128
+    );
+    qc_byte_order!(
+        prop_int128_16,
+        Wi128<i128>,
+        16,
+        16,
+        read_int128,
+        write_int128
+    );
+
+    // Test that all of the byte conversion functions panic when given a
+    // buffer that is too small.
+    //
+    // These tests are critical to ensure safety, otherwise we might end up
+    // with a buffer overflow.
+    macro_rules! too_small {
+        ($name:ident, $maximally_small:expr, $zero:expr,
+         $read:ident, $write:ident) => {
+            mod $name {
+                use crate::{
+                    BigEndian, ByteOrder, LittleEndian, NativeEndian,
+                };
+
+                #[test]
+                #[should_panic]
+                fn read_big_endian() {
+                    let buf = [0; $maximally_small];
+                    BigEndian::$read(&buf);
+                }
+
+                #[test]
+                #[should_panic]
+                fn read_little_endian() {
+                    let buf = [0; $maximally_small];
+                    LittleEndian::$read(&buf);
+                }
+
+                #[test]
+                #[should_panic]
+                fn read_native_endian() {
+                    let buf = [0; $maximally_small];
+                    NativeEndian::$read(&buf);
+                }
+
+                #[test]
+                #[should_panic]
+                fn write_big_endian() {
+                    let mut buf = [0; $maximally_small];
+                    BigEndian::$write(&mut buf, $zero);
+                }
+
+                #[test]
+                #[should_panic]
+                fn write_little_endian() {
+                    let mut buf = [0; $maximally_small];
+                    LittleEndian::$write(&mut buf, $zero);
+                }
+
+                #[test]
+                #[should_panic]
+                fn write_native_endian() {
+                    let mut buf = [0; $maximally_small];
+                    NativeEndian::$write(&mut buf, $zero);
+                }
+            }
+        };
+        ($name:ident, $maximally_small:expr, $read:ident) => {
+            mod $name {
+                use crate::{
+                    BigEndian, ByteOrder, LittleEndian, NativeEndian,
+                };
+
+                #[test]
+                #[should_panic]
+                fn read_big_endian() {
+                    let buf = [0; $maximally_small];
+                    BigEndian::$read(&buf, $maximally_small + 1);
+                }
+
+                #[test]
+                #[should_panic]
+                fn read_little_endian() {
+                    let buf = [0; $maximally_small];
+                    LittleEndian::$read(&buf, $maximally_small + 1);
+                }
+
+                #[test]
+                #[should_panic]
+                fn read_native_endian() {
+                    let buf = [0; $maximally_small];
+                    NativeEndian::$read(&buf, $maximally_small + 1);
+                }
+            }
+        };
+    }
+
+    too_small!(small_u16, 1, 0, read_u16, write_u16);
+    too_small!(small_i16, 1, 0, read_i16, write_i16);
+    too_small!(small_u32, 3, 0, read_u32, write_u32);
+    too_small!(small_i32, 3, 0, read_i32, write_i32);
+    too_small!(small_u64, 7, 0, read_u64, write_u64);
+    too_small!(small_i64, 7, 0, read_i64, write_i64);
+    too_small!(small_f32, 3, 0.0, read_f32, write_f32);
+    too_small!(small_f64, 7, 0.0, read_f64, write_f64);
+    too_small!(small_u128, 15, 0, read_u128, write_u128);
+    too_small!(small_i128, 15, 0, read_i128, write_i128);
+
+    too_small!(small_uint_1, 1, read_uint);
+    too_small!(small_uint_2, 2, read_uint);
+    too_small!(small_uint_3, 3, read_uint);
+    too_small!(small_uint_4, 4, read_uint);
+    too_small!(small_uint_5, 5, read_uint);
+    too_small!(small_uint_6, 6, read_uint);
+    too_small!(small_uint_7, 7, read_uint);
+
+    too_small!(small_uint128_1, 1, read_uint128);
+    too_small!(small_uint128_2, 2, read_uint128);
+    too_small!(small_uint128_3, 3, read_uint128);
+    too_small!(small_uint128_4, 4, read_uint128);
+    too_small!(small_uint128_5, 5, read_uint128);
+    too_small!(small_uint128_6, 6, read_uint128);
+    too_small!(small_uint128_7, 7, read_uint128);
+    too_small!(small_uint128_8, 8, read_uint128);
+    too_small!(small_uint128_9, 9, read_uint128);
+    too_small!(small_uint128_10, 10, read_uint128);
+    too_small!(small_uint128_11, 11, read_uint128);
+    too_small!(small_uint128_12, 12, read_uint128);
+    too_small!(small_uint128_13, 13, read_uint128);
+    too_small!(small_uint128_14, 14, read_uint128);
+    too_small!(small_uint128_15, 15, read_uint128);
+
+    too_small!(small_int_1, 1, read_int);
+    too_small!(small_int_2, 2, read_int);
+    too_small!(small_int_3, 3, read_int);
+    too_small!(small_int_4, 4, read_int);
+    too_small!(small_int_5, 5, read_int);
+    too_small!(small_int_6, 6, read_int);
+    too_small!(small_int_7, 7, read_int);
+
+    too_small!(small_int128_1, 1, read_int128);
+    too_small!(small_int128_2, 2, read_int128);
+    too_small!(small_int128_3, 3, read_int128);
+    too_small!(small_int128_4, 4, read_int128);
+    too_small!(small_int128_5, 5, read_int128);
+    too_small!(small_int128_6, 6, read_int128);
+    too_small!(small_int128_7, 7, read_int128);
+    too_small!(small_int128_8, 8, read_int128);
+    too_small!(small_int128_9, 9, read_int128);
+    too_small!(small_int128_10, 10, read_int128);
+    too_small!(small_int128_11, 11, read_int128);
+    too_small!(small_int128_12, 12, read_int128);
+    too_small!(small_int128_13, 13, read_int128);
+    too_small!(small_int128_14, 14, read_int128);
+    too_small!(small_int128_15, 15, read_int128);
+
+    // Test that reading/writing slices enforces the correct lengths.
+    macro_rules! slice_lengths {
+        ($name:ident, $read:ident, $write:ident,
+         $num_bytes:expr, $numbers:expr) => {
+            mod $name {
+                use crate::{
+                    BigEndian, ByteOrder, LittleEndian, NativeEndian,
+                };
+
+                #[test]
+                #[should_panic]
+                fn read_big_endian() {
+                    let bytes = [0; $num_bytes];
+                    let mut numbers = $numbers;
+                    BigEndian::$read(&bytes, &mut numbers);
+                }
+
+                #[test]
+                #[should_panic]
+                fn read_little_endian() {
+                    let bytes = [0; $num_bytes];
+                    let mut numbers = $numbers;
+                    LittleEndian::$read(&bytes, &mut numbers);
+                }
+
+                #[test]
+                #[should_panic]
+                fn read_native_endian() {
+                    let bytes = [0; $num_bytes];
+                    let mut numbers = $numbers;
+                    NativeEndian::$read(&bytes, &mut numbers);
+                }
+
+                #[test]
+                #[should_panic]
+                fn write_big_endian() {
+                    let mut bytes = [0; $num_bytes];
+                    let numbers = $numbers;
+                    BigEndian::$write(&numbers, &mut bytes);
+                }
+
+                #[test]
+                #[should_panic]
+                fn write_little_endian() {
+                    let mut bytes = [0; $num_bytes];
+                    let numbers = $numbers;
+                    LittleEndian::$write(&numbers, &mut bytes);
+                }
+
+                #[test]
+                #[should_panic]
+                fn write_native_endian() {
+                    let mut bytes = [0; $num_bytes];
+                    let numbers = $numbers;
+                    NativeEndian::$write(&numbers, &mut bytes);
+                }
+            }
+        };
+    }
+
+    slice_lengths!(
+        slice_len_too_small_u16,
+        read_u16_into,
+        write_u16_into,
+        3,
+        [0, 0]
+    );
+    slice_lengths!(
+        slice_len_too_big_u16,
+        read_u16_into,
+        write_u16_into,
+        5,
+        [0, 0]
+    );
+    slice_lengths!(
+        slice_len_too_small_i16,
+        read_i16_into,
+        write_i16_into,
+        3,
+        [0, 0]
+    );
+    slice_lengths!(
+        slice_len_too_big_i16,
+        read_i16_into,
+        write_i16_into,
+        5,
+        [0, 0]
+    );
+
+    slice_lengths!(
+        slice_len_too_small_u32,
+        read_u32_into,
+        write_u32_into,
+        7,
+        [0, 0]
+    );
+    slice_lengths!(
+        slice_len_too_big_u32,
+        read_u32_into,
+        write_u32_into,
+        9,
+        [0, 0]
+    );
+    slice_lengths!(
+        slice_len_too_small_i32,
+        read_i32_into,
+        write_i32_into,
+        7,
+        [0, 0]
+    );
+    slice_lengths!(
+        slice_len_too_big_i32,
+        read_i32_into,
+        write_i32_into,
+        9,
+        [0, 0]
+    );
+
+    slice_lengths!(
+        slice_len_too_small_u64,
+        read_u64_into,
+        write_u64_into,
+        15,
+        [0, 0]
+    );
+    slice_lengths!(
+        slice_len_too_big_u64,
+        read_u64_into,
+        write_u64_into,
+        17,
+        [0, 0]
+    );
+    slice_lengths!(
+        slice_len_too_small_i64,
+        read_i64_into,
+        write_i64_into,
+        15,
+        [0, 0]
+    );
+    slice_lengths!(
+        slice_len_too_big_i64,
+        read_i64_into,
+        write_i64_into,
+        17,
+        [0, 0]
+    );
+
+    slice_lengths!(
+        slice_len_too_small_u128,
+        read_u128_into,
+        write_u128_into,
+        31,
+        [0, 0]
+    );
+    slice_lengths!(
+        slice_len_too_big_u128,
+        read_u128_into,
+        write_u128_into,
+        33,
+        [0, 0]
+    );
+    slice_lengths!(
+        slice_len_too_small_i128,
+        read_i128_into,
+        write_i128_into,
+        31,
+        [0, 0]
+    );
+    slice_lengths!(
+        slice_len_too_big_i128,
+        read_i128_into,
+        write_i128_into,
+        33,
+        [0, 0]
+    );
+
+    #[test]
+    fn uint_bigger_buffer() {
+        use crate::{ByteOrder, LittleEndian};
+        let n = LittleEndian::read_uint(&[1, 2, 3, 4, 5, 6, 7, 8], 5);
+        assert_eq!(n, 0x05_0403_0201);
+    }
+
+    #[test]
+    fn regression173_array_impl() {
+        use crate::{BigEndian, ByteOrder, LittleEndian};
+
+        let xs = [0; 100];
+
+        let x = BigEndian::read_u16(&xs);
+        assert_eq!(x, 0);
+        let x = BigEndian::read_u32(&xs);
+        assert_eq!(x, 0);
+        let x = BigEndian::read_u64(&xs);
+        assert_eq!(x, 0);
+        let x = BigEndian::read_u128(&xs);
+        assert_eq!(x, 0);
+        let x = BigEndian::read_i16(&xs);
+        assert_eq!(x, 0);
+        let x = BigEndian::read_i32(&xs);
+        assert_eq!(x, 0);
+        let x = BigEndian::read_i64(&xs);
+        assert_eq!(x, 0);
+        let x = BigEndian::read_i128(&xs);
+        assert_eq!(x, 0);
+
+        let x = LittleEndian::read_u16(&xs);
+        assert_eq!(x, 0);
+        let x = LittleEndian::read_u32(&xs);
+        assert_eq!(x, 0);
+        let x = LittleEndian::read_u64(&xs);
+        assert_eq!(x, 0);
+        let x = LittleEndian::read_u128(&xs);
+        assert_eq!(x, 0);
+        let x = LittleEndian::read_i16(&xs);
+        assert_eq!(x, 0);
+        let x = LittleEndian::read_i32(&xs);
+        assert_eq!(x, 0);
+        let x = LittleEndian::read_i64(&xs);
+        assert_eq!(x, 0);
+        let x = LittleEndian::read_i128(&xs);
+        assert_eq!(x, 0);
+    }
+}
+
+#[cfg(test)]
+#[cfg(feature = "std")]
+mod stdtests {
+    extern crate quickcheck;
+    extern crate rand;
+
+    use self::quickcheck::{QuickCheck, StdGen, Testable};
+    use self::rand::thread_rng;
+
+    fn qc_unsized<A: Testable>(f: A) {
+        QuickCheck::new()
+            .gen(StdGen::new(thread_rng(), 16))
+            .tests(1_00)
+            .max_tests(10_000)
+            .quickcheck(f);
+    }
+
+    macro_rules! calc_max {
+        ($max:expr, $bytes:expr) => {
+            ($max - 1) >> (8 * (8 - $bytes))
+        };
+    }
+
+    macro_rules! qc_bytes_ext {
+        ($name:ident, $ty_int:ty, $max:expr,
+         $bytes:expr, $read:ident, $write:ident) => {
+            #[cfg(not(miri))]
+            mod $name {
+                #[allow(unused_imports)]
+                use crate::test::{qc_sized, Wi128};
+                use crate::{
+                    BigEndian, LittleEndian, NativeEndian, ReadBytesExt,
+                    WriteBytesExt,
+                };
+                use std::io::Cursor;
+
+                #[test]
+                fn big_endian() {
+                    fn prop(n: $ty_int) -> bool {
+                        let mut wtr = vec![];
+                        wtr.$write::<BigEndian>(n.clone()).unwrap();
+                        let offset = wtr.len() - $bytes;
+                        let mut rdr = Cursor::new(&mut wtr[offset..]);
+                        n == rdr.$read::<BigEndian>($bytes).unwrap()
+                    }
+                    qc_sized(prop as fn($ty_int) -> bool, $max);
+                }
+
+                #[test]
+                fn little_endian() {
+                    fn prop(n: $ty_int) -> bool {
+                        let mut wtr = vec![];
+                        wtr.$write::<LittleEndian>(n.clone()).unwrap();
+                        let mut rdr = Cursor::new(wtr);
+                        n == rdr.$read::<LittleEndian>($bytes).unwrap()
+                    }
+                    qc_sized(prop as fn($ty_int) -> bool, $max);
+                }
+
+                #[test]
+                fn native_endian() {
+                    fn prop(n: $ty_int) -> bool {
+                        let mut wtr = vec![];
+                        wtr.$write::<NativeEndian>(n.clone()).unwrap();
+                        let offset = if cfg!(target_endian = "big") {
+                            wtr.len() - $bytes
+                        } else {
+                            0
+                        };
+                        let mut rdr = Cursor::new(&mut wtr[offset..]);
+                        n == rdr.$read::<NativeEndian>($bytes).unwrap()
+                    }
+                    qc_sized(prop as fn($ty_int) -> bool, $max);
+                }
+            }
+        };
+        ($name:ident, $ty_int:ty, $max:expr, $read:ident, $write:ident) => {
+            #[cfg(not(miri))]
+            mod $name {
+                #[allow(unused_imports)]
+                use crate::test::{qc_sized, Wi128};
+                use crate::{
+                    BigEndian, LittleEndian, NativeEndian, ReadBytesExt,
+                    WriteBytesExt,
+                };
+                use std::io::Cursor;
+
+                #[test]
+                fn big_endian() {
+                    fn prop(n: $ty_int) -> bool {
+                        let mut wtr = vec![];
+                        wtr.$write::<BigEndian>(n.clone()).unwrap();
+                        let mut rdr = Cursor::new(wtr);
+                        n == rdr.$read::<BigEndian>().unwrap()
+                    }
+                    qc_sized(prop as fn($ty_int) -> bool, $max - 1);
+                }
+
+                #[test]
+                fn little_endian() {
+                    fn prop(n: $ty_int) -> bool {
+                        let mut wtr = vec![];
+                        wtr.$write::<LittleEndian>(n.clone()).unwrap();
+                        let mut rdr = Cursor::new(wtr);
+                        n == rdr.$read::<LittleEndian>().unwrap()
+                    }
+                    qc_sized(prop as fn($ty_int) -> bool, $max - 1);
+                }
+
+                #[test]
+                fn native_endian() {
+                    fn prop(n: $ty_int) -> bool {
+                        let mut wtr = vec![];
+                        wtr.$write::<NativeEndian>(n.clone()).unwrap();
+                        let mut rdr = Cursor::new(wtr);
+                        n == rdr.$read::<NativeEndian>().unwrap()
+                    }
+                    qc_sized(prop as fn($ty_int) -> bool, $max - 1);
+                }
+            }
+        };
+    }
+
+    qc_bytes_ext!(
+        prop_ext_u16,
+        u16,
+        ::std::u16::MAX as u64,
+        read_u16,
+        write_u16
+    );
+    qc_bytes_ext!(
+        prop_ext_i16,
+        i16,
+        ::std::i16::MAX as u64,
+        read_i16,
+        write_i16
+    );
+    qc_bytes_ext!(
+        prop_ext_u32,
+        u32,
+        ::std::u32::MAX as u64,
+        read_u32,
+        write_u32
+    );
+    qc_bytes_ext!(
+        prop_ext_i32,
+        i32,
+        ::std::i32::MAX as u64,
+        read_i32,
+        write_i32
+    );
+    qc_bytes_ext!(
+        prop_ext_u64,
+        u64,
+        ::std::u64::MAX as u64,
+        read_u64,
+        write_u64
+    );
+    qc_bytes_ext!(
+        prop_ext_i64,
+        i64,
+        ::std::i64::MAX as u64,
+        read_i64,
+        write_i64
+    );
+    qc_bytes_ext!(
+        prop_ext_f32,
+        f32,
+        ::std::u64::MAX as u64,
+        read_f32,
+        write_f32
+    );
+    qc_bytes_ext!(
+        prop_ext_f64,
+        f64,
+        ::std::i64::MAX as u64,
+        read_f64,
+        write_f64
+    );
+
+    qc_bytes_ext!(prop_ext_u128, Wi128<u128>, 16 + 1, read_u128, write_u128);
+    qc_bytes_ext!(prop_ext_i128, Wi128<i128>, 16 + 1, read_i128, write_i128);
+
+    qc_bytes_ext!(
+        prop_ext_uint_1,
+        u64,
+        calc_max!(crate::test::U64_MAX, 1),
+        1,
+        read_uint,
+        write_u64
+    );
+    qc_bytes_ext!(
+        prop_ext_uint_2,
+        u64,
+        calc_max!(crate::test::U64_MAX, 2),
+        2,
+        read_uint,
+        write_u64
+    );
+    qc_bytes_ext!(
+        prop_ext_uint_3,
+        u64,
+        calc_max!(crate::test::U64_MAX, 3),
+        3,
+        read_uint,
+        write_u64
+    );
+    qc_bytes_ext!(
+        prop_ext_uint_4,
+        u64,
+        calc_max!(crate::test::U64_MAX, 4),
+        4,
+        read_uint,
+        write_u64
+    );
+    qc_bytes_ext!(
+        prop_ext_uint_5,
+        u64,
+        calc_max!(crate::test::U64_MAX, 5),
+        5,
+        read_uint,
+        write_u64
+    );
+    qc_bytes_ext!(
+        prop_ext_uint_6,
+        u64,
+        calc_max!(crate::test::U64_MAX, 6),
+        6,
+        read_uint,
+        write_u64
+    );
+    qc_bytes_ext!(
+        prop_ext_uint_7,
+        u64,
+        calc_max!(crate::test::U64_MAX, 7),
+        7,
+        read_uint,
+        write_u64
+    );
+    qc_bytes_ext!(
+        prop_ext_uint_8,
+        u64,
+        calc_max!(crate::test::U64_MAX, 8),
+        8,
+        read_uint,
+        write_u64
+    );
+
+    qc_bytes_ext!(
+        prop_ext_uint128_1,
+        Wi128<u128>,
+        1,
+        1,
+        read_uint128,
+        write_u128
+    );
+    qc_bytes_ext!(
+        prop_ext_uint128_2,
+        Wi128<u128>,
+        2,
+        2,
+        read_uint128,
+        write_u128
+    );
+    qc_bytes_ext!(
+        prop_ext_uint128_3,
+        Wi128<u128>,
+        3,
+        3,
+        read_uint128,
+        write_u128
+    );
+    qc_bytes_ext!(
+        prop_ext_uint128_4,
+        Wi128<u128>,
+        4,
+        4,
+        read_uint128,
+        write_u128
+    );
+    qc_bytes_ext!(
+        prop_ext_uint128_5,
+        Wi128<u128>,
+        5,
+        5,
+        read_uint128,
+        write_u128
+    );
+    qc_bytes_ext!(
+        prop_ext_uint128_6,
+        Wi128<u128>,
+        6,
+        6,
+        read_uint128,
+        write_u128
+    );
+    qc_bytes_ext!(
+        prop_ext_uint128_7,
+        Wi128<u128>,
+        7,
+        7,
+        read_uint128,
+        write_u128
+    );
+    qc_bytes_ext!(
+        prop_ext_uint128_8,
+        Wi128<u128>,
+        8,
+        8,
+        read_uint128,
+        write_u128
+    );
+    qc_bytes_ext!(
+        prop_ext_uint128_9,
+        Wi128<u128>,
+        9,
+        9,
+        read_uint128,
+        write_u128
+    );
+    qc_bytes_ext!(
+        prop_ext_uint128_10,
+        Wi128<u128>,
+        10,
+        10,
+        read_uint128,
+        write_u128
+    );
+    qc_bytes_ext!(
+        prop_ext_uint128_11,
+        Wi128<u128>,
+        11,
+        11,
+        read_uint128,
+        write_u128
+    );
+    qc_bytes_ext!(
+        prop_ext_uint128_12,
+        Wi128<u128>,
+        12,
+        12,
+        read_uint128,
+        write_u128
+    );
+    qc_bytes_ext!(
+        prop_ext_uint128_13,
+        Wi128<u128>,
+        13,
+        13,
+        read_uint128,
+        write_u128
+    );
+    qc_bytes_ext!(
+        prop_ext_uint128_14,
+        Wi128<u128>,
+        14,
+        14,
+        read_uint128,
+        write_u128
+    );
+    qc_bytes_ext!(
+        prop_ext_uint128_15,
+        Wi128<u128>,
+        15,
+        15,
+        read_uint128,
+        write_u128
+    );
+    qc_bytes_ext!(
+        prop_ext_uint128_16,
+        Wi128<u128>,
+        16,
+        16,
+        read_uint128,
+        write_u128
+    );
+
+    qc_bytes_ext!(
+        prop_ext_int_1,
+        i64,
+        calc_max!(crate::test::I64_MAX, 1),
+        1,
+        read_int,
+        write_i64
+    );
+    qc_bytes_ext!(
+        prop_ext_int_2,
+        i64,
+        calc_max!(crate::test::I64_MAX, 2),
+        2,
+        read_int,
+        write_i64
+    );
+    qc_bytes_ext!(
+        prop_ext_int_3,
+        i64,
+        calc_max!(crate::test::I64_MAX, 3),
+        3,
+        read_int,
+        write_i64
+    );
+    qc_bytes_ext!(
+        prop_ext_int_4,
+        i64,
+        calc_max!(crate::test::I64_MAX, 4),
+        4,
+        read_int,
+        write_i64
+    );
+    qc_bytes_ext!(
+        prop_ext_int_5,
+        i64,
+        calc_max!(crate::test::I64_MAX, 5),
+        5,
+        read_int,
+        write_i64
+    );
+    qc_bytes_ext!(
+        prop_ext_int_6,
+        i64,
+        calc_max!(crate::test::I64_MAX, 6),
+        6,
+        read_int,
+        write_i64
+    );
+    qc_bytes_ext!(
+        prop_ext_int_7,
+        i64,
+        calc_max!(crate::test::I64_MAX, 1),
+        7,
+        read_int,
+        write_i64
+    );
+    qc_bytes_ext!(
+        prop_ext_int_8,
+        i64,
+        calc_max!(crate::test::I64_MAX, 8),
+        8,
+        read_int,
+        write_i64
+    );
+
+    qc_bytes_ext!(
+        prop_ext_int128_1,
+        Wi128<i128>,
+        1,
+        1,
+        read_int128,
+        write_i128
+    );
+    qc_bytes_ext!(
+        prop_ext_int128_2,
+        Wi128<i128>,
+        2,
+        2,
+        read_int128,
+        write_i128
+    );
+    qc_bytes_ext!(
+        prop_ext_int128_3,
+        Wi128<i128>,
+        3,
+        3,
+        read_int128,
+        write_i128
+    );
+    qc_bytes_ext!(
+        prop_ext_int128_4,
+        Wi128<i128>,
+        4,
+        4,
+        read_int128,
+        write_i128
+    );
+    qc_bytes_ext!(
+        prop_ext_int128_5,
+        Wi128<i128>,
+        5,
+        5,
+        read_int128,
+        write_i128
+    );
+    qc_bytes_ext!(
+        prop_ext_int128_6,
+        Wi128<i128>,
+        6,
+        6,
+        read_int128,
+        write_i128
+    );
+    qc_bytes_ext!(
+        prop_ext_int128_7,
+        Wi128<i128>,
+        7,
+        7,
+        read_int128,
+        write_i128
+    );
+    qc_bytes_ext!(
+        prop_ext_int128_8,
+        Wi128<i128>,
+        8,
+        8,
+        read_int128,
+        write_i128
+    );
+    qc_bytes_ext!(
+        prop_ext_int128_9,
+        Wi128<i128>,
+        9,
+        9,
+        read_int128,
+        write_i128
+    );
+    qc_bytes_ext!(
+        prop_ext_int128_10,
+        Wi128<i128>,
+        10,
+        10,
+        read_int128,
+        write_i128
+    );
+    qc_bytes_ext!(
+        prop_ext_int128_11,
+        Wi128<i128>,
+        11,
+        11,
+        read_int128,
+        write_i128
+    );
+    qc_bytes_ext!(
+        prop_ext_int128_12,
+        Wi128<i128>,
+        12,
+        12,
+        read_int128,
+        write_i128
+    );
+    qc_bytes_ext!(
+        prop_ext_int128_13,
+        Wi128<i128>,
+        13,
+        13,
+        read_int128,
+        write_i128
+    );
+    qc_bytes_ext!(
+        prop_ext_int128_14,
+        Wi128<i128>,
+        14,
+        14,
+        read_int128,
+        write_i128
+    );
+    qc_bytes_ext!(
+        prop_ext_int128_15,
+        Wi128<i128>,
+        15,
+        15,
+        read_int128,
+        write_i128
+    );
+    qc_bytes_ext!(
+        prop_ext_int128_16,
+        Wi128<i128>,
+        16,
+        16,
+        read_int128,
+        write_i128
+    );
+
+    // Test slice serialization/deserialization.
+    macro_rules! qc_slice {
+        ($name:ident, $ty_int:ty, $read:ident, $write:ident, $zero:expr) => {
+            #[cfg(not(miri))]
+            mod $name {
+                use super::qc_unsized;
+                #[allow(unused_imports)]
+                use crate::test::Wi128;
+                use crate::{
+                    BigEndian, ByteOrder, LittleEndian, NativeEndian,
+                };
+                use core::mem::size_of;
+
+                #[test]
+                fn big_endian() {
+                    #[allow(unused_unsafe)]
+                    fn prop(numbers: Vec<$ty_int>) -> bool {
+                        let numbers: Vec<_> =
+                            numbers.into_iter().map(|x| x.clone()).collect();
+                        let num_bytes = size_of::<$ty_int>() * numbers.len();
+                        let mut bytes = vec![0; num_bytes];
+
+                        BigEndian::$write(&numbers, &mut bytes);
+
+                        let mut got = vec![$zero; numbers.len()];
+                        unsafe {
+                            BigEndian::$read(&bytes, &mut got);
+                        }
+
+                        numbers == got
+                    }
+                    qc_unsized(prop as fn(_) -> bool);
+                }
+
+                #[test]
+                fn little_endian() {
+                    #[allow(unused_unsafe)]
+                    fn prop(numbers: Vec<$ty_int>) -> bool {
+                        let numbers: Vec<_> =
+                            numbers.into_iter().map(|x| x.clone()).collect();
+                        let num_bytes = size_of::<$ty_int>() * numbers.len();
+                        let mut bytes = vec![0; num_bytes];
+
+                        LittleEndian::$write(&numbers, &mut bytes);
+
+                        let mut got = vec![$zero; numbers.len()];
+                        unsafe {
+                            LittleEndian::$read(&bytes, &mut got);
+                        }
+
+                        numbers == got
+                    }
+                    qc_unsized(prop as fn(_) -> bool);
+                }
+
+                #[test]
+                fn native_endian() {
+                    #[allow(unused_unsafe)]
+                    fn prop(numbers: Vec<$ty_int>) -> bool {
+                        let numbers: Vec<_> =
+                            numbers.into_iter().map(|x| x.clone()).collect();
+                        let num_bytes = size_of::<$ty_int>() * numbers.len();
+                        let mut bytes = vec![0; num_bytes];
+
+                        NativeEndian::$write(&numbers, &mut bytes);
+
+                        let mut got = vec![$zero; numbers.len()];
+                        unsafe {
+                            NativeEndian::$read(&bytes, &mut got);
+                        }
+
+                        numbers == got
+                    }
+                    qc_unsized(prop as fn(_) -> bool);
+                }
+            }
+        };
+    }
+
+    qc_slice!(prop_slice_u16, u16, read_u16_into, write_u16_into, 0);
+    qc_slice!(prop_slice_i16, i16, read_i16_into, write_i16_into, 0);
+    qc_slice!(prop_slice_u32, u32, read_u32_into, write_u32_into, 0);
+    qc_slice!(prop_slice_i32, i32, read_i32_into, write_i32_into, 0);
+    qc_slice!(prop_slice_u64, u64, read_u64_into, write_u64_into, 0);
+    qc_slice!(prop_slice_i64, i64, read_i64_into, write_i64_into, 0);
+    qc_slice!(
+        prop_slice_u128,
+        Wi128<u128>,
+        read_u128_into,
+        write_u128_into,
+        0
+    );
+    qc_slice!(
+        prop_slice_i128,
+        Wi128<i128>,
+        read_i128_into,
+        write_i128_into,
+        0
+    );
+
+    qc_slice!(prop_slice_f32, f32, read_f32_into, write_f32_into, 0.0);
+    qc_slice!(prop_slice_f64, f64, read_f64_into, write_f64_into, 0.0);
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/.cargo-checksum.json b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/.cargo-checksum.json
new file mode 100644
index 0000000..697c9ce
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{}}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/.cargo_vcs_info.json
new file mode 100644
index 0000000..f7a5c05
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+  "git": {
+    "sha1": "e3d3eeb3b30c9a50e0c3646046648ae708154099"
+  },
+  "path_in_vcs": "jxl"
+}
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/Cargo.lock b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/Cargo.lock
new file mode 100644
index 0000000..ab342b0
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/Cargo.lock
@@ -0,0 +1,588 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "anstream"
+version = "0.6.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
+dependencies = [
+ "anstyle",
+ "once_cell_polyfill",
+ "windows-sys",
+]
+
+[[package]]
+name = "arbitrary"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
+
+[[package]]
+name = "arbtest"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a3be567977128c0f71ad1462d9624ccda712193d124e944252f0c5789a06d46"
+dependencies = [
+ "arbitrary",
+]
+
+[[package]]
+name = "array-init"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc"
+
+[[package]]
+name = "autocfg"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
+
+[[package]]
+name = "env_filter"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2"
+dependencies = [
+ "log",
+]
+
+[[package]]
+name = "env_logger"
+version = "0.11.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "env_filter",
+ "log",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "wasip2",
+]
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
+
+[[package]]
+name = "jxl"
+version = "0.1.4"
+dependencies = [
+ "arbtest",
+ "array-init",
+ "byteorder",
+ "jxl_macros",
+ "jxl_simd",
+ "jxl_transforms",
+ "num-derive",
+ "num-traits",
+ "paste",
+ "rand",
+ "rand_xorshift",
+ "test-log",
+ "thiserror",
+ "tracing",
+]
+
+[[package]]
+name = "jxl_macros"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1d637bd43aa1385b06fc96dd1bb05c0324b5ae07bf49f93da037df7cf855a9b"
+dependencies = [
+ "proc-macro-error2",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "jxl_simd"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb6db6beb1373c3fe4fbeac894a67ac03e9996d94b8e3bb6ecd9ec97727c50b9"
+
+[[package]]
+name = "jxl_transforms"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "752aa46baabece5849df25fd42f879093f19b70f7d5c6ac83b369efb463899f0"
+dependencies = [
+ "jxl_simd",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
+[[package]]
+name = "libc"
+version = "0.2.177"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
+
+[[package]]
+name = "log"
+version = "0.4.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
+
+[[package]]
+name = "matchers"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
+dependencies = [
+ "regex-automata",
+]
+
+[[package]]
+name = "memchr"
+version = "2.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
+
+[[package]]
+name = "nu-ansi-term"
+version = "0.50.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "num-derive"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+
+[[package]]
+name = "once_cell_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
+
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "proc-macro-error-attr2"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+]
+
+[[package]]
+name = "proc-macro-error2"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
+dependencies = [
+ "proc-macro-error-attr2",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.103"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "5.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
+
+[[package]]
+name = "rand"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
+dependencies = [
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rand_xorshift"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
+
+[[package]]
+name = "sharded-slab"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.110"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "test-log"
+version = "0.2.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e33b98a582ea0be1168eba097538ee8dd4bbe0f2b01b22ac92ea30054e5be7b"
+dependencies = [
+ "env_logger",
+ "test-log-macros",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "test-log-macros"
+version = "0.2.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "451b374529930d7601b1eef8d32bc79ae870b6079b069401709c2a8bf9e75f36"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "thread_local"
+version = "1.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "tracing"
+version = "0.1.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
+dependencies = [
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
+dependencies = [
+ "once_cell",
+ "valuable",
+]
+
+[[package]]
+name = "tracing-log"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
+dependencies = [
+ "log",
+ "once_cell",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-subscriber"
+version = "0.3.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5"
+dependencies = [
+ "matchers",
+ "nu-ansi-term",
+ "once_cell",
+ "regex-automata",
+ "sharded-slab",
+ "thread_local",
+ "tracing",
+ "tracing-core",
+ "tracing-log",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "valuable"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
+
+[[package]]
+name = "wasip2"
+version = "1.0.1+wasi-0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
+dependencies = [
+ "wit-bindgen",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "wit-bindgen"
+version = "0.46.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
+
+[[package]]
+name = "zerocopy"
+version = "0.8.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/Cargo.toml
new file mode 100644
index 0000000..4e2abac3
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/Cargo.toml
@@ -0,0 +1,99 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2024"
+name = "jxl"
+version = "0.1.4"
+authors = ["Luca Versari <veluca93@gmail.com>"]
+build = false
+exclude = ["resources/"]
+autolib = false
+autobins = false
+autoexamples = false
+autotests = false
+autobenches = false
+description = "High performance Rust implementation of a JPEG XL decoder"
+readme = "README.md"
+keywords = [
+    "jpeg-xl",
+    "decoder",
+]
+categories = ["multimedia::images"]
+license = "BSD-3-Clause"
+repository = "https://github.com/libjxl/jxl-rs"
+resolver = "2"
+
+[features]
+all-simd = ["jxl_simd/all-simd"]
+avx = ["jxl_simd/avx"]
+avx512 = ["jxl_simd/avx512"]
+neon = ["jxl_simd/neon"]
+sse42 = ["jxl_simd/sse42"]
+
+[lib]
+name = "jxl"
+path = "src/lib.rs"
+
+[dependencies.array-init]
+version = "2.0.0"
+
+[dependencies.byteorder]
+version = "1.4.3"
+
+[dependencies.jxl_macros]
+version = "=0.1.4"
+
+[dependencies.jxl_simd]
+version = "=0.1.4"
+
+[dependencies.jxl_transforms]
+version = "0.1.4"
+
+[dependencies.num-derive]
+version = "0.4"
+
+[dependencies.num-traits]
+version = "0.2.14"
+
+[dependencies.thiserror]
+version = "2.0"
+
+[dependencies.tracing]
+version = "0.1.40"
+optional = true
+
+[dev-dependencies.arbtest]
+version = "0.3.2"
+
+[dev-dependencies.jxl_macros]
+version = "=0.1.4"
+features = ["test"]
+
+[dev-dependencies.paste]
+version = "1.0.15"
+
+[dev-dependencies.rand]
+version = "0.9.2"
+
+[dev-dependencies.rand_xorshift]
+version = "0.4.0"
+
+[dev-dependencies.test-log]
+version = "0.2.16"
+features = ["trace"]
+
+[lints.clippy]
+missing_safety_doc = "deny"
+undocumented_unsafe_blocks = "deny"
+
+[lints.rust]
+unsafe_op_in_unsafe_fn = "deny"
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/Cargo.toml.orig
new file mode 100644
index 0000000..cd82cbb
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/Cargo.toml.orig
@@ -0,0 +1,42 @@
+[package]
+name = "jxl"
+description = "High performance Rust implementation of a JPEG XL decoder"
+version = "0.1.4"
+readme = "../README.md"
+keywords = ["jpeg-xl", "decoder"]
+categories = ["multimedia::images"]
+authors = ["Luca Versari <veluca93@gmail.com>"]
+repository = "https://github.com/libjxl/jxl-rs"
+edition = "2024"
+license = "BSD-3-Clause"
+
+exclude = ["resources/"]
+
+[dependencies]
+jxl_transforms = { path = "../jxl_transforms", version = "0.1.4" }
+thiserror = "2.0"
+byteorder = "1.4.3"
+num-derive = "0.4"
+num-traits = "0.2.14"
+array-init = "2.0.0"
+tracing = { version = "0.1.40", optional = true }
+jxl_macros = { path = "../jxl_macros", version = "=0.1.4" }
+jxl_simd = { path = "../jxl_simd", version = "=0.1.4" }
+
+[dev-dependencies]
+arbtest = "0.3.2"
+paste = "1.0.15"
+rand = "0.9.2"
+rand_xorshift = "0.4.0"
+test-log = { version = "0.2.16", features = ["trace"] }
+jxl_macros = { path = "../jxl_macros", version = "=0.1.4", features = ["test"] }
+
+[features]
+all-simd = ["jxl_simd/all-simd"]
+sse42 = ["jxl_simd/sse42"]
+avx = ["jxl_simd/avx"]
+avx512 = ["jxl_simd/avx512"]
+neon = ["jxl_simd/neon"]
+
+[lints]
+workspace = true
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/LICENSE b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/LICENSE
new file mode 100644
index 0000000..c66034b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) the JPEG XL Project Authors.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/README.md b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/README.md
new file mode 100644
index 0000000..b6bf14a
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/README.md
@@ -0,0 +1,9 @@
+# JPEG XL in Rust
+
+This is a work-in-progress reimplementation of a JPEG XL decoder in Rust, aiming to be conforming, safe, and fast.
+
+We strive to decode all conformant JPEG XL bitstreams correctly. If you find an image that can be decoded with the reference 
+implementation `djxl` (from [`libjxl`](https://github.com/libjxl/libjxl)) but is decoded incorrectly or not at all by `jxl-rs`, 
+please report it by [opening an issue](https://github.com/libjxl/jxl-rs/issues/new).
+
+For more information, including contributing instructions, refer to the [libjxl repository](https://github.com/libjxl/libjxl).
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/color.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/color.rs
new file mode 100644
index 0000000..64ba2ae
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/color.rs
@@ -0,0 +1,2326 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::{borrow::Cow, fmt};
+
+use crate::{
+    color::tf::{hlg_to_scene, linear_to_pq_precise, pq_to_linear_precise},
+    error::{Error, Result},
+    headers::color_encoding::{
+        ColorEncoding, ColorSpace, Primaries, RenderingIntent, TransferFunction, WhitePoint,
+    },
+    util::{Matrix3x3, Vector3, inv_3x3_matrix, mul_3x3_matrix, mul_3x3_vector},
+};
+
+// Bradford matrices for chromatic adaptation
+const K_BRADFORD: Matrix3x3<f64> = [
+    [0.8951, 0.2664, -0.1614],
+    [-0.7502, 1.7135, 0.0367],
+    [0.0389, -0.0685, 1.0296],
+];
+
+const K_BRADFORD_INV: Matrix3x3<f64> = [
+    [0.9869929, -0.1470543, 0.1599627],
+    [0.4323053, 0.5183603, 0.0492912],
+    [-0.0085287, 0.0400428, 0.9684867],
+];
+
+pub fn compute_md5(data: &[u8]) -> [u8; 16] {
+    let mut sum = [0u8; 16];
+    let mut data64 = data.to_vec();
+    data64.push(128);
+
+    // Add bytes such that ((size + 8) & 63) == 0
+    let extra = (64 - ((data64.len() + 8) & 63)) & 63;
+    data64.resize(data64.len() + extra, 0);
+
+    // Append length in bits as 64-bit little-endian
+    let bit_len = (data.len() as u64) << 3;
+    for i in (0..64).step_by(8) {
+        data64.push((bit_len >> i) as u8);
+    }
+
+    const SINEPARTS: [u32; 64] = [
+        0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613,
+        0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193,
+        0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d,
+        0x02441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+        0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122,
+        0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa,
+        0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244,
+        0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+        0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb,
+        0xeb86d391,
+    ];
+
+    const SHIFT: [u32; 64] = [
+        7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5,
+        9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10,
+        15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
+    ];
+
+    let mut a0: u32 = 0x67452301;
+    let mut b0: u32 = 0xefcdab89;
+    let mut c0: u32 = 0x98badcfe;
+    let mut d0: u32 = 0x10325476;
+
+    for i in (0..data64.len()).step_by(64) {
+        let mut a = a0;
+        let mut b = b0;
+        let mut c = c0;
+        let mut d = d0;
+
+        for j in 0..64 {
+            let (f, g) = if j < 16 {
+                ((b & c) | ((!b) & d), j)
+            } else if j < 32 {
+                ((d & b) | ((!d) & c), (5 * j + 1) & 0xf)
+            } else if j < 48 {
+                (b ^ c ^ d, (3 * j + 5) & 0xf)
+            } else {
+                (c ^ (b | (!d)), (7 * j) & 0xf)
+            };
+
+            let dg0 = data64[i + g * 4] as u32;
+            let dg1 = data64[i + g * 4 + 1] as u32;
+            let dg2 = data64[i + g * 4 + 2] as u32;
+            let dg3 = data64[i + g * 4 + 3] as u32;
+            let u = dg0 | (dg1 << 8) | (dg2 << 16) | (dg3 << 24);
+
+            let f = f.wrapping_add(a).wrapping_add(SINEPARTS[j]).wrapping_add(u);
+            a = d;
+            d = c;
+            c = b;
+            b = b.wrapping_add((f << SHIFT[j]) | (f >> (32 - SHIFT[j])));
+        }
+
+        a0 = a0.wrapping_add(a);
+        b0 = b0.wrapping_add(b);
+        c0 = c0.wrapping_add(c);
+        d0 = d0.wrapping_add(d);
+    }
+
+    sum[0] = a0 as u8;
+    sum[1] = (a0 >> 8) as u8;
+    sum[2] = (a0 >> 16) as u8;
+    sum[3] = (a0 >> 24) as u8;
+    sum[4] = b0 as u8;
+    sum[5] = (b0 >> 8) as u8;
+    sum[6] = (b0 >> 16) as u8;
+    sum[7] = (b0 >> 24) as u8;
+    sum[8] = c0 as u8;
+    sum[9] = (c0 >> 8) as u8;
+    sum[10] = (c0 >> 16) as u8;
+    sum[11] = (c0 >> 24) as u8;
+    sum[12] = d0 as u8;
+    sum[13] = (d0 >> 8) as u8;
+    sum[14] = (d0 >> 16) as u8;
+    sum[15] = (d0 >> 24) as u8;
+    sum
+}
+
+#[allow(clippy::too_many_arguments)]
+pub(crate) fn primaries_to_xyz(
+    rx: f32,
+    ry: f32,
+    gx: f32,
+    gy: f32,
+    bx: f32,
+    by: f32,
+    wx: f32,
+    wy: f32,
+) -> Result<Matrix3x3<f64>, Error> {
+    // Validate white point coordinates
+    if !((0.0..=1.0).contains(&wx) && (wy > 0.0 && wy <= 1.0)) {
+        return Err(Error::IccInvalidWhitePoint(
+            wx,
+            wy,
+            "White point coordinates out of range ([0,1] for x, (0,1] for y)".to_string(),
+        ));
+    }
+    // Comment from libjxl:
+    // TODO(lode): also require rx, ry, gx, gy, bx, to be in range 0-1? ICC
+    // profiles in theory forbid negative XYZ values, but in practice the ACES P0
+    // color space uses a negative y for the blue primary.
+
+    // Construct the primaries matrix P. Its columns are the XYZ coordinates
+    // of the R, G, B primaries (derived from their chromaticities x, y, z=1-x-y).
+    // P = [[xr, xg, xb],
+    //      [yr, yg, yb],
+    //      [zr, zg, zb]]
+    let rz = 1.0 - rx as f64 - ry as f64;
+    let gz = 1.0 - gx as f64 - gy as f64;
+    let bz = 1.0 - bx as f64 - by as f64;
+    let p_matrix = [
+        [rx as f64, gx as f64, bx as f64],
+        [ry as f64, gy as f64, by as f64],
+        [rz, gz, bz],
+    ];
+
+    let p_inv_matrix = inv_3x3_matrix(&p_matrix)?;
+
+    // Convert reference white point (wx, wy) to XYZ form with Y=1
+    // This is WhitePoint_XYZ_wp = [wx/wy, 1, (1-wx-wy)/wy]
+    let x_over_y_wp = wx as f64 / wy as f64;
+    let z_over_y_wp = (1.0 - wx as f64 - wy as f64) / wy as f64;
+
+    if !x_over_y_wp.is_finite() || !z_over_y_wp.is_finite() {
+        return Err(Error::IccInvalidWhitePoint(
+            wx,
+            wy,
+            "Calculated X/Y or Z/Y for white point is not finite.".to_string(),
+        ));
+    }
+    let white_point_xyz_vec: Vector3<f64> = [x_over_y_wp, 1.0, z_over_y_wp];
+
+    // Calculate scaling factors S = [Sr, Sg, Sb] such that P * S = WhitePoint_XYZ_wp
+    // So, S = P_inv * WhitePoint_XYZ_wp
+    let s_vec = mul_3x3_vector(&p_inv_matrix, &white_point_xyz_vec);
+
+    // Construct diagonal matrix S_diag from s_vec
+    let s_diag_matrix = [
+        [s_vec[0], 0.0, 0.0],
+        [0.0, s_vec[1], 0.0],
+        [0.0, 0.0, s_vec[2]],
+    ];
+    // The final RGB-to-XYZ matrix is P * S_diag
+    let result_matrix = mul_3x3_matrix(&p_matrix, &s_diag_matrix);
+
+    Ok(result_matrix)
+}
+
+pub(crate) fn adapt_to_xyz_d50(wx: f32, wy: f32) -> Result<Matrix3x3<f64>, Error> {
+    if !((0.0..=1.0).contains(&wx) && (wy > 0.0 && wy <= 1.0)) {
+        return Err(Error::IccInvalidWhitePoint(
+            wx,
+            wy,
+            "White point coordinates out of range ([0,1] for x, (0,1] for y)".to_string(),
+        ));
+    }
+
+    // Convert white point (wx, wy) to XYZ with Y=1
+    let x_over_y = wx as f64 / wy as f64;
+    let z_over_y = (1.0 - wx as f64 - wy as f64) / wy as f64;
+
+    // Check for finiteness, as 1.0 / tiny float can overflow.
+    if !x_over_y.is_finite() || !z_over_y.is_finite() {
+        return Err(Error::IccInvalidWhitePoint(
+            wx,
+            wy,
+            "Calculated X/Y or Z/Y for white point is not finite.".to_string(),
+        ));
+    }
+    let w: Vector3<f64> = [x_over_y, 1.0, z_over_y];
+
+    // D50 white point in XYZ (Y=1 form)
+    // These are X_D50/Y_D50, 1.0, Z_D50/Y_D50
+    let w50: Vector3<f64> = [0.96422, 1.0, 0.82521];
+
+    // Transform to LMS color space
+    let lms_source = mul_3x3_vector(&K_BRADFORD, &w);
+    let lms_d50 = mul_3x3_vector(&K_BRADFORD, &w50);
+
+    // Check for invalid LMS values which would lead to division by zero
+    if lms_source.contains(&0.0) {
+        return Err(Error::IccInvalidWhitePoint(
+            wx,
+            wy,
+            "LMS components for source white point are zero, leading to division by zero."
+                .to_string(),
+        ));
+    }
+
+    // Create diagonal scaling matrix in LMS space
+    let mut a_diag_matrix: Matrix3x3<f64> = [[0.0; 3]; 3];
+    for i in 0..3 {
+        a_diag_matrix[i][i] = lms_d50[i] / lms_source[i];
+        if !a_diag_matrix[i][i].is_finite() {
+            return Err(Error::IccInvalidWhitePoint(
+                wx,
+                wy,
+                format!("Diagonal adaptation matrix component {i} is not finite."),
+            ));
+        }
+    }
+
+    // Combine transformations
+    let b_matrix = mul_3x3_matrix(&a_diag_matrix, &K_BRADFORD);
+    let final_adaptation_matrix = mul_3x3_matrix(&K_BRADFORD_INV, &b_matrix);
+
+    Ok(final_adaptation_matrix)
+}
+
+#[allow(clippy::too_many_arguments)]
+pub(crate) fn primaries_to_xyz_d50(
+    rx: f32,
+    ry: f32,
+    gx: f32,
+    gy: f32,
+    bx: f32,
+    by: f32,
+    wx: f32,
+    wy: f32,
+) -> Result<Matrix3x3<f64>, Error> {
+    // Get the matrix to convert RGB to XYZ, adapted to its native white point (wx, wy).
+    let rgb_to_xyz_native_wp_matrix = primaries_to_xyz(rx, ry, gx, gy, bx, by, wx, wy)?;
+
+    // Get the chromatic adaptation matrix from the native white point (wx, wy) to D50.
+    let adaptation_to_d50_matrix = adapt_to_xyz_d50(wx, wy)?;
+    // This matrix converts XYZ values relative to white point (wx, wy)
+    // to XYZ values relative to D50.
+
+    // Combine the matrices: M_RGBtoD50XYZ = M_AdaptToD50 * M_RGBtoNativeXYZ
+    // Applying M_RGBtoNativeXYZ first gives XYZ relative to native white point.
+    // Then applying M_AdaptToD50 converts these XYZ values to be relative to D50.
+    let result_matrix = mul_3x3_matrix(&adaptation_to_d50_matrix, &rgb_to_xyz_native_wp_matrix);
+
+    Ok(result_matrix)
+}
+
+#[allow(clippy::too_many_arguments)]
+fn create_icc_rgb_matrix(
+    rx: f32,
+    ry: f32,
+    gx: f32,
+    gy: f32,
+    bx: f32,
+    by: f32,
+    wx: f32,
+    wy: f32,
+) -> Result<Matrix3x3<f32>, Error> {
+    // TODO: think about if we need/want to change precision to f64 for some calculations here
+    let result_f64 = primaries_to_xyz_d50(rx, ry, gx, gy, bx, by, wx, wy)?;
+    Ok(std::array::from_fn(|r_idx| {
+        std::array::from_fn(|c_idx| result_f64[r_idx][c_idx] as f32)
+    }))
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub enum JxlWhitePoint {
+    D65,
+    E,
+    DCI,
+    Chromaticity { wx: f32, wy: f32 },
+}
+
+impl fmt::Display for JxlWhitePoint {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            JxlWhitePoint::D65 => f.write_str("D65"),
+            JxlWhitePoint::E => f.write_str("EER"),
+            JxlWhitePoint::DCI => f.write_str("DCI"),
+            JxlWhitePoint::Chromaticity { wx, wy } => write!(f, "{wx:.7};{wy:.7}"),
+        }
+    }
+}
+
+impl JxlWhitePoint {
+    pub fn to_xy_coords(&self) -> (f32, f32) {
+        match self {
+            JxlWhitePoint::Chromaticity { wx, wy } => (*wx, *wy),
+            JxlWhitePoint::D65 => (0.3127, 0.3290),
+            JxlWhitePoint::DCI => (0.314, 0.351),
+            JxlWhitePoint::E => (1.0 / 3.0, 1.0 / 3.0),
+        }
+    }
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub enum JxlPrimaries {
+    SRGB,
+    BT2100,
+    P3,
+    Chromaticities {
+        rx: f32,
+        ry: f32,
+        gx: f32,
+        gy: f32,
+        bx: f32,
+        by: f32,
+    },
+}
+
+impl fmt::Display for JxlPrimaries {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            JxlPrimaries::SRGB => f.write_str("SRG"),
+            JxlPrimaries::BT2100 => f.write_str("202"),
+            JxlPrimaries::P3 => f.write_str("DCI"),
+            JxlPrimaries::Chromaticities {
+                rx,
+                ry,
+                gx,
+                gy,
+                bx,
+                by,
+            } => write!(f, "{rx:.7},{ry:.7};{gx:.7},{gy:.7};{bx:.7},{by:.7}"),
+        }
+    }
+}
+
+impl JxlPrimaries {
+    pub fn to_xy_coords(&self) -> [(f32, f32); 3] {
+        match self {
+            JxlPrimaries::Chromaticities {
+                rx,
+                ry,
+                gx,
+                gy,
+                bx,
+                by,
+            } => [(*rx, *ry), (*gx, *gy), (*bx, *by)],
+            JxlPrimaries::SRGB => [
+                // libjxl has these weird numbers for some reason.
+                (0.639_998_7, 0.330_010_15),
+                //(0.640, 0.330), // R
+                (0.300_003_8, 0.600_003_36),
+                //(0.300, 0.600), // G
+                (0.150_002_05, 0.059_997_204),
+                //(0.150, 0.060), // B
+            ],
+            JxlPrimaries::BT2100 => [
+                (0.708, 0.292), // R
+                (0.170, 0.797), // G
+                (0.131, 0.046), // B
+            ],
+            JxlPrimaries::P3 => [
+                (0.680, 0.320), // R
+                (0.265, 0.690), // G
+                (0.150, 0.060), // B
+            ],
+        }
+    }
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub enum JxlTransferFunction {
+    BT709,
+    Linear,
+    SRGB,
+    PQ,
+    DCI,
+    HLG,
+    Gamma(f32),
+}
+
+impl fmt::Display for JxlTransferFunction {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            JxlTransferFunction::BT709 => f.write_str("709"),
+            JxlTransferFunction::Linear => f.write_str("Lin"),
+            JxlTransferFunction::SRGB => f.write_str("SRG"),
+            JxlTransferFunction::PQ => f.write_str("PeQ"),
+            JxlTransferFunction::DCI => f.write_str("DCI"),
+            JxlTransferFunction::HLG => f.write_str("HLG"),
+            JxlTransferFunction::Gamma(g) => write!(f, "g{g:.7}"),
+        }
+    }
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub enum JxlColorEncoding {
+    RgbColorSpace {
+        white_point: JxlWhitePoint,
+        primaries: JxlPrimaries,
+        transfer_function: JxlTransferFunction,
+        rendering_intent: RenderingIntent,
+    },
+    GrayscaleColorSpace {
+        white_point: JxlWhitePoint,
+        transfer_function: JxlTransferFunction,
+        rendering_intent: RenderingIntent,
+    },
+    XYB {
+        rendering_intent: RenderingIntent,
+    },
+}
+
+impl fmt::Display for JxlColorEncoding {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::RgbColorSpace { .. } => f.write_str("RGB"),
+            Self::GrayscaleColorSpace { .. } => f.write_str("Gra"),
+            Self::XYB { .. } => f.write_str("XYB"),
+        }
+    }
+}
+
+impl JxlColorEncoding {
+    pub fn from_internal(internal: &ColorEncoding) -> Result<Self> {
+        let rendering_intent = internal.rendering_intent;
+        if internal.color_space == ColorSpace::XYB {
+            if rendering_intent != RenderingIntent::Perceptual {
+                return Err(Error::InvalidRenderingIntent);
+            }
+            return Ok(Self::XYB { rendering_intent });
+        }
+
+        let white_point = match internal.white_point {
+            WhitePoint::D65 => JxlWhitePoint::D65,
+            WhitePoint::E => JxlWhitePoint::E,
+            WhitePoint::DCI => JxlWhitePoint::DCI,
+            WhitePoint::Custom => {
+                let (wx, wy) = internal.white.as_f32_coords();
+                JxlWhitePoint::Chromaticity { wx, wy }
+            }
+        };
+        let transfer_function = if internal.tf.have_gamma {
+            JxlTransferFunction::Gamma(internal.tf.gamma())
+        } else {
+            match internal.tf.transfer_function {
+                TransferFunction::BT709 => JxlTransferFunction::BT709,
+                TransferFunction::Linear => JxlTransferFunction::Linear,
+                TransferFunction::SRGB => JxlTransferFunction::SRGB,
+                TransferFunction::PQ => JxlTransferFunction::PQ,
+                TransferFunction::DCI => JxlTransferFunction::DCI,
+                TransferFunction::HLG => JxlTransferFunction::HLG,
+                TransferFunction::Unknown => {
+                    return Err(Error::InvalidColorEncoding);
+                }
+            }
+        };
+
+        if internal.color_space == ColorSpace::Gray {
+            return Ok(Self::GrayscaleColorSpace {
+                white_point,
+                transfer_function,
+                rendering_intent,
+            });
+        }
+
+        let primaries = match internal.primaries {
+            Primaries::SRGB => JxlPrimaries::SRGB,
+            Primaries::BT2100 => JxlPrimaries::BT2100,
+            Primaries::P3 => JxlPrimaries::P3,
+            Primaries::Custom => {
+                let (rx, ry) = internal.custom_primaries[0].as_f32_coords();
+                let (gx, gy) = internal.custom_primaries[1].as_f32_coords();
+                let (bx, by) = internal.custom_primaries[2].as_f32_coords();
+                JxlPrimaries::Chromaticities {
+                    rx,
+                    ry,
+                    gx,
+                    gy,
+                    bx,
+                    by,
+                }
+            }
+        };
+
+        match internal.color_space {
+            ColorSpace::Gray | ColorSpace::XYB => unreachable!(),
+            ColorSpace::RGB => Ok(Self::RgbColorSpace {
+                white_point,
+                primaries,
+                transfer_function,
+                rendering_intent,
+            }),
+            ColorSpace::Unknown => Err(Error::InvalidColorSpace),
+        }
+    }
+
+    fn create_icc_cicp_tag_data(&self, tags_data: &mut Vec<u8>) -> Result<Option<TagInfo>, Error> {
+        let JxlColorEncoding::RgbColorSpace {
+            white_point,
+            primaries,
+            transfer_function,
+            ..
+        } = self
+        else {
+            return Ok(None);
+        };
+
+        // Determine the CICP value for primaries.
+        let primaries_val: u8 = match (white_point, primaries) {
+            (JxlWhitePoint::D65, JxlPrimaries::SRGB) => 1,
+            (JxlWhitePoint::D65, JxlPrimaries::BT2100) => 9,
+            (JxlWhitePoint::D65, JxlPrimaries::P3) => 12,
+            (JxlWhitePoint::DCI, JxlPrimaries::P3) => 11,
+            _ => return Ok(None),
+        };
+
+        let tf_val = match transfer_function {
+            JxlTransferFunction::BT709 => 1,
+            JxlTransferFunction::Linear => 8,
+            JxlTransferFunction::SRGB => 13,
+            JxlTransferFunction::PQ => 16,
+            JxlTransferFunction::DCI => 17,
+            JxlTransferFunction::HLG => 18,
+            // Custom gamma cannot be represented.
+            JxlTransferFunction::Gamma(_) => return Ok(None),
+        };
+
+        let signature = b"cicp";
+        let start_offset = tags_data.len() as u32;
+        tags_data.extend_from_slice(signature);
+        let data_len = tags_data.len();
+        tags_data.resize(tags_data.len() + 4, 0);
+        write_u32_be(tags_data, data_len, 0)?;
+        tags_data.push(primaries_val);
+        tags_data.push(tf_val);
+        // Matrix Coefficients (RGB is non-constant luminance)
+        tags_data.push(0);
+        // Video Full Range Flag
+        tags_data.push(1);
+
+        Ok(Some(TagInfo {
+            signature: *signature,
+            offset_in_tags_blob: start_offset,
+            size_unpadded: 12,
+        }))
+    }
+
+    fn can_tone_map_for_icc(&self) -> bool {
+        let JxlColorEncoding::RgbColorSpace {
+            white_point,
+            primaries,
+            transfer_function,
+            ..
+        } = self
+        else {
+            return false;
+        };
+        // This function determines if an ICC profile can be used for tone mapping.
+        // The logic is ported from the libjxl `CanToneMap` function.
+        // The core idea is that if the color space can be represented by a CICP tag
+        // in the ICC profile, then there's more freedom to use other parts of the
+        // profile (like the A2B0 LUT) for tone mapping. Otherwise, the profile must
+        // unambiguously describe the color space.
+
+        // The conditions for being able to tone map are:
+        // 1. The color space must be RGB.
+        // 2. The transfer function must be either PQ (Perceptual Quantizer) or HLG (Hybrid Log-Gamma).
+        // 3. The combination of primaries and white point must be one that is commonly
+        //    describable by a standard CICP value. This includes:
+        //    a) P3 primaries with either a D65 or DCI white point.
+        //    b) Any non-custom primaries, as long as the white point is D65.
+
+        if let JxlPrimaries::Chromaticities { .. } = primaries {
+            return false;
+        }
+
+        matches!(
+            transfer_function,
+            JxlTransferFunction::PQ | JxlTransferFunction::HLG
+        ) && (*white_point == JxlWhitePoint::D65
+            || (*white_point == JxlWhitePoint::DCI && *primaries == JxlPrimaries::P3))
+    }
+
+    pub fn get_color_encoding_description(&self) -> String {
+        // Handle special known color spaces first
+        if let Some(common_name) = match self {
+            JxlColorEncoding::RgbColorSpace {
+                white_point: JxlWhitePoint::D65,
+                primaries: JxlPrimaries::SRGB,
+                transfer_function: JxlTransferFunction::SRGB,
+                rendering_intent: RenderingIntent::Perceptual,
+            } => Some("sRGB"),
+            JxlColorEncoding::RgbColorSpace {
+                white_point: JxlWhitePoint::D65,
+                primaries: JxlPrimaries::P3,
+                transfer_function: JxlTransferFunction::SRGB,
+                rendering_intent: RenderingIntent::Perceptual,
+            } => Some("DisplayP3"),
+            JxlColorEncoding::RgbColorSpace {
+                white_point: JxlWhitePoint::D65,
+                primaries: JxlPrimaries::BT2100,
+                transfer_function: JxlTransferFunction::PQ,
+                rendering_intent: RenderingIntent::Relative,
+            } => Some("Rec2100PQ"),
+            JxlColorEncoding::RgbColorSpace {
+                white_point: JxlWhitePoint::D65,
+                primaries: JxlPrimaries::BT2100,
+                transfer_function: JxlTransferFunction::HLG,
+                rendering_intent: RenderingIntent::Relative,
+            } => Some("Rec2100HLG"),
+            _ => None,
+        } {
+            return common_name.to_string();
+        }
+
+        // Build the string part by part for other case
+        let mut d = String::with_capacity(64);
+
+        match self {
+            JxlColorEncoding::RgbColorSpace {
+                white_point,
+                primaries,
+                transfer_function,
+                rendering_intent,
+            } => {
+                d.push_str("RGB_");
+                d.push_str(&white_point.to_string());
+                d.push('_');
+                d.push_str(&primaries.to_string());
+                d.push('_');
+                d.push_str(&rendering_intent.to_string());
+                d.push('_');
+                d.push_str(&transfer_function.to_string());
+            }
+            JxlColorEncoding::GrayscaleColorSpace {
+                white_point,
+                transfer_function,
+                rendering_intent,
+            } => {
+                d.push_str("Gra_");
+                d.push_str(&white_point.to_string());
+                d.push('_');
+                d.push_str(&rendering_intent.to_string());
+                d.push('_');
+                d.push_str(&transfer_function.to_string());
+            }
+            JxlColorEncoding::XYB { rendering_intent } => {
+                d.push_str("XYB_");
+                d.push_str(&rendering_intent.to_string());
+            }
+        }
+
+        d
+    }
+
+    fn create_icc_header(&self) -> Result<Vec<u8>, Error> {
+        let mut header_data = vec![0u8; 128];
+
+        // Profile size - To be filled in at the end of profile creation.
+        write_u32_be(&mut header_data, 0, 0)?;
+        const CMM_TAG: &str = "jxl ";
+        // CMM Type
+        write_icc_tag(&mut header_data, 4, CMM_TAG)?;
+
+        // Profile version - ICC v4.4 (0x04400000)
+        // Conformance tests have v4.3, libjxl produces v4.4
+        write_u32_be(&mut header_data, 8, 0x04400000u32)?;
+
+        let profile_class_str = match self {
+            JxlColorEncoding::XYB { .. } => "scnr",
+            _ => "mntr",
+        };
+        write_icc_tag(&mut header_data, 12, profile_class_str)?;
+
+        // Data color space
+        let data_color_space_str = match self {
+            JxlColorEncoding::GrayscaleColorSpace { .. } => "GRAY",
+            _ => "RGB ",
+        };
+        write_icc_tag(&mut header_data, 16, data_color_space_str)?;
+
+        // PCS - Profile Connection Space
+        // Corresponds to: if (kEnable3DToneMapping && CanToneMap(c))
+        // Assuming kEnable3DToneMapping is true for this port for now.
+        const K_ENABLE_3D_ICC_TONEMAPPING: bool = true;
+        if K_ENABLE_3D_ICC_TONEMAPPING && self.can_tone_map_for_icc() {
+            write_icc_tag(&mut header_data, 20, "Lab ")?;
+        } else {
+            write_icc_tag(&mut header_data, 20, "XYZ ")?;
+        }
+
+        // Date and Time - Placeholder values from libjxl
+        write_u16_be(&mut header_data, 24, 2019)?; // Year
+        write_u16_be(&mut header_data, 26, 12)?; // Month
+        write_u16_be(&mut header_data, 28, 1)?; // Day
+        write_u16_be(&mut header_data, 30, 0)?; // Hours
+        write_u16_be(&mut header_data, 32, 0)?; // Minutes
+        write_u16_be(&mut header_data, 34, 0)?; // Seconds
+
+        write_icc_tag(&mut header_data, 36, "acsp")?;
+        write_icc_tag(&mut header_data, 40, "APPL")?;
+
+        // Profile flags
+        write_u32_be(&mut header_data, 44, 0)?;
+        // Device manufacturer
+        write_u32_be(&mut header_data, 48, 0)?;
+        // Device model
+        write_u32_be(&mut header_data, 52, 0)?;
+        // Device attributes
+        write_u32_be(&mut header_data, 56, 0)?;
+        write_u32_be(&mut header_data, 60, 0)?;
+
+        // Rendering Intent
+        let rendering_intent = match self {
+            JxlColorEncoding::RgbColorSpace {
+                rendering_intent, ..
+            }
+            | JxlColorEncoding::GrayscaleColorSpace {
+                rendering_intent, ..
+            }
+            | JxlColorEncoding::XYB { rendering_intent } => rendering_intent,
+        };
+        write_u32_be(&mut header_data, 64, *rendering_intent as u32)?;
+
+        // Whitepoint is fixed to D50 for ICC.
+        write_u32_be(&mut header_data, 68, 0x0000F6D6)?;
+        write_u32_be(&mut header_data, 72, 0x00010000)?;
+        write_u32_be(&mut header_data, 76, 0x0000D32D)?;
+
+        // Profile Creator
+        write_icc_tag(&mut header_data, 80, CMM_TAG)?;
+
+        // Profile ID (MD5 checksum) (offset 84) - 16 bytes.
+        // This is calculated at the end of profile creation and written here.
+
+        // Reserved (offset 100-127) - already zeroed here.
+
+        Ok(header_data)
+    }
+
+    pub fn maybe_create_profile(&self) -> Result<Option<Vec<u8>>, Error> {
+        if let JxlColorEncoding::XYB { rendering_intent } = self
+            && *rendering_intent != RenderingIntent::Perceptual
+        {
+            return Err(Error::InvalidRenderingIntent);
+        }
+        let header = self.create_icc_header()?;
+        let mut tags_data: Vec<u8> = Vec::new();
+        let mut collected_tags: Vec<TagInfo> = Vec::new();
+
+        // Create 'desc' (ProfileDescription) tag
+        let description_string = self.get_color_encoding_description();
+
+        let desc_tag_start_offset = tags_data.len() as u32; // 0 at this point ...
+        create_icc_mluc_tag(&mut tags_data, &description_string)?;
+        let desc_tag_unpadded_size = (tags_data.len() as u32) - desc_tag_start_offset;
+        pad_to_4_byte_boundary(&mut tags_data);
+        collected_tags.push(TagInfo {
+            signature: *b"desc",
+            offset_in_tags_blob: desc_tag_start_offset,
+            size_unpadded: desc_tag_unpadded_size,
+        });
+
+        // Create 'cprt' (Copyright) tag
+        let copyright_string = "CC0";
+        let cprt_tag_start_offset = tags_data.len() as u32;
+        create_icc_mluc_tag(&mut tags_data, copyright_string)?;
+        let cprt_tag_unpadded_size = (tags_data.len() as u32) - cprt_tag_start_offset;
+        pad_to_4_byte_boundary(&mut tags_data);
+        collected_tags.push(TagInfo {
+            signature: *b"cprt",
+            offset_in_tags_blob: cprt_tag_start_offset,
+            size_unpadded: cprt_tag_unpadded_size,
+        });
+
+        match self {
+            JxlColorEncoding::GrayscaleColorSpace { white_point, .. } => {
+                let (wx, wy) = white_point.to_xy_coords();
+                collected_tags.push(create_icc_xyz_tag(
+                    &mut tags_data,
+                    &cie_xyz_from_white_cie_xy(wx, wy)?,
+                )?);
+            }
+            _ => {
+                // Ok, in this case we will add the chad tag below
+                const D50: [f32; 3] = [0.964203f32, 1.0, 0.824905];
+                collected_tags.push(create_icc_xyz_tag(&mut tags_data, &D50)?);
+            }
+        }
+        pad_to_4_byte_boundary(&mut tags_data);
+        if !matches!(self, JxlColorEncoding::GrayscaleColorSpace { .. }) {
+            let (wx, wy) = match self {
+                JxlColorEncoding::GrayscaleColorSpace { .. } => unreachable!(),
+                JxlColorEncoding::RgbColorSpace { white_point, .. } => white_point.to_xy_coords(),
+                JxlColorEncoding::XYB { .. } => JxlWhitePoint::D65.to_xy_coords(),
+            };
+            let chad_matrix_f64 = adapt_to_xyz_d50(wx, wy)?;
+            let chad_matrix = std::array::from_fn(|r_idx| {
+                std::array::from_fn(|c_idx| chad_matrix_f64[r_idx][c_idx] as f32)
+            });
+            collected_tags.push(create_icc_chad_tag(&mut tags_data, &chad_matrix)?);
+            pad_to_4_byte_boundary(&mut tags_data);
+        }
+
+        if let JxlColorEncoding::RgbColorSpace {
+            white_point,
+            primaries,
+            ..
+        } = self
+        {
+            if let Some(tag_info) = self.create_icc_cicp_tag_data(&mut tags_data)? {
+                collected_tags.push(tag_info);
+                // Padding here not necessary, since we add 12 bytes to already 4-byte aligned
+                // buffer
+                // pad_to_4_byte_boundary(&mut tags_data);
+            }
+
+            // Get colorant and white point coordinates to build the conversion matrix.
+            let primaries_coords = primaries.to_xy_coords();
+            let (rx, ry) = primaries_coords[0];
+            let (gx, gy) = primaries_coords[1];
+            let (bx, by) = primaries_coords[2];
+            let (wx, wy) = white_point.to_xy_coords();
+
+            // Calculate the RGB to XYZD50 matrix.
+            let m = create_icc_rgb_matrix(rx, ry, gx, gy, bx, by, wx, wy)?;
+
+            // Extract the columns, which are the XYZ values for the R, G, and B primaries.
+            let r_xyz = [m[0][0], m[1][0], m[2][0]];
+            let g_xyz = [m[0][1], m[1][1], m[2][1]];
+            let b_xyz = [m[0][2], m[1][2], m[2][2]];
+
+            // Helper to create the raw data for any 'XYZ ' type tag.
+            let create_xyz_type_tag_data =
+                |tags: &mut Vec<u8>, xyz: &[f32; 3]| -> Result<u32, Error> {
+                    let start_offset = tags.len();
+                    // The tag *type* is 'XYZ ' for all three
+                    tags.extend_from_slice(b"XYZ ");
+                    tags.extend_from_slice(&0u32.to_be_bytes());
+                    for &val in xyz {
+                        append_s15_fixed_16(tags, val)?;
+                    }
+                    Ok((tags.len() - start_offset) as u32)
+                };
+
+            // Create the 'rXYZ' tag.
+            let r_xyz_tag_start_offset = tags_data.len() as u32;
+            let r_xyz_tag_unpadded_size = create_xyz_type_tag_data(&mut tags_data, &r_xyz)?;
+            pad_to_4_byte_boundary(&mut tags_data);
+            collected_tags.push(TagInfo {
+                signature: *b"rXYZ", // Making the *signature* is unique.
+                offset_in_tags_blob: r_xyz_tag_start_offset,
+                size_unpadded: r_xyz_tag_unpadded_size,
+            });
+
+            // Create the 'gXYZ' tag.
+            let g_xyz_tag_start_offset = tags_data.len() as u32;
+            let g_xyz_tag_unpadded_size = create_xyz_type_tag_data(&mut tags_data, &g_xyz)?;
+            pad_to_4_byte_boundary(&mut tags_data);
+            collected_tags.push(TagInfo {
+                signature: *b"gXYZ",
+                offset_in_tags_blob: g_xyz_tag_start_offset,
+                size_unpadded: g_xyz_tag_unpadded_size,
+            });
+
+            // Create the 'bXYZ' tag.
+            let b_xyz_tag_start_offset = tags_data.len() as u32;
+            let b_xyz_tag_unpadded_size = create_xyz_type_tag_data(&mut tags_data, &b_xyz)?;
+            pad_to_4_byte_boundary(&mut tags_data);
+            collected_tags.push(TagInfo {
+                signature: *b"bXYZ",
+                offset_in_tags_blob: b_xyz_tag_start_offset,
+                size_unpadded: b_xyz_tag_unpadded_size,
+            });
+        }
+        if self.can_tone_map_for_icc() {
+            // Create A2B0 tag for HDR tone mapping
+            if let JxlColorEncoding::RgbColorSpace {
+                white_point,
+                primaries,
+                transfer_function,
+                ..
+            } = self
+            {
+                let a2b0_start = tags_data.len() as u32;
+                create_icc_lut_atob_tag_for_hdr(
+                    transfer_function,
+                    primaries,
+                    white_point,
+                    &mut tags_data,
+                )?;
+                pad_to_4_byte_boundary(&mut tags_data);
+                let a2b0_size = (tags_data.len() as u32) - a2b0_start;
+                collected_tags.push(TagInfo {
+                    signature: *b"A2B0",
+                    offset_in_tags_blob: a2b0_start,
+                    size_unpadded: a2b0_size,
+                });
+
+                // Create B2A0 tag (no-op, required by Apple software including Safari/Preview)
+                let b2a0_start = tags_data.len() as u32;
+                create_icc_noop_btoa_tag(&mut tags_data)?;
+                pad_to_4_byte_boundary(&mut tags_data);
+                let b2a0_size = (tags_data.len() as u32) - b2a0_start;
+                collected_tags.push(TagInfo {
+                    signature: *b"B2A0",
+                    offset_in_tags_blob: b2a0_start,
+                    size_unpadded: b2a0_size,
+                });
+            }
+        } else {
+            match self {
+                JxlColorEncoding::XYB { .. } => todo!("implement A2B0 and B2A0 tags"),
+                JxlColorEncoding::RgbColorSpace {
+                    transfer_function, ..
+                }
+                | JxlColorEncoding::GrayscaleColorSpace {
+                    transfer_function, ..
+                } => {
+                    let trc_tag_start_offset = tags_data.len() as u32;
+                    let trc_tag_unpadded_size = match transfer_function {
+                        JxlTransferFunction::Gamma(g) => {
+                            // Type 0 parametric curve: Y = X^gamma
+                            let gamma = 1.0 / g;
+                            create_icc_curv_para_tag(&mut tags_data, &[gamma], 0)?
+                        }
+                        JxlTransferFunction::SRGB => {
+                            // Type 3 parametric curve for sRGB standard.
+                            const PARAMS: [f32; 5] =
+                                [2.4, 1.0 / 1.055, 0.055 / 1.055, 1.0 / 12.92, 0.04045];
+                            create_icc_curv_para_tag(&mut tags_data, &PARAMS, 3)?
+                        }
+                        JxlTransferFunction::BT709 => {
+                            // Type 3 parametric curve for BT.709 standard.
+                            const PARAMS: [f32; 5] =
+                                [1.0 / 0.45, 1.0 / 1.099, 0.099 / 1.099, 1.0 / 4.5, 0.081];
+                            create_icc_curv_para_tag(&mut tags_data, &PARAMS, 3)?
+                        }
+                        JxlTransferFunction::Linear => {
+                            // Type 3 can also represent a linear response (gamma=1.0).
+                            const PARAMS: [f32; 5] = [1.0, 1.0, 0.0, 1.0, 0.0];
+                            create_icc_curv_para_tag(&mut tags_data, &PARAMS, 3)?
+                        }
+                        JxlTransferFunction::DCI => {
+                            // Type 3 can also represent a pure power curve (gamma=2.6).
+                            const PARAMS: [f32; 5] = [2.6, 1.0, 0.0, 1.0, 0.0];
+                            create_icc_curv_para_tag(&mut tags_data, &PARAMS, 3)?
+                        }
+                        JxlTransferFunction::HLG | JxlTransferFunction::PQ => {
+                            let params = create_table_curve(64, transfer_function, false)?;
+                            create_icc_curv_para_tag(&mut tags_data, params.as_slice(), 3)?
+                        }
+                    };
+                    pad_to_4_byte_boundary(&mut tags_data);
+
+                    match self {
+                        JxlColorEncoding::GrayscaleColorSpace { .. } => {
+                            // Grayscale profiles use a single 'kTRC' tag.
+                            collected_tags.push(TagInfo {
+                                signature: *b"kTRC",
+                                offset_in_tags_blob: trc_tag_start_offset,
+                                size_unpadded: trc_tag_unpadded_size,
+                            });
+                        }
+                        _ => {
+                            // For RGB, rTRC, gTRC, and bTRC all point to the same curve data,
+                            // an optimization to keep the profile size small.
+                            collected_tags.push(TagInfo {
+                                signature: *b"rTRC",
+                                offset_in_tags_blob: trc_tag_start_offset,
+                                size_unpadded: trc_tag_unpadded_size,
+                            });
+                            collected_tags.push(TagInfo {
+                                signature: *b"gTRC",
+                                offset_in_tags_blob: trc_tag_start_offset, // Same offset
+                                size_unpadded: trc_tag_unpadded_size,      // Same size
+                            });
+                            collected_tags.push(TagInfo {
+                                signature: *b"bTRC",
+                                offset_in_tags_blob: trc_tag_start_offset, // Same offset
+                                size_unpadded: trc_tag_unpadded_size,      // Same size
+                            });
+                        }
+                    }
+                }
+            }
+        }
+
+        // Construct the Tag Table bytes
+        let mut tag_table_bytes: Vec<u8> = Vec::new();
+        // First, the number of tags (u32)
+        tag_table_bytes.extend_from_slice(&(collected_tags.len() as u32).to_be_bytes());
+
+        let header_size = header.len() as u32;
+        // Each entry in the tag table on disk is 12 bytes: signature (4), offset (4), size (4)
+        let tag_table_on_disk_size = 4 + (collected_tags.len() as u32 * 12);
+
+        for tag_info in &collected_tags {
+            tag_table_bytes.extend_from_slice(&tag_info.signature);
+            // The offset in the tag table is absolute from the start of the ICC profile file
+            let final_profile_offset_for_tag =
+                header_size + tag_table_on_disk_size + tag_info.offset_in_tags_blob;
+            tag_table_bytes.extend_from_slice(&final_profile_offset_for_tag.to_be_bytes());
+            // In https://www.color.org/specification/ICC.1-2022-05.pdf, section 7.3.5 reads:
+            //
+            // "The value of the tag data element size shall be the number of actual data
+            // bytes and shall not include any padding at the end of the tag data element."
+            //
+            // The reference from conformance tests and libjxl use the padded size here instead.
+
+            tag_table_bytes.extend_from_slice(&tag_info.size_unpadded.to_be_bytes());
+            // In order to get byte_exact the same output as libjxl, remove the line above
+            // and uncomment the lines below
+            // let padded_size = tag_info.size_unpadded.next_multiple_of(4);
+            // tag_table_bytes.extend_from_slice(&padded_size.to_be_bytes());
+        }
+
+        // Assemble the final ICC profile parts: header + tag_table + tags_data
+        let mut final_icc_profile_data: Vec<u8> =
+            Vec::with_capacity(header.len() + tag_table_bytes.len() + tags_data.len());
+        final_icc_profile_data.extend_from_slice(&header);
+        final_icc_profile_data.extend_from_slice(&tag_table_bytes);
+        final_icc_profile_data.extend_from_slice(&tags_data);
+
+        // Update the profile size in the header (at offset 0)
+        let total_profile_size = final_icc_profile_data.len() as u32;
+        write_u32_be(&mut final_icc_profile_data, 0, total_profile_size)?;
+
+        // Assemble the final ICC profile parts: header + tag_table + tags_data
+        let mut final_icc_profile_data: Vec<u8> =
+            Vec::with_capacity(header.len() + tag_table_bytes.len() + tags_data.len());
+        final_icc_profile_data.extend_from_slice(&header);
+        final_icc_profile_data.extend_from_slice(&tag_table_bytes);
+        final_icc_profile_data.extend_from_slice(&tags_data);
+
+        // Update the profile size in the header (at offset 0)
+        let total_profile_size = final_icc_profile_data.len() as u32;
+        write_u32_be(&mut final_icc_profile_data, 0, total_profile_size)?;
+
+        // The MD5 checksum (Profile ID) must be computed on the profile with
+        // specific header fields zeroed out, as per the ICC specification.
+        let mut profile_for_checksum = final_icc_profile_data.clone();
+
+        if profile_for_checksum.len() >= 84 {
+            // Zero out Profile Flags at offset 44.
+            profile_for_checksum[44..48].fill(0);
+            // Zero out Rendering Intent at offset 64.
+            profile_for_checksum[64..68].fill(0);
+            // The Profile ID field at offset 84 is already zero at this stage.
+        }
+
+        // Compute the MD5 hash on the modified profile data.
+        let checksum = compute_md5(&profile_for_checksum);
+
+        // Write the 16-byte checksum into the "Profile ID" field of the *original*
+        // profile data buffer, starting at offset 84.
+        if final_icc_profile_data.len() >= 100 {
+            final_icc_profile_data[84..100].copy_from_slice(&checksum);
+        }
+
+        Ok(Some(final_icc_profile_data))
+    }
+
+    pub fn srgb(grayscale: bool) -> Self {
+        if grayscale {
+            JxlColorEncoding::GrayscaleColorSpace {
+                white_point: JxlWhitePoint::D65,
+                transfer_function: JxlTransferFunction::SRGB,
+                rendering_intent: RenderingIntent::Relative,
+            }
+        } else {
+            JxlColorEncoding::RgbColorSpace {
+                white_point: JxlWhitePoint::D65,
+                primaries: JxlPrimaries::SRGB,
+                transfer_function: JxlTransferFunction::SRGB,
+                rendering_intent: RenderingIntent::Relative,
+            }
+        }
+    }
+}
+
+#[derive(Clone)]
+pub enum JxlColorProfile {
+    Icc(Vec<u8>),
+    Simple(JxlColorEncoding),
+}
+
+impl JxlColorProfile {
+    /// Returns the ICC profile, panicking if unavailable.
+    ///
+    /// # Panics
+    /// Panics if the color encoding cannot generate an ICC profile.
+    /// Consider using `try_as_icc` for fallible conversion.
+    pub fn as_icc(&self) -> Cow<'_, Vec<u8>> {
+        match self {
+            Self::Icc(x) => Cow::Borrowed(x),
+            Self::Simple(encoding) => Cow::Owned(encoding.maybe_create_profile().unwrap().unwrap()),
+        }
+    }
+
+    /// Attempts to get an ICC profile, returning None if unavailable.
+    ///
+    /// Returns `None` for color encodings that cannot generate ICC profiles.
+    pub fn try_as_icc(&self) -> Option<Cow<'_, Vec<u8>>> {
+        match self {
+            Self::Icc(x) => Some(Cow::Borrowed(x)),
+            Self::Simple(encoding) => encoding
+                .maybe_create_profile()
+                .ok()
+                .flatten()
+                .map(Cow::Owned),
+        }
+    }
+}
+
+impl fmt::Display for JxlColorProfile {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Icc(_) => f.write_str("ICC"),
+            Self::Simple(enc) => write!(f, "{}", enc),
+        }
+    }
+}
+
+pub trait JxlCmsTransformer {
+    /// Runs a single transform. The buffers each contain `num_pixels` x `num_channels` interleaved
+    /// floating point (0..1) samples, where `num_channels` is the number of color channels of
+    /// their respective color profiles. For CMYK data, 0 represents the maximum amount of ink
+    /// while 1 represents no ink.
+    fn do_transform(&mut self, input: &[f32], output: &mut [f32]) -> Result<()>;
+
+    /// Runs a single transform in-place. The buffer contains `num_pixels` x `num_channels`
+    /// interleaved floating point (0..1) samples, where `num_channels` is the number of color
+    /// channels of the input and output color profiles. For CMYK data, 0 represents the maximum
+    /// amount of ink while 1 represents no ink.
+    fn do_transform_inplace(&mut self, inout: &mut [f32]) -> Result<()>;
+}
+
+pub trait JxlCms {
+    /// Initializes `n` transforms (different transforms might be used in parallel) to
+    /// convert from color space `input` to colorspace `output`, assuming an intensity of 1.0 for
+    /// non-absolute luminance colorspaces of `intensity_target`.
+    /// It is an error to not return `n` transforms.
+    /// Returns the number of channels the ICC outputs, and the transforms.
+    fn initialize_transforms(
+        &self,
+        n: usize,
+        max_pixels_per_transform: usize,
+        input: JxlColorProfile,
+        output: JxlColorProfile,
+        intensity_target: f32,
+    ) -> Result<(usize, Vec<Box<dyn JxlCmsTransformer>>)>;
+}
+
+/// Writes a u32 value in big-endian format to the slice at the given position.
+fn write_u32_be(slice: &mut [u8], pos: usize, value: u32) -> Result<(), Error> {
+    if pos.checked_add(4).is_none_or(|end| end > slice.len()) {
+        return Err(Error::IccWriteOutOfBounds);
+    }
+    slice[pos..pos + 4].copy_from_slice(&value.to_be_bytes());
+    Ok(())
+}
+
+/// Writes a u16 value in big-endian format to the slice at the given position.
+fn write_u16_be(slice: &mut [u8], pos: usize, value: u16) -> Result<(), Error> {
+    if pos.checked_add(2).is_none_or(|end| end > slice.len()) {
+        return Err(Error::IccWriteOutOfBounds);
+    }
+    slice[pos..pos + 2].copy_from_slice(&value.to_be_bytes());
+    Ok(())
+}
+
+/// Writes a 4-character ASCII tag string to the slice at the given position.
+fn write_icc_tag(slice: &mut [u8], pos: usize, tag_str: &str) -> Result<(), Error> {
+    if tag_str.len() != 4 || !tag_str.is_ascii() {
+        return Err(Error::IccInvalidTagString(tag_str.to_string()));
+    }
+    if pos.checked_add(4).is_none_or(|end| end > slice.len()) {
+        return Err(Error::IccWriteOutOfBounds);
+    }
+    slice[pos..pos + 4].copy_from_slice(tag_str.as_bytes());
+    Ok(())
+}
+
+/// Creates an ICC 'mluc' tag with a single "enUS" record.
+///
+/// The input `text` must be ASCII, as it will be encoded as UTF-16BE by prepending
+/// a null byte to each ASCII character.
+fn create_icc_mluc_tag(tags: &mut Vec<u8>, text: &str) -> Result<(), Error> {
+    // libjxl comments that "The input text must be ASCII".
+    // We enforce this.
+    if !text.is_ascii() {
+        return Err(Error::IccMlucTextNotAscii(text.to_string()));
+    }
+    // Tag signature 'mluc' (4 bytes)
+    tags.extend_from_slice(b"mluc");
+    // Reserved, must be 0 (4 bytes)
+    tags.extend_from_slice(&0u32.to_be_bytes());
+    // Number of records (u32, 4 bytes) - Hardcoded to 1.
+    tags.extend_from_slice(&1u32.to_be_bytes());
+    // Record size (u32, 4 bytes) - Each record descriptor is 12 bytes.
+    // (Language Code [2] + Country Code [2] + String Length [4] + String Offset [4])
+    tags.extend_from_slice(&12u32.to_be_bytes());
+    // Language Code (2 bytes) - "en" for English
+    tags.extend_from_slice(b"en");
+    // Country Code (2 bytes) - "US" for United States
+    tags.extend_from_slice(b"US");
+    // Length of the string (u32, 4 bytes)
+    // For ASCII text encoded as UTF-16BE, each char becomes 2 bytes.
+    let string_actual_byte_length = text.len() * 2;
+    tags.extend_from_slice(&(string_actual_byte_length as u32).to_be_bytes());
+    // Offset of the string (u32, 4 bytes)
+    // The string data for this record starts at offset 28.
+    tags.extend_from_slice(&28u32.to_be_bytes());
+    // The actual string data, encoded as UTF-16BE.
+    // For ASCII char 'X', UTF-16BE is 0x00 0x58.
+    for ascii_char_code in text.as_bytes() {
+        tags.push(0u8);
+        tags.push(*ascii_char_code);
+    }
+
+    Ok(())
+}
+
+struct TagInfo {
+    signature: [u8; 4],
+    // Offset of this tag's data relative to the START of the `tags_data` block
+    offset_in_tags_blob: u32,
+    // Unpadded size of this tag's actual data content.
+    size_unpadded: u32,
+}
+
+fn pad_to_4_byte_boundary(data: &mut Vec<u8>) {
+    data.resize(data.len().next_multiple_of(4), 0u8);
+}
+
+/// Converts an f32 to s15Fixed16 format and appends it as big-endian bytes.
+/// s15Fixed16 is a signed 32-bit number with 1 sign bit, 15 integer bits,
+/// and 16 fractional bits.
+fn append_s15_fixed_16(tags_data: &mut Vec<u8>, value: f32) -> Result<(), Error> {
+    // In libjxl, the following specific range check is used: (-32767.995f <= value) && (value <= 32767.995f)
+    // This is slightly tighter than the theoretical max positive s15.16 value.
+    // We replicate this for consistency.
+    if !(value.is_finite() && (-32767.995..=32767.995).contains(&value)) {
+        return Err(Error::IccValueOutOfRangeS15Fixed16(value));
+    }
+
+    // Multiply by 2^16 and round to nearest integer
+    let scaled_value = (value * 65536.0).round();
+    // Cast to i32 for correct two's complement representation
+    let int_value = scaled_value as i32;
+    tags_data.extend_from_slice(&int_value.to_be_bytes());
+    Ok(())
+}
+
+/// Creates the data for an ICC 'XYZ ' tag and appends it to `tags_data`.
+/// The 'XYZ ' tag contains three s15Fixed16Number values.
+fn create_icc_xyz_tag(tags_data: &mut Vec<u8>, xyz_color: &[f32; 3]) -> Result<TagInfo, Error> {
+    // Tag signature 'XYZ ' (4 bytes, note the trailing space)
+    let start_offset = tags_data.len() as u32;
+    let signature = b"XYZ ";
+    tags_data.extend_from_slice(signature);
+
+    // Reserved, must be 0 (4 bytes)
+    tags_data.extend_from_slice(&0u32.to_be_bytes());
+
+    // XYZ data (3 * s15Fixed16Number = 3 * 4 bytes)
+    for &val in xyz_color {
+        append_s15_fixed_16(tags_data, val)?;
+    }
+
+    Ok(TagInfo {
+        signature: *b"wtpt",
+        offset_in_tags_blob: start_offset,
+        size_unpadded: (tags_data.len() as u32) - start_offset,
+    })
+}
+
+fn create_icc_chad_tag(
+    tags_data: &mut Vec<u8>,
+    chad_matrix: &Matrix3x3<f32>,
+) -> Result<TagInfo, Error> {
+    // The tag type signature "sf32" (4 bytes).
+    let signature = b"sf32";
+    let start_offset = tags_data.len() as u32;
+    tags_data.extend_from_slice(signature);
+
+    // A reserved field (4 bytes), which must be set to 0.
+    tags_data.extend_from_slice(&0u32.to_be_bytes());
+
+    // The 9 matrix elements as s15Fixed16Number values.
+    // m[0][0], m[0][1], m[0][2], m[1][0], ..., m[2][2]
+    for row_array in chad_matrix.iter() {
+        for &value in row_array.iter() {
+            append_s15_fixed_16(tags_data, value)?;
+        }
+    }
+    Ok(TagInfo {
+        signature: *b"chad",
+        offset_in_tags_blob: start_offset,
+        size_unpadded: (tags_data.len() as u32) - start_offset,
+    })
+}
+
+/// Converts CIE xy white point coordinates to CIE XYZ values (Y is normalized to 1.0).
+fn cie_xyz_from_white_cie_xy(wx: f32, wy: f32) -> Result<[f32; 3], Error> {
+    // Check for wy being too close to zero to prevent division by zero or extreme values.
+    if wy.abs() < 1e-12 {
+        return Err(Error::IccInvalidWhitePointY(wy));
+    }
+    let factor = 1.0 / wy;
+    let x_val = wx * factor;
+    let y_val = 1.0f32;
+    let z_val = (1.0 - wx - wy) * factor;
+    Ok([x_val, y_val, z_val])
+}
+
+/// Creates the data for an ICC `para` (parametricCurveType) tag.
+/// It writes `12 + 4 * params.len()` bytes.
+fn create_icc_curv_para_tag(
+    tags_data: &mut Vec<u8>,
+    params: &[f32],
+    curve_type: u16,
+) -> Result<u32, Error> {
+    let start_offset = tags_data.len();
+    // Tag type 'para' (4 bytes)
+    tags_data.extend_from_slice(b"para");
+    // Reserved, must be 0 (4 bytes)
+    tags_data.extend_from_slice(&0u32.to_be_bytes());
+    // Function type (u16, 2 bytes)
+    tags_data.extend_from_slice(&curve_type.to_be_bytes());
+    // Reserved, must be 0 (u16, 2 bytes)
+    tags_data.extend_from_slice(&0u16.to_be_bytes());
+    // Parameters (s15Fixed16Number each)
+    for &param in params {
+        append_s15_fixed_16(tags_data, param)?;
+    }
+    Ok((tags_data.len() - start_offset) as u32)
+}
+
+fn display_from_encoded_pq(display_intensity_target: f32, mut e: f64) -> f64 {
+    const M1: f64 = 2610.0 / 16384.0;
+    const M2: f64 = (2523.0 / 4096.0) * 128.0;
+    const C1: f64 = 3424.0 / 4096.0;
+    const C2: f64 = (2413.0 / 4096.0) * 32.0;
+    const C3: f64 = (2392.0 / 4096.0) * 32.0;
+    // Handle the zero case directly.
+    if e == 0.0 {
+        return 0.0;
+    }
+
+    // Handle negative inputs by using their absolute
+    // value for the calculation and reapplying the sign at the end.
+    let original_sign = e.signum();
+    e = e.abs();
+
+    // Core PQ EOTF formula from ST 2084.
+    let xp = e.powf(1.0 / M2);
+    let num = (xp - C1).max(0.0);
+    let den = C2 - C3 * xp;
+
+    // In release builds, a zero denominator would lead to `inf` or `NaN`,
+    // which is handled by the assertion below. For valid inputs (e in [0,1]),
+    // the denominator is always positive.
+    debug_assert!(den != 0.0, "PQ transfer function denominator is zero.");
+
+    let d = (num / den).powf(1.0 / M1);
+
+    // The result `d` should always be non-negative for non-negative inputs.
+    debug_assert!(
+        d >= 0.0,
+        "PQ intermediate value `d` should not be negative."
+    );
+
+    // The libjxl implementation includes a scaling factor. Note that `d` represents
+    // a value normalized to a 10,000 nit peak.
+    let scaled_d = d * (10000.0 / display_intensity_target as f64);
+
+    // Re-apply the original sign.
+    scaled_d.copysign(original_sign)
+}
+
+/// TF_HLG_Base class for BT.2100 HLG.
+///
+/// This struct provides methods to convert between non-linear encoded HLG signals
+/// and linear display-referred light, following the definitions in BT.2100-2.
+///
+/// - **"display"**: linear light, normalized to [0, 1].
+/// - **"encoded"**: a non-linear HLG signal, nominally in [0, 1].
+/// - **"scene"**: scene-referred linear light, normalized to [0, 1].
+///
+/// The functions are designed to be unbounded to handle inputs outside the
+/// nominal [0, 1] range, which can occur during color space conversions. Negative
+/// inputs are handled by mirroring the function (`f(-x) = -f(x)`).
+#[allow(non_camel_case_types)]
+struct TF_HLG;
+
+impl TF_HLG {
+    // Constants for the HLG formula, as defined in BT.2100.
+    const A: f64 = 0.17883277;
+    const RA: f64 = 1.0 / Self::A;
+    const B: f64 = 1.0 - 4.0 * Self::A;
+    const C: f64 = 0.5599107295;
+    const INV_12: f64 = 1.0 / 12.0;
+
+    /// Converts a non-linear encoded signal to a linear display value (EOTF).
+    ///
+    /// This corresponds to `DisplayFromEncoded(e) = OOTF(InvOETF(e))`.
+    /// Since the OOTF is simplified to an identity function, this is equivalent
+    /// to calling `inv_oetf(e)`.
+    #[inline]
+    fn display_from_encoded(e: f64) -> f64 {
+        Self::inv_oetf(e)
+    }
+
+    /// Converts a linear display value to a non-linear encoded signal (inverse EOTF).
+    ///
+    /// This corresponds to `EncodedFromDisplay(d) = OETF(InvOOTF(d))`.
+    /// Since the InvOOTF is an identity function, this is equivalent to `oetf(d)`.
+    #[inline]
+    #[allow(dead_code)]
+    fn encoded_from_display(d: f64) -> f64 {
+        Self::oetf(d)
+    }
+
+    /// The private HLG OETF, converting scene-referred light to a non-linear signal.
+    fn oetf(mut s: f64) -> f64 {
+        if s == 0.0 {
+            return 0.0;
+        }
+        let original_sign = s.signum();
+        s = s.abs();
+
+        let e = if s <= Self::INV_12 {
+            (3.0 * s).sqrt()
+        } else {
+            Self::A * (12.0 * s - Self::B).ln() + Self::C
+        };
+
+        // The result should be positive for positive inputs.
+        debug_assert!(e > 0.0);
+
+        e.copysign(original_sign)
+    }
+
+    /// The private HLG inverse OETF, converting a non-linear signal back to scene-referred light.
+    fn inv_oetf(mut e: f64) -> f64 {
+        if e == 0.0 {
+            return 0.0;
+        }
+        let original_sign = e.signum();
+        e = e.abs();
+
+        let s = if e <= 0.5 {
+            // The `* (1.0 / 3.0)` is slightly more efficient than `/ 3.0`.
+            e * e * (1.0 / 3.0)
+        } else {
+            (((e - Self::C) * Self::RA).exp() + Self::B) * Self::INV_12
+        };
+
+        // The result should be non-negative for non-negative inputs.
+        debug_assert!(s >= 0.0);
+
+        s.copysign(original_sign)
+    }
+}
+
+/// Creates a lookup table for an ICC `curv` tag from a transfer function.
+///
+/// This function generates a vector of 16-bit integers representing the response
+/// of the HLG or PQ electro-optical transfer functions (EOTF).
+///
+/// ### Arguments
+/// * `n` - The number of entries in the lookup table. Must not exceed 4096.
+/// * `tf` - The transfer function to model, either `TransferFunction::HLG` or `TransferFunction::PQ`.
+/// * `tone_map` - A boolean to enable tone mapping for PQ curves. Currently a stub.
+///
+/// ### Returns
+/// A `Result` containing the `Vec<f32>` lookup table or an `Error`.
+fn create_table_curve(
+    n: usize,
+    tf: &JxlTransferFunction,
+    tone_map: bool,
+) -> Result<Vec<f32>, Error> {
+    // ICC Specification (v4.4, section 10.6) for `curveType` with `curv`
+    // processing elements states the table can have at most 4096 entries.
+    if n > 4096 {
+        return Err(Error::IccTableSizeExceeded(n));
+    }
+
+    if !matches!(tf, JxlTransferFunction::PQ | JxlTransferFunction::HLG) {
+        return Err(Error::IccUnsupportedTransferFunction);
+    }
+
+    // The peak luminance for PQ decoding, as specified in the original C++ code.
+    const PQ_INTENSITY_TARGET: f64 = 10000.0;
+    // The target peak luminance for SDR, used if tone mapping is applied.
+    const DEFAULT_INTENSITY_TARGET: f64 = 255.0; // Placeholder value
+
+    let mut table = Vec::with_capacity(n);
+    for i in 0..n {
+        // `x` represents the normalized input signal, from 0.0 to 1.0.
+        let x = i as f64 / (n - 1) as f64;
+
+        // Apply the specified EOTF to get the linear light value `y`.
+        // The output `y` is normalized to the range [0.0, 1.0].
+        let y = match tf {
+            JxlTransferFunction::HLG => TF_HLG::display_from_encoded(x),
+            JxlTransferFunction::PQ => {
+                // For PQ, the output of the EOTF is absolute luminance, so we
+                // normalize it back to [0, 1] relative to the peak luminance.
+                display_from_encoded_pq(PQ_INTENSITY_TARGET as f32, x) / PQ_INTENSITY_TARGET
+            }
+            _ => unreachable!(), // Already checked above.
+        };
+
+        // Apply tone mapping if requested.
+        if tone_map
+            && *tf == JxlTransferFunction::PQ
+            && PQ_INTENSITY_TARGET > DEFAULT_INTENSITY_TARGET
+        {
+            // TODO(firsching): add tone mapping here. (make y mutable for this)
+            // let linear_luminance = y * PQ_INTENSITY_TARGET;
+            // let tone_mapped_luminance = rec2408_tone_map(linear_luminance)?;
+            // y = tone_mapped_luminance / DEFAULT_INTENSITY_TARGET;
+        }
+
+        // Clamp the final value to the valid range [0.0, 1.0]. This is
+        // particularly important for HLG, which can exceed 1.0.
+        let y_clamped = y.clamp(0.0, 1.0);
+
+        // table.push((y_clamped * 65535.0).round() as u16);
+        table.push(y_clamped as f32);
+    }
+
+    Ok(table)
+}
+
+// ============================================================================
+// HDR Tone Mapping Implementation
+// ============================================================================
+
+/// BT.2408 HDR to SDR tone mapper.
+/// Maps PQ content from source range (e.g., 0-10000 nits) to target range (e.g., 0-250 nits).
+struct Rec2408ToneMapper {
+    source_range: (f32, f32), // (min, max) in nits
+    target_range: (f32, f32),
+    luminances: [f32; 3], // RGB luminance coefficients (Y values)
+
+    // Precomputed values
+    pq_mastering_min: f32,
+    #[allow(dead_code)] // Stored for potential future use / debugging
+    pq_mastering_max: f32,
+    pq_mastering_range: f32,
+    inv_pq_mastering_range: f32,
+    min_lum: f32,
+    max_lum: f32,
+    ks: f32,
+    inv_one_minus_ks: f32,
+    normalizer: f32,
+    inv_target_peak: f32,
+}
+
+impl Rec2408ToneMapper {
+    fn new(source_range: (f32, f32), target_range: (f32, f32), luminances: [f32; 3]) -> Self {
+        let pq_mastering_min = Self::linear_to_pq(source_range.0);
+        let pq_mastering_max = Self::linear_to_pq(source_range.1);
+        let pq_mastering_range = pq_mastering_max - pq_mastering_min;
+        let inv_pq_mastering_range = 1.0 / pq_mastering_range;
+
+        let min_lum =
+            (Self::linear_to_pq(target_range.0) - pq_mastering_min) * inv_pq_mastering_range;
+        let max_lum =
+            (Self::linear_to_pq(target_range.1) - pq_mastering_min) * inv_pq_mastering_range;
+        let ks = 1.5 * max_lum - 0.5;
+
+        Self {
+            source_range,
+            target_range,
+            luminances,
+            pq_mastering_min,
+            pq_mastering_max,
+            pq_mastering_range,
+            inv_pq_mastering_range,
+            min_lum,
+            max_lum,
+            ks,
+            inv_one_minus_ks: 1.0 / (1.0 - ks).max(1e-6),
+            normalizer: source_range.1 / target_range.1,
+            inv_target_peak: 1.0 / target_range.1,
+        }
+    }
+
+    /// PQ inverse EOTF - converts luminance (nits) to PQ encoded value.
+    /// Uses the existing `linear_to_pq_precise` from color::tf.
+    fn linear_to_pq(luminance: f32) -> f32 {
+        let mut val = [luminance / 10000.0]; // Normalize to 0-1 for 10000 nits
+        linear_to_pq_precise(10000.0, &mut val);
+        val[0]
+    }
+
+    /// PQ EOTF - converts PQ encoded value to luminance (nits).
+    /// Uses the existing `pq_to_linear_precise` from color::tf.
+    fn pq_to_linear(encoded: f32) -> f32 {
+        let mut val = [encoded];
+        pq_to_linear_precise(10000.0, &mut val);
+        val[0] * 10000.0
+    }
+
+    fn t(&self, a: f32) -> f32 {
+        (a - self.ks) * self.inv_one_minus_ks
+    }
+
+    fn p(&self, b: f32) -> f32 {
+        let t_b = self.t(b);
+        let t_b_2 = t_b * t_b;
+        let t_b_3 = t_b_2 * t_b;
+        (2.0 * t_b_3 - 3.0 * t_b_2 + 1.0) * self.ks
+            + (t_b_3 - 2.0 * t_b_2 + t_b) * (1.0 - self.ks)
+            + (-2.0 * t_b_3 + 3.0 * t_b_2) * self.max_lum
+    }
+
+    /// Apply tone mapping to RGB values (in-place)
+    fn tone_map(&self, rgb: &mut [f32; 3]) {
+        let luminance = self.source_range.1
+            * (self.luminances[0] * rgb[0]
+                + self.luminances[1] * rgb[1]
+                + self.luminances[2] * rgb[2]);
+
+        let normalized_pq = ((Self::linear_to_pq(luminance) - self.pq_mastering_min)
+            * self.inv_pq_mastering_range)
+            .min(1.0);
+
+        let e2 = if normalized_pq < self.ks {
+            normalized_pq
+        } else {
+            self.p(normalized_pq)
+        };
+
+        let one_minus_e2 = 1.0 - e2;
+        let one_minus_e2_2 = one_minus_e2 * one_minus_e2;
+        let one_minus_e2_4 = one_minus_e2_2 * one_minus_e2_2;
+        let e3 = self.min_lum * one_minus_e2_4 + e2;
+        let e4 = e3 * self.pq_mastering_range + self.pq_mastering_min;
+        let d4 = Self::pq_to_linear(e4);
+        let new_luminance = d4.clamp(0.0, self.target_range.1);
+
+        let min_luminance = 1e-6;
+        let use_cap = luminance <= min_luminance;
+        let ratio = new_luminance / luminance.max(min_luminance);
+        let cap = new_luminance * self.inv_target_peak;
+        let multiplier = ratio * self.normalizer;
+
+        for c in rgb.iter_mut() {
+            *c = if use_cap { cap } else { *c * multiplier };
+        }
+    }
+}
+
+/// Apply HLG OOTF for tone mapping HLG content to SDR.
+/// This implements the HLG OOTF inline for a single pixel, based on the same math
+/// as `color::tf::hlg_scene_to_display` but avoiding the bulk-processing API.
+fn apply_hlg_ootf(rgb: &mut [f32; 3], target_luminance: f32, luminances: [f32; 3]) {
+    // HLG OOTF: scene-referred to display-referred conversion
+    // system_gamma = 1.2 * 1.111^log2(intensity_display / 1000)
+    let system_gamma = 1.2_f32 * 1.111_f32.powf((target_luminance / 1e3).log2());
+    let exp = system_gamma - 1.0;
+
+    if exp.abs() < 0.1 {
+        return;
+    }
+
+    // Compute luminance and apply OOTF
+    let mixed = rgb[0] * luminances[0] + rgb[1] * luminances[1] + rgb[2] * luminances[2];
+    let mult = crate::util::fast_powf(mixed, exp);
+    rgb[0] *= mult;
+    rgb[1] *= mult;
+    rgb[2] *= mult;
+}
+
+/// Desaturate out-of-gamut pixels while preserving luminance.
+fn gamut_map(rgb: &mut [f32; 3], luminances: &[f32; 3], preserve_saturation: f32) {
+    let luminance = luminances[0] * rgb[0] + luminances[1] * rgb[1] + luminances[2] * rgb[2];
+
+    let mut gray_mix_saturation = 0.0_f32;
+    let mut gray_mix_luminance = 0.0_f32;
+
+    for &val in rgb.iter() {
+        let val_minus_gray = val - luminance;
+        let inv_val_minus_gray = if val_minus_gray == 0.0 {
+            1.0
+        } else {
+            1.0 / val_minus_gray
+        };
+        let val_over_val_minus_gray = val * inv_val_minus_gray;
+
+        if val_minus_gray < 0.0 {
+            gray_mix_saturation = gray_mix_saturation.max(val_over_val_minus_gray);
+        }
+
+        gray_mix_luminance = gray_mix_luminance.max(if val_minus_gray <= 0.0 {
+            gray_mix_saturation
+        } else {
+            val_over_val_minus_gray - inv_val_minus_gray
+        });
+    }
+
+    let gray_mix = (preserve_saturation * (gray_mix_saturation - gray_mix_luminance)
+        + gray_mix_luminance)
+        .clamp(0.0, 1.0);
+
+    for val in rgb.iter_mut() {
+        *val = gray_mix * (luminance - *val) + *val;
+    }
+
+    let max_clr = rgb[0].max(rgb[1]).max(rgb[2]).max(1.0);
+    let normalizer = 1.0 / max_clr;
+    for v in rgb.iter_mut() {
+        *v *= normalizer;
+    }
+}
+
+/// Tone map a single pixel and convert to PCS Lab for ICC profile.
+fn tone_map_pixel(
+    transfer_function: &JxlTransferFunction,
+    primaries: &JxlPrimaries,
+    white_point: &JxlWhitePoint,
+    input: [f32; 3],
+) -> Result<[u8; 3], Error> {
+    // Get primaries coordinates
+    let primaries_coords = primaries.to_xy_coords();
+    let (rx, ry) = primaries_coords[0];
+    let (gx, gy) = primaries_coords[1];
+    let (bx, by) = primaries_coords[2];
+    let (wx, wy) = white_point.to_xy_coords();
+
+    // Get the RGB to XYZ matrix (not adapted to D50 yet)
+    let primaries_xyz = primaries_to_xyz(rx, ry, gx, gy, bx, by, wx, wy)?;
+
+    // Extract luminances from Y row of the matrix
+    let luminances = [
+        primaries_xyz[1][0] as f32,
+        primaries_xyz[1][1] as f32,
+        primaries_xyz[1][2] as f32,
+    ];
+
+    // Apply EOTF to get linear values
+    let mut linear = match transfer_function {
+        JxlTransferFunction::PQ => {
+            // PQ EOTF - convert from encoded to linear (normalized to 0-1 range for 10000 nits)
+            [
+                Rec2408ToneMapper::pq_to_linear(input[0]) / 10000.0,
+                Rec2408ToneMapper::pq_to_linear(input[1]) / 10000.0,
+                Rec2408ToneMapper::pq_to_linear(input[2]) / 10000.0,
+            ]
+        }
+        JxlTransferFunction::HLG => {
+            // Use existing hlg_to_scene from color::tf
+            let mut vals = [input[0], input[1], input[2]];
+            hlg_to_scene(&mut vals);
+            vals
+        }
+        _ => return Err(Error::IccUnsupportedTransferFunction),
+    };
+
+    // Apply tone mapping
+    match transfer_function {
+        JxlTransferFunction::PQ => {
+            let tone_mapper = Rec2408ToneMapper::new(
+                (0.0, 10000.0), // PQ source range
+                (0.0, 250.0),   // SDR target range
+                luminances,
+            );
+            tone_mapper.tone_map(&mut linear);
+        }
+        JxlTransferFunction::HLG => {
+            // Apply HLG OOTF (80 nit SDR target)
+            apply_hlg_ootf(&mut linear, 80.0, luminances);
+        }
+        _ => {}
+    }
+
+    // Gamut map
+    gamut_map(&mut linear, &luminances, 0.3);
+
+    // Get chromatic adaptation matrix
+    let chad = adapt_to_xyz_d50(wx, wy)?;
+
+    // Combine matrices: to_xyzd50 = chad * primaries_xyz
+    // Use mul_3x3_matrix from util which works with f64
+    let to_xyzd50_f64 = mul_3x3_matrix(&chad, &primaries_xyz);
+
+    // Convert to f32 for the final calculation
+    let to_xyzd50: [[f32; 3]; 3] =
+        std::array::from_fn(|r| std::array::from_fn(|c| to_xyzd50_f64[r][c] as f32));
+
+    // Apply matrix to get XYZ D50
+    let xyz = [
+        linear[0] * to_xyzd50[0][0] + linear[1] * to_xyzd50[0][1] + linear[2] * to_xyzd50[0][2],
+        linear[0] * to_xyzd50[1][0] + linear[1] * to_xyzd50[1][1] + linear[2] * to_xyzd50[1][2],
+        linear[0] * to_xyzd50[2][0] + linear[1] * to_xyzd50[2][1] + linear[2] * to_xyzd50[2][2],
+    ];
+
+    // Convert XYZ to Lab
+    // D50 reference white
+    const XN: f32 = 0.964212;
+    const YN: f32 = 1.0;
+    const ZN: f32 = 0.825188;
+    const DELTA: f32 = 6.0 / 29.0;
+
+    let lab_f = |x: f32| -> f32 {
+        if x <= DELTA * DELTA * DELTA {
+            x * (1.0 / (3.0 * DELTA * DELTA)) + 4.0 / 29.0
+        } else {
+            x.cbrt()
+        }
+    };
+
+    let f_x = lab_f(xyz[0] / XN);
+    let f_y = lab_f(xyz[1] / YN);
+    let f_z = lab_f(xyz[2] / ZN);
+
+    // Convert to ICC PCS Lab encoding (8-bit)
+    // L* = 116 * f(Y/Yn) - 16, encoded as L* / 100 * 255
+    // a* = 500 * (f(X/Xn) - f(Y/Yn)), encoded as (a* + 128) for 8-bit
+    // b* = 200 * (f(Y/Yn) - f(Z/Zn)), encoded as (b* + 128) for 8-bit
+    Ok([
+        (255.0 * (1.16 * f_y - 0.16).clamp(0.0, 1.0)).round() as u8,
+        (128.0 + (500.0 * (f_x - f_y)).clamp(-128.0, 127.0)).round() as u8,
+        (128.0 + (200.0 * (f_y - f_z)).clamp(-128.0, 127.0)).round() as u8,
+    ])
+}
+
+/// Create mft1 (8-bit LUT) A2B0 tag for HDR tone mapping.
+fn create_icc_lut_atob_tag_for_hdr(
+    transfer_function: &JxlTransferFunction,
+    primaries: &JxlPrimaries,
+    white_point: &JxlWhitePoint,
+    tags: &mut Vec<u8>,
+) -> Result<(), Error> {
+    const LUT_DIM: usize = 9; // 9x9x9 3D LUT
+
+    // Tag signature: 'mft1'
+    tags.extend_from_slice(b"mft1");
+    // Reserved
+    tags.extend_from_slice(&0u32.to_be_bytes());
+    // Number of input channels
+    tags.push(3);
+    // Number of output channels
+    tags.push(3);
+    // Number of CLUT grid points
+    tags.push(LUT_DIM as u8);
+    // Padding
+    tags.push(0);
+
+    // Identity matrix (3x3, s15Fixed16)
+    for i in 0..3 {
+        for j in 0..3 {
+            let val: f32 = if i == j { 1.0 } else { 0.0 };
+            append_s15_fixed_16(tags, val)?;
+        }
+    }
+
+    // Input tables (identity, 256 entries per channel)
+    for _ in 0..3 {
+        for i in 0..256 {
+            tags.push(i as u8);
+        }
+    }
+
+    // 3D CLUT
+    for ix in 0..LUT_DIM {
+        for iy in 0..LUT_DIM {
+            for ib in 0..LUT_DIM {
+                let input = [
+                    ix as f32 / (LUT_DIM - 1) as f32,
+                    iy as f32 / (LUT_DIM - 1) as f32,
+                    ib as f32 / (LUT_DIM - 1) as f32,
+                ];
+                let pcslab = tone_map_pixel(transfer_function, primaries, white_point, input)?;
+                tags.extend_from_slice(&pcslab);
+            }
+        }
+    }
+
+    // Output tables (identity, 256 entries per channel)
+    for _ in 0..3 {
+        for i in 0..256 {
+            tags.push(i as u8);
+        }
+    }
+
+    Ok(())
+}
+
+/// Create mBA B2A0 tag (no-op, required by some software like Safari).
+fn create_icc_noop_btoa_tag(tags: &mut Vec<u8>) -> Result<(), Error> {
+    // Tag signature: 'mBA '
+    tags.extend_from_slice(b"mBA ");
+    // Reserved
+    tags.extend_from_slice(&0u32.to_be_bytes());
+    // Number of input channels
+    tags.push(3);
+    // Number of output channels
+    tags.push(3);
+    // Padding
+    tags.extend_from_slice(&0u16.to_be_bytes());
+    // Offset to first B curve
+    tags.extend_from_slice(&32u32.to_be_bytes());
+    // Offset to matrix (0 = none)
+    tags.extend_from_slice(&0u32.to_be_bytes());
+    // Offset to first M curve (0 = none)
+    tags.extend_from_slice(&0u32.to_be_bytes());
+    // Offset to CLUT (0 = none)
+    tags.extend_from_slice(&0u32.to_be_bytes());
+    // Offset to first A curve (0 = none)
+    tags.extend_from_slice(&0u32.to_be_bytes());
+
+    // Three identity parametric curves (gamma = 1.0)
+    // Each curve is a 'para' type with function type 0 (simple gamma)
+    for _ in 0..3 {
+        create_icc_curv_para_tag(tags, &[1.0], 0)?;
+    }
+
+    Ok(())
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn test_md5() {
+        // Test vectors
+        let test_cases = vec![
+            ("", "d41d8cd98f00b204e9800998ecf8427e"),
+            (
+                "The quick brown fox jumps over the lazy dog",
+                "9e107d9d372bb6826bd81d3542a419d6",
+            ),
+            ("abc", "900150983cd24fb0d6963f7d28e17f72"),
+            ("message digest", "f96b697d7cb7938d525a2f31aaf161d0"),
+            (
+                "abcdefghijklmnopqrstuvwxyz",
+                "c3fcd3d76192e4007dfb496cca67e13b",
+            ),
+            (
+                "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+                "57edf4a22be3c955ac49da2e2107b67a",
+            ),
+        ];
+
+        for (input, expected) in test_cases {
+            let hash = compute_md5(input.as_bytes());
+            let hex: String = hash.iter().map(|e| format!("{:02x}", e)).collect();
+            assert_eq!(hex, expected, "Failed for input: '{}'", input);
+        }
+    }
+
+    #[test]
+    fn test_description() {
+        assert_eq!(
+            JxlColorEncoding::srgb(false).get_color_encoding_description(),
+            "RGB_D65_SRG_Rel_SRG"
+        );
+        assert_eq!(
+            JxlColorEncoding::srgb(true).get_color_encoding_description(),
+            "Gra_D65_Rel_SRG"
+        );
+        assert_eq!(
+            JxlColorEncoding::RgbColorSpace {
+                white_point: JxlWhitePoint::D65,
+                primaries: JxlPrimaries::BT2100,
+                transfer_function: JxlTransferFunction::Gamma(1.7),
+                rendering_intent: RenderingIntent::Relative
+            }
+            .get_color_encoding_description(),
+            "RGB_D65_202_Rel_g1.7000000"
+        );
+        assert_eq!(
+            JxlColorEncoding::RgbColorSpace {
+                white_point: JxlWhitePoint::D65,
+                primaries: JxlPrimaries::P3,
+                transfer_function: JxlTransferFunction::SRGB,
+                rendering_intent: RenderingIntent::Perceptual
+            }
+            .get_color_encoding_description(),
+            "DisplayP3"
+        );
+    }
+
+    #[test]
+    fn test_rec2408_tone_mapper() {
+        // Test the Rec2408ToneMapper with BT.2100 luminances
+        let luminances = [0.2627, 0.6780, 0.0593]; // BT.2100/BT.2020
+        let tone_mapper = Rec2408ToneMapper::new((0.0, 10000.0), (0.0, 250.0), luminances);
+
+        // Test with a bright HDR pixel (should be compressed)
+        let mut rgb = [0.8, 0.8, 0.8]; // High values in PQ space = very bright
+        tone_mapper.tone_map(&mut rgb);
+        // Result should be within valid range
+        assert!(rgb[0] >= 0.0 && rgb[0] <= 1.0, "R out of range: {}", rgb[0]);
+        assert!(rgb[1] >= 0.0 && rgb[1] <= 1.0, "G out of range: {}", rgb[1]);
+        assert!(rgb[2] >= 0.0 && rgb[2] <= 1.0, "B out of range: {}", rgb[2]);
+
+        // Test with a dark pixel (should not be affected much)
+        let mut rgb_dark = [0.1, 0.1, 0.1];
+        tone_mapper.tone_map(&mut rgb_dark);
+        assert!(
+            rgb_dark[0] >= 0.0 && rgb_dark[0] <= 1.0,
+            "R out of range: {}",
+            rgb_dark[0]
+        );
+    }
+
+    #[test]
+    fn test_hlg_ootf() {
+        let luminances = [0.2627, 0.6780, 0.0593];
+
+        let mut rgb = [0.5, 0.5, 0.5];
+        apply_hlg_ootf(&mut rgb, 80.0, luminances);
+        // Result should be in valid range
+        assert!(rgb[0] >= 0.0, "R should be non-negative");
+        assert!(rgb[1] >= 0.0, "G should be non-negative");
+        assert!(rgb[2] >= 0.0, "B should be non-negative");
+    }
+
+    #[test]
+    fn test_gamut_map() {
+        let luminances = [0.2627, 0.6780, 0.0593];
+
+        // Test out-of-gamut pixel (negative value)
+        let mut rgb = [-0.1, 0.5, 0.5];
+        gamut_map(&mut rgb, &luminances, 0.3);
+        // All values should be non-negative after gamut mapping
+        assert!(rgb[0] >= 0.0, "R should be non-negative after gamut map");
+        assert!(rgb[1] >= 0.0, "G should be non-negative after gamut map");
+        assert!(rgb[2] >= 0.0, "B should be non-negative after gamut map");
+
+        // Test in-gamut pixel (should not change much)
+        let mut rgb_valid = [0.5, 0.3, 0.2];
+        gamut_map(&mut rgb_valid, &luminances, 0.3);
+        assert!(rgb_valid[0] >= 0.0 && rgb_valid[0] <= 1.0);
+        assert!(rgb_valid[1] >= 0.0 && rgb_valid[1] <= 1.0);
+        assert!(rgb_valid[2] >= 0.0 && rgb_valid[2] <= 1.0);
+    }
+
+    #[test]
+    fn test_tone_map_pixel_pq() {
+        let result = tone_map_pixel(
+            &JxlTransferFunction::PQ,
+            &JxlPrimaries::BT2100,
+            &JxlWhitePoint::D65,
+            [0.5, 0.5, 0.5],
+        );
+        assert!(result.is_ok());
+        let lab = result.unwrap();
+        // Lab L* should be in reasonable range for mid-gray after tone mapping
+        assert!(lab[0] > 0, "L* should be positive for non-black input");
+        // a* and b* should be near neutral (128) for achromatic input
+        assert!(
+            (lab[1] as i32 - 128).abs() < 10,
+            "a* should be near neutral"
+        );
+        assert!(
+            (lab[2] as i32 - 128).abs() < 10,
+            "b* should be near neutral"
+        );
+    }
+
+    #[test]
+    fn test_tone_map_pixel_hlg() {
+        let result = tone_map_pixel(
+            &JxlTransferFunction::HLG,
+            &JxlPrimaries::BT2100,
+            &JxlWhitePoint::D65,
+            [0.5, 0.5, 0.5],
+        );
+        assert!(result.is_ok());
+        let lab = result.unwrap();
+        // Lab L* should be in reasonable range
+        assert!(lab[0] > 0, "L* should be positive for non-black input");
+        // a* and b* should be near neutral (128) for achromatic input
+        assert!(
+            (lab[1] as i32 - 128).abs() < 10,
+            "a* should be near neutral"
+        );
+        assert!(
+            (lab[2] as i32 - 128).abs() < 10,
+            "b* should be near neutral"
+        );
+    }
+
+    #[test]
+    fn test_hdr_icc_profile_generation_pq() {
+        // Test that PQ HDR color encoding generates an ICC profile with A2B0/B2A0 tags.
+        // This tests the complete HDR tone mapping pipeline without needing an actual
+        // HDR JXL file - the color encoding is constructed programmatically.
+        let encoding = JxlColorEncoding::RgbColorSpace {
+            white_point: JxlWhitePoint::D65,
+            primaries: JxlPrimaries::BT2100,
+            transfer_function: JxlTransferFunction::PQ,
+            rendering_intent: RenderingIntent::Relative,
+        };
+
+        assert!(encoding.can_tone_map_for_icc());
+
+        let result = encoding.maybe_create_profile();
+        assert!(result.is_ok(), "Profile creation should succeed");
+        let profile_opt = result.unwrap();
+        assert!(profile_opt.is_some(), "Profile should be generated for PQ");
+
+        let profile = profile_opt.unwrap();
+        // Profile should be a valid ICC profile (starts with profile size, then signature)
+        assert!(profile.len() > 128, "Profile should have header + tags");
+
+        // Verify header has Lab PCS (bytes 20-23 should be "Lab ")
+        assert_eq!(
+            &profile[20..24],
+            b"Lab ",
+            "PCS should be Lab for HDR profiles"
+        );
+
+        // Check for 'mft1' (A2B0 tag type) somewhere in the profile
+        assert!(
+            profile.windows(4).any(|w| w == b"mft1"),
+            "Profile should contain mft1 tag (A2B0)"
+        );
+        assert!(
+            profile.windows(4).any(|w| w == b"mBA "),
+            "Profile should contain mBA tag (B2A0)"
+        );
+
+        // Verify CICP tag is present (for standard primaries)
+        assert!(
+            profile.windows(4).any(|w| w == b"cicp"),
+            "Profile should contain cicp tag"
+        );
+    }
+
+    #[test]
+    fn test_hdr_icc_profile_generation_hlg() {
+        // Test that HLG HDR color encoding generates an ICC profile with A2B0/B2A0 tags
+        let encoding = JxlColorEncoding::RgbColorSpace {
+            white_point: JxlWhitePoint::D65,
+            primaries: JxlPrimaries::BT2100,
+            transfer_function: JxlTransferFunction::HLG,
+            rendering_intent: RenderingIntent::Relative,
+        };
+
+        assert!(encoding.can_tone_map_for_icc());
+
+        let result = encoding.maybe_create_profile();
+        assert!(result.is_ok(), "Profile creation should succeed");
+        let profile_opt = result.unwrap();
+        assert!(profile_opt.is_some(), "Profile should be generated for HLG");
+
+        let profile = profile_opt.unwrap();
+        assert!(profile.len() > 128, "Profile should have header + tags");
+    }
+
+    #[test]
+    fn test_pq_eotf_inv_eotf_roundtrip() {
+        // Test that linear_to_pq and pq_to_linear are inverses
+        let test_values: [f32; 5] = [0.0, 100.0, 1000.0, 5000.0, 10000.0];
+        for &luminance in &test_values {
+            let encoded = Rec2408ToneMapper::linear_to_pq(luminance);
+            let decoded = Rec2408ToneMapper::pq_to_linear(encoded);
+            let diff = (luminance - decoded).abs();
+            assert!(
+                diff < 1.0,
+                "Roundtrip failed for {}: got {}, diff {}",
+                luminance,
+                decoded,
+                diff
+            );
+        }
+    }
+
+    #[test]
+    fn test_can_tone_map_for_icc() {
+        // PQ with D65 and standard primaries should be able to tone map
+        let pq_bt2100 = JxlColorEncoding::RgbColorSpace {
+            white_point: JxlWhitePoint::D65,
+            primaries: JxlPrimaries::BT2100,
+            transfer_function: JxlTransferFunction::PQ,
+            rendering_intent: RenderingIntent::Relative,
+        };
+        assert!(pq_bt2100.can_tone_map_for_icc());
+
+        // HLG with D65 and standard primaries should be able to tone map
+        let hlg_bt2100 = JxlColorEncoding::RgbColorSpace {
+            white_point: JxlWhitePoint::D65,
+            primaries: JxlPrimaries::BT2100,
+            transfer_function: JxlTransferFunction::HLG,
+            rendering_intent: RenderingIntent::Relative,
+        };
+        assert!(hlg_bt2100.can_tone_map_for_icc());
+
+        // sRGB should NOT be able to tone map (not HDR)
+        let srgb = JxlColorEncoding::srgb(false);
+        assert!(!srgb.can_tone_map_for_icc());
+
+        // Custom primaries should NOT be able to tone map
+        let custom_pq = JxlColorEncoding::RgbColorSpace {
+            white_point: JxlWhitePoint::D65,
+            primaries: JxlPrimaries::Chromaticities {
+                rx: 0.7,
+                ry: 0.3,
+                gx: 0.2,
+                gy: 0.8,
+                bx: 0.15,
+                by: 0.05,
+            },
+            transfer_function: JxlTransferFunction::PQ,
+            rendering_intent: RenderingIntent::Relative,
+        };
+        assert!(!custom_pq.can_tone_map_for_icc());
+    }
+
+    /// Integration test: decode actual HDR PQ test file and verify ICC profile
+    #[test]
+    fn test_hdr_pq_file_icc_profile() {
+        use crate::api::{JxlDecoder, JxlDecoderOptions, ProcessingResult};
+
+        let data = std::fs::read("resources/test/hdr_pq_test.jxl")
+            .expect("Failed to read hdr_pq_test.jxl - run from jxl crate directory");
+
+        let options = JxlDecoderOptions::default();
+        let decoder = JxlDecoder::new(options);
+        let mut input: &[u8] = &data;
+
+        let decoder_info = match decoder.process(&mut input).unwrap() {
+            ProcessingResult::Complete { result } => result,
+            _ => panic!("Expected complete decoding"),
+        };
+
+        // Get the color profile
+        let color_profile = decoder_info.output_color_profile();
+
+        // For HDR PQ content, we should be able to generate an ICC profile
+        let icc = color_profile.try_as_icc();
+        assert!(
+            icc.is_some(),
+            "Should generate ICC profile for HDR PQ content"
+        );
+
+        let profile = icc.unwrap();
+        // Verify it's an HDR profile with Lab PCS
+        assert_eq!(&profile[20..24], b"Lab ", "PCS should be Lab for HDR");
+        // Verify A2B0 tag exists
+        assert!(
+            profile.windows(4).any(|w| w == b"A2B0"),
+            "Should have A2B0 tag"
+        );
+        // Verify B2A0 tag exists
+        assert!(
+            profile.windows(4).any(|w| w == b"B2A0"),
+            "Should have B2A0 tag"
+        );
+    }
+
+    /// Integration test: decode actual HDR HLG test file and verify ICC profile
+    #[test]
+    fn test_hdr_hlg_file_icc_profile() {
+        use crate::api::{JxlDecoder, JxlDecoderOptions, ProcessingResult};
+
+        let data = std::fs::read("resources/test/hdr_hlg_test.jxl")
+            .expect("Failed to read hdr_hlg_test.jxl - run from jxl crate directory");
+
+        let options = JxlDecoderOptions::default();
+        let decoder = JxlDecoder::new(options);
+        let mut input: &[u8] = &data;
+
+        let decoder_info = match decoder.process(&mut input).unwrap() {
+            ProcessingResult::Complete { result } => result,
+            _ => panic!("Expected complete decoding"),
+        };
+
+        // Get the color profile
+        let color_profile = decoder_info.output_color_profile();
+
+        // For HDR HLG content, we should be able to generate an ICC profile
+        let icc = color_profile.try_as_icc();
+        assert!(
+            icc.is_some(),
+            "Should generate ICC profile for HDR HLG content"
+        );
+
+        let profile = icc.unwrap();
+        // Verify it's an HDR profile with Lab PCS
+        assert_eq!(&profile[20..24], b"Lab ", "PCS should be Lab for HDR");
+        // Verify A2B0 tag exists
+        assert!(
+            profile.windows(4).any(|w| w == b"A2B0"),
+            "Should have A2B0 tag"
+        );
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/data_types.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/data_types.rs
new file mode 100644
index 0000000..5dd4417
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/data_types.rs
@@ -0,0 +1,156 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{headers::extra_channels::ExtraChannel, image::DataTypeTag};
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum JxlColorType {
+    Grayscale,
+    GrayscaleAlpha,
+    Rgb,
+    Rgba,
+    Bgr,
+    Bgra,
+}
+
+impl JxlColorType {
+    pub fn has_alpha(&self) -> bool {
+        match self {
+            Self::Grayscale => false,
+            Self::GrayscaleAlpha => true,
+            Self::Rgb | Self::Bgr => false,
+            Self::Rgba | Self::Bgra => true,
+        }
+    }
+    pub fn samples_per_pixel(&self) -> usize {
+        match self {
+            Self::Grayscale => 1,
+            Self::GrayscaleAlpha => 2,
+            Self::Rgb | Self::Bgr => 3,
+            Self::Rgba | Self::Bgra => 4,
+        }
+    }
+    pub fn is_grayscale(&self) -> bool {
+        match self {
+            Self::Grayscale => true,
+            Self::GrayscaleAlpha => true,
+            Self::Rgb | Self::Bgr => false,
+            Self::Rgba | Self::Bgra => false,
+        }
+    }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum Endianness {
+    LittleEndian,
+    BigEndian,
+}
+
+impl Endianness {
+    pub fn native() -> Self {
+        #[cfg(target_endian = "little")]
+        {
+            Endianness::LittleEndian
+        }
+        #[cfg(target_endian = "big")]
+        {
+            Endianness::BigEndian
+        }
+    }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum JxlDataFormat {
+    U8 {
+        bit_depth: u8,
+    },
+    U16 {
+        endianness: Endianness,
+        bit_depth: u8,
+    },
+    F16 {
+        endianness: Endianness,
+    },
+    F32 {
+        endianness: Endianness,
+    },
+}
+
+impl JxlDataFormat {
+    pub fn bytes_per_sample(&self) -> usize {
+        match self {
+            Self::U8 { .. } => 1,
+            Self::U16 { .. } | Self::F16 { .. } => 2,
+            Self::F32 { .. } => 4,
+        }
+    }
+
+    pub fn f32() -> Self {
+        Self::F32 {
+            endianness: Endianness::native(),
+        }
+    }
+
+    pub(crate) fn data_type(&self) -> DataTypeTag {
+        match self {
+            JxlDataFormat::U8 { .. } => DataTypeTag::U8,
+            JxlDataFormat::U16 { .. } => DataTypeTag::U16,
+            JxlDataFormat::F16 { .. } => DataTypeTag::F16,
+            JxlDataFormat::F32 { .. } => DataTypeTag::F32,
+        }
+    }
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct JxlPixelFormat {
+    pub color_type: JxlColorType,
+    // None -> ignore
+    pub color_data_format: Option<JxlDataFormat>,
+    pub extra_channel_format: Vec<Option<JxlDataFormat>>,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum JxlBitDepth {
+    Int {
+        bits_per_sample: u32,
+    },
+    Float {
+        bits_per_sample: u32,
+        exponent_bits_per_sample: u32,
+    },
+}
+
+impl JxlBitDepth {
+    pub fn bits_per_sample(&self) -> u32 {
+        match self {
+            JxlBitDepth::Int { bits_per_sample: b } => *b,
+            JxlBitDepth::Float {
+                bits_per_sample: b, ..
+            } => *b,
+        }
+    }
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct JxlExtraChannel {
+    pub ec_type: ExtraChannel,
+    pub alpha_associated: bool,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct JxlAnimation {
+    pub tps_numerator: u32,
+    pub tps_denominator: u32,
+    pub num_loops: u32,
+    pub have_timecodes: bool,
+}
+
+#[derive(Clone, Debug)]
+pub struct JxlFrameHeader {
+    pub name: String,
+    pub duration: Option<f64>,
+    /// Frame size (width, height)
+    pub size: (usize, usize),
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/decoder.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/decoder.rs
new file mode 100644
index 0000000..9adba5c
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/decoder.rs
@@ -0,0 +1,527 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use super::{
+    JxlBasicInfo, JxlBitstreamInput, JxlColorProfile, JxlDecoderInner, JxlDecoderOptions,
+    JxlOutputBuffer, JxlPixelFormat, ProcessingResult,
+};
+#[cfg(test)]
+use crate::frame::Frame;
+use crate::{api::JxlFrameHeader, error::Result};
+use states::*;
+use std::marker::PhantomData;
+
+pub mod states {
+    pub trait JxlState {}
+    pub struct Initialized;
+    pub struct WithImageInfo;
+    pub struct WithFrameInfo;
+    impl JxlState for Initialized {}
+    impl JxlState for WithImageInfo {}
+    impl JxlState for WithFrameInfo {}
+}
+
+// Q: do we plan to add support for box decoding?
+// If we do, one way is to take a callback &[u8; 4] -> Box<dyn Write>.
+
+/// High level API using the typestate pattern to forbid invalid usage.
+pub struct JxlDecoder<State: JxlState> {
+    inner: Box<JxlDecoderInner>,
+    _state: PhantomData<State>,
+}
+
+#[cfg(test)]
+pub type FrameCallback = dyn FnMut(&Frame, usize) -> Result<()>;
+
+impl<S: JxlState> JxlDecoder<S> {
+    fn wrap_inner(inner: Box<JxlDecoderInner>) -> Self {
+        Self {
+            inner,
+            _state: PhantomData,
+        }
+    }
+
+    /// Sets a callback that processes all frames by calling `callback(frame, frame_index)`.
+    #[cfg(test)]
+    pub fn set_frame_callback(&mut self, callback: Box<FrameCallback>) {
+        self.inner.set_frame_callback(callback);
+    }
+
+    #[cfg(test)]
+    pub fn decoded_frames(&self) -> usize {
+        self.inner.decoded_frames()
+    }
+
+    /// Rewinds a decoder to the start of the file, allowing past frames to be displayed again.
+    pub fn rewind(mut self) -> JxlDecoder<Initialized> {
+        self.inner.rewind();
+        JxlDecoder::wrap_inner(self.inner)
+    }
+
+    fn map_inner_processing_result<SuccessState: JxlState>(
+        self,
+        inner_result: ProcessingResult<(), ()>,
+    ) -> ProcessingResult<JxlDecoder<SuccessState>, Self> {
+        match inner_result {
+            ProcessingResult::Complete { .. } => ProcessingResult::Complete {
+                result: JxlDecoder::wrap_inner(self.inner),
+            },
+            ProcessingResult::NeedsMoreInput { size_hint, .. } => {
+                ProcessingResult::NeedsMoreInput {
+                    size_hint,
+                    fallback: self,
+                }
+            }
+        }
+    }
+}
+
+impl JxlDecoder<Initialized> {
+    pub fn new(options: JxlDecoderOptions) -> Self {
+        Self::wrap_inner(Box::new(JxlDecoderInner::new(options)))
+    }
+
+    pub fn process(
+        mut self,
+        input: &mut impl JxlBitstreamInput,
+    ) -> Result<ProcessingResult<JxlDecoder<WithImageInfo>, Self>> {
+        let inner_result = self.inner.process(input, None)?;
+        Ok(self.map_inner_processing_result(inner_result))
+    }
+}
+
+impl JxlDecoder<WithImageInfo> {
+    // TODO(veluca): once frame skipping is implemented properly, expose that in the API.
+
+    /// Obtains the image's basic information.
+    pub fn basic_info(&self) -> &JxlBasicInfo {
+        self.inner.basic_info().unwrap()
+    }
+
+    /// Retrieves the file's color profile.
+    pub fn embedded_color_profile(&self) -> &JxlColorProfile {
+        self.inner.embedded_color_profile().unwrap()
+    }
+
+    /// Retrieves the current output color profile.
+    pub fn output_color_profile(&self) -> &JxlColorProfile {
+        self.inner.output_color_profile().unwrap()
+    }
+
+    /// Specifies the preferred color profile to be used for outputting data.
+    /// Same semantics as JxlDecoderSetOutputColorProfile.
+    pub fn set_output_color_profile(&mut self, profile: JxlColorProfile) -> Result<()> {
+        self.inner.set_output_color_profile(profile)
+    }
+
+    pub fn current_pixel_format(&self) -> &JxlPixelFormat {
+        self.inner.current_pixel_format().unwrap()
+    }
+
+    pub fn set_pixel_format(&mut self, pixel_format: JxlPixelFormat) {
+        self.inner.set_pixel_format(pixel_format);
+    }
+
+    pub fn process(
+        mut self,
+        input: &mut impl JxlBitstreamInput,
+    ) -> Result<ProcessingResult<JxlDecoder<WithFrameInfo>, Self>> {
+        let inner_result = self.inner.process(input, None)?;
+        Ok(self.map_inner_processing_result(inner_result))
+    }
+
+    pub fn has_more_frames(&self) -> bool {
+        self.inner.has_more_frames()
+    }
+
+    #[cfg(test)]
+    pub(crate) fn set_use_simple_pipeline(&mut self, u: bool) {
+        self.inner.set_use_simple_pipeline(u);
+    }
+}
+
+impl JxlDecoder<WithFrameInfo> {
+    /// Skip the current frame.
+    pub fn skip_frame(
+        mut self,
+        input: &mut impl JxlBitstreamInput,
+    ) -> Result<ProcessingResult<JxlDecoder<WithImageInfo>, Self>> {
+        let inner_result = self.inner.process(input, None)?;
+        Ok(self.map_inner_processing_result(inner_result))
+    }
+
+    pub fn frame_header(&self) -> JxlFrameHeader {
+        self.inner.frame_header().unwrap()
+    }
+
+    /// Number of passes we have full data for.
+    pub fn num_completed_passes(&self) -> usize {
+        self.inner.num_completed_passes().unwrap()
+    }
+
+    /// Draws all the pixels we have data for.
+    pub fn flush_pixels(&mut self, buffers: &mut [JxlOutputBuffer<'_>]) -> Result<()> {
+        self.inner.flush_pixels(buffers)
+    }
+
+    /// Guarantees to populate exactly the appropriate part of the buffers.
+    /// Wants one buffer for each non-ignored pixel type, i.e. color channels and each extra channel.
+    pub fn process<In: JxlBitstreamInput>(
+        mut self,
+        input: &mut In,
+        buffers: &mut [JxlOutputBuffer<'_>],
+    ) -> Result<ProcessingResult<JxlDecoder<WithImageInfo>, Self>> {
+        let inner_result = self.inner.process(input, Some(buffers))?;
+        Ok(self.map_inner_processing_result(inner_result))
+    }
+}
+
+#[cfg(test)]
+pub(crate) mod tests {
+    use super::*;
+    use crate::api::{JxlDataFormat, JxlDecoderOptions};
+    use crate::error::Error;
+    use crate::image::{Image, Rect};
+    use crate::util::test::assert_almost_abs_eq_coords;
+    use jxl_macros::for_each_test_file;
+    use std::path::Path;
+
+    #[test]
+    fn decode_small_chunks() {
+        arbtest::arbtest(|u| {
+            decode(
+                &std::fs::read("resources/test/green_queen_vardct_e3.jxl").unwrap(),
+                u.arbitrary::<u8>().unwrap() as usize + 1,
+                false,
+                None,
+            )
+            .unwrap();
+            Ok(())
+        });
+    }
+
+    #[allow(clippy::type_complexity)]
+    pub fn decode(
+        mut input: &[u8],
+        chunk_size: usize,
+        use_simple_pipeline: bool,
+        callback: Option<Box<dyn FnMut(&Frame, usize) -> Result<(), Error>>>,
+    ) -> Result<(usize, Vec<Vec<Image<f32>>>), Error> {
+        let options = JxlDecoderOptions::default();
+        let mut initialized_decoder = JxlDecoder::<states::Initialized>::new(options);
+
+        if let Some(callback) = callback {
+            initialized_decoder.set_frame_callback(callback);
+        }
+
+        let mut chunk_input = &input[0..0];
+
+        macro_rules! advance_decoder {
+            ($decoder: ident $(, $extra_arg: expr)?) => {
+                loop {
+                    chunk_input =
+                        &input[..(chunk_input.len().saturating_add(chunk_size)).min(input.len())];
+                    let available_before = chunk_input.len();
+                    let process_result = $decoder.process(&mut chunk_input $(, $extra_arg)?);
+                    input = &input[(available_before - chunk_input.len())..];
+                    match process_result.unwrap() {
+                        ProcessingResult::Complete { result } => break result,
+                        ProcessingResult::NeedsMoreInput { fallback, .. } => {
+                            if input.is_empty() {
+                                panic!("Unexpected end of input");
+                            }
+                            $decoder = fallback;
+                        }
+                    }
+                }
+            };
+        }
+
+        // Process until we have image info
+        let mut decoder_with_image_info = advance_decoder!(initialized_decoder);
+        decoder_with_image_info.set_use_simple_pipeline(use_simple_pipeline);
+
+        // Get basic info
+        let basic_info = decoder_with_image_info.basic_info().clone();
+        assert!(basic_info.bit_depth.bits_per_sample() > 0);
+
+        // Get image dimensions (after upsampling, which is the actual output size)
+        let (buffer_width, buffer_height) = basic_info.size;
+        assert!(buffer_width > 0);
+        assert!(buffer_height > 0);
+
+        // Explicitly request F32 pixel format (test helper returns Image<f32>)
+        let default_format = decoder_with_image_info.current_pixel_format();
+        let requested_format = JxlPixelFormat {
+            color_type: default_format.color_type,
+            color_data_format: Some(JxlDataFormat::f32()),
+            extra_channel_format: default_format
+                .extra_channel_format
+                .iter()
+                .map(|_| Some(JxlDataFormat::f32()))
+                .collect(),
+        };
+        decoder_with_image_info.set_pixel_format(requested_format);
+
+        // Get the configured pixel format
+        let pixel_format = decoder_with_image_info.current_pixel_format().clone();
+
+        let num_channels = pixel_format.color_type.samples_per_pixel();
+        assert!(num_channels > 0);
+
+        let mut frames = vec![];
+
+        loop {
+            // Process until we have frame info
+            let mut decoder_with_frame_info = advance_decoder!(decoder_with_image_info);
+
+            // First channel is interleaved.
+            let mut buffers = vec![Image::new_with_value(
+                (buffer_width * num_channels, buffer_height),
+                f32::NAN,
+            )?];
+
+            for ecf in pixel_format.extra_channel_format.iter() {
+                if ecf.is_none() {
+                    continue;
+                }
+                buffers.push(Image::new_with_value(
+                    (buffer_width, buffer_height),
+                    f32::NAN,
+                )?);
+            }
+
+            let mut api_buffers: Vec<_> = buffers
+                .iter_mut()
+                .map(|b| {
+                    JxlOutputBuffer::from_image_rect_mut(
+                        b.get_rect_mut(Rect {
+                            origin: (0, 0),
+                            size: b.size(),
+                        })
+                        .into_raw(),
+                    )
+                })
+                .collect();
+
+            decoder_with_image_info = advance_decoder!(decoder_with_frame_info, &mut api_buffers);
+
+            // All pixels should have been overwritten, so they should no longer be NaNs.
+            for buf in buffers.iter() {
+                let (xs, ys) = buf.size();
+                for y in 0..ys {
+                    let row = buf.row(y);
+                    for (x, v) in row.iter().enumerate() {
+                        assert!(!v.is_nan(), "NaN at {x} {y} (image size {xs}x{ys})");
+                    }
+                }
+            }
+
+            frames.push(buffers);
+
+            // Check if there are more frames
+            if !decoder_with_image_info.has_more_frames() {
+                let decoded_frames = decoder_with_image_info.decoded_frames();
+
+                // Ensure we decoded at least one frame
+                assert!(decoded_frames > 0, "No frames were decoded");
+
+                return Ok((decoded_frames, frames));
+            }
+        }
+    }
+
+    fn decode_test_file(path: &Path) -> Result<(), Error> {
+        decode(&std::fs::read(path)?, usize::MAX, false, None)?;
+        Ok(())
+    }
+
+    for_each_test_file!(decode_test_file);
+
+    fn compare_pipelines(path: &Path) -> Result<(), Error> {
+        let file = std::fs::read(path)?;
+        let simple_frames = decode(&file, usize::MAX, true, None)?.1;
+        let frames = decode(&file, usize::MAX, false, None)?.1;
+        assert_eq!(frames.len(), simple_frames.len());
+        for (fc, (f, sf)) in frames
+            .into_iter()
+            .zip(simple_frames.into_iter())
+            .enumerate()
+        {
+            assert_eq!(
+                f.len(),
+                sf.len(),
+                "Frame {fc} has different channels counts",
+            );
+            for (c, (b, sb)) in f.into_iter().zip(sf.into_iter()).enumerate() {
+                assert_eq!(
+                    b.size(),
+                    sb.size(),
+                    "Channel {c} in frame {fc} has different sizes",
+                );
+                // TODO(veluca): This check actually succeeds if we disable SIMD.
+                // With SIMD, the exact output of computations in epf.rs appear to depend on the
+                // lane that the computation was done in (???). We should investigate this.
+                // b.as_rect().check_equal(sb.as_rect());
+                let sz = b.size();
+                if false {
+                    let f = std::fs::File::create(Path::new("/tmp/").join(format!(
+                        "{}_diff_chan{c}.pbm",
+                        path.as_os_str().to_string_lossy().replace("/", "_")
+                    )))?;
+                    use std::io::Write;
+                    let mut f = std::io::BufWriter::new(f);
+                    writeln!(f, "P1\n{} {}", sz.0, sz.1)?;
+                    for y in 0..sz.1 {
+                        for x in 0..sz.0 {
+                            if (b.row(y)[x] - sb.row(y)[x]).abs() > 1e-8 {
+                                write!(f, "1")?;
+                            } else {
+                                write!(f, "0")?;
+                            }
+                        }
+                    }
+                    drop(f);
+                }
+                for y in 0..sz.1 {
+                    for x in 0..sz.0 {
+                        assert_almost_abs_eq_coords(b.row(y)[x], sb.row(y)[x], 1e-5, (x, y), c);
+                    }
+                }
+            }
+        }
+        Ok(())
+    }
+
+    for_each_test_file!(compare_pipelines);
+
+    #[test]
+    fn test_preview_size_none_for_regular_files() {
+        let file = std::fs::read("resources/test/basic.jxl").unwrap();
+        let options = JxlDecoderOptions::default();
+        let mut decoder = JxlDecoder::<states::Initialized>::new(options);
+        let mut input = file.as_slice();
+        let decoder = loop {
+            match decoder.process(&mut input).unwrap() {
+                ProcessingResult::Complete { result } => break result,
+                ProcessingResult::NeedsMoreInput { fallback, .. } => decoder = fallback,
+            }
+        };
+        assert!(decoder.basic_info().preview_size.is_none());
+    }
+
+    #[test]
+    fn test_preview_size_some_for_preview_files() {
+        let file = std::fs::read("resources/test/with_preview.jxl").unwrap();
+        let options = JxlDecoderOptions::default();
+        let mut decoder = JxlDecoder::<states::Initialized>::new(options);
+        let mut input = file.as_slice();
+        let decoder = loop {
+            match decoder.process(&mut input).unwrap() {
+                ProcessingResult::Complete { result } => break result,
+                ProcessingResult::NeedsMoreInput { fallback, .. } => decoder = fallback,
+            }
+        };
+        assert_eq!(decoder.basic_info().preview_size, Some((16, 16)));
+    }
+
+    #[test]
+    fn test_num_completed_passes() {
+        use crate::image::{Image, Rect};
+        let file = std::fs::read("resources/test/basic.jxl").unwrap();
+        let options = JxlDecoderOptions::default();
+        let mut decoder = JxlDecoder::<states::Initialized>::new(options);
+        let mut input = file.as_slice();
+        // Process until we have image info
+        let mut decoder_with_info = loop {
+            match decoder.process(&mut input).unwrap() {
+                ProcessingResult::Complete { result } => break result,
+                ProcessingResult::NeedsMoreInput { fallback, .. } => decoder = fallback,
+            }
+        };
+        let info = decoder_with_info.basic_info().clone();
+        let mut decoder_with_frame = loop {
+            match decoder_with_info.process(&mut input).unwrap() {
+                ProcessingResult::Complete { result } => break result,
+                ProcessingResult::NeedsMoreInput { fallback, .. } => {
+                    decoder_with_info = fallback;
+                }
+            }
+        };
+        // Before processing frame, passes should be 0
+        assert_eq!(decoder_with_frame.num_completed_passes(), 0);
+        // Process the frame
+        let mut output = Image::<f32>::new((info.size.0 * 3, info.size.1)).unwrap();
+        let rect = Rect {
+            size: output.size(),
+            origin: (0, 0),
+        };
+        let mut bufs = [JxlOutputBuffer::from_image_rect_mut(
+            output.get_rect_mut(rect).into_raw(),
+        )];
+        loop {
+            match decoder_with_frame.process(&mut input, &mut bufs).unwrap() {
+                ProcessingResult::Complete { .. } => break,
+                ProcessingResult::NeedsMoreInput { fallback, .. } => decoder_with_frame = fallback,
+            }
+        }
+    }
+
+    #[test]
+    fn test_set_pixel_format() {
+        use crate::api::{JxlColorType, JxlDataFormat, JxlPixelFormat};
+
+        let file = std::fs::read("resources/test/basic.jxl").unwrap();
+        let options = JxlDecoderOptions::default();
+        let mut decoder = JxlDecoder::<states::Initialized>::new(options);
+        let mut input = file.as_slice();
+        let mut decoder = loop {
+            match decoder.process(&mut input).unwrap() {
+                ProcessingResult::Complete { result } => break result,
+                ProcessingResult::NeedsMoreInput { fallback, .. } => decoder = fallback,
+            }
+        };
+        // Check default pixel format
+        let default_format = decoder.current_pixel_format().clone();
+        assert_eq!(default_format.color_type, JxlColorType::Rgb);
+
+        // Set a new pixel format
+        let new_format = JxlPixelFormat {
+            color_type: JxlColorType::Grayscale,
+            color_data_format: Some(JxlDataFormat::U8 { bit_depth: 8 }),
+            extra_channel_format: vec![],
+        };
+        decoder.set_pixel_format(new_format.clone());
+
+        // Verify it was set
+        assert_eq!(decoder.current_pixel_format(), &new_format);
+    }
+
+    #[test]
+    fn test_set_output_color_profile() {
+        use crate::api::JxlColorProfile;
+
+        let file = std::fs::read("resources/test/basic.jxl").unwrap();
+        let options = JxlDecoderOptions::default();
+        let mut decoder = JxlDecoder::<states::Initialized>::new(options);
+        let mut input = file.as_slice();
+        let mut decoder = loop {
+            match decoder.process(&mut input).unwrap() {
+                ProcessingResult::Complete { result } => break result,
+                ProcessingResult::NeedsMoreInput { fallback, .. } => decoder = fallback,
+            }
+        };
+
+        // Get the embedded profile and set it as output (should work)
+        let embedded = decoder.embedded_color_profile().clone();
+        let result = decoder.set_output_color_profile(embedded);
+        assert!(result.is_ok());
+
+        // Setting an ICC profile without CMS should fail
+        let icc_profile = JxlColorProfile::Icc(vec![0u8; 100]);
+        let result = decoder.set_output_color_profile(icc_profile);
+        assert!(result.is_err());
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/inner/box_parser.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/inner/box_parser.rs
new file mode 100644
index 0000000..a59b723
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/inner/box_parser.rs
@@ -0,0 +1,171 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::error::{Error, Result};
+
+use crate::api::{
+    JxlBitstreamInput, JxlSignatureType, check_signature_internal, inner::process::SmallBuffer,
+};
+
+#[derive(Clone)]
+enum ParseState {
+    SignatureNeeded,
+    BoxNeeded,
+    CodestreamBox(u64),
+    SkippableBox(u64),
+}
+
+enum CodestreamBoxType {
+    None,
+    Jxlc,
+    Jxlp(u32),
+    LastJxlp,
+}
+
+pub(super) struct BoxParser {
+    pub(super) box_buffer: SmallBuffer<128>,
+    state: ParseState,
+    box_type: CodestreamBoxType,
+}
+
+impl BoxParser {
+    pub(super) fn new() -> Self {
+        BoxParser {
+            box_buffer: SmallBuffer::new(),
+            state: ParseState::SignatureNeeded,
+            box_type: CodestreamBoxType::None,
+        }
+    }
+
+    // Reads input until the next byte of codestream is available.
+    // This function might over-read bytes. Thus, the contents of self.box_buffer should always be
+    // read after this function call.
+    // Returns the number of codestream bytes that will be available to be read after this call,
+    // including any bytes in self.box_buffer.
+    // Might return `u64::MAX`, indicating that the rest of the file is codestream.
+    pub(super) fn get_more_codestream(&mut self, input: &mut dyn JxlBitstreamInput) -> Result<u64> {
+        loop {
+            match self.state.clone() {
+                ParseState::SignatureNeeded => {
+                    self.box_buffer.refill(|b| input.read(b), None)?;
+                    match check_signature_internal(&self.box_buffer)? {
+                        None => return Err(Error::InvalidSignature),
+                        Some(JxlSignatureType::Codestream) => {
+                            self.state = ParseState::CodestreamBox(u64::MAX);
+                            return Ok(u64::MAX);
+                        }
+                        Some(JxlSignatureType::Container) => {
+                            self.box_buffer
+                                .consume(JxlSignatureType::Container.signature().len());
+                            self.state = ParseState::BoxNeeded;
+                        }
+                    }
+                }
+                ParseState::CodestreamBox(b) => {
+                    return Ok(b);
+                }
+                ParseState::SkippableBox(mut s) => {
+                    let num = s.min(usize::MAX as u64) as usize;
+                    let skipped = if !self.box_buffer.is_empty() {
+                        self.box_buffer.consume(num)
+                    } else {
+                        input.skip(num)?
+                    };
+                    if skipped == 0 {
+                        return Err(Error::OutOfBounds(num));
+                    }
+                    s -= skipped as u64;
+                    if s == 0 {
+                        self.state = ParseState::BoxNeeded;
+                    } else {
+                        self.state = ParseState::SkippableBox(s);
+                    }
+                }
+                ParseState::BoxNeeded => {
+                    self.box_buffer.refill(|b| input.read(b), None)?;
+                    let min_len = match &self.box_buffer[..] {
+                        [0, 0, 0, 1, ..] => 16,
+                        _ => 8,
+                    };
+                    if self.box_buffer.len() <= min_len {
+                        return Err(Error::OutOfBounds(min_len - self.box_buffer.len()));
+                    }
+                    let ty: [_; 4] = self.box_buffer[4..8].try_into().unwrap();
+                    let extra_len = if &ty == b"jxlp" { 4 } else { 0 };
+                    if self.box_buffer.len() <= min_len + extra_len {
+                        return Err(Error::OutOfBounds(
+                            min_len + extra_len - self.box_buffer.len(),
+                        ));
+                    }
+                    let box_len = match &self.box_buffer[..] {
+                        [0, 0, 0, 1, ..] => {
+                            u64::from_be_bytes(self.box_buffer[8..16].try_into().unwrap())
+                        }
+                        _ => u32::from_be_bytes(self.box_buffer[0..4].try_into().unwrap()) as u64,
+                    };
+                    // Per JXL spec: jxlc box with length 0 has special meaning "extends to EOF"
+                    let content_len = if box_len == 0 && (&ty == b"jxlp" || &ty == b"jxlc") {
+                        u64::MAX
+                    } else {
+                        if box_len <= (min_len + extra_len) as u64 {
+                            return Err(Error::InvalidBox);
+                        }
+                        box_len - min_len as u64 - extra_len as u64
+                    };
+                    match &ty {
+                        b"jxlc" => {
+                            if matches!(
+                                self.box_type,
+                                CodestreamBoxType::Jxlp(..) | CodestreamBoxType::LastJxlp
+                            ) {
+                                return Err(Error::InvalidBox);
+                            }
+                            self.box_type = CodestreamBoxType::Jxlc;
+                            self.state = ParseState::CodestreamBox(content_len);
+                        }
+                        b"jxlp" => {
+                            let index = u32::from_be_bytes(
+                                self.box_buffer[min_len..min_len + 4].try_into().unwrap(),
+                            );
+                            let wanted_idx = match self.box_type {
+                                CodestreamBoxType::Jxlc | CodestreamBoxType::LastJxlp => {
+                                    return Err(Error::InvalidBox);
+                                }
+                                CodestreamBoxType::None => 0,
+                                CodestreamBoxType::Jxlp(i) => i + 1,
+                            };
+                            let last = index & 0x80000000 != 0;
+                            let idx = index & 0x7fffffff;
+                            if idx != wanted_idx {
+                                return Err(Error::InvalidBox);
+                            }
+                            self.box_type = if last {
+                                CodestreamBoxType::LastJxlp
+                            } else {
+                                CodestreamBoxType::Jxlp(idx)
+                            };
+                            self.state = ParseState::CodestreamBox(content_len);
+                        }
+                        _ => {
+                            self.state = ParseState::SkippableBox(content_len);
+                        }
+                    }
+                    self.box_buffer.consume(min_len + extra_len);
+                }
+            }
+        }
+    }
+
+    pub(super) fn consume_codestream(&mut self, amount: u64) {
+        if let ParseState::CodestreamBox(cb) = &mut self.state {
+            *cb = cb.checked_sub(amount).unwrap();
+            if *cb == 0 {
+                self.state = ParseState::BoxNeeded;
+            }
+        } else if amount != 0 {
+            unreachable!()
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/inner/codestream_parser/mod.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/inner/codestream_parser/mod.rs
new file mode 100644
index 0000000..412adab
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/inner/codestream_parser/mod.rs
@@ -0,0 +1,324 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::{collections::VecDeque, io::IoSliceMut};
+
+use sections::SectionState;
+
+#[cfg(test)]
+use crate::api::FrameCallback;
+use crate::{
+    api::{
+        JxlBasicInfo, JxlBitstreamInput, JxlColorProfile, JxlDecoderOptions, JxlOutputBuffer,
+        JxlPixelFormat,
+        inner::{box_parser::BoxParser, process::SmallBuffer},
+    },
+    error::{Error, Result},
+    frame::{DecoderState, Frame, Section},
+    headers::{Animation, FileHeader, frame_header::FrameHeader, toc::IncrementalTocReader},
+    icc::IncrementalIccReader,
+};
+
+mod non_section;
+mod sections;
+
+struct SectionBuffer {
+    len: usize,
+    data: Vec<u8>,
+    section: Section,
+}
+
+// This number should be big enough to guarantee that we can always make progress by reading
+// fragments of size at most *half* of it, if not reading a section.
+const NON_SECTION_CHUNK_SIZE: usize = 4096;
+
+pub(super) struct CodestreamParser {
+    // TODO(veluca): this would probably be cleaner with some kind of state enum.
+    pub(super) file_header: Option<FileHeader>,
+    icc_parser: Option<IncrementalIccReader>,
+    // These fields are populated once image information is available.
+    decoder_state: Option<DecoderState>,
+    pub(super) basic_info: Option<JxlBasicInfo>,
+    pub(super) animation: Option<Animation>,
+    pub(super) embedded_color_profile: Option<JxlColorProfile>,
+    pub(super) output_color_profile: Option<JxlColorProfile>,
+    pub(super) pixel_format: Option<JxlPixelFormat>,
+
+    // These fields are populated when starting to decode a frame, and cleared once
+    // the frame is done.
+    frame_header: Option<FrameHeader>,
+    toc_parser: Option<IncrementalTocReader>,
+    pub(super) frame: Option<Frame>,
+
+    // Buffers.
+    non_section_buf: SmallBuffer<NON_SECTION_CHUNK_SIZE>,
+    non_section_bit_offset: u8,
+    sections: VecDeque<SectionBuffer>,
+    ready_section_data: usize,
+    skip_sections: bool,
+    // True when we need to process frames without copying them to output buffers, e.g. reference frames
+    process_without_output: bool,
+    // True once the preview frame has been processed (if there is one)
+    preview_done: bool,
+    // Saved file header for recreating decoder state after preview frame
+    saved_file_header: Option<crate::headers::FileHeader>,
+
+    section_state: SectionState,
+    available_sections: Vec<SectionBuffer>,
+
+    pub(super) has_more_frames: bool,
+
+    #[cfg(test)]
+    pub frame_callback: Option<Box<FrameCallback>>,
+    #[cfg(test)]
+    pub decoded_frames: usize,
+}
+
+impl CodestreamParser {
+    pub(super) fn new() -> Self {
+        Self {
+            file_header: None,
+            icc_parser: None,
+            decoder_state: None,
+            basic_info: None,
+            animation: None,
+            embedded_color_profile: None,
+            output_color_profile: None,
+            pixel_format: None,
+            frame_header: None,
+            toc_parser: None,
+            frame: None,
+            non_section_buf: SmallBuffer::new(),
+            non_section_bit_offset: 0,
+            sections: VecDeque::new(),
+            ready_section_data: 0,
+            skip_sections: false,
+            process_without_output: false,
+            preview_done: false,
+            saved_file_header: None,
+            section_state: SectionState::new(0, 0),
+            available_sections: vec![],
+            has_more_frames: true,
+            #[cfg(test)]
+            frame_callback: None,
+            #[cfg(test)]
+            decoded_frames: 0,
+        }
+    }
+
+    fn has_visible_frame(&self) -> bool {
+        if let Some(frame) = &self.frame {
+            frame.header().is_visible()
+        } else {
+            false
+        }
+    }
+
+    /// Returns the number of passes that are fully completed across all groups.
+    pub(super) fn num_completed_passes(&self) -> usize {
+        self.section_state.num_completed_passes()
+    }
+
+    #[cfg(test)]
+    pub(crate) fn set_use_simple_pipeline(&mut self, u: bool) {
+        self.decoder_state
+            .as_mut()
+            .unwrap()
+            .set_use_simple_pipeline(u);
+    }
+
+    pub(super) fn process(
+        &mut self,
+        box_parser: &mut BoxParser,
+        input: &mut dyn JxlBitstreamInput,
+        decode_options: &JxlDecoderOptions,
+        mut output_buffers: Option<&mut [JxlOutputBuffer]>,
+    ) -> Result<()> {
+        if let Some(output_buffers) = &output_buffers {
+            let px = self.pixel_format.as_ref().unwrap();
+            let expected_len = std::iter::once(&px.color_data_format)
+                .chain(px.extra_channel_format.iter())
+                .filter(|x| x.is_some())
+                .count();
+            if output_buffers.len() != expected_len {
+                return Err(Error::WrongBufferCount(output_buffers.len(), expected_len));
+            }
+        }
+        // If we have sections to read, read into sections; otherwise, read into the local buffer.
+        loop {
+            if !self.sections.is_empty() {
+                let regular_frame = self.has_visible_frame();
+                if !self.process_without_output && output_buffers.is_none() {
+                    self.skip_sections = true;
+                }
+
+                if !self.skip_sections {
+                    // This is just an estimate as there could be box bytes in the middle.
+                    let mut readable_section_data = (self.non_section_buf.len()
+                        + input.available_bytes()?
+                        + self.ready_section_data)
+                        .max(1);
+                    // Ensure enough section buffers are available for reading available data.
+                    for buf in self.sections.iter_mut() {
+                        if buf.data.is_empty() {
+                            buf.data.resize(buf.len, 0);
+                        }
+                        readable_section_data =
+                            readable_section_data.saturating_sub(buf.data.len());
+                        if readable_section_data == 0 {
+                            break;
+                        }
+                    }
+                    // Read sections up to the end of the current box.
+                    let mut available_codestream = match box_parser.get_more_codestream(input) {
+                        Err(Error::OutOfBounds(_)) => 0,
+                        Ok(c) => c as usize,
+                        Err(e) => return Err(e),
+                    };
+                    let mut section_buffers = vec![];
+                    let mut ready = self.ready_section_data;
+                    for buf in self.sections.iter_mut() {
+                        if buf.data.is_empty() {
+                            break;
+                        }
+                        let len = buf.data.len();
+                        if len > ready {
+                            let readable = (available_codestream + ready).min(len);
+                            section_buffers.push(IoSliceMut::new(&mut buf.data[ready..readable]));
+                            available_codestream =
+                                available_codestream.saturating_sub(readable - ready);
+                            if available_codestream == 0 {
+                                break;
+                            }
+                        }
+                        ready = ready.saturating_sub(len);
+                    }
+                    let mut buffers = &mut section_buffers[..];
+                    loop {
+                        let num = if !box_parser.box_buffer.is_empty() {
+                            box_parser.box_buffer.take(buffers)
+                        } else {
+                            input.read(buffers)?
+                        };
+                        self.ready_section_data += num;
+                        box_parser.consume_codestream(num as u64);
+                        IoSliceMut::advance_slices(&mut buffers, num);
+                        if num == 0 || buffers.is_empty() {
+                            break;
+                        }
+                    }
+                    match self.process_sections(decode_options, &mut output_buffers) {
+                        Ok(None) => Ok(()),
+                        Ok(Some(missing)) => Err(Error::OutOfBounds(missing)),
+                        Err(Error::OutOfBounds(_)) => Err(Error::SectionTooShort),
+                        Err(err) => Err(err),
+                    }?;
+                } else {
+                    let total_size = self.sections.iter().map(|x| x.len).sum::<usize>();
+                    loop {
+                        let to_skip = total_size - self.ready_section_data;
+                        if to_skip == 0 {
+                            break;
+                        }
+                        let available_codestream = box_parser.get_more_codestream(input)? as usize;
+                        let to_skip = to_skip.min(available_codestream);
+                        let skipped = if !box_parser.box_buffer.is_empty() {
+                            box_parser.box_buffer.consume(to_skip)
+                        } else {
+                            input.skip(to_skip)?
+                        };
+                        box_parser.consume_codestream(skipped as u64);
+                        self.ready_section_data += skipped;
+                        if skipped == 0 {
+                            break;
+                        }
+                    }
+                    if self.ready_section_data < total_size {
+                        return Err(Error::OutOfBounds(total_size - self.ready_section_data));
+                    } else {
+                        self.sections.clear();
+                    }
+                }
+                if self.sections.is_empty() {
+                    // Go back to parsing a new frame header, if any.
+                    // Only return if this was a regular visible frame that was actually decoded
+                    // (not a frame we were skipping like a preview frame)
+                    let was_skipping = self.process_without_output;
+                    self.process_without_output = false;
+                    if regular_frame && !was_skipping {
+                        return Ok(());
+                    }
+                    continue;
+                }
+            } else {
+                // Trying to read a frame or a file header.
+                assert!(self.frame.is_none());
+                assert!(self.has_more_frames);
+
+                // Loop to handle incremental parsing (e.g. large ICC profiles) that may need
+                // multiple buffer refills to complete.
+                loop {
+                    let available_codestream = match box_parser.get_more_codestream(input) {
+                        Err(Error::OutOfBounds(_)) => 0,
+                        Ok(c) => c as usize,
+                        Err(e) => return Err(e),
+                    };
+                    let c = self.non_section_buf.refill(
+                        |buf| {
+                            if !box_parser.box_buffer.is_empty() {
+                                Ok(box_parser.box_buffer.take(buf))
+                            } else {
+                                input.read(buf)
+                            }
+                        },
+                        Some(available_codestream),
+                    )?;
+                    box_parser.consume_codestream(c as u64);
+
+                    match self.process_non_section(decode_options) {
+                        Ok(()) => break,
+                        Err(Error::OutOfBounds(n)) => {
+                            // Check if input still has data - if so, refill and retry
+                            if input.available_bytes().unwrap_or(0) > 0 {
+                                continue;
+                            } else {
+                                return Err(Error::OutOfBounds(n));
+                            }
+                        }
+                        Err(e) => return Err(e),
+                    }
+                }
+
+                if self.decoder_state.is_some() && self.frame_header.is_none() {
+                    // Return to caller if we found image info.
+                    return Ok(());
+                }
+                if self.frame.is_some() {
+                    // Check if this is a preview frame that should be skipped
+                    let is_preview_frame = !self.preview_done
+                        && self
+                            .basic_info
+                            .as_ref()
+                            .is_some_and(|info| info.preview_size.is_some());
+                    if is_preview_frame {
+                        self.preview_done = true;
+                        if decode_options.skip_preview {
+                            self.process_without_output = true;
+                            continue;
+                        }
+                    }
+
+                    if self.has_visible_frame() {
+                        // Return to caller if we found visible frame info.
+                        return Ok(());
+                    } else {
+                        self.process_without_output = true;
+                        continue;
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/inner/codestream_parser/non_section.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/inner/codestream_parser/non_section.rs
new file mode 100644
index 0000000..28a4b6d5
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/inner/codestream_parser/non_section.rs
@@ -0,0 +1,327 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::io::IoSliceMut;
+
+use crate::{
+    api::{
+        Endianness, JxlBasicInfo, JxlBitDepth, JxlColorEncoding, JxlColorProfile, JxlColorType,
+        JxlDataFormat, JxlDecoderOptions, JxlExtraChannel, JxlPixelFormat, JxlTransferFunction,
+        inner::codestream_parser::SectionState,
+    },
+    bit_reader::BitReader,
+    error::{Error, Result},
+    frame::{DecoderState, Frame, Section},
+    headers::{
+        FileHeader, JxlHeader, color_encoding::ColorSpace, encodings::UnconditionalCoder,
+        frame_header::FrameHeader, toc::IncrementalTocReader,
+    },
+    icc::IncrementalIccReader,
+};
+
+use super::{CodestreamParser, SectionBuffer};
+use crate::api::ToneMapping;
+
+impl CodestreamParser {
+    #[cold]
+    pub(super) fn process_non_section(&mut self, decode_options: &JxlDecoderOptions) -> Result<()> {
+        if self.decoder_state.is_none() && self.file_header.is_none() {
+            // We don't have a file header yet. Try parsing that.
+            // TODO(veluca): make this incremental, as a file header might be multiple megabytes.
+            let mut br = BitReader::new(&self.non_section_buf);
+            br.skip_bits(self.non_section_bit_offset as usize)?;
+            let file_header = FileHeader::read(&mut br)?;
+            let data = &file_header.image_metadata;
+            self.animation = data.animation.clone();
+            self.basic_info = Some(JxlBasicInfo {
+                size: if data.orientation.is_transposing() {
+                    (
+                        file_header.size.ysize() as usize,
+                        file_header.size.xsize() as usize,
+                    )
+                } else {
+                    (
+                        file_header.size.xsize() as usize,
+                        file_header.size.ysize() as usize,
+                    )
+                },
+                bit_depth: if data.bit_depth.floating_point_sample() {
+                    JxlBitDepth::Float {
+                        bits_per_sample: data.bit_depth.bits_per_sample(),
+                        exponent_bits_per_sample: data.bit_depth.exponent_bits_per_sample(),
+                    }
+                } else {
+                    JxlBitDepth::Int {
+                        bits_per_sample: data.bit_depth.bits_per_sample(),
+                    }
+                },
+                orientation: data.orientation,
+                extra_channels: data
+                    .extra_channel_info
+                    .iter()
+                    .map(|info| JxlExtraChannel {
+                        ec_type: info.ec_type,
+                        alpha_associated: info.alpha_associated(),
+                    })
+                    .collect(),
+                animation: data
+                    .animation
+                    .as_ref()
+                    .map(|anim| crate::api::JxlAnimation {
+                        tps_numerator: anim.tps_numerator,
+                        tps_denominator: anim.tps_denominator,
+                        num_loops: anim.num_loops,
+                        have_timecodes: anim.have_timecodes,
+                    }),
+                uses_original_profile: !data.xyb_encoded,
+                tone_mapping: ToneMapping {
+                    intensity_target: data.tone_mapping.intensity_target,
+                    min_nits: data.tone_mapping.min_nits,
+                    relative_to_max_display: data.tone_mapping.relative_to_max_display,
+                    linear_below: data.tone_mapping.linear_below,
+                },
+                preview_size: data
+                    .preview
+                    .as_ref()
+                    .map(|p| (p.xsize() as usize, p.ysize() as usize)),
+            });
+            self.file_header = Some(file_header);
+            let bits = br.total_bits_read();
+            self.non_section_buf.consume(bits / 8);
+            self.non_section_bit_offset = (bits % 8) as u8;
+        }
+
+        if self.decoder_state.is_none() && self.embedded_color_profile.is_none() {
+            let file_header = self.file_header.as_ref().unwrap();
+            // Parse (or extract from file header) the ICC profile.
+            let mut br = BitReader::new(&self.non_section_buf);
+            br.skip_bits(self.non_section_bit_offset as usize)?;
+            let embedded_color_profile = if file_header.image_metadata.color_encoding.want_icc {
+                if self.icc_parser.is_none() {
+                    self.icc_parser = Some(IncrementalIccReader::new(&mut br)?);
+                }
+                let icc_parser = self.icc_parser.as_mut().unwrap();
+                let mut bits = br.total_bits_read();
+                for _ in 0..icc_parser.remaining() {
+                    match icc_parser.read_one(&mut br) {
+                        Ok(()) => bits = br.total_bits_read(),
+                        Err(Error::OutOfBounds(c)) => {
+                            self.non_section_buf.consume(bits / 8);
+                            self.non_section_bit_offset = (bits % 8) as u8;
+                            // Estimate >= one bit per remaining character to read.
+                            return Err(Error::OutOfBounds(c + icc_parser.remaining() / 8));
+                        }
+                        Err(e) => return Err(e),
+                    }
+                }
+                let icc_result = self.icc_parser.take().unwrap().finalize(&mut br);
+                self.non_section_buf.consume(bits / 8);
+                self.non_section_bit_offset = (bits % 8) as u8;
+                JxlColorProfile::Icc(icc_result?)
+            } else {
+                JxlColorProfile::Simple(JxlColorEncoding::from_internal(
+                    &file_header.image_metadata.color_encoding,
+                )?)
+            };
+            let output_color_profile = if file_header.image_metadata.xyb_encoded {
+                let nonlinear_output_color_profile = match &embedded_color_profile {
+                    JxlColorProfile::Icc(_) => JxlColorEncoding::srgb(
+                        file_header.image_metadata.color_encoding.color_space == ColorSpace::Gray,
+                    ),
+                    JxlColorProfile::Simple(encoding) => encoding.clone(),
+                };
+                JxlColorProfile::Simple(if decode_options.xyb_output_linear {
+                    match nonlinear_output_color_profile {
+                        JxlColorEncoding::RgbColorSpace {
+                            white_point,
+                            primaries,
+                            transfer_function: _,
+                            rendering_intent,
+                        } => JxlColorEncoding::RgbColorSpace {
+                            white_point,
+                            primaries,
+                            transfer_function: JxlTransferFunction::Linear,
+                            rendering_intent,
+                        },
+                        JxlColorEncoding::GrayscaleColorSpace {
+                            white_point,
+                            transfer_function: _,
+                            rendering_intent,
+                        } => JxlColorEncoding::GrayscaleColorSpace {
+                            white_point,
+                            transfer_function: JxlTransferFunction::Linear,
+                            rendering_intent,
+                        },
+                        JxlColorEncoding::XYB { .. } => unreachable!(),
+                    }
+                } else {
+                    nonlinear_output_color_profile
+                })
+            } else {
+                embedded_color_profile.clone()
+            };
+            self.embedded_color_profile = Some(embedded_color_profile);
+            self.output_color_profile = Some(output_color_profile);
+            self.pixel_format = Some(JxlPixelFormat {
+                color_type: if file_header.image_metadata.color_encoding.color_space
+                    == ColorSpace::Gray
+                {
+                    JxlColorType::Grayscale
+                } else {
+                    JxlColorType::Rgb
+                },
+                color_data_format: Some(JxlDataFormat::F32 {
+                    endianness: Endianness::native(),
+                }),
+                extra_channel_format: vec![
+                    Some(JxlDataFormat::F32 {
+                        endianness: Endianness::native()
+                    });
+                    file_header.image_metadata.extra_channel_info.len()
+                ],
+            });
+
+            let mut br = BitReader::new(&self.non_section_buf);
+            br.skip_bits(self.non_section_bit_offset as usize)?;
+            br.jump_to_byte_boundary()?;
+            self.non_section_buf.consume(br.total_bits_read() / 8);
+
+            // We now have image information.
+            let mut decoder_state = DecoderState::new(self.file_header.take().unwrap());
+            decoder_state.xyb_output_linear = decode_options.xyb_output_linear;
+            decoder_state.render_spotcolors = decode_options.render_spot_colors;
+            decoder_state.high_precision = decode_options.high_precision;
+            self.decoder_state = Some(decoder_state);
+            // Reset bit offset to 0 since we've consumed everything up to a byte boundary
+            self.non_section_bit_offset = 0;
+            return Ok(());
+        }
+
+        let decoder_state = self.decoder_state.as_mut().unwrap();
+
+        if self.frame_header.is_none() {
+            // We don't have a frame header yet. Try parsing that.
+            // TODO(veluca): do we need to make this incremental?
+            let mut br = BitReader::new(&self.non_section_buf);
+            br.skip_bits(self.non_section_bit_offset as usize)?;
+
+            // For preview frames, use the preview dimensions instead of main image dimensions
+            let nonserialized = if !self.preview_done {
+                decoder_state
+                    .file_header
+                    .preview_frame_header_nonserialized()
+                    .unwrap_or_else(|| decoder_state.file_header.frame_header_nonserialized())
+            } else {
+                decoder_state.file_header.frame_header_nonserialized()
+            };
+
+            let mut frame_header = FrameHeader::read_unconditional(&(), &mut br, &nonserialized)?;
+            frame_header.postprocess(&nonserialized);
+            self.frame_header = Some(frame_header);
+            let bits = br.total_bits_read();
+            self.non_section_buf.consume(bits / 8);
+            self.non_section_bit_offset = (bits % 8) as u8;
+        }
+
+        let toc = {
+            let mut br = BitReader::new(&self.non_section_buf);
+            br.skip_bits(self.non_section_bit_offset as usize)?;
+            if self.toc_parser.is_none() {
+                let num_toc_entries = self.frame_header.as_ref().unwrap().num_toc_entries();
+                self.toc_parser = Some(IncrementalTocReader::new(num_toc_entries as u32, &mut br)?);
+            }
+
+            let toc_parser = self.toc_parser.as_mut().unwrap();
+            let mut bits = br.total_bits_read();
+            while !toc_parser.is_complete() {
+                match toc_parser.read_step(&mut br) {
+                    Ok(()) => bits = br.total_bits_read(),
+                    Err(Error::OutOfBounds(c)) => {
+                        self.non_section_buf.consume(bits / 8);
+                        self.non_section_bit_offset = (bits % 8) as u8;
+                        // Estimate >= 16 bits per remaining entry to read.
+                        return Err(Error::OutOfBounds(
+                            c + toc_parser.remaining_entries() as usize * 2,
+                        ));
+                    }
+                    Err(e) => return Err(e),
+                }
+            }
+            br.jump_to_byte_boundary()?;
+
+            bits = br.total_bits_read();
+            self.non_section_buf.consume(bits / 8);
+            self.non_section_bit_offset = (bits % 8) as u8;
+            self.toc_parser.take().unwrap().finalize()
+        };
+
+        // Save file_header before creating frame (for preview frame recovery)
+        self.saved_file_header = self.decoder_state.as_ref().map(|ds| ds.file_header.clone());
+
+        let frame = Frame::from_header_and_toc(
+            self.frame_header.take().unwrap(),
+            toc,
+            self.decoder_state.take().unwrap(),
+        )?;
+
+        let mut sections: Vec<_> = frame
+            .toc()
+            .entries
+            .iter()
+            .map(|x| SectionBuffer {
+                len: *x as usize,
+                data: vec![],
+                section: Section::LfGlobal, // will be fixed later
+            })
+            .collect();
+
+        let order = if frame.toc().permuted {
+            frame.toc().permutation.0.clone()
+        } else {
+            (0..sections.len() as u32).collect()
+        };
+
+        if sections.len() > 1 {
+            let base_sections = [Section::LfGlobal, Section::HfGlobal];
+            let lf_sections = (0..frame.header().num_lf_groups()).map(|x| Section::Lf { group: x });
+            let hf_sections = (0..frame.header().passes.num_passes).flat_map(|p| {
+                (0..frame.header().num_groups()).map(move |g| Section::Hf {
+                    group: g,
+                    pass: p as usize,
+                })
+            });
+
+            for section in base_sections
+                .into_iter()
+                .chain(lf_sections)
+                .chain(hf_sections)
+            {
+                sections[order[frame.get_section_idx(section)] as usize].section = section;
+            }
+        }
+
+        self.sections = sections.into_iter().collect();
+        self.ready_section_data = 0;
+
+        // Move data from the pre-section buffer into the sections.
+        for buf in self.sections.iter_mut() {
+            if self.non_section_buf.is_empty() {
+                break;
+            }
+            buf.data = vec![0; buf.len];
+            self.ready_section_data += self
+                .non_section_buf
+                .take(&mut [IoSliceMut::new(&mut buf.data)]);
+        }
+
+        self.section_state =
+            SectionState::new(frame.header().num_lf_groups(), frame.header().num_groups());
+        assert!(self.available_sections.is_empty());
+
+        self.frame = Some(frame);
+
+        Ok(())
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/inner/codestream_parser/sections.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/inner/codestream_parser/sections.rs
new file mode 100644
index 0000000..b60520e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/inner/codestream_parser/sections.rs
@@ -0,0 +1,225 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{
+    api::{JxlDecoderOptions, JxlOutputBuffer},
+    bit_reader::BitReader,
+    error::Result,
+    frame::Section,
+};
+
+use super::CodestreamParser;
+
+pub(super) struct SectionState {
+    lf_global_done: bool,
+    remaining_lf: usize,
+    hf_global_done: bool,
+    completed_passes: Vec<u8>,
+}
+
+impl SectionState {
+    pub(super) fn new(num_lf_groups: usize, num_groups: usize) -> Self {
+        Self {
+            lf_global_done: false,
+            remaining_lf: num_lf_groups,
+            hf_global_done: false,
+            completed_passes: vec![0; num_groups],
+        }
+    }
+
+    /// Returns the number of passes that are fully completed across all groups.
+    /// A pass is fully completed when all groups have decoded that pass.
+    pub(super) fn num_completed_passes(&self) -> usize {
+        self.completed_passes.iter().copied().min().unwrap_or(0) as usize
+    }
+}
+
+// No guarantees on the order of calls to f, or the order of retained elements in vec.
+fn retain_by_value<T>(vec: &mut Vec<T>, mut f: impl FnMut(T) -> Option<T>) {
+    for pos in (0..vec.len()).rev() {
+        let element_to_test = vec.swap_remove(pos);
+        if let Some(v) = f(element_to_test) {
+            vec.push(v);
+        }
+    }
+}
+
+impl CodestreamParser {
+    pub(super) fn process_sections(
+        &mut self,
+        decode_options: &JxlDecoderOptions,
+        output_buffers: &mut Option<&mut [JxlOutputBuffer<'_>]>,
+    ) -> Result<Option<usize>> {
+        // Dequeue ready sections.
+        while self
+            .sections
+            .front()
+            .is_some_and(|s| s.len <= self.ready_section_data)
+        {
+            let s = self.sections.pop_front().unwrap();
+            self.ready_section_data -= s.len;
+            self.available_sections.push(s);
+        }
+        if self.available_sections.is_empty() {
+            return Ok(Some(
+                self.sections.front().unwrap().len - self.ready_section_data,
+            ));
+        }
+        let frame = self.frame.as_mut().unwrap();
+        let frame_header = frame.header();
+        let pixel_format = self.pixel_format.as_ref().unwrap();
+        if frame_header.num_groups() == 1 && frame_header.passes.num_passes == 1 {
+            // Single-group special case.
+            assert_eq!(self.available_sections.len(), 1);
+            assert!(self.sections.is_empty());
+            let mut br = BitReader::new(&self.available_sections[0].data);
+            frame.decode_lf_global(&mut br)?;
+            frame.decode_lf_group(0, &mut br)?;
+            frame.decode_hf_global(&mut br)?;
+            frame.prepare_render_pipeline(
+                self.pixel_format.as_ref().unwrap(),
+                decode_options.cms.as_deref(),
+            )?;
+            frame.finalize_lf()?;
+            frame.decode_and_render_hf_groups(
+                output_buffers,
+                pixel_format,
+                vec![(0, vec![(0, br)])],
+            )?;
+            self.available_sections.clear();
+        } else {
+            let mut lf_global_section = None;
+            let mut lf_sections = vec![];
+            let mut hf_global_section = None;
+            let mut sorted_sections_for_each_group = Vec::with_capacity(frame_header.num_groups());
+            for _ in 0..frame_header.num_groups() {
+                sorted_sections_for_each_group.push(vec![]);
+            }
+
+            loop {
+                let initial_sz = self.available_sections.len();
+                retain_by_value(&mut self.available_sections, |sec| match sec.section {
+                    Section::LfGlobal => {
+                        lf_global_section = Some(sec);
+                        self.section_state.lf_global_done = true;
+                        None
+                    }
+                    Section::Lf { .. } => {
+                        if !self.section_state.lf_global_done {
+                            Some(sec)
+                        } else {
+                            lf_sections.push(sec);
+                            self.section_state.remaining_lf -= 1;
+                            None
+                        }
+                    }
+                    Section::HfGlobal => {
+                        if self.section_state.remaining_lf != 0 {
+                            Some(sec)
+                        } else {
+                            hf_global_section = Some(sec);
+                            self.section_state.hf_global_done = true;
+                            None
+                        }
+                    }
+                    Section::Hf { group, pass } => {
+                        if !self.section_state.hf_global_done
+                            || self.section_state.completed_passes[group] != pass as u8
+                        {
+                            Some(sec)
+                        } else {
+                            sorted_sections_for_each_group[group].push(sec);
+                            self.section_state.completed_passes[group] += 1;
+                            None
+                        }
+                    }
+                });
+                if self.available_sections.len() == initial_sz {
+                    break;
+                }
+            }
+
+            if let Some(lf_global) = lf_global_section {
+                frame.decode_lf_global(&mut BitReader::new(&lf_global.data))?;
+            }
+
+            for lf_section in lf_sections {
+                let Section::Lf { group } = lf_section.section else {
+                    unreachable!()
+                };
+                frame.decode_lf_group(group, &mut BitReader::new(&lf_section.data))?;
+            }
+
+            if let Some(hf_global) = hf_global_section {
+                frame.decode_hf_global(&mut BitReader::new(&hf_global.data))?;
+                frame.prepare_render_pipeline(
+                    self.pixel_format.as_ref().unwrap(),
+                    decode_options.cms.as_deref(),
+                )?;
+                frame.finalize_lf()?;
+            }
+
+            let groups = sorted_sections_for_each_group
+                .iter()
+                .enumerate()
+                .map(|(g, grp)| {
+                    (
+                        g,
+                        grp.iter()
+                            .map(|sec| {
+                                let Section::Hf { group, pass } = sec.section else {
+                                    unreachable!()
+                                };
+                                assert_eq!(group, g);
+                                (pass, BitReader::new(&sec.data))
+                            })
+                            .collect(),
+                    )
+                })
+                .collect();
+
+            frame.decode_and_render_hf_groups(output_buffers, pixel_format, groups)?;
+        }
+
+        // Frame is not yet complete.
+        if !self.sections.is_empty() {
+            return Ok(None);
+        }
+        assert!(self.available_sections.is_empty());
+
+        #[cfg(test)]
+        {
+            self.frame_callback.as_mut().map_or(Ok(()), |cb| {
+                cb(self.frame.as_ref().unwrap(), self.decoded_frames)
+            })?;
+            self.decoded_frames += 1;
+        }
+
+        // Check if this might be a preview frame (skipped frame with preview enabled)
+        let has_preview = self
+            .basic_info
+            .as_ref()
+            .is_some_and(|info| info.preview_size.is_some());
+        let might_be_preview = self.process_without_output && has_preview;
+
+        let decoder_state = self.frame.take().unwrap().finalize()?;
+        if let Some(state) = decoder_state {
+            self.decoder_state = Some(state);
+        } else if might_be_preview {
+            // Preview frame has is_last=true but the main frame follows.
+            // Recreate decoder state from saved file header for the main frame.
+            if let Some(fh) = self.saved_file_header.take() {
+                let mut new_state = crate::frame::DecoderState::new(fh);
+                new_state.xyb_output_linear = decode_options.xyb_output_linear;
+                new_state.render_spotcolors = decode_options.render_spot_colors;
+                new_state.enable_output = decode_options.enable_output;
+                self.decoder_state = Some(new_state);
+            }
+        } else {
+            self.has_more_frames = false;
+        }
+        Ok(None)
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/inner/mod.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/inner/mod.rs
new file mode 100644
index 0000000..33a95c8
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/inner/mod.rs
@@ -0,0 +1,119 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#[cfg(test)]
+use crate::api::FrameCallback;
+use crate::{
+    api::JxlFrameHeader,
+    error::{Error, Result},
+};
+
+use super::{JxlBasicInfo, JxlColorProfile, JxlDecoderOptions, JxlPixelFormat};
+use box_parser::BoxParser;
+use codestream_parser::CodestreamParser;
+
+mod box_parser;
+mod codestream_parser;
+mod process;
+
+/// Low-level, less-type-safe API.
+pub struct JxlDecoderInner {
+    options: JxlDecoderOptions,
+    box_parser: BoxParser,
+    codestream_parser: CodestreamParser,
+}
+
+impl JxlDecoderInner {
+    /// Creates a new decoder with the given options and, optionally, CMS.
+    pub fn new(options: JxlDecoderOptions) -> Self {
+        JxlDecoderInner {
+            options,
+            box_parser: BoxParser::new(),
+            codestream_parser: CodestreamParser::new(),
+        }
+    }
+
+    #[cfg(test)]
+    pub fn set_frame_callback(&mut self, callback: Box<FrameCallback>) {
+        self.codestream_parser.frame_callback = Some(callback);
+    }
+
+    #[cfg(test)]
+    pub fn decoded_frames(&self) -> usize {
+        self.codestream_parser.decoded_frames
+    }
+
+    /// Obtains the image's basic information, if available.
+    pub fn basic_info(&self) -> Option<&JxlBasicInfo> {
+        self.codestream_parser.basic_info.as_ref()
+    }
+
+    /// Retrieves the file's color profile, if available.
+    pub fn embedded_color_profile(&self) -> Option<&JxlColorProfile> {
+        self.codestream_parser.embedded_color_profile.as_ref()
+    }
+
+    /// Retrieves the current output color profile, if available.
+    pub fn output_color_profile(&self) -> Option<&JxlColorProfile> {
+        self.codestream_parser.output_color_profile.as_ref()
+    }
+
+    /// Specifies the preferred color profile to be used for outputting data.
+    /// Same semantics as JxlDecoderSetOutputColorProfile.
+    pub fn set_output_color_profile(&mut self, profile: JxlColorProfile) -> Result<()> {
+        if let (JxlColorProfile::Icc(_), None) = (&profile, &self.options.cms) {
+            return Err(Error::ICCOutputNoCMS);
+        }
+        self.codestream_parser.output_color_profile = Some(profile);
+        Ok(())
+    }
+
+    pub fn current_pixel_format(&self) -> Option<&JxlPixelFormat> {
+        self.codestream_parser.pixel_format.as_ref()
+    }
+
+    pub fn set_pixel_format(&mut self, pixel_format: JxlPixelFormat) {
+        self.codestream_parser.pixel_format = Some(pixel_format);
+    }
+
+    pub fn frame_header(&self) -> Option<JxlFrameHeader> {
+        let frame_header = self.codestream_parser.frame.as_ref()?.header();
+        // The render pipeline always adds ExtendToImageDimensionsStage which extends
+        // frames to the full image size. So the output size is always the image size,
+        // not the frame's upsampled size.
+        let size = self.codestream_parser.basic_info.as_ref()?.size;
+        Some(JxlFrameHeader {
+            name: frame_header.name.clone(),
+            duration: self
+                .codestream_parser
+                .animation
+                .as_ref()
+                .map(|anim| frame_header.duration(anim)),
+            size,
+        })
+    }
+
+    /// Number of passes we have full data for.
+    /// Returns the minimum number of passes completed across all groups.
+    pub fn num_completed_passes(&self) -> Option<usize> {
+        Some(self.codestream_parser.num_completed_passes())
+    }
+
+    /// Rewinds a decoder to the start of the file, allowing past frames to be displayed again.
+    pub fn rewind(&mut self) {
+        // TODO(veluca): keep track of frame offsets for skipping.
+        self.box_parser = BoxParser::new();
+        self.codestream_parser = CodestreamParser::new();
+    }
+
+    pub fn has_more_frames(&self) -> bool {
+        self.codestream_parser.has_more_frames
+    }
+
+    #[cfg(test)]
+    pub(crate) fn set_use_simple_pipeline(&mut self, u: bool) {
+        self.codestream_parser.set_use_simple_pipeline(u);
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/inner/process.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/inner/process.rs
new file mode 100644
index 0000000..8f3f4c3
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/inner/process.rs
@@ -0,0 +1,121 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::{
+    io::IoSliceMut,
+    ops::{Deref, Range},
+};
+
+use crate::error::Result;
+
+use crate::api::{JxlBitstreamInput, JxlDecoderInner, JxlOutputBuffer, ProcessingResult};
+
+// General implementation strategy:
+// - Anything that is not a section is read into a small buffer.
+// - As soon as we know section sizes, data is read directly into sections.
+// When the start of the populated range in `buf` goes past half of its length,
+// the data in the buffer is moved back to the beginning.
+
+pub(super) struct SmallBuffer<const SIZE: usize> {
+    buf: [u8; SIZE],
+    range: Range<usize>,
+}
+
+impl<const SIZE: usize> SmallBuffer<SIZE> {
+    pub(super) fn refill(
+        &mut self,
+        mut get_input: impl FnMut(&mut [IoSliceMut]) -> Result<usize, std::io::Error>,
+        max: Option<usize>,
+    ) -> Result<usize> {
+        let mut total = 0;
+        loop {
+            if self.range.start >= SIZE / 2 {
+                let start = self.range.start;
+                let len = self.range.len();
+                let (pre, post) = self.buf.split_at_mut(start);
+                pre[0..len].copy_from_slice(&post[0..len]);
+                self.range.start -= start;
+                self.range.end -= start;
+            }
+            if self.range.len() >= SIZE / 2 {
+                break;
+            }
+            let stop = if let Some(max) = max {
+                (self.range.end + max.saturating_sub(total)).min(SIZE)
+            } else {
+                SIZE
+            };
+            let num = get_input(&mut [IoSliceMut::new(&mut self.buf[self.range.end..stop])])?;
+            total += num;
+            self.range.end += num;
+            if num == 0 {
+                break;
+            }
+        }
+        Ok(total)
+    }
+
+    pub(super) fn take(&mut self, mut buffers: &mut [IoSliceMut]) -> usize {
+        let mut num = 0;
+        while !self.range.is_empty() {
+            let Some((buf, rest)) = buffers.split_first_mut() else {
+                break;
+            };
+            buffers = rest;
+            let len = self.range.len().min(buf.len());
+            // Only copy 'len' bytes, not the entire range, to avoid panic when buf is smaller than range
+            buf[..len].copy_from_slice(&self.buf[self.range.start..self.range.start + len]);
+            self.range.start += len;
+            num += len;
+        }
+        num
+    }
+
+    pub(super) fn consume(&mut self, amount: usize) -> usize {
+        let amount = amount.min(self.range.len());
+        self.range.start += amount;
+        amount
+    }
+
+    pub(super) fn new() -> Self {
+        Self {
+            buf: [0; SIZE],
+            range: 0..0,
+        }
+    }
+}
+
+impl<const SIZE: usize> Deref for SmallBuffer<SIZE> {
+    type Target = [u8];
+    fn deref(&self) -> &Self::Target {
+        &self.buf[self.range.clone()]
+    }
+}
+
+impl JxlDecoderInner {
+    /// Process more of the input file.
+    /// This function will return when reaching the next decoding stage (i.e. finished decoding
+    /// file/frame header, or finished decoding a frame).
+    /// If called when decoding a frame with `None` for buffers, the frame will still be read,
+    /// but pixel data will not be produced.
+    #[inline(never)]
+    pub fn process(
+        &mut self,
+        input: &mut dyn JxlBitstreamInput,
+        buffers: Option<&mut [JxlOutputBuffer]>,
+    ) -> Result<ProcessingResult<(), ()>> {
+        ProcessingResult::new(self.codestream_parser.process(
+            &mut self.box_parser,
+            input,
+            &self.options,
+            buffers,
+        ))
+    }
+
+    /// Draws all the pixels we have data for.
+    pub fn flush_pixels(&mut self, _buffers: &mut [JxlOutputBuffer]) -> Result<()> {
+        todo!()
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/input.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/input.rs
new file mode 100644
index 0000000..5e87925
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/input.rs
@@ -0,0 +1,82 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::io::{BufRead, BufReader, Error, IoSliceMut, Read, Seek, SeekFrom};
+
+pub trait JxlBitstreamInput {
+    /// Returns an estimate bound of the total number of bytes that can be read via `read`.
+    /// Returning a too-low estimate here can impede parallelism. Returning a too-high
+    /// estimate can increase memory usage.
+    fn available_bytes(&mut self) -> Result<usize, Error>;
+
+    /// Fills in `bufs` with more bytes, returning the number of bytes written.
+    /// Buffers are filled in order and to completion.
+    fn read(&mut self, bufs: &mut [IoSliceMut]) -> Result<usize, Error>;
+
+    /// Skips up to `bytes` bytes of input. The provided implementation just uses `read`, but in
+    /// some cases this can be implemented faster.
+    /// Returns the number of bytes that were skipped. If this returns 0, it is assumed that no
+    /// more input is available.
+    fn skip(&mut self, bytes: usize) -> Result<usize, Error> {
+        let mut bytes = bytes;
+        const BUF_SIZE: usize = 1024;
+        let mut skip_buf = [0; BUF_SIZE];
+        let mut skipped = 0;
+        while bytes > 0 {
+            let num = bytes.min(BUF_SIZE);
+            self.read(&mut [IoSliceMut::new(&mut skip_buf[..num])])?;
+            bytes -= num;
+            skipped += num;
+        }
+        Ok(skipped)
+    }
+
+    /// Un-consumes read bytes. This will only be called at the end of a file stream,
+    /// to un-read potentially over-read bytes. If ensuring that data is not read past
+    /// the file end is not required, this method can safely be implemented as a no-op.
+    /// The provided implementation does nothing.
+    fn unconsume(&mut self, _count: usize) -> Result<(), Error> {
+        Ok(())
+    }
+}
+
+impl JxlBitstreamInput for &[u8] {
+    fn available_bytes(&mut self) -> Result<usize, Error> {
+        Ok(self.len())
+    }
+
+    fn read(&mut self, bufs: &mut [IoSliceMut]) -> Result<usize, Error> {
+        self.read_vectored(bufs)
+    }
+
+    fn skip(&mut self, bytes: usize) -> Result<usize, Error> {
+        let num = bytes.min(self.len());
+        self.consume(num);
+        Ok(num)
+    }
+}
+
+impl<R: Read + Seek> JxlBitstreamInput for BufReader<R> {
+    fn available_bytes(&mut self) -> Result<usize, Error> {
+        let pos = self.stream_position()?;
+        let end = self.seek(SeekFrom::End(0))?;
+        self.seek(SeekFrom::Start(pos))?;
+        Ok(end.saturating_sub(pos) as usize)
+    }
+
+    fn read(&mut self, bufs: &mut [IoSliceMut]) -> Result<usize, Error> {
+        self.read_vectored(bufs)
+    }
+
+    fn skip(&mut self, bytes: usize) -> Result<usize, Error> {
+        let cur = self.stream_position()?;
+        self.seek(SeekFrom::Current(bytes as i64))
+            .map(|x| x.saturating_sub(cur) as usize)
+    }
+
+    fn unconsume(&mut self, count: usize) -> Result<(), Error> {
+        self.seek_relative(-(count as i64))
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/mod.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/mod.rs
new file mode 100644
index 0000000..5be3ef12
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/mod.rs
@@ -0,0 +1,73 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// #![warn(missing_docs)]
+
+mod color;
+mod data_types;
+mod decoder;
+mod inner;
+mod input;
+mod options;
+mod signature;
+
+pub use crate::image::JxlOutputBuffer;
+pub use color::*;
+pub use data_types::*;
+pub use decoder::*;
+pub use inner::*;
+pub use input::*;
+pub use options::*;
+pub use signature::*;
+
+use crate::headers::image_metadata::Orientation;
+
+/// This type represents the return value of a function that reads input from a bitstream. The
+/// variant `Complete` indicates that the operation was completed successfully, and its return
+/// value is available. The variant `NeedsMoreInput` indicates that more input is needed, and the
+/// function should be called again. This variant comes with a `size_hint`, representing an
+/// estimate of the number of additional bytes needed, and a `fallback`, representing additional
+/// information that might be needed to call the function again (i.e. because it takes a decoder
+/// object by value).
+#[derive(Debug, PartialEq)]
+pub enum ProcessingResult<T, U> {
+    Complete { result: T },
+    NeedsMoreInput { size_hint: usize, fallback: U },
+}
+
+impl<T> ProcessingResult<T, ()> {
+    fn new(
+        result: Result<T, crate::error::Error>,
+    ) -> Result<ProcessingResult<T, ()>, crate::error::Error> {
+        match result {
+            Ok(v) => Ok(ProcessingResult::Complete { result: v }),
+            Err(crate::error::Error::OutOfBounds(v)) => Ok(ProcessingResult::NeedsMoreInput {
+                size_hint: v,
+                fallback: (),
+            }),
+            Err(e) => Err(e),
+        }
+    }
+}
+
+#[derive(Clone)]
+pub struct ToneMapping {
+    pub intensity_target: f32,
+    pub min_nits: f32,
+    pub relative_to_max_display: bool,
+    pub linear_below: f32,
+}
+
+#[derive(Clone)]
+pub struct JxlBasicInfo {
+    pub size: (usize, usize),
+    pub bit_depth: JxlBitDepth,
+    pub orientation: Orientation,
+    pub extra_channels: Vec<JxlExtraChannel>,
+    pub animation: Option<JxlAnimation>,
+    pub uses_original_profile: bool,
+    pub tone_mapping: ToneMapping,
+    pub preview_size: Option<(usize, usize)>,
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/options.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/options.rs
new file mode 100644
index 0000000..d7b0a7c
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/options.rs
@@ -0,0 +1,54 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::api::JxlCms;
+
+pub enum JxlProgressiveMode {
+    /// Renders all pixels in every call to Process.
+    Eager,
+    /// Renders pixels once passes are completed.
+    Pass,
+    /// Renders pixels only once the final frame is ready.
+    FullFrame,
+}
+
+#[non_exhaustive]
+pub struct JxlDecoderOptions {
+    pub adjust_orientation: bool,
+    pub unpremultiply_alpha: bool,
+    pub render_spot_colors: bool,
+    pub coalescing: bool,
+    pub desired_intensity_target: Option<f32>,
+    pub skip_preview: bool,
+    pub progressive_mode: JxlProgressiveMode,
+    pub xyb_output_linear: bool,
+    pub enable_output: bool,
+    pub cms: Option<Box<dyn JxlCms>>,
+    /// Use high precision mode for decoding.
+    /// When false (default), uses lower precision settings that match libjxl's default.
+    /// When true, uses higher precision at the cost of performance.
+    ///
+    /// This affects multiple decoder decisions including spline rendering precision
+    /// and potentially intermediate buffer storage (e.g., using f32 vs f16).
+    pub high_precision: bool,
+}
+
+impl Default for JxlDecoderOptions {
+    fn default() -> Self {
+        Self {
+            adjust_orientation: true,
+            unpremultiply_alpha: false,
+            render_spot_colors: true,
+            coalescing: true,
+            skip_preview: true,
+            desired_intensity_target: None,
+            progressive_mode: JxlProgressiveMode::Pass,
+            xyb_output_linear: true,
+            enable_output: true,
+            cms: None,
+            high_precision: false,
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/signature.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/signature.rs
new file mode 100644
index 0000000..0cd06b4
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/signature.rs
@@ -0,0 +1,162 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{
+    api::ProcessingResult,
+    error::{Error, Result},
+};
+
+/// The magic bytes for a bare JPEG XL codestream.
+pub(crate) const CODESTREAM_SIGNATURE: [u8; 2] = [0xff, 0x0a];
+/// The magic bytes for a file using the JPEG XL container format.
+pub(crate) const CONTAINER_SIGNATURE: [u8; 12] =
+    [0, 0, 0, 0xc, b'J', b'X', b'L', b' ', 0xd, 0xa, 0x87, 0xa];
+
+#[derive(Debug, PartialEq)]
+pub enum JxlSignatureType {
+    Codestream,
+    Container,
+}
+
+impl JxlSignatureType {
+    pub(crate) fn signature(&self) -> &[u8] {
+        match self {
+            JxlSignatureType::Container => &CONTAINER_SIGNATURE,
+            JxlSignatureType::Codestream => &CODESTREAM_SIGNATURE,
+        }
+    }
+}
+
+pub(crate) fn check_signature_internal(file_prefix: &[u8]) -> Result<Option<JxlSignatureType>> {
+    let prefix_len = file_prefix.len();
+
+    for st in [JxlSignatureType::Codestream, JxlSignatureType::Container] {
+        let len = st.signature().len();
+        // Determine the number of bytes to compare (the length of the shorter slice)
+        let len_to_check = prefix_len.min(len);
+
+        if file_prefix[..len_to_check] == st.signature()[..len_to_check] {
+            // The prefix is a valid start. Now, is it complete?
+            return if prefix_len >= len {
+                Ok(Some(st))
+            } else {
+                Err(Error::OutOfBounds(len - prefix_len))
+            };
+        }
+    }
+    // The prefix doesn't match the start of any known signature.
+    Ok(None)
+}
+
+/// Checks if the given buffer starts with a valid JPEG XL signature.
+///
+/// # Returns
+///
+/// A `ProcessingResult` which is:
+/// - `Complete(Some(_))` if a full container or codestream signature is found.
+/// - `Complete(None)` if the prefix is definitively not a JXL signature.
+/// - `NeedsMoreInput` if the prefix matches a signature but is too short.
+pub fn check_signature(file_prefix: &[u8]) -> ProcessingResult<Option<JxlSignatureType>, ()> {
+    ProcessingResult::new(check_signature_internal(file_prefix)).unwrap()
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::api::{
+        CODESTREAM_SIGNATURE, CONTAINER_SIGNATURE, JxlSignatureType, ProcessingResult,
+        check_signature,
+    };
+
+    macro_rules! signature_test {
+        ($test_name:ident, $bytes:expr, Complete(Some($expected_type:expr))) => {
+            #[test]
+            fn $test_name() {
+                let result = check_signature($bytes);
+                match result {
+                    ProcessingResult::Complete { result } => {
+                        assert_eq!(result, Some($expected_type));
+                    }
+                    _ => panic!("Expected Complete(Some(_)), but got {:?}", result),
+                }
+            }
+        };
+        ($test_name:ident, $bytes:expr, Complete(None)) => {
+            #[test]
+            fn $test_name() {
+                let result = check_signature($bytes);
+                match result {
+                    ProcessingResult::Complete { result } => {
+                        assert_eq!(result, None);
+                    }
+                    _ => panic!("Expected Complete(None), but got {:?}", result),
+                }
+            }
+        };
+        ($test_name:ident, $bytes:expr, NeedsMoreInput($expected_hint:expr)) => {
+            #[test]
+            fn $test_name() {
+                let result = check_signature($bytes);
+                match result {
+                    ProcessingResult::NeedsMoreInput { size_hint, .. } => {
+                        assert_eq!(size_hint, $expected_hint);
+                    }
+                    _ => panic!("Expected NeedsMoreInput, but got {:?}", result),
+                }
+            }
+        };
+    }
+
+    signature_test!(
+        full_container_sig,
+        &CONTAINER_SIGNATURE,
+        Complete(Some(JxlSignatureType::Container))
+    );
+
+    signature_test!(
+        partial_container_sig,
+        &CONTAINER_SIGNATURE[..5],
+        NeedsMoreInput(CONTAINER_SIGNATURE.len() - 5)
+    );
+
+    signature_test!(
+        full_codestream_sig,
+        &CODESTREAM_SIGNATURE,
+        Complete(Some(JxlSignatureType::Codestream))
+    );
+
+    signature_test!(
+        partial_codestream_sig,
+        &CODESTREAM_SIGNATURE[..1],
+        NeedsMoreInput(CODESTREAM_SIGNATURE.len() - 1)
+    );
+
+    signature_test!(
+        empty_prefix,
+        &[],
+        NeedsMoreInput(CODESTREAM_SIGNATURE.len())
+    );
+
+    signature_test!(invalid_sig, &[0x12, 0x34, 0x56, 0x77], Complete(None));
+
+    signature_test!(
+        container_with_extra_data,
+        &{
+            let mut data = CONTAINER_SIGNATURE.to_vec();
+            data.extend_from_slice(&[0x11, 0x22, 0x33]);
+            data
+        },
+        Complete(Some(JxlSignatureType::Container))
+    );
+
+    signature_test!(
+        codestream_with_extra_data,
+        &{
+            let mut data = CODESTREAM_SIGNATURE.to_vec();
+            data.extend_from_slice(&[0x44, 0x55, 0x66]);
+            data
+        },
+        Complete(Some(JxlSignatureType::Codestream))
+    );
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/bit_reader.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/bit_reader.rs
new file mode 100644
index 0000000..d127b3a
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/bit_reader.rs
@@ -0,0 +1,265 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::fmt::Debug;
+
+use crate::{error::Error, util::tracing_wrappers::*};
+use byteorder::{ByteOrder, LittleEndian};
+
+/// Reads bits from a sequence of bytes.
+#[derive(Clone)]
+pub struct BitReader<'a> {
+    data: &'a [u8],
+    bit_buf: u64,
+    bits_in_buf: usize,
+    total_bits_read: usize,
+    initial_bits: usize,
+}
+
+impl Debug for BitReader<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "BitReader{{ data: [{} bytes], bit_buf: {:0width$b}, total_bits_read: {} }}",
+            self.data.len(),
+            self.bit_buf,
+            self.total_bits_read,
+            width = self.bits_in_buf
+        )
+    }
+}
+
+pub const MAX_BITS_PER_CALL: usize = 56;
+
+impl<'a> BitReader<'a> {
+    /// Constructs a BitReader for a given range of data.
+    pub fn new(data: &[u8]) -> BitReader<'_> {
+        BitReader {
+            data,
+            bit_buf: 0,
+            bits_in_buf: 0,
+            total_bits_read: 0,
+            initial_bits: data.len() * 8,
+        }
+    }
+
+    /// Reads `num` bits from the buffer without consuming them.
+    #[inline]
+    pub fn peek(&mut self, num: usize) -> u64 {
+        debug_assert!(num <= MAX_BITS_PER_CALL);
+        if self.bits_in_buf < num {
+            self.refill();
+        }
+        self.bit_buf & ((1u64 << num) - 1)
+    }
+
+    /// Advances by `num` bits. Similar to `skip_bits`, but bits must be in the buffer.
+    pub fn consume(&mut self, num: usize) -> Result<(), Error> {
+        if self.bits_in_buf < num {
+            return Err(Error::OutOfBounds((num - self.bits_in_buf).div_ceil(8)));
+        }
+        self.bit_buf >>= num;
+        self.bits_in_buf -= num;
+        self.total_bits_read = self.total_bits_read.wrapping_add(num);
+        Ok(())
+    }
+
+    #[inline]
+    pub fn consume_optimistic(&mut self, num: usize) {
+        self.bit_buf >>= num;
+        self.bits_in_buf = self.bits_in_buf.saturating_sub(num);
+        self.total_bits_read = self.total_bits_read.wrapping_add(num);
+    }
+
+    /// Reads `num` bits from the buffer.
+    /// ```
+    /// # use jxl::bit_reader::BitReader;
+    /// let mut br = BitReader::new(&[0, 1]);
+    /// assert_eq!(br.read(8)?, 0);
+    /// assert_eq!(br.read(4)?, 1);
+    /// assert_eq!(br.read(4)?, 0);
+    /// assert_eq!(br.total_bits_read(), 16);
+    /// assert!(br.read(1).is_err());
+    /// # Ok::<(), jxl::error::Error>(())
+    /// ```
+    #[inline]
+    pub fn read(&mut self, num: usize) -> Result<u64, Error> {
+        let ret = self.peek(num);
+        self.consume(num)?;
+        Ok(ret)
+    }
+
+    #[inline]
+    pub fn read_optimistic(&mut self, num: usize) -> u64 {
+        let ret = self.peek(num);
+        self.consume_optimistic(num);
+        ret
+    }
+
+    pub fn check_for_error(&self) -> Result<(), Error> {
+        if self.total_bits_read > self.initial_bits {
+            Err(Error::OutOfBounds(self.total_bits_read - self.initial_bits))
+        } else {
+            Ok(())
+        }
+    }
+
+    /// Returns the total number of bits that have been read or skipped.
+    pub fn total_bits_read(&self) -> usize {
+        self.total_bits_read
+    }
+
+    /// Returns the total number of bits that can still be read or skipped.
+    pub fn total_bits_available(&self) -> usize {
+        self.data.len() * 8 + self.bits_in_buf
+    }
+
+    /// Skips `num` bits.
+    /// ```
+    /// # use jxl::bit_reader::BitReader;
+    /// let mut br = BitReader::new(&[0, 1]);
+    /// assert_eq!(br.read(8)?, 0);
+    /// br.skip_bits(4)?;
+    /// assert_eq!(br.total_bits_read(), 12);
+    /// # Ok::<(), jxl::error::Error>(())
+    /// ```
+    #[inline(never)]
+    pub fn skip_bits(&mut self, mut n: usize) -> Result<(), Error> {
+        // Check if we can skip within the current buffer
+        if let Some(next_remaining_bits) = self.bits_in_buf.checked_sub(n) {
+            self.total_bits_read += n;
+            self.bits_in_buf = next_remaining_bits;
+            self.bit_buf >>= n;
+            return Ok(());
+        }
+
+        // Adjust the number of bits to skip and reset the buffer
+        n -= self.bits_in_buf;
+        self.total_bits_read += self.bits_in_buf;
+        self.bit_buf = 0;
+        self.bits_in_buf = 0;
+
+        // Check if the remaining bits to skip exceed the total bits in `data`
+        let bits_available = self.data.len() * 8;
+        if n > bits_available {
+            self.total_bits_read += bits_available;
+            return Err(Error::OutOfBounds(n - bits_available));
+        }
+
+        // Skip bytes directly in `data`, then handle leftover bits
+        self.total_bits_read += n / 8 * 8;
+        self.data = &self.data[n / 8..];
+        n %= 8;
+
+        // Refill the buffer and adjust for any remaining bits
+        self.refill();
+        let to_consume = self.bits_in_buf.min(n);
+        // The bits loaded by refill() haven't been counted in total_bits_read yet,
+        // so we add (not subtract) the bits we're consuming. The original code
+        // incorrectly subtracted here, causing underflow when skip_bits was called
+        // on a fresh BitReader.
+        self.total_bits_read += to_consume;
+        n -= to_consume;
+        self.bit_buf >>= to_consume;
+        self.bits_in_buf -= to_consume;
+        if n > 0 {
+            Err(Error::OutOfBounds(n))
+        } else {
+            Ok(())
+        }
+    }
+
+    /// Return the number of bits
+    pub fn bits_to_next_byte(&self) -> usize {
+        let byte_boundary = self.total_bits_read.div_ceil(8) * 8;
+        byte_boundary - self.total_bits_read
+    }
+
+    /// Jumps to the next byte boundary. The skipped bytes have to be 0.
+    /// ```
+    /// # use jxl::bit_reader::BitReader;
+    /// let mut br = BitReader::new(&[0, 1]);
+    /// assert_eq!(br.read(8)?, 0);
+    /// br.skip_bits(4)?;
+    /// br.jump_to_byte_boundary()?;
+    /// assert_eq!(br.total_bits_read(), 16);
+    /// # Ok::<(), jxl::error::Error>(())
+    /// ```
+    #[inline(never)]
+    pub fn jump_to_byte_boundary(&mut self) -> Result<(), Error> {
+        if self.read(self.bits_to_next_byte())? != 0 {
+            return Err(Error::NonZeroPadding);
+        }
+        Ok(())
+    }
+
+    #[inline]
+    fn refill(&mut self) {
+        // See Refill() in C++ code.
+        if self.data.len() >= 8 {
+            let bits = LittleEndian::read_u64(self.data);
+            self.bit_buf |= bits << self.bits_in_buf;
+            let read_bytes = (63 - self.bits_in_buf) >> 3;
+            self.bits_in_buf |= 56;
+            self.data = &self.data[read_bytes..];
+            debug_assert!(56 <= self.bits_in_buf && self.bits_in_buf < 64);
+        } else {
+            self.refill_slow()
+        }
+    }
+
+    #[inline(never)]
+    fn refill_slow(&mut self) {
+        while self.bits_in_buf < 56 {
+            if self.data.is_empty() {
+                return;
+            }
+            self.bit_buf |= (self.data[0] as u64) << self.bits_in_buf;
+            self.bits_in_buf += 8;
+            self.data = &self.data[1..];
+        }
+    }
+
+    /// Splits off a separate BitReader to handle the next `n` *full* bytes.
+    /// If `self` is not aligned to a byte boundary, it skips to the next byte boundary.
+    /// `self` is automatically advanced by `n` bytes.
+    pub fn split_at(&mut self, n: usize) -> Result<BitReader<'a>, Error> {
+        self.jump_to_byte_boundary()?;
+        let mut ret = Self { ..*self };
+        self.skip_bits(n * 8)?;
+        let bytes_in_buf = ret.bits_in_buf / 8;
+        if n > bytes_in_buf {
+            // Prevent the returned bitreader from over-reading.
+            ret.data = &ret.data[..n - bytes_in_buf];
+        } else {
+            ret.bits_in_buf = n * 8;
+            ret.bit_buf &= (1u64 << (n * 8)) - 1;
+            ret.data = &[];
+        }
+        debug!(?n, ret=?ret);
+        Ok(ret)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_skip_bits_on_fresh_reader() {
+        // This test checks if skip_bits works correctly on a fresh BitReader
+        let data = [0x12, 0x34, 0x56, 0x78];
+        let mut br = BitReader::new(&data);
+
+        // Try to skip 1 bit on a fresh reader - this should work
+        br.skip_bits(1)
+            .expect("skip_bits should work on fresh reader");
+        assert_eq!(br.total_bits_read(), 1);
+
+        // Read the next 7 bits to complete the byte
+        let val = br.read(7).expect("read should work");
+        assert_eq!(val, 0x12 >> 1); // Should get the lower 7 bits of 0x12
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/color/mod.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/color/mod.rs
new file mode 100644
index 0000000..e9e061b9
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/color/mod.rs
@@ -0,0 +1,6 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+pub mod tf;
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/color/tf.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/color/tf.rs
new file mode 100644
index 0000000..f9a4f7e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/color/tf.rs
@@ -0,0 +1,672 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::util::{eval_rational_poly, eval_rational_poly_simd};
+use jxl_simd::{F32SimdVec, SimdDescriptor, SimdMask};
+
+/// Converts the linear samples with the sRGB transfer curve (SIMD version).
+// Max error ~5e-7
+#[inline(always)]
+pub fn linear_to_srgb_simd<D: SimdDescriptor>(d: D, samples: &mut [f32]) {
+    #[allow(clippy::excessive_precision)]
+    const P: [f32; 5] = [
+        -5.135152395e-4,
+        5.287254571e-3,
+        3.903842876e-1,
+        1.474205315,
+        7.352629620e-1,
+    ];
+
+    #[allow(clippy::excessive_precision)]
+    const Q: [f32; 5] = [
+        1.004519624e-2,
+        3.036675394e-1,
+        1.340816930,
+        9.258482155e-1,
+        2.424867759e-2,
+    ];
+
+    for vec in samples.chunks_exact_mut(D::F32Vec::LEN) {
+        let x = D::F32Vec::load(d, vec);
+        let a = x.abs();
+        D::F32Vec::splat(d, 0.0031308)
+            .gt(a)
+            .if_then_else_f32(
+                a * D::F32Vec::splat(d, 12.92),
+                eval_rational_poly_simd(d, a.sqrt(), P, Q),
+            )
+            .copysign(x)
+            .store(vec);
+    }
+}
+
+/// Converts samples in sRGB transfer curve to linear. Inverse of `linear_to_srgb`.
+pub fn srgb_to_linear(samples: &mut [f32]) {
+    #[allow(clippy::excessive_precision)]
+    const P: [f32; 5] = [
+        2.200248328e-4,
+        1.043637593e-2,
+        1.624820318e-1,
+        7.961564959e-1,
+        8.210152774e-1,
+    ];
+
+    #[allow(clippy::excessive_precision)]
+    const Q: [f32; 5] = [
+        2.631846970e-1,
+        1.076976492,
+        4.987528350e-1,
+        -5.512498495e-2,
+        6.521209011e-3,
+    ];
+
+    for x in samples {
+        let a = x.abs();
+        *x = if a <= 0.04045 {
+            a / 12.92
+        } else {
+            eval_rational_poly(a, P, Q)
+        }
+        .copysign(*x);
+    }
+}
+
+#[inline(always)]
+pub fn srgb_to_linear_simd<D: SimdDescriptor>(d: D, samples: &mut [f32]) {
+    #[allow(clippy::excessive_precision)]
+    const P: [f32; 5] = [
+        2.200248328e-4,
+        1.043637593e-2,
+        1.624820318e-1,
+        7.961564959e-1,
+        8.210152774e-1,
+    ];
+
+    #[allow(clippy::excessive_precision)]
+    const Q: [f32; 5] = [
+        2.631846970e-1,
+        1.076976492,
+        4.987528350e-1,
+        -5.512498495e-2,
+        6.521209011e-3,
+    ];
+
+    for vec in samples.chunks_exact_mut(D::F32Vec::LEN) {
+        let x = D::F32Vec::load(d, vec);
+        let a = x.abs();
+        D::F32Vec::splat(d, 0.04045)
+            .gt(a)
+            .if_then_else_f32(
+                a / D::F32Vec::splat(d, 12.92),
+                eval_rational_poly_simd(d, a, P, Q),
+            )
+            .copysign(x)
+            .store(vec);
+    }
+}
+
+/// Converts the linear samples with the BT.709 transfer curve (SIMD version).
+// Rational polynomial approximation of 1.099 * x^0.45 - 0.099 on sqrt(x).
+// Max error ~3e-7
+#[inline(always)]
+pub fn linear_to_bt709_simd<D: SimdDescriptor>(d: D, samples: &mut [f32]) {
+    // Coefficients for rational polynomial P(y)/Q(y) where y = sqrt(x)
+    // Approximates 1.099 * y^0.9 - 0.099 on [sqrt(0.018), 1]
+    #[allow(clippy::excessive_precision)]
+    const P: [f32; 5] = [
+        -9.625309705734253e-2,
+        -2.2635456919670105e-1,
+        1.935774803161621e1,
+        5.897886276245117e1,
+        2.3947298049926758e1,
+    ];
+
+    #[allow(clippy::excessive_precision)]
+    const Q: [f32; 5] = [
+        1.0,
+        1.877663230895996e1,
+        5.5292449951171875e1,
+        2.6565317153930664e1,
+        3.269049823284149e-1,
+    ];
+
+    for vec in samples.chunks_exact_mut(D::F32Vec::LEN) {
+        let x = D::F32Vec::load(d, vec);
+        let a = x.abs();
+        D::F32Vec::splat(d, 0.018)
+            .gt(a)
+            .if_then_else_f32(
+                a * D::F32Vec::splat(d, 4.5),
+                eval_rational_poly_simd(d, a.sqrt(), P, Q),
+            )
+            .copysign(x)
+            .store(vec);
+    }
+}
+
+/// Converts samples in BT.709 transfer curve to linear. Inverse of `linear_to_bt709_simd`.
+pub fn bt709_to_linear(samples: &mut [f32]) {
+    for s in samples {
+        let a = s.abs();
+        *s = if a <= 0.081 {
+            a / 4.5
+        } else {
+            crate::util::fast_powf(a.mul_add(1.0 / 1.099, 0.099 / 1.099), 1.0 / 0.45)
+        }
+        .copysign(*s);
+    }
+}
+
+const PQ_M1: f64 = 2610.0 / 16384.0;
+const PQ_M2: f64 = (2523.0 / 4096.0) * 128.0;
+const PQ_C1: f64 = 3424.0 / 4096.0;
+const PQ_C2: f64 = (2413.0 / 4096.0) * 32.0;
+const PQ_C3: f64 = (2392.0 / 4096.0) * 32.0;
+
+/// Converts linear sample to PQ signal using PQ inverse EOTF, where linear sample value of 1.0
+/// represents `intensity_target` display nits.
+///
+/// This version uses original EOTF using double precision arithmetic internally.
+pub fn linear_to_pq_precise(intensity_target: f32, samples: &mut [f32]) {
+    let mult = intensity_target as f64 * 10000f64.recip();
+
+    for s in samples {
+        if *s == 0.0 {
+            continue;
+        }
+
+        let a = s.abs() as f64;
+        let xp = (a * mult).powf(PQ_M1);
+        let num = PQ_C1 + xp * PQ_C2;
+        let den = 1.0 + xp * PQ_C3;
+        let e = (num / den).powf(PQ_M2);
+        *s = (e as f32).copysign(*s);
+    }
+}
+
+/// Converts PQ signal to linear sample using PQ EOTF, where linear sample value of 1.0 represents
+/// `intensity_target` display nits.
+///
+/// This version uses original EOTF using double precision arithmetic internally.
+pub fn pq_to_linear_precise(intensity_target: f32, samples: &mut [f32]) {
+    let mult = 10000.0 / intensity_target as f64;
+
+    for s in samples {
+        if *s == 0.0 {
+            continue;
+        }
+
+        let a = s.abs() as f64;
+        let xp = a.powf(PQ_M2.recip());
+        let num = (xp - PQ_C1).max(0.0);
+        let den = PQ_C2 - PQ_C3 * xp;
+        let y = (num / den).powf(PQ_M1.recip());
+        *s = ((y * mult) as f32).copysign(*s);
+    }
+}
+
+const PQ_EOTF_P: [f32; 5] = [
+    2.6297566e-4,
+    -6.235531e-3,
+    7.386023e-1,
+    2.6455317,
+    5.500349e-1,
+];
+const PQ_EOTF_Q: [f32; 5] = [
+    4.213501e2,
+    -4.2873682e2,
+    1.7436467e2,
+    -3.3907887e1,
+    2.6771877,
+];
+
+const PQ_INV_EOTF_P: [f32; 5] = [1.351392e-2, -1.095778, 5.522776e1, 1.492516e2, 4.838434e1];
+const PQ_INV_EOTF_Q: [f32; 5] = [1.012416, 2.016708e1, 9.26371e1, 1.120607e2, 2.590418e1];
+const PQ_INV_EOTF_P_SMALL: [f32; 5] = [
+    9.863406e-6,
+    3.881234e-1,
+    1.352821e2,
+    6.889862e4,
+    -2.864824e5,
+];
+const PQ_INV_EOTF_Q_SMALL: [f32; 5] =
+    [3.371868e1, 1.477719e3, 1.608477e4, -4.389884e4, -2.072546e5];
+
+/// Converts linear sample to PQ signal using PQ inverse EOTF, where linear sample value of 1.0
+/// represents `intensity_target` display nits.
+///
+/// This version uses approximate curve using rational polynomial.
+// Max error: ~7e-7 at intensity_target = 10000
+pub fn linear_to_pq(intensity_target: f32, samples: &mut [f32]) {
+    let y_mult = intensity_target * 10000f32.recip();
+
+    for s in samples {
+        let a = s.abs();
+        let a_scaled = a * y_mult;
+        let a_1_4 = a_scaled.sqrt().sqrt();
+
+        let y = if a < 1e-4 {
+            eval_rational_poly(a_1_4, PQ_INV_EOTF_P_SMALL, PQ_INV_EOTF_Q_SMALL)
+        } else {
+            eval_rational_poly(a_1_4, PQ_INV_EOTF_P, PQ_INV_EOTF_Q)
+        };
+
+        *s = y.copysign(*s);
+    }
+}
+
+/// Converts PQ signal to linear sample using PQ EOTF, where linear sample value of 1.0 represents
+/// `intensity_target` display nits.
+///
+/// This version uses approximate curve using rational polynomial.
+// Max error: ~3e-6 at intensity_target = 10000
+pub fn pq_to_linear(intensity_target: f32, samples: &mut [f32]) {
+    let y_mult = 10000.0 / intensity_target;
+
+    for s in samples {
+        let a = s.abs();
+        // a + a * a
+        let x = a.mul_add(a, a);
+        let y = eval_rational_poly(x, PQ_EOTF_P, PQ_EOTF_Q);
+        *s = (y * y_mult).copysign(*s);
+    }
+}
+
+const HLG_A: f64 = 0.17883277;
+const HLG_B: f64 = 1.0 - 4.0 * HLG_A;
+const HLG_C: f64 = 0.5599107295;
+
+fn hlg_ootf_inner_precise(exp: f64, [lr, lg, lb]: [f32; 3], [sr, sg, sb]: [&mut [f32]; 3]) {
+    if exp.abs() < 0.1 {
+        return;
+    }
+
+    let lr = lr as f64;
+    let lg = lg as f64;
+    let lb = lb as f64;
+    for ((r, g), b) in std::iter::zip(sr, sg).zip(sb) {
+        let dr = *r as f64;
+        let dg = *g as f64;
+        let db = *b as f64;
+        let mixed = dr.mul_add(lr, dg.mul_add(lg, db * lb));
+        let mult = mixed.powf(exp);
+        *r = (dr * mult) as f32;
+        *g = (dg * mult) as f32;
+        *b = (db * mult) as f32;
+    }
+}
+
+fn hlg_ootf_inner(exp: f32, [lr, lg, lb]: [f32; 3], [sr, sg, sb]: [&mut [f32]; 3]) {
+    if exp.abs() < 0.1 {
+        return;
+    }
+
+    for ((r, g), b) in std::iter::zip(sr, sg).zip(sb) {
+        let mixed = r.mul_add(lr, g.mul_add(lg, *b * lb));
+        let mult = crate::util::fast_powf(mixed, exp);
+        *r *= mult;
+        *g *= mult;
+        *b *= mult;
+    }
+}
+
+/// Converts scene-referred linear samples to display-referred linear samples using HLG OOTF.
+///
+/// This version uses double precision arithmetic internally.
+pub fn hlg_scene_to_display_precise(
+    intensity_display: f32,
+    luminance_rgb: [f32; 3],
+    samples_rgb: [&mut [f32]; 3],
+) {
+    let system_gamma = 1.2f64 * 1.111f64.powf((intensity_display as f64 / 1e3).log2());
+    let gamma_sub_one = system_gamma - 1.0;
+    hlg_ootf_inner_precise(gamma_sub_one, luminance_rgb, samples_rgb);
+}
+
+/// Converts display-referred linear samples to scene-referred linear samples using HLG inverse
+/// OOTF.
+///
+/// This version uses double precision arithmetic internally.
+pub fn hlg_display_to_scene_precise(
+    intensity_display: f32,
+    luminance_rgb: [f32; 3],
+    samples_rgb: [&mut [f32]; 3],
+) {
+    let system_gamma = 1.2f64 * 1.111f64.powf((intensity_display as f64 / 1e3).log2());
+    let one_sub_gamma = 1.0 - system_gamma;
+    hlg_ootf_inner_precise(one_sub_gamma / system_gamma, luminance_rgb, samples_rgb);
+}
+
+/// Converts scene-referred linear samples to display-referred linear samples using HLG OOTF.
+///
+/// This version uses `fast_powf` to compute power function.
+pub fn hlg_scene_to_display(
+    intensity_display: f32,
+    luminance_rgb: [f32; 3],
+    samples_rgb: [&mut [f32]; 3],
+) {
+    let system_gamma = 1.2f32 * 1.111f32.powf((intensity_display / 1e3).log2());
+    let gamma_sub_one = system_gamma - 1.0;
+    hlg_ootf_inner(gamma_sub_one, luminance_rgb, samples_rgb);
+}
+
+/// Converts display-referred linear samples to scene-referred linear samples using HLG inverse
+/// OOTF.
+///
+/// This version uses `fast_powf` to compute power function.
+pub fn hlg_display_to_scene(
+    intensity_display: f32,
+    luminance_rgb: [f32; 3],
+    samples_rgb: [&mut [f32]; 3],
+) {
+    let system_gamma = 1.2f32 * 1.111f32.powf((intensity_display / 1e3).log2());
+    let one_sub_gamma = 1.0 - system_gamma;
+    hlg_ootf_inner(one_sub_gamma / system_gamma, luminance_rgb, samples_rgb);
+}
+
+/// Converts scene-referred linear sample to HLG signal.
+///
+/// This version uses double precision arithmetic internally.
+pub fn scene_to_hlg_precise(samples: &mut [f32]) {
+    for s in samples {
+        let a = s.abs() as f64;
+        let y = if a <= 1.0 / 12.0 {
+            (3.0 * a).sqrt()
+        } else {
+            // TODO(tirr-c): maybe use mul_add?
+            HLG_A * (12.0 * a - HLG_B).ln() + HLG_C
+        };
+        *s = (y as f32).copysign(*s);
+    }
+}
+
+/// Converts HLG signal to scene-referred linear sample.
+///
+/// This version uses double precision arithmetic internally.
+pub fn hlg_to_scene_precise(samples: &mut [f32]) {
+    for s in samples {
+        let a = s.abs() as f64;
+        let y = if a <= 0.5 {
+            a * a / 3.0
+        } else {
+            (((a - HLG_C) / HLG_A).exp() + HLG_B) / 12.0
+        };
+        *s = (y as f32).copysign(*s);
+    }
+}
+
+/// Converts scene-referred linear sample to HLG signal.
+///
+/// This version uses `fast_log2f` to apply logarithmic function.
+// Max error: ~5e-7
+pub fn scene_to_hlg(samples: &mut [f32]) {
+    for s in samples {
+        let a = s.abs();
+        let y = if a <= 1.0 / 12.0 {
+            (3.0 * a).sqrt()
+        } else {
+            // TODO(tirr-c): maybe use mul_add?
+            let log = crate::util::fast_log2f(12.0 * a - HLG_B as f32);
+            // log2 x = ln x / ln 2, therefore ln x = (ln 2)(log2 x)
+            (HLG_A * std::f64::consts::LN_2) as f32 * log + HLG_C as f32
+        };
+        *s = y.copysign(*s);
+    }
+}
+
+/// Converts HLG signal to scene-referred linear sample.
+///
+/// This version uses `fast_pow2f` to apply logarithmic function.
+// Max error: ~5e-6
+pub fn hlg_to_scene(samples: &mut [f32]) {
+    for s in samples {
+        let a = s.abs();
+        let y = if a <= 0.5 {
+            a * a / 3.0
+        } else {
+            const POW: f32 = (std::f64::consts::LOG2_E / HLG_A) as f32;
+            const ADD: f32 = (HLG_B / 12.0) as f32;
+            // TODO(OneDeuxTriSeiGo): replace raw constant with the below equation
+            // when std::f64::exp() can is available as a const fn.
+            //
+            // Equation: ((-HLG_B / HLG_A).exp() / 12.0)
+            // Constant: 0.003_639_807_079_052_639
+            const MUL: f32 = 0.003_639_807;
+
+            // TODO(OneDeuxTriSeiGo): maybe use mul_add?
+            crate::util::fast_pow2f(a * POW) * MUL + ADD
+        };
+        *s = y.copysign(*s);
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use test_log::test;
+
+    use super::*;
+    use crate::util::test::assert_all_almost_abs_eq;
+
+    fn arb_samples(
+        u: &mut arbtest::arbitrary::Unstructured,
+    ) -> arbtest::arbitrary::Result<Vec<f32>> {
+        const DENOM: u32 = 1 << 24;
+
+        let mut samples = Vec::new();
+
+        // uniform distribution in [-1.0, 1.0]
+        while !u.is_empty() {
+            let a: u32 = u.int_in_range(0..=DENOM)?;
+            let signed: bool = u.arbitrary()?;
+            let x = a as f32 / DENOM as f32;
+            samples.push(if signed { -x } else { x });
+        }
+
+        Ok(samples)
+    }
+
+    /// Naive linear to sRGB using actual pow for testing.
+    fn linear_to_srgb_naive(samples: &mut [f32]) {
+        for x in samples {
+            let a = x.abs();
+            *x = if a <= 0.0031308 {
+                a * 12.92
+            } else {
+                a.powf(1.0 / 2.4).mul_add(1.055, -0.055)
+            }
+            .copysign(*x);
+        }
+    }
+
+    /// Naive linear to BT.709 using actual pow for testing.
+    fn linear_to_bt709_naive(samples: &mut [f32]) {
+        for x in samples {
+            let a = x.abs();
+            *x = if a <= 0.018 {
+                a * 4.5
+            } else {
+                a.powf(0.45).mul_add(1.099, -0.099)
+            }
+            .copysign(*x);
+        }
+    }
+
+    #[test]
+    fn srgb_roundtrip_arb() {
+        arbtest::arbtest(|u| {
+            let samples = arb_samples(u)?;
+            let mut output = samples.clone();
+
+            linear_to_srgb_simd(jxl_simd::ScalarDescriptor::new().unwrap(), &mut output);
+            srgb_to_linear(&mut output);
+            assert_all_almost_abs_eq(&output, &samples, 2e-6);
+            Ok(())
+        });
+    }
+
+    #[test]
+    fn bt709_roundtrip_arb() {
+        arbtest::arbtest(|u| {
+            let samples = arb_samples(u)?;
+            let mut output = samples.clone();
+
+            linear_to_bt709_simd(jxl_simd::ScalarDescriptor::new().unwrap(), &mut output);
+            bt709_to_linear(&mut output);
+            assert_all_almost_abs_eq(&output, &samples, 5e-6);
+            Ok(())
+        });
+    }
+
+    #[test]
+    fn linear_to_srgb_simd_arb() {
+        arbtest::arbtest(|u| {
+            let mut samples = arb_samples(u)?;
+            let mut simd = samples.clone();
+
+            linear_to_srgb_naive(&mut samples);
+            linear_to_srgb_simd(jxl_simd::ScalarDescriptor::new().unwrap(), &mut simd);
+            assert_all_almost_abs_eq(&samples, &simd, 1e-6);
+            Ok(())
+        });
+    }
+
+    #[test]
+    fn linear_to_bt709_simd_arb() {
+        arbtest::arbtest(|u| {
+            let mut samples = arb_samples(u)?;
+            let mut simd = samples.clone();
+
+            linear_to_bt709_naive(&mut samples);
+            linear_to_bt709_simd(jxl_simd::ScalarDescriptor::new().unwrap(), &mut simd);
+            assert_all_almost_abs_eq(&samples, &simd, 1e-6);
+            Ok(())
+        });
+    }
+
+    #[test]
+    fn linear_to_pq_arb() {
+        arbtest::arbtest(|u| {
+            let intensity_target = u.int_in_range(9900..=10100)? as f32;
+            let mut samples = arb_samples(u)?;
+            let mut precise = samples.clone();
+
+            linear_to_pq(intensity_target, &mut samples);
+            linear_to_pq_precise(intensity_target, &mut precise);
+            // Error seems to increase at intensity_target < 10000
+            assert_all_almost_abs_eq(&samples, &precise, 8e-7);
+            Ok(())
+        });
+    }
+
+    #[test]
+    fn pq_to_linear_arb() {
+        arbtest::arbtest(|u| {
+            let intensity_target = u.int_in_range(9900..=10100)? as f32;
+            let mut samples = arb_samples(u)?;
+            let mut precise = samples.clone();
+
+            pq_to_linear(intensity_target, &mut samples);
+            pq_to_linear_precise(intensity_target, &mut precise);
+            assert_all_almost_abs_eq(&samples, &precise, 3e-6);
+            Ok(())
+        });
+    }
+
+    #[test]
+    fn hlg_ootf_arb() {
+        arbtest::arbtest(|u| {
+            let intensity_target = u.int_in_range(900..=1100)? as f32;
+
+            let lr = 0.2 + u.int_in_range(0..=255)? as f32 / 255.0;
+            let lb = 0.2 + u.int_in_range(0..=255)? as f32 / 255.0;
+            let lg = 1.0 - lr - lb;
+            let luminance_rgb = [lr, lg, lb];
+
+            let r = u.int_in_range(0u32..=(1 << 24))? as f32 / (1 << 24) as f32;
+            let g = u.int_in_range(0u32..=(1 << 24))? as f32 / (1 << 24) as f32;
+            let b = u.int_in_range(0u32..=(1 << 24))? as f32 / (1 << 24) as f32;
+
+            let mut fast_r = r;
+            let mut fast_g = g;
+            let mut fast_b = b;
+            let fast = [
+                std::slice::from_mut(&mut fast_r),
+                std::slice::from_mut(&mut fast_g),
+                std::slice::from_mut(&mut fast_b),
+            ];
+            hlg_display_to_scene(intensity_target, luminance_rgb, fast);
+
+            let mut precise_r = r;
+            let mut precise_g = g;
+            let mut precise_b = b;
+            let precise = [
+                std::slice::from_mut(&mut precise_r),
+                std::slice::from_mut(&mut precise_g),
+                std::slice::from_mut(&mut precise_b),
+            ];
+            hlg_display_to_scene(intensity_target, luminance_rgb, precise);
+
+            assert_all_almost_abs_eq(
+                &[fast_r, fast_g, fast_b],
+                &[precise_r, precise_g, precise_b],
+                7.2e-7,
+            );
+
+            let mut fast_r = r;
+            let mut fast_g = g;
+            let mut fast_b = b;
+            let fast = [
+                std::slice::from_mut(&mut fast_r),
+                std::slice::from_mut(&mut fast_g),
+                std::slice::from_mut(&mut fast_b),
+            ];
+            hlg_scene_to_display(intensity_target, luminance_rgb, fast);
+
+            let mut precise_r = r;
+            let mut precise_g = g;
+            let mut precise_b = b;
+            let precise = [
+                std::slice::from_mut(&mut precise_r),
+                std::slice::from_mut(&mut precise_g),
+                std::slice::from_mut(&mut precise_b),
+            ];
+            hlg_scene_to_display(intensity_target, luminance_rgb, precise);
+
+            assert_all_almost_abs_eq(
+                &[fast_r, fast_g, fast_b],
+                &[precise_r, precise_g, precise_b],
+                7.2e-7,
+            );
+
+            Ok(())
+        });
+    }
+
+    #[test]
+    fn scene_to_hlg_arb() {
+        arbtest::arbtest(|u| {
+            let mut samples = arb_samples(u)?;
+            let mut precise = samples.clone();
+
+            scene_to_hlg(&mut samples);
+            scene_to_hlg_precise(&mut precise);
+            assert_all_almost_abs_eq(&samples, &precise, 5e-7);
+            Ok(())
+        });
+    }
+
+    #[test]
+    fn hlg_to_scene_arb() {
+        arbtest::arbtest(|u| {
+            let mut samples = arb_samples(u)?;
+            let mut precise = samples.clone();
+
+            hlg_to_scene(&mut samples);
+            hlg_to_scene_precise(&mut precise);
+            assert_all_almost_abs_eq(&samples, &precise, 5e-6);
+            Ok(())
+        });
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/container/box_header.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/container/box_header.rs
new file mode 100644
index 0000000..780bc06
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/container/box_header.rs
@@ -0,0 +1,113 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// Originally written for jxl-oxide.
+
+use crate::error::Error;
+
+/// Box header used in JPEG XL containers.
+#[derive(Debug, Clone)]
+pub struct ContainerBoxHeader {
+    ty: ContainerBoxType,
+    box_size: Option<u64>,
+    is_last: bool,
+}
+
+pub enum HeaderParseResult {
+    Done {
+        header: ContainerBoxHeader,
+        header_size: usize,
+    },
+    NeedMoreData,
+}
+
+impl ContainerBoxHeader {
+    pub(super) fn parse(buf: &[u8]) -> Result<HeaderParseResult, Error> {
+        let (tbox, box_size, header_size) = match *buf {
+            [
+                0,
+                0,
+                0,
+                1,
+                t0,
+                t1,
+                t2,
+                t3,
+                s0,
+                s1,
+                s2,
+                s3,
+                s4,
+                s5,
+                s6,
+                s7,
+                ..,
+            ] => {
+                let xlbox = u64::from_be_bytes([s0, s1, s2, s3, s4, s5, s6, s7]);
+                let tbox = ContainerBoxType([t0, t1, t2, t3]);
+                let xlbox = xlbox.checked_sub(16).ok_or(Error::InvalidBox)?;
+                (tbox, Some(xlbox), 16)
+            }
+            [s0, s1, s2, s3, t0, t1, t2, t3, ..] => {
+                let sbox = u32::from_be_bytes([s0, s1, s2, s3]);
+                let tbox = ContainerBoxType([t0, t1, t2, t3]);
+                let sbox = if sbox == 0 {
+                    None
+                } else if let Some(sbox) = sbox.checked_sub(8) {
+                    Some(sbox as u64)
+                } else {
+                    return Err(Error::InvalidBox);
+                };
+                (tbox, sbox, 8)
+            }
+            _ => return Ok(HeaderParseResult::NeedMoreData),
+        };
+        let is_last = box_size.is_none();
+
+        let header = Self {
+            ty: tbox,
+            box_size,
+            is_last,
+        };
+        Ok(HeaderParseResult::Done {
+            header,
+            header_size,
+        })
+    }
+}
+
+impl ContainerBoxHeader {
+    #[inline]
+    pub fn box_type(&self) -> ContainerBoxType {
+        self.ty
+    }
+
+    #[inline]
+    pub fn box_size(&self) -> Option<u64> {
+        self.box_size
+    }
+
+    #[inline]
+    pub fn is_last(&self) -> bool {
+        self.is_last
+    }
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+pub struct ContainerBoxType(pub [u8; 4]);
+
+impl ContainerBoxType {
+    pub const JXL: Self = Self(*b"JXL ");
+    pub const FILE_TYPE: Self = Self(*b"ftyp");
+    pub const JXL_LEVEL: Self = Self(*b"jxll");
+    pub const JUMBF: Self = Self(*b"jumb");
+    pub const EXIF: Self = Self(*b"Exif");
+    pub const XML: Self = Self(*b"xml ");
+    pub const BROTLI_COMPRESSED: Self = Self(*b"brob");
+    pub const FRAME_INDEX: Self = Self(*b"jxli");
+    pub const CODESTREAM: Self = Self(*b"jxlc");
+    pub const PARTIAL_CODESTREAM: Self = Self(*b"jxlp");
+    pub const JPEG_RECONSTRUCTION: Self = Self(*b"jbrd");
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/container/mod.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/container/mod.rs
new file mode 100644
index 0000000..c6e9e50
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/container/mod.rs
@@ -0,0 +1,187 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// Originally written for jxl-oxide.
+
+pub mod box_header;
+pub mod parse;
+
+use box_header::*;
+pub use parse::ParseEvent;
+use parse::*;
+
+/// Container format parser.
+#[derive(Debug, Default)]
+pub struct ContainerParser {
+    state: DetectState,
+    jxlp_index_state: JxlpIndexState,
+    previous_consumed_bytes: usize,
+}
+
+#[derive(Debug, Default)]
+enum DetectState {
+    #[default]
+    WaitingSignature,
+    WaitingBoxHeader,
+    WaitingJxlpIndex(ContainerBoxHeader),
+    InAuxBox {
+        #[allow(unused)]
+        header: ContainerBoxHeader,
+        bytes_left: Option<usize>,
+    },
+    InCodestream {
+        kind: BitstreamKind,
+        bytes_left: Option<usize>,
+    },
+}
+
+/// Structure of the decoded bitstream.
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum BitstreamKind {
+    /// Decoder can't determine structure of the bitstream.
+    Unknown,
+    /// Bitstream is a direct JPEG XL codestream without box structure.
+    BareCodestream,
+    /// Bitstream is a JPEG XL container with box structure.
+    Container,
+    /// Bitstream is not a valid JPEG XL image.
+    Invalid,
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
+enum JxlpIndexState {
+    #[default]
+    Initial,
+    SingleJxlc,
+    Jxlp(u32),
+    JxlpFinished,
+}
+
+impl ContainerParser {
+    pub fn new() -> Self {
+        Self::default()
+    }
+
+    pub fn kind(&self) -> BitstreamKind {
+        match self.state {
+            DetectState::WaitingSignature => BitstreamKind::Unknown,
+            DetectState::WaitingBoxHeader
+            | DetectState::WaitingJxlpIndex(..)
+            | DetectState::InAuxBox { .. } => BitstreamKind::Container,
+            DetectState::InCodestream { kind, .. } => kind,
+        }
+    }
+
+    /// Parses input buffer and generates parser events.
+    ///
+    /// The parser might not fully consume the buffer. Use [`previous_consumed_bytes`] to get how
+    /// many bytes are consumed. Bytes not consumed by the parser should be processed again.
+    ///
+    /// [`previous_consumed_bytes`]: ContainerParser::previous_consumed_bytes
+    pub fn process_bytes<'inner, 'buf>(
+        &'inner mut self,
+        input: &'buf [u8],
+    ) -> ParseEvents<'inner, 'buf> {
+        ParseEvents::new(self, input)
+    }
+
+    /// Get how many bytes are consumed by the previous call to [`process_bytes`].
+    ///
+    /// Bytes not consumed by the parser should be processed again.
+    ///
+    /// [`process_bytes`]: ContainerParser::process_bytes
+    pub fn previous_consumed_bytes(&self) -> usize {
+        self.previous_consumed_bytes
+    }
+}
+
+#[cfg(test)]
+impl ContainerParser {
+    pub(crate) fn collect_codestream(input: &[u8]) -> crate::error::Result<Vec<u8>> {
+        let mut parser = Self::new();
+        let mut codestream = Vec::new();
+        for event in parser.process_bytes(input) {
+            match event? {
+                ParseEvent::BitstreamKind(_) => {}
+                ParseEvent::Codestream(buf) => {
+                    codestream.extend_from_slice(buf);
+                }
+            }
+        }
+        Ok(codestream)
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use test_log::test;
+
+    #[rustfmt::skip]
+    const HEADER: &[u8] = &[
+        0x00, 0x00, 0x00, 0x0c, b'J', b'X', b'L', b' ', 0x0d, 0x0a, 0x87, 0x0a, 0x00, 0x00, 0x00, 0x14,
+        b'f', b't', b'y', b'p', b'j', b'x', b'l', b' ', 0x00, 0x00, 0x00, 0x00, b'j', b'x', b'l', b' ',
+    ];
+
+    #[test]
+    fn parse_partial() {
+        arbtest::arbtest(|u| {
+            // Prepare arbitrary container format data with two jxlp boxes.
+            let total_len = u.arbitrary_len::<u8>()?;
+            let mut codestream0 = vec![0u8; total_len / 2];
+            u.fill_buffer(&mut codestream0)?;
+            let mut codestream1 = vec![0u8; total_len - codestream0.len()];
+            u.fill_buffer(&mut codestream1)?;
+
+            let mut container = HEADER.to_vec();
+            container.extend_from_slice(&(12 + codestream0.len() as u32).to_be_bytes());
+            container.extend_from_slice(b"jxlp\x00\x00\x00\x00");
+            container.extend_from_slice(&codestream0);
+
+            container.extend_from_slice(&(12 + codestream1.len() as u32).to_be_bytes());
+            container.extend_from_slice(b"jxlp\x80\x00\x00\x01");
+            container.extend_from_slice(&codestream1);
+
+            let mut expected = codestream0;
+            expected.extend(codestream1);
+
+            // Create a list of arbitrary splits.
+            let mut tests = Vec::new();
+            u.arbitrary_loop(Some(1), Some(10), |u| {
+                let split_at_idx = u.choose_index(container.len())?;
+                tests.push(container.split_at(split_at_idx));
+                Ok(std::ops::ControlFlow::Continue(()))
+            })?;
+
+            // Test if split index doesn't affect final codestream.
+            for (first, second) in tests {
+                let mut codestream = Vec::new();
+                let mut parser = ContainerParser::new();
+
+                for event in parser.process_bytes(first) {
+                    let event = event.unwrap();
+                    if let ParseEvent::Codestream(data) = event {
+                        codestream.extend_from_slice(data);
+                    }
+                }
+
+                let consumed = parser.previous_consumed_bytes();
+                let mut second_chunk = first[consumed..].to_vec();
+                second_chunk.extend_from_slice(second);
+
+                for event in parser.process_bytes(&second_chunk) {
+                    let event = event.unwrap();
+                    if let ParseEvent::Codestream(data) = event {
+                        codestream.extend_from_slice(data);
+                    }
+                }
+
+                assert_eq!(codestream, expected);
+            }
+
+            Ok(())
+        });
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/container/parse.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/container/parse.rs
new file mode 100644
index 0000000..726516d2
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/container/parse.rs
@@ -0,0 +1,273 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// Originally written for jxl-oxide.
+
+use super::{BitstreamKind, ContainerParser, DetectState, JxlpIndexState, box_header::*};
+use crate::{
+    api::{CODESTREAM_SIGNATURE, CONTAINER_SIGNATURE},
+    error::{Error, Result},
+    util::tracing_wrappers::*,
+};
+
+/// Iterator that reads over a buffer and emits parser events.
+pub struct ParseEvents<'inner, 'buf> {
+    inner: &'inner mut ContainerParser,
+    remaining_input: &'buf [u8],
+    finished: bool,
+}
+
+impl<'inner, 'buf> ParseEvents<'inner, 'buf> {
+    pub(super) fn new(parser: &'inner mut ContainerParser, input: &'buf [u8]) -> Self {
+        parser.previous_consumed_bytes = 0;
+        Self {
+            inner: parser,
+            remaining_input: input,
+            finished: false,
+        }
+    }
+
+    fn emit_single(&mut self) -> Result<Option<ParseEvent<'buf>>> {
+        let state = &mut self.inner.state;
+        let jxlp_index_state = &mut self.inner.jxlp_index_state;
+        let buf = &mut self.remaining_input;
+
+        loop {
+            if buf.is_empty() {
+                self.finished = true;
+                return Ok(None);
+            }
+
+            match state {
+                DetectState::WaitingSignature => {
+                    if buf.starts_with(&CODESTREAM_SIGNATURE) {
+                        info!("Codestream signature found");
+                        *state = DetectState::InCodestream {
+                            kind: BitstreamKind::BareCodestream,
+                            bytes_left: None,
+                        };
+                        return Ok(Some(ParseEvent::BitstreamKind(
+                            BitstreamKind::BareCodestream,
+                        )));
+                    } else if buf.starts_with(&CONTAINER_SIGNATURE) {
+                        info!("Container signature found");
+                        *state = DetectState::WaitingBoxHeader;
+                        *buf = &buf[CONTAINER_SIGNATURE.len()..];
+                        return Ok(Some(ParseEvent::BitstreamKind(BitstreamKind::Container)));
+                    } else if !CODESTREAM_SIGNATURE.starts_with(buf)
+                        && !CONTAINER_SIGNATURE.starts_with(buf)
+                    {
+                        warn!(?buf, "Invalid signature");
+                        *state = DetectState::InCodestream {
+                            kind: BitstreamKind::Invalid,
+                            bytes_left: None,
+                        };
+                        return Ok(Some(ParseEvent::BitstreamKind(BitstreamKind::Invalid)));
+                    } else {
+                        return Ok(None);
+                    }
+                }
+                DetectState::WaitingBoxHeader => match ContainerBoxHeader::parse(buf)? {
+                    HeaderParseResult::Done {
+                        header,
+                        header_size,
+                    } => {
+                        *buf = &buf[header_size..];
+                        let tbox = header.box_type();
+                        if tbox == ContainerBoxType::CODESTREAM {
+                            match jxlp_index_state {
+                                JxlpIndexState::Initial => {
+                                    *jxlp_index_state = JxlpIndexState::SingleJxlc;
+                                }
+                                JxlpIndexState::SingleJxlc => {
+                                    warn!("Duplicate jxlc box found");
+                                    return Err(Error::InvalidBox);
+                                }
+                                JxlpIndexState::Jxlp(_) | JxlpIndexState::JxlpFinished => {
+                                    warn!("Found jxlc box instead of jxlp box");
+                                    return Err(Error::InvalidBox);
+                                }
+                            }
+
+                            *state = DetectState::InCodestream {
+                                kind: BitstreamKind::Container,
+                                bytes_left: header.box_size().map(|x| x as usize),
+                            };
+                        } else if tbox == ContainerBoxType::PARTIAL_CODESTREAM {
+                            if let Some(box_size) = header.box_size()
+                                && box_size < 4
+                            {
+                                return Err(Error::InvalidBox);
+                            }
+
+                            match jxlp_index_state {
+                                JxlpIndexState::Initial => {
+                                    *jxlp_index_state = JxlpIndexState::Jxlp(0);
+                                }
+                                JxlpIndexState::Jxlp(index) => {
+                                    *index += 1;
+                                }
+                                JxlpIndexState::SingleJxlc => {
+                                    warn!("jxlp box found after jxlc box");
+                                    return Err(Error::InvalidBox);
+                                }
+                                JxlpIndexState::JxlpFinished => {
+                                    warn!("found another jxlp box after the final one");
+                                    return Err(Error::InvalidBox);
+                                }
+                            }
+
+                            *state = DetectState::WaitingJxlpIndex(header);
+                        } else {
+                            let bytes_left = header.box_size().map(|x| x as usize);
+                            *state = DetectState::InAuxBox { header, bytes_left };
+                        }
+                    }
+                    HeaderParseResult::NeedMoreData => return Ok(None),
+                },
+                DetectState::WaitingJxlpIndex(header) => {
+                    let &[b0, b1, b2, b3, ..] = &**buf else {
+                        return Ok(None);
+                    };
+
+                    let index = u32::from_be_bytes([b0, b1, b2, b3]);
+                    *buf = &buf[4..];
+                    let is_last = index & 0x80000000 != 0;
+                    let index = index & 0x7fffffff;
+
+                    match *jxlp_index_state {
+                        JxlpIndexState::Jxlp(expected_index) if expected_index == index => {
+                            if is_last {
+                                *jxlp_index_state = JxlpIndexState::JxlpFinished;
+                            }
+                        }
+                        #[allow(unused_variables)]
+                        JxlpIndexState::Jxlp(expected_index) => {
+                            warn!(
+                                expected_index,
+                                actual_index = index,
+                                "Out-of-order jxlp box found",
+                            );
+                            return Err(Error::InvalidBox);
+                        }
+                        state => {
+                            unreachable!("invalid jxlp index state in WaitingJxlpIndex: {state:?}");
+                        }
+                    }
+
+                    *state = DetectState::InCodestream {
+                        kind: BitstreamKind::Container,
+                        bytes_left: header.box_size().map(|x| x as usize - 4),
+                    };
+                }
+                DetectState::InCodestream {
+                    bytes_left: None, ..
+                } => {
+                    let payload = *buf;
+                    *buf = &[];
+                    return Ok(Some(ParseEvent::Codestream(payload)));
+                }
+                DetectState::InCodestream {
+                    bytes_left: Some(bytes_left),
+                    ..
+                } => {
+                    let payload = if buf.len() >= *bytes_left {
+                        let (payload, remaining) = buf.split_at(*bytes_left);
+                        *state = DetectState::WaitingBoxHeader;
+                        *buf = remaining;
+                        payload
+                    } else {
+                        let payload = *buf;
+                        *bytes_left -= buf.len();
+                        *buf = &[];
+                        payload
+                    };
+                    return Ok(Some(ParseEvent::Codestream(payload)));
+                }
+                DetectState::InAuxBox {
+                    header: _,
+                    bytes_left: None,
+                } => {
+                    let _payload = *buf;
+                    *buf = &[];
+                    // FIXME: emit auxiliary box event
+                }
+                DetectState::InAuxBox {
+                    header: _,
+                    bytes_left: Some(bytes_left),
+                } => {
+                    let _payload = if buf.len() >= *bytes_left {
+                        let (payload, remaining) = buf.split_at(*bytes_left);
+                        *state = DetectState::WaitingBoxHeader;
+                        *buf = remaining;
+                        payload
+                    } else {
+                        let payload = *buf;
+                        *bytes_left -= buf.len();
+                        *buf = &[];
+                        payload
+                    };
+                    // FIXME: emit auxiliary box event
+                }
+            }
+        }
+    }
+}
+
+impl std::fmt::Debug for ParseEvents<'_, '_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.debug_struct("ParseEvents")
+            .field("inner", &self.inner)
+            .field(
+                "remaining_input",
+                &format_args!("({} byte(s))", self.remaining_input.len()),
+            )
+            .field("finished", &self.finished)
+            .finish()
+    }
+}
+
+impl<'buf> Iterator for ParseEvents<'_, 'buf> {
+    type Item = Result<ParseEvent<'buf>>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.finished {
+            return None;
+        }
+
+        let initial_buf = self.remaining_input;
+        let event = self.emit_single();
+
+        if event.is_err() {
+            self.finished = true;
+        }
+
+        self.inner.previous_consumed_bytes += initial_buf.len() - self.remaining_input.len();
+        event.transpose()
+    }
+}
+
+/// Parser event emitted by [`ParseEvents`].
+pub enum ParseEvent<'buf> {
+    /// Bitstream structure is detected.
+    BitstreamKind(BitstreamKind),
+    /// Codestream data is read.
+    ///
+    /// Returned data may be partial. Complete codestream can be obtained by concatenating all data
+    /// of `Codestream` events.
+    Codestream(&'buf [u8]),
+}
+
+impl std::fmt::Debug for ParseEvent<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Self::BitstreamKind(kind) => f.debug_tuple("BitstreamKind").field(kind).finish(),
+            Self::Codestream(buf) => f
+                .debug_tuple("Codestream")
+                .field(&format_args!("{} byte(s)", buf.len()))
+                .finish(),
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/entropy_coding/ans.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/entropy_coding/ans.rs
new file mode 100644
index 0000000..c6b95d1
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/entropy_coding/ans.rs
@@ -0,0 +1,491 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// Originally written for jxl-oxide.
+
+use crate::bit_reader::BitReader;
+use crate::error::{Error, Result};
+
+const LOG_SUM_PROBS: usize = 12;
+const SUM_PROBS: u16 = 1 << LOG_SUM_PROBS;
+
+const RLE_MARKER_SYM: u16 = LOG_SUM_PROBS as u16 + 1;
+
+#[derive(Debug)]
+struct AnsHistogram {
+    buckets: Vec<Bucket>,
+    log_bucket_size: usize,
+    bucket_mask: u32,
+    // For optimizing fast-lossless case.
+    single_symbol: Option<u32>,
+}
+
+// log_alphabet_size <= 8 and log_bucket_size <= 7, so u8 is sufficient for symbols and cutoffs.
+#[derive(Debug, Copy, Clone)]
+#[repr(C)]
+struct Bucket {
+    alias_symbol: u8,
+    alias_cutoff: u8,
+    dist: u16,
+    alias_offset: u16,
+    alias_dist_xor: u16,
+}
+
+impl AnsHistogram {
+    fn decode_dist_two_symbols(br: &mut BitReader, dist: &mut [u16]) -> Result<usize> {
+        let table_size = dist.len();
+
+        let v0 = Self::read_u8(br)? as usize;
+        let v1 = Self::read_u8(br)? as usize;
+        if v0 == v1 {
+            return Err(Error::InvalidAnsHistogram);
+        }
+
+        let alphabet_size = v0.max(v1) + 1;
+        if alphabet_size > table_size {
+            return Err(Error::InvalidAnsHistogram);
+        }
+
+        let prob = br.read(LOG_SUM_PROBS)? as u16;
+        dist[v0] = prob;
+        dist[v1] = SUM_PROBS - prob;
+
+        Ok(alphabet_size)
+    }
+
+    fn decode_dist_single_symbol(br: &mut BitReader, dist: &mut [u16]) -> Result<usize> {
+        let table_size = dist.len();
+
+        let val = Self::read_u8(br)? as usize;
+        let alphabet_size = val + 1;
+        if alphabet_size > table_size {
+            return Err(Error::InvalidAnsHistogram);
+        }
+
+        dist[val] = SUM_PROBS;
+
+        Ok(alphabet_size)
+    }
+
+    fn decode_dist_evenly_distributed(br: &mut BitReader, dist: &mut [u16]) -> Result<usize> {
+        let table_size = dist.len();
+
+        let alphabet_size = Self::read_u8(br)? as usize + 1;
+        if alphabet_size > table_size {
+            return Err(Error::InvalidAnsHistogram);
+        }
+
+        let base = SUM_PROBS as usize / alphabet_size;
+        let remainder = SUM_PROBS as usize % alphabet_size;
+        dist[0..remainder].fill(base as u16 + 1);
+        dist[remainder..alphabet_size].fill(base as u16);
+
+        Ok(alphabet_size)
+    }
+
+    fn decode_dist_complex(br: &mut BitReader, dist: &mut [u16]) -> Result<usize> {
+        let table_size = dist.len();
+
+        let mut len = 0usize;
+        while len < 3 {
+            if br.read(1)? != 0 {
+                len += 1;
+            } else {
+                break;
+            }
+        }
+
+        let shift = (br.read(len)? + (1 << len) - 1) as i16;
+        if shift > 13 {
+            return Err(Error::InvalidAnsHistogram);
+        }
+
+        let alphabet_size = Self::read_u8(br)? as usize + 3;
+        if alphabet_size > table_size {
+            return Err(Error::InvalidAnsHistogram);
+        }
+
+        // TODO(tirr-c): This could be an array of length `SUM_PROB / 4` (4 is from the minimum
+        // value of `repeat_count`). Change if using array is faster.
+        let mut repeat_ranges = Vec::new();
+        let mut omit_data = None;
+        let mut idx = 0;
+        while idx < alphabet_size {
+            dist[idx] = Self::read_prefix(br)?;
+            if dist[idx] == RLE_MARKER_SYM {
+                let repeat_count = Self::read_u8(br)? as usize + 4;
+                if idx + repeat_count > alphabet_size {
+                    return Err(Error::InvalidAnsHistogram);
+                }
+                repeat_ranges.push(idx..(idx + repeat_count));
+                idx += repeat_count;
+                continue;
+            }
+            match &mut omit_data {
+                Some((log, pos)) => {
+                    if dist[idx] > *log {
+                        *log = dist[idx];
+                        *pos = idx;
+                    }
+                }
+                data => {
+                    *data = Some((dist[idx], idx));
+                }
+            }
+            idx += 1;
+        }
+        let Some((_, omit_pos)) = omit_data else {
+            return Err(Error::InvalidAnsHistogram);
+        };
+        if dist.get(omit_pos + 1) == Some(&RLE_MARKER_SYM) {
+            return Err(Error::InvalidAnsHistogram);
+        }
+
+        let mut repeat_range_idx = 0usize;
+        let mut acc = 0;
+        let mut prev_dist = 0u16;
+        for (idx, code) in dist.iter_mut().enumerate() {
+            if repeat_range_idx < repeat_ranges.len()
+                && repeat_ranges[repeat_range_idx].start <= idx
+            {
+                if repeat_ranges[repeat_range_idx].end == idx {
+                    repeat_range_idx += 1;
+                } else {
+                    *code = prev_dist;
+                    acc += *code;
+                    // dist[omit_pos] > 0
+                    if acc >= SUM_PROBS {
+                        return Err(Error::InvalidAnsHistogram);
+                    }
+                    continue;
+                }
+            }
+
+            if *code == 0 {
+                prev_dist = 0;
+                continue;
+            }
+            if idx == omit_pos {
+                prev_dist = 0;
+                continue;
+            }
+            if *code > 1 {
+                let zeros = (*code - 1) as i16;
+                let bitcount = (shift - ((LOG_SUM_PROBS as i16 - zeros) >> 1)).clamp(0, zeros);
+                *code = (1 << zeros) + ((br.read(bitcount as usize)? as u16) << (zeros - bitcount));
+            }
+
+            prev_dist = *code;
+            acc += *code;
+            // dist[omit_pos] > 0
+            if acc >= SUM_PROBS {
+                return Err(Error::InvalidAnsHistogram);
+            }
+        }
+        dist[omit_pos] = SUM_PROBS - acc;
+
+        Ok(alphabet_size)
+    }
+
+    fn build_alias_map(alphabet_size: usize, log_bucket_size: usize, dist: &[u16]) -> Vec<Bucket> {
+        #[derive(Debug)]
+        struct WorkingBucket {
+            dist: u16,
+            alias_symbol: u16,
+            alias_offset: u16,
+            alias_cutoff: u16,
+        }
+
+        let bucket_size = 1u16 << log_bucket_size;
+        let mut buckets: Vec<_> = dist
+            .iter()
+            .enumerate()
+            .map(|(i, &dist)| WorkingBucket {
+                dist,
+                alias_symbol: if i < alphabet_size { i as u16 } else { 0 },
+                alias_offset: 0,
+                alias_cutoff: dist,
+            })
+            .collect();
+
+        let mut underfull = Vec::new();
+        let mut overfull = Vec::new();
+        for (idx, &WorkingBucket { dist, .. }) in buckets.iter().enumerate() {
+            match dist.cmp(&bucket_size) {
+                std::cmp::Ordering::Less => underfull.push(idx),
+                std::cmp::Ordering::Equal => {}
+                std::cmp::Ordering::Greater => overfull.push(idx),
+            }
+        }
+        while let (Some(o), Some(u)) = (overfull.pop(), underfull.pop()) {
+            let by = bucket_size - buckets[u].alias_cutoff;
+            buckets[o].alias_cutoff -= by;
+            buckets[u].alias_symbol = o as u16;
+            buckets[u].alias_offset = buckets[o].alias_cutoff;
+            match buckets[o].alias_cutoff.cmp(&bucket_size) {
+                std::cmp::Ordering::Less => underfull.push(o),
+                std::cmp::Ordering::Equal => {}
+                std::cmp::Ordering::Greater => overfull.push(o),
+            }
+        }
+
+        // Assertion failure happens only if `dist` doesn't sum to `SUM_PROB`, which is checked
+        // before building alias map.
+        assert!(overfull.is_empty() && underfull.is_empty());
+
+        buckets
+            .iter()
+            .enumerate()
+            .map(|(idx, bucket)| {
+                if bucket.alias_cutoff == bucket_size {
+                    Bucket {
+                        dist: bucket.dist,
+                        alias_symbol: idx as u8,
+                        alias_offset: 0,
+                        alias_cutoff: 0,
+                        alias_dist_xor: 0,
+                    }
+                } else {
+                    Bucket {
+                        dist: bucket.dist,
+                        alias_symbol: bucket.alias_symbol as u8,
+                        alias_offset: bucket.alias_offset - bucket.alias_cutoff,
+                        alias_cutoff: bucket.alias_cutoff as u8,
+                        alias_dist_xor: bucket.dist ^ buckets[bucket.alias_symbol as usize].dist,
+                    }
+                }
+            })
+            .collect()
+    }
+
+    // log_alphabet_size: 5 + u(2)
+    pub fn decode(br: &mut BitReader, log_alpha_size: usize) -> Result<Self> {
+        debug_assert!((5..=8).contains(&log_alpha_size));
+        let table_size = (1u16 << log_alpha_size) as usize;
+        // 4 <= log_bucket_size <= 7
+        let log_bucket_size = LOG_SUM_PROBS - log_alpha_size;
+        let bucket_size = 1u16 << log_bucket_size;
+        let bucket_mask = bucket_size as u32 - 1;
+
+        let mut dist = vec![0u16; table_size];
+        let alphabet_size = if br.read(1)? != 0 {
+            if br.read(1)? != 0 {
+                Self::decode_dist_two_symbols(br, &mut dist)?
+            } else {
+                Self::decode_dist_single_symbol(br, &mut dist)?
+            }
+        } else if br.read(1)? != 0 {
+            Self::decode_dist_evenly_distributed(br, &mut dist)?
+        } else {
+            Self::decode_dist_complex(br, &mut dist)?
+        };
+
+        if let Some(single_sym_idx) = dist.iter().position(|&d| d == SUM_PROBS) {
+            let buckets = dist
+                .into_iter()
+                .enumerate()
+                .map(|(i, dist)| Bucket {
+                    dist,
+                    alias_symbol: single_sym_idx as u8,
+                    alias_offset: bucket_size * i as u16,
+                    alias_cutoff: 0,
+                    alias_dist_xor: dist ^ SUM_PROBS,
+                })
+                .collect();
+            return Ok(Self {
+                buckets,
+                log_bucket_size,
+                bucket_mask,
+                single_symbol: Some(single_sym_idx as u32),
+            });
+        }
+
+        Ok(Self {
+            buckets: Self::build_alias_map(alphabet_size, log_bucket_size, &dist),
+            log_bucket_size,
+            bucket_mask,
+            single_symbol: None,
+        })
+    }
+
+    fn read_u8(bitstream: &mut BitReader) -> Result<u8> {
+        Ok(if bitstream.read(1)? != 0 {
+            let n = bitstream.read(3)?;
+            ((1 << n) + bitstream.read(n as usize)?) as u8
+        } else {
+            0
+        })
+    }
+
+    fn read_prefix(br: &mut BitReader) -> Result<u16> {
+        // Prefix code lookup table.
+        #[rustfmt::skip]
+        const TABLE: [(u8, u8); 128] = [
+            (10, 3), (12, 7), (7, 3), (3, 4), (6, 3), (8, 3), (9, 3), (5, 4),
+            (10, 3), ( 4, 4), (7, 3), (1, 4), (6, 3), (8, 3), (9, 3), (2, 4),
+            (10, 3), ( 0, 5), (7, 3), (3, 4), (6, 3), (8, 3), (9, 3), (5, 4),
+            (10, 3), ( 4, 4), (7, 3), (1, 4), (6, 3), (8, 3), (9, 3), (2, 4),
+            (10, 3), (11, 6), (7, 3), (3, 4), (6, 3), (8, 3), (9, 3), (5, 4),
+            (10, 3), ( 4, 4), (7, 3), (1, 4), (6, 3), (8, 3), (9, 3), (2, 4),
+            (10, 3), ( 0, 5), (7, 3), (3, 4), (6, 3), (8, 3), (9, 3), (5, 4),
+            (10, 3), ( 4, 4), (7, 3), (1, 4), (6, 3), (8, 3), (9, 3), (2, 4),
+            (10, 3), (13, 7), (7, 3), (3, 4), (6, 3), (8, 3), (9, 3), (5, 4),
+            (10, 3), ( 4, 4), (7, 3), (1, 4), (6, 3), (8, 3), (9, 3), (2, 4),
+            (10, 3), ( 0, 5), (7, 3), (3, 4), (6, 3), (8, 3), (9, 3), (5, 4),
+            (10, 3), ( 4, 4), (7, 3), (1, 4), (6, 3), (8, 3), (9, 3), (2, 4),
+            (10, 3), (11, 6), (7, 3), (3, 4), (6, 3), (8, 3), (9, 3), (5, 4),
+            (10, 3), ( 4, 4), (7, 3), (1, 4), (6, 3), (8, 3), (9, 3), (2, 4),
+            (10, 3), ( 0, 5), (7, 3), (3, 4), (6, 3), (8, 3), (9, 3), (5, 4),
+            (10, 3), ( 4, 4), (7, 3), (1, 4), (6, 3), (8, 3), (9, 3), (2, 4),
+        ];
+
+        let index = br.peek(7);
+        let (sym, bits) = TABLE[index as usize];
+        br.consume(bits as usize)?;
+        Ok(sym as u16)
+    }
+}
+
+impl AnsHistogram {
+    #[inline]
+    pub fn read(&self, br: &mut BitReader, state: &mut u32) -> u32 {
+        let idx = *state & 0xfff;
+        let i = (idx >> self.log_bucket_size) as usize;
+        let pos = idx & self.bucket_mask;
+
+        debug_assert!(self.buckets.len().is_power_of_two());
+        let bucket = self.buckets[i & (self.buckets.len() - 1)];
+        let alias_symbol = bucket.alias_symbol as u32;
+        let alias_cutoff = bucket.alias_cutoff as u32;
+        let dist = bucket.dist as u32;
+
+        let map_to_alias = (pos >= alias_cutoff) as u32;
+        let offset = (bucket.alias_offset as u32) * map_to_alias;
+        let dist_xor = (bucket.alias_dist_xor as u32) * map_to_alias;
+
+        let dist = dist ^ dist_xor;
+        let symbol = (alias_symbol * map_to_alias) | (i as u32 * (1 - map_to_alias));
+        let offset = offset + pos;
+
+        let next_state = (*state >> LOG_SUM_PROBS) * dist + offset;
+        let select_appended = (next_state < (1 << 16)) as u32;
+        let appended_state = (next_state << 16) | (br.peek(16) as u32);
+        *state = (appended_state * select_appended) | (next_state * (1 - select_appended));
+        br.consume_optimistic((16 * select_appended) as usize);
+        symbol
+    }
+
+    // For optimizing fast-lossless case.
+    #[inline]
+    pub fn single_symbol(&self) -> Option<u32> {
+        self.single_symbol
+    }
+}
+
+#[derive(Debug)]
+pub struct AnsCodes {
+    histograms: Vec<AnsHistogram>,
+}
+
+impl AnsCodes {
+    pub fn decode(num: usize, log_alpha_size: usize, br: &mut BitReader) -> Result<AnsCodes> {
+        let histograms = (0..num)
+            .map(|_| AnsHistogram::decode(br, log_alpha_size))
+            .collect::<Result<_>>()?;
+        Ok(Self { histograms })
+    }
+
+    pub fn single_symbol(&self, ctx: usize) -> Option<u32> {
+        self.histograms[ctx].single_symbol()
+    }
+}
+
+#[derive(Debug)]
+pub struct AnsReader(u32);
+
+impl AnsReader {
+    /// Expected final ANS state.
+    const CHECKSUM: u32 = 0x130000;
+
+    pub fn new_unused() -> Self {
+        Self(Self::CHECKSUM)
+    }
+
+    pub fn init(br: &mut BitReader) -> Result<Self> {
+        let initial_state = br.read(32)? as u32;
+        Ok(Self(initial_state))
+    }
+
+    #[inline]
+    pub fn read(&mut self, codes: &AnsCodes, br: &mut BitReader, ctx: usize) -> u32 {
+        codes.histograms[ctx].read(br, &mut self.0)
+    }
+
+    pub fn check_final_state(self) -> Result<()> {
+        if self.0 == Self::CHECKSUM {
+            Ok(())
+        } else {
+            Err(Error::AnsChecksumMismatch)
+        }
+    }
+
+    pub(super) fn checkpoint(&self) -> Self {
+        Self(self.0)
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    fn validate_buckets(buckets: &[Bucket]) {
+        let dist_sum: u16 = buckets.iter().map(|bucket| bucket.dist).sum();
+        assert_eq!(dist_sum, SUM_PROBS);
+    }
+
+    #[test]
+    fn single_symbol() {
+        // Single symbol of 20
+        let mut br = BitReader::new(&[0b00100101, 0b01]);
+        let histogram = AnsHistogram::decode(&mut br, 5).unwrap();
+        validate_buckets(&histogram.buckets);
+        assert_eq!(histogram.buckets[20].dist, SUM_PROBS);
+        assert_eq!(histogram.single_symbol, Some(20));
+
+        // Single symbol of 32 (invalid)
+        let mut br = BitReader::new(&[0b00101101, 0b000]);
+        assert!(AnsHistogram::decode(&mut br, 5).is_err());
+    }
+
+    #[test]
+    fn two_symbols() {
+        // two symbols of 10 and 20, where the prob of symbol 10 is 256
+        let mut br = BitReader::new(&[0b10011111, 0b10010010, 0b00000000, 0b00010]);
+        let histogram = AnsHistogram::decode(&mut br, 5).unwrap();
+        validate_buckets(&histogram.buckets);
+        assert_eq!(histogram.buckets[10].dist, 256);
+        assert_eq!(histogram.buckets[20].dist, SUM_PROBS - 256);
+    }
+
+    #[test]
+    fn decode_arb() {
+        arbtest::arbtest(|u| {
+            let total_len = u.arbitrary_len::<u8>()?;
+            let mut buf = vec![0u8; total_len];
+            u.fill_buffer(&mut buf)?;
+            let mut br = BitReader::new(&buf);
+
+            loop {
+                match AnsHistogram::decode(&mut br, 8) {
+                    Ok(histogram) => validate_buckets(&histogram.buckets),
+                    Err(Error::OutOfBounds(_)) => break,
+                    Err(_) => {}
+                }
+            }
+
+            Ok(())
+        });
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/entropy_coding/context_map.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/entropy_coding/context_map.rs
new file mode 100644
index 0000000..95e7353
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/entropy_coding/context_map.rs
@@ -0,0 +1,76 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::bit_reader::BitReader;
+use crate::error::Error;
+use std::collections::HashSet;
+
+use crate::entropy_coding::decode::*;
+
+fn move_to_front(v: &mut [u8], index: u8) {
+    let value = v[index as usize];
+    for i in (1..=index as usize).rev() {
+        v[i] = v[i - 1];
+    }
+    v[0] = value;
+}
+
+fn inverse_move_to_front(v: &mut [u8]) {
+    let mut mtf: [u8; 256] = std::array::from_fn(|x| x as u8);
+    for val in v.iter_mut() {
+        let index = *val;
+        *val = mtf[index as usize];
+        if index != 0 {
+            move_to_front(&mut mtf, index);
+        }
+    }
+}
+
+fn verify_context_map(ctx_map: &[u8]) -> Result<(), Error> {
+    let num_histograms = *ctx_map.iter().max().unwrap() as u32 + 1;
+    let distinct_histograms = ctx_map.iter().collect::<HashSet<_>>().len() as u32;
+    if distinct_histograms != num_histograms {
+        return Err(Error::InvalidContextMapHole(
+            num_histograms,
+            distinct_histograms,
+        ));
+    }
+    Ok(())
+}
+
+pub fn decode_context_map(num_contexts: usize, br: &mut BitReader) -> Result<Vec<u8>, Error> {
+    let is_simple = br.read(1)? != 0;
+    if is_simple {
+        let bits_per_entry = br.read(2)? as usize;
+        if bits_per_entry != 0 {
+            (0..num_contexts)
+                .map(|_| Ok(br.read(bits_per_entry)? as u8))
+                .collect()
+        } else {
+            Ok(vec![0u8; num_contexts])
+        }
+    } else {
+        let use_mtf = br.read(1)? != 0;
+        let histograms = Histograms::decode(1, br, /*allow_lz77=*/ num_contexts > 2)?;
+        let mut reader = SymbolReader::new(&histograms, br, None)?;
+
+        let mut ctx_map: Vec<u8> = (0..num_contexts)
+            .map(|_| {
+                let mv = reader.read_unsigned(&histograms, br, 0usize);
+                if mv > u8::MAX as u32 {
+                    Err(Error::InvalidContextMap(mv))
+                } else {
+                    Ok(mv as u8)
+                }
+            })
+            .collect::<Result<_, _>>()?;
+        reader.check_final_state(&histograms, br)?;
+        if use_mtf {
+            inverse_move_to_front(&mut ctx_map[..]);
+        }
+        verify_context_map(&ctx_map[..])?;
+        Ok(ctx_map)
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/entropy_coding/decode.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/entropy_coding/decode.rs
new file mode 100644
index 0000000..c58d1f4
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/entropy_coding/decode.rs
@@ -0,0 +1,682 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use jxl_macros::UnconditionalCoder;
+
+use crate::bit_reader::BitReader;
+use crate::entropy_coding::ans::*;
+use crate::entropy_coding::context_map::*;
+use crate::entropy_coding::huffman::*;
+use crate::entropy_coding::hybrid_uint::*;
+use crate::error::{Error, Result};
+use crate::headers::encodings::*;
+use crate::util::tracing_wrappers::*;
+
+pub fn decode_varint16(br: &mut BitReader) -> Result<u16> {
+    if br.read(1)? != 0 {
+        let nbits = br.read(4)? as usize;
+        if nbits == 0 {
+            Ok(1)
+        } else {
+            Ok((1 << nbits) + br.read(nbits)? as u16)
+        }
+    } else {
+        Ok(0)
+    }
+}
+
+pub fn unpack_signed(unsigned: u32) -> i32 {
+    ((unsigned >> 1) ^ ((!unsigned) & 1).wrapping_sub(1)) as i32
+}
+
+#[derive(UnconditionalCoder, Debug)]
+struct Lz77Params {
+    pub enabled: bool,
+    #[condition(enabled)]
+    #[coder(u2S(224, 512, 4096, Bits(15) + 8))]
+    pub min_symbol: Option<u32>,
+    #[condition(enabled)]
+    #[coder(u2S(3, 4, Bits(2) + 5, Bits(8) + 9))]
+    pub min_length: Option<u32>,
+}
+
+#[derive(Debug)]
+enum Codes {
+    Huffman(HuffmanCodes),
+    Ans(AnsCodes),
+}
+
+impl Codes {
+    fn single_symbol(&self, ctx: usize) -> Option<u32> {
+        match self {
+            Self::Huffman(hc) => hc.single_symbol(ctx),
+            Self::Ans(ans) => ans.single_symbol(ctx),
+        }
+    }
+}
+
+#[derive(Debug)]
+pub struct Histograms {
+    lz77_params: Lz77Params,
+    lz77_length_uint: Option<HybridUint>,
+    context_map: Vec<u8>,
+    // TODO(veluca): figure out why this is unused.
+    #[allow(dead_code)]
+    log_alpha_size: usize,
+    uint_configs: Vec<HybridUint>,
+    codes: Codes,
+}
+
+#[derive(Debug)]
+pub struct Lz77State {
+    min_symbol: u32,
+    min_length: u32,
+    dist_multiplier: u32,
+    window: Vec<u32>,
+    num_to_copy: u32,
+    copy_pos: u32,
+    num_decoded: u32,
+}
+
+impl Lz77State {
+    const LOG_WINDOW_SIZE: u32 = 20;
+    const WINDOW_MASK: u32 = (1 << Self::LOG_WINDOW_SIZE) - 1;
+
+    #[rustfmt::skip]
+    const SPECIAL_DISTANCES: [(i8, u8); 120] = [
+        ( 0, 1), ( 1, 0), ( 1, 1), (-1, 1), ( 0, 2), ( 2, 0), ( 1, 2), (-1, 2), ( 2, 1), (-2, 1),
+        ( 2, 2), (-2, 2), ( 0, 3), ( 3, 0), ( 1, 3), (-1, 3), ( 3, 1), (-3, 1), ( 2, 3), (-2, 3),
+        ( 3, 2), (-3, 2), ( 0, 4), ( 4, 0), ( 1, 4), (-1, 4), ( 4, 1), (-4, 1), ( 3, 3), (-3, 3),
+        ( 2, 4), (-2, 4), ( 4, 2), (-4, 2), ( 0, 5), ( 3, 4), (-3, 4), ( 4, 3), (-4, 3), ( 5, 0),
+        ( 1, 5), (-1, 5), ( 5, 1), (-5, 1), ( 2, 5), (-2, 5), ( 5, 2), (-5, 2), ( 4, 4), (-4, 4),
+        ( 3, 5), (-3, 5), ( 5, 3), (-5, 3), ( 0, 6), ( 6, 0), ( 1, 6), (-1, 6), ( 6, 1), (-6, 1),
+        ( 2, 6), (-2, 6), ( 6, 2), (-6, 2), ( 4, 5), (-4, 5), ( 5, 4), (-5, 4), ( 3, 6), (-3, 6),
+        ( 6, 3), (-6, 3), ( 0, 7), ( 7, 0), ( 1, 7), (-1, 7), ( 5, 5), (-5, 5), ( 7, 1), (-7, 1),
+        ( 4, 6), (-4, 6), ( 6, 4), (-6, 4), ( 2, 7), (-2, 7), ( 7, 2), (-7, 2), ( 3, 7), (-3, 7),
+        ( 7, 3), (-7, 3), ( 5, 6), (-5, 6), ( 6, 5), (-6, 5), ( 8, 0), ( 4, 7), (-4, 7), ( 7, 4),
+        (-7, 4), ( 8, 1), ( 8, 2), ( 6, 6), (-6, 6), ( 8, 3), ( 5, 7), (-5, 7), ( 7, 5), (-7, 5),
+        ( 8, 4), ( 6, 7), (-6, 7), ( 7, 6), (-7, 6), ( 8, 5), ( 7, 7), (-7, 7), ( 8, 6), ( 8, 7),
+    ];
+
+    #[inline]
+    fn apply_copy(&mut self, distance_sym: u32, num_to_copy: u32) {
+        let distance_sub_1 = if self.dist_multiplier == 0 {
+            distance_sym
+        } else if let Some(distance) = distance_sym.checked_sub(120) {
+            distance
+        } else {
+            let (offset, dist) = Lz77State::SPECIAL_DISTANCES[distance_sym as usize];
+            let dist = (self.dist_multiplier * dist as u32).checked_add_signed(offset as i32 - 1);
+            dist.unwrap_or(0)
+        };
+
+        let distance = (((1 << 20) - 1).min(distance_sub_1) + 1).min(self.num_decoded);
+        self.copy_pos = self.num_decoded - distance;
+        self.num_to_copy = num_to_copy;
+    }
+
+    #[inline]
+    fn push_decoded_symbol(&mut self, token: u32) {
+        let offset = (self.num_decoded & Self::WINDOW_MASK) as usize;
+        if let Some(slot) = self.window.get_mut(offset) {
+            *slot = token;
+        } else {
+            debug_assert_eq!(self.window.len(), offset);
+            self.window.push(token);
+        }
+        self.num_decoded += 1;
+    }
+
+    #[inline]
+    fn pull_symbol(&mut self) -> Option<u32> {
+        if let Some(next_num_to_copy) = self.num_to_copy.checked_sub(1) {
+            let sym = self.window[(self.copy_pos & Self::WINDOW_MASK) as usize];
+            self.copy_pos += 1;
+            self.num_to_copy = next_num_to_copy;
+            Some(sym)
+        } else {
+            None
+        }
+    }
+}
+
+#[derive(Debug)]
+struct RleState {
+    min_symbol: u32,
+    min_length: u32,
+    last_sym: Option<u32>,
+    repeat_count: u32,
+}
+
+impl RleState {
+    #[inline]
+    fn push_token(
+        &mut self,
+        token: u32,
+        histograms: &Histograms,
+        br: &mut BitReader,
+        cluster: usize,
+    ) {
+        if let Some(token) = token.checked_sub(self.min_symbol) {
+            let lz_length_conf = histograms.lz77_length_uint.as_ref().unwrap();
+            let count = lz_length_conf.read(token, br);
+            self.repeat_count = count + self.min_length;
+        } else {
+            let sym = histograms.uint_configs[cluster].read(token, br);
+            self.last_sym = Some(sym);
+            self.repeat_count = 1;
+        }
+    }
+
+    #[inline]
+    fn pull_symbol(&mut self) -> Option<u32> {
+        if self.repeat_count > 0 {
+            self.repeat_count -= 1;
+            self.last_sym
+        } else {
+            None
+        }
+    }
+}
+
+#[derive(Debug)]
+enum SymbolReaderState {
+    None,
+    Lz77(Lz77State),
+    Rle(RleState),
+}
+
+#[derive(Debug, Clone, Default)]
+struct ErrorState {
+    lz77_repeat: bool,
+    arithmetic_overflow: bool,
+}
+
+impl ErrorState {
+    fn new() -> Self {
+        Self::default()
+    }
+
+    fn check_for_error(&self) -> Result<()> {
+        if self.lz77_repeat {
+            Err(Error::UnexpectedLz77Repeat)
+        } else if self.arithmetic_overflow {
+            Err(Error::ArithmeticOverflow)
+        } else {
+            Ok(())
+        }
+    }
+}
+
+#[derive(Debug)]
+pub struct SymbolReader {
+    state: SymbolReaderState,
+    ans_reader: AnsReader,
+    errors: ErrorState,
+}
+
+impl SymbolReader {
+    pub fn new(
+        histograms: &Histograms,
+        br: &mut BitReader,
+        image_width: Option<usize>,
+    ) -> Result<Self> {
+        let ans_reader = if matches!(histograms.codes, Codes::Ans(_)) {
+            AnsReader::init(br)?
+        } else {
+            AnsReader::new_unused()
+        };
+
+        let Lz77Params {
+            enabled: lz77_enabled,
+            min_symbol,
+            min_length,
+        } = histograms.lz77_params;
+
+        let state = if lz77_enabled {
+            let min_symbol = min_symbol.unwrap();
+            let min_length = min_length.unwrap();
+            let dist_multiplier = image_width.unwrap_or(0) as u32;
+
+            let lz_dist_cluster = *histograms.context_map.last().unwrap() as usize;
+            let lz_conf = &histograms.uint_configs[lz_dist_cluster];
+            let is_rle = histograms.codes.single_symbol(lz_dist_cluster) == Some(1)
+                && lz_conf.is_split_exponent_zero();
+
+            if is_rle {
+                SymbolReaderState::Rle(RleState {
+                    min_symbol,
+                    min_length,
+                    last_sym: None,
+                    repeat_count: 0,
+                })
+            } else {
+                SymbolReaderState::Lz77(Lz77State {
+                    min_symbol,
+                    min_length,
+                    dist_multiplier,
+                    window: Vec::new(),
+                    num_to_copy: 0,
+                    copy_pos: 0,
+                    num_decoded: 0,
+                })
+            }
+        } else {
+            SymbolReaderState::None
+        };
+
+        Ok(Self {
+            state,
+            ans_reader,
+            errors: ErrorState::new(),
+        })
+    }
+}
+
+impl SymbolReader {
+    #[inline]
+    pub fn read_unsigned(
+        &mut self,
+        histograms: &Histograms,
+        br: &mut BitReader,
+        context: usize,
+    ) -> u32 {
+        let cluster = histograms.map_context_to_cluster(context);
+        self.read_unsigned_clustered(histograms, br, cluster)
+    }
+
+    #[inline(always)]
+    pub fn read_signed(
+        &mut self,
+        histograms: &Histograms,
+        br: &mut BitReader,
+        context: usize,
+    ) -> i32 {
+        let unsigned = self.read_unsigned(histograms, br, context);
+        unpack_signed(unsigned)
+    }
+
+    #[inline]
+    pub fn read_unsigned_clustered(
+        &mut self,
+        histograms: &Histograms,
+        br: &mut BitReader,
+        cluster: usize,
+    ) -> u32 {
+        match &mut self.state {
+            SymbolReaderState::None => {
+                let token = match &histograms.codes {
+                    Codes::Huffman(hc) => hc.read(br, cluster),
+                    Codes::Ans(ans) => self.ans_reader.read(ans, br, cluster),
+                };
+                histograms.uint_configs[cluster].read(token, br)
+            }
+
+            SymbolReaderState::Lz77(lz77_state) => {
+                if let Some(sym) = lz77_state.pull_symbol() {
+                    lz77_state.push_decoded_symbol(sym);
+                    return sym;
+                }
+                let token = match &histograms.codes {
+                    Codes::Huffman(hc) => hc.read(br, cluster),
+                    Codes::Ans(ans) => self.ans_reader.read(ans, br, cluster),
+                };
+                let Some(lz77_token) = token.checked_sub(lz77_state.min_symbol) else {
+                    let sym = histograms.uint_configs[cluster].read(token, br);
+                    lz77_state.push_decoded_symbol(sym);
+                    return sym;
+                };
+                if lz77_state.num_decoded == 0 {
+                    self.errors.lz77_repeat = true;
+                    return 0;
+                }
+
+                let num_to_copy = histograms
+                    .lz77_length_uint
+                    .as_ref()
+                    .unwrap()
+                    .read(lz77_token, br);
+                let Some(num_to_copy) = num_to_copy.checked_add(lz77_state.min_length) else {
+                    warn!(
+                        num_to_copy,
+                        lz77_state.min_length, "LZ77 num_to_copy overflow"
+                    );
+                    self.errors.arithmetic_overflow = true;
+                    return 0;
+                };
+
+                let lz_dist_cluster = *histograms.context_map.last().unwrap() as usize;
+                let distance_sym = match &histograms.codes {
+                    Codes::Huffman(hc) => hc.read(br, lz_dist_cluster),
+                    Codes::Ans(ans) => self.ans_reader.read(ans, br, lz_dist_cluster),
+                };
+                let distance_sym = histograms.uint_configs[lz_dist_cluster].read(distance_sym, br);
+                lz77_state.apply_copy(distance_sym, num_to_copy);
+
+                let sym = lz77_state.pull_symbol().unwrap();
+                lz77_state.push_decoded_symbol(sym);
+                sym
+            }
+
+            SymbolReaderState::Rle(rle_state) => {
+                if let Some(sym) = rle_state.pull_symbol() {
+                    return sym;
+                }
+
+                let token = match &histograms.codes {
+                    Codes::Huffman(hc) => hc.read(br, cluster),
+                    Codes::Ans(ans) => self.ans_reader.read(ans, br, cluster),
+                };
+                rle_state.push_token(token, histograms, br, cluster);
+                if let Some(sym) = rle_state.pull_symbol() {
+                    sym
+                } else {
+                    self.errors.lz77_repeat = true;
+                    0
+                }
+            }
+        }
+    }
+
+    #[inline(always)]
+    pub fn read_signed_clustered(
+        &mut self,
+        histograms: &Histograms,
+        br: &mut BitReader,
+        cluster: usize,
+    ) -> i32 {
+        let unsigned = self.read_unsigned_clustered(histograms, br, cluster);
+        unpack_signed(unsigned)
+    }
+
+    pub fn check_final_state(self, histograms: &Histograms, br: &mut BitReader) -> Result<()> {
+        self.errors.check_for_error()?;
+        br.check_for_error()?;
+        match &histograms.codes {
+            Codes::Huffman(_) => Ok(()),
+            Codes::Ans(_) => self.ans_reader.check_final_state(),
+        }
+    }
+
+    pub fn checkpoint<const N: usize>(&self) -> Checkpoint<N> {
+        let state = match &self.state {
+            SymbolReaderState::None => StateCheckpoint::None,
+            SymbolReaderState::Lz77(lz77_state) => {
+                let mut window = [0u32; N];
+                let start = (lz77_state.num_decoded & Lz77State::WINDOW_MASK) as usize;
+                let end = ((lz77_state.num_decoded + N as u32) & Lz77State::WINDOW_MASK) as usize;
+                if start < end {
+                    let window_first = &lz77_state.window[start..];
+                    let actual_size = window_first.len().min(N);
+                    window[..actual_size].copy_from_slice(&window_first[..actual_size]);
+                } else {
+                    let window_first = &lz77_state.window[start..];
+                    let first_len = window_first
+                        .len()
+                        .min((1 << Lz77State::LOG_WINDOW_SIZE) - start);
+                    window[..first_len].copy_from_slice(&window_first[..first_len]);
+                    window[N - end..].copy_from_slice(&lz77_state.window[..end]);
+                }
+                StateCheckpoint::Lz77 {
+                    num_to_copy: lz77_state.num_to_copy,
+                    copy_pos: lz77_state.copy_pos,
+                    num_decoded: lz77_state.num_decoded,
+                    window,
+                }
+            }
+            SymbolReaderState::Rle(rle_state) => StateCheckpoint::Rle {
+                last_sym: rle_state.last_sym,
+                repeat_count: rle_state.repeat_count,
+            },
+        };
+
+        Checkpoint {
+            state,
+            ans_reader: self.ans_reader.checkpoint(),
+            errors: self.errors.clone(),
+        }
+    }
+
+    pub fn restore<const N: usize>(&mut self, checkpoint: Checkpoint<N>) {
+        match checkpoint.state {
+            StateCheckpoint::None => {
+                if !matches!(self.state, SymbolReaderState::None) {
+                    panic!("checkpoint type mismatch");
+                }
+            }
+            StateCheckpoint::Lz77 {
+                num_to_copy,
+                copy_pos,
+                num_decoded,
+                window,
+            } => {
+                let SymbolReaderState::Lz77(lz77_state) = &mut self.state else {
+                    panic!("checkpoint type mismatch");
+                };
+
+                let num_rewind = lz77_state.num_decoded - num_decoded;
+                let rewind_window = &window[..num_rewind as usize];
+
+                let start = (num_decoded & Lz77State::WINDOW_MASK) as usize;
+                let end = ((num_decoded + num_rewind) & Lz77State::WINDOW_MASK) as usize;
+                if start < end {
+                    lz77_state.window[start..end].copy_from_slice(rewind_window);
+                } else {
+                    let window_first = &mut lz77_state.window[start..];
+                    let first_len = window_first.len();
+                    window_first.copy_from_slice(&rewind_window[..first_len]);
+                    lz77_state.window[..end].copy_from_slice(&rewind_window[first_len..]);
+                }
+
+                lz77_state.num_to_copy = num_to_copy;
+                lz77_state.copy_pos = copy_pos;
+                lz77_state.num_decoded = num_decoded;
+            }
+            StateCheckpoint::Rle {
+                last_sym,
+                repeat_count,
+            } => {
+                let SymbolReaderState::Rle(rle_state) = &mut self.state else {
+                    panic!("checkpoint type mismatch");
+                };
+
+                rle_state.last_sym = last_sym;
+                rle_state.repeat_count = repeat_count;
+            }
+        }
+
+        self.ans_reader = checkpoint.ans_reader;
+        self.errors = checkpoint.errors;
+    }
+}
+
+impl Histograms {
+    pub fn decode(num_contexts: usize, br: &mut BitReader, allow_lz77: bool) -> Result<Histograms> {
+        let lz77_params = Lz77Params::read_unconditional(&(), br, &Empty {})?;
+        if !allow_lz77 && lz77_params.enabled {
+            return Err(Error::Lz77Disallowed);
+        }
+        let (num_contexts, lz77_length_uint) = if lz77_params.enabled {
+            (
+                num_contexts + 1,
+                Some(HybridUint::decode(/*log_alpha_size=*/ 8, br)?),
+            )
+        } else {
+            (num_contexts, None)
+        };
+
+        let context_map = if num_contexts > 1 {
+            decode_context_map(num_contexts, br)?
+        } else {
+            vec![0]
+        };
+        assert_eq!(context_map.len(), num_contexts);
+
+        let use_prefix_code = br.read(1)? != 0;
+        let log_alpha_size = if use_prefix_code {
+            HUFFMAN_MAX_BITS
+        } else {
+            br.read(2)? as usize + 5
+        };
+        let num_histograms = *context_map.iter().max().unwrap() + 1;
+        let uint_configs = ((0..num_histograms).map(|_| HybridUint::decode(log_alpha_size, br)))
+            .collect::<Result<_>>()?;
+
+        let codes = if use_prefix_code {
+            Codes::Huffman(HuffmanCodes::decode(num_histograms as usize, br)?)
+        } else {
+            Codes::Ans(AnsCodes::decode(
+                num_histograms as usize,
+                log_alpha_size,
+                br,
+            )?)
+        };
+
+        Ok(Histograms {
+            lz77_params,
+            lz77_length_uint,
+            context_map,
+            log_alpha_size,
+            uint_configs,
+            codes,
+        })
+    }
+
+    pub fn map_context_to_cluster(&self, context: usize) -> usize {
+        self.context_map[context] as usize
+    }
+
+    pub fn num_histograms(&self) -> usize {
+        *self.context_map.iter().max().unwrap() as usize + 1
+    }
+}
+
+#[cfg(test)]
+impl Histograms {
+    /// Builds a decoder that reads an octet at a time and emits its bit-reversed value.
+    pub fn reverse_octet(num_contexts: usize) -> Self {
+        let d = HuffmanCodes::byte_histogram();
+        let codes = Codes::Huffman(d);
+        let uint_configs = vec![HybridUint::new(8, 0, 0)];
+        Self {
+            lz77_params: Lz77Params {
+                enabled: false,
+                min_symbol: None,
+                min_length: None,
+            },
+            lz77_length_uint: None,
+            uint_configs,
+            log_alpha_size: 15,
+            context_map: vec![0u8; num_contexts],
+            codes,
+        }
+    }
+
+    pub fn rle(num_contexts: usize, min_symbol: u32, min_length: u32) -> Self {
+        let d = HuffmanCodes::byte_histogram_rle();
+        let codes = Codes::Huffman(d);
+        let uint_configs = vec![HybridUint::new(8, 0, 0), HybridUint::new(0, 0, 0)];
+        let mut context_map = vec![0u8; num_contexts + 1];
+        *context_map.last_mut().unwrap() = 1;
+        Self {
+            lz77_params: Lz77Params {
+                enabled: true,
+                min_symbol: Some(min_symbol),
+                min_length: Some(min_length),
+            },
+            lz77_length_uint: Some(HybridUint::new(8, 0, 0)),
+            uint_configs,
+            log_alpha_size: 15,
+            context_map,
+            codes,
+        }
+    }
+}
+
+#[derive(Debug)]
+enum StateCheckpoint<const N: usize> {
+    None,
+    Lz77 {
+        num_to_copy: u32,
+        copy_pos: u32,
+        num_decoded: u32,
+        window: [u32; N],
+    },
+    Rle {
+        last_sym: Option<u32>,
+        repeat_count: u32,
+    },
+}
+
+#[derive(Debug)]
+pub struct Checkpoint<const N: usize> {
+    state: StateCheckpoint<N>,
+    ans_reader: AnsReader,
+    errors: ErrorState,
+}
+
+#[cfg(test)]
+mod test {
+    use std::ops::ControlFlow;
+
+    use test_log::test;
+
+    use super::*;
+
+    #[test]
+    fn rle_arb() {
+        let histograms = Histograms::rle(1, 240, 3);
+
+        arbtest::arbtest(|u| {
+            let width = u.int_in_range(1usize..=256)?;
+
+            let mut bitstream = Vec::new();
+            let mut expected_bytes = Vec::new();
+            u.arbitrary_loop(None, None, |u| {
+                let do_repeat = !expected_bytes.is_empty() && u.ratio(1, 4)?;
+                let range = if do_repeat { 240u8..=255 } else { 0u8..=239 };
+                let byte = u.int_in_range(range)?;
+                bitstream.push(byte);
+
+                if do_repeat {
+                    let count = byte as usize - 237;
+                    let sym = *expected_bytes.last().unwrap();
+                    for _ in 0..count {
+                        expected_bytes.push(sym);
+                    }
+                } else {
+                    expected_bytes.push(byte);
+                }
+
+                Ok(if expected_bytes.len() >= 256 {
+                    ControlFlow::Break(())
+                } else {
+                    ControlFlow::Continue(())
+                })
+            })?;
+            for b in &mut bitstream {
+                *b = b.reverse_bits();
+            }
+
+            // Read RLE
+            let mut br = BitReader::new(&bitstream);
+            let mut reader = SymbolReader::new(&histograms, &mut br, Some(width)).unwrap();
+
+            for expected in expected_bytes {
+                let actual = reader.read_unsigned_clustered(&histograms, &mut br, 0);
+                assert_eq!(actual, expected as u32);
+            }
+
+            let SymbolReaderState::Rle(rle_state) = &reader.state else {
+                panic!()
+            };
+            assert_eq!(rle_state.repeat_count, 0);
+            assert!(reader.check_final_state(&histograms, &mut br).is_ok());
+            assert_eq!(br.total_bits_available(), 0);
+
+            Ok(())
+        });
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/entropy_coding/huffman.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/entropy_coding/huffman.rs
new file mode 100644
index 0000000..943ec32
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/entropy_coding/huffman.rs
@@ -0,0 +1,563 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::fmt::Debug;
+
+use crate::bit_reader::BitReader;
+use crate::entropy_coding::decode::*;
+use crate::error::{Error, Result};
+use crate::util::{CeilLog2, NewWithCapacity, tracing_wrappers::*};
+
+pub const HUFFMAN_MAX_BITS: usize = 15;
+const TABLE_BITS: usize = 8;
+const TABLE_SIZE: usize = 1 << TABLE_BITS;
+const CODE_LENGTHS_CODE: usize = 18;
+const DEFAULT_CODE_LENGTH: u8 = 8;
+const CODE_LENGTH_REPEAT_CODE: u8 = 16;
+
+#[derive(Clone, Copy)]
+struct TableEntry {
+    bits: u8,
+    value: u16,
+}
+
+impl Debug for TableEntry {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{}l{}", self.value, self.bits)
+    }
+}
+
+#[derive(Debug)]
+struct Table {
+    entries: Vec<TableEntry>,
+}
+
+/* Returns reverse(reverse(key, len) + 1, len), where reverse(key, len) is the
+bit-wise reversal of the len least significant bits of key. */
+fn get_next_key(key: u32, len: usize) -> u32 {
+    let mut step = 1 << (len - 1);
+    while key & step != 0 {
+        step >>= 1;
+    }
+    (key & (step.wrapping_sub(1))) + step
+}
+
+/* Stores code in table[0], table[step], table[2*step], ..., table[end] */
+/* Assumes that end is an integer multiple of step */
+fn replicate_value(table: &mut [TableEntry], step: usize, value: TableEntry) {
+    for v in table.iter_mut().step_by(step) {
+        *v = value;
+    }
+}
+
+/* Returns the table width of the next 2nd level table. count is the histogram
+of bit lengths for the remaining symbols, len is the code length of the next
+processed symbol */
+fn next_table_bit_size(count: &[u16], len: usize, root_bits: usize) -> usize {
+    let mut len = len;
+    let mut left = 1 << (len - root_bits);
+    while len < HUFFMAN_MAX_BITS {
+        if left <= count[len] {
+            break;
+        }
+        left -= count[len];
+        len += 1;
+        left <<= 1;
+    }
+    len - root_bits
+}
+
+impl Table {
+    fn decode_simple_table(al_size: usize, br: &mut BitReader) -> Result<Vec<TableEntry>> {
+        let max_bits = al_size.ceil_log2();
+        let num_symbols = (br.read(2)? + 1) as usize;
+        let mut symbols = [0u16; 4];
+        for symbol in symbols.iter_mut().take(num_symbols) {
+            let sym = br.read(max_bits)? as usize;
+            if sym >= al_size {
+                return Err(Error::InvalidHuffman);
+            }
+            *symbol = sym as u16;
+        }
+        if (0..num_symbols - 1).any(|i| symbols[..i].contains(&symbols[i + 1])) {
+            return Err(Error::InvalidHuffman);
+        }
+
+        let special_4_symbols = if num_symbols == 4 {
+            br.read(1)? != 0
+        } else {
+            false
+        };
+        debug!(symbols = ?symbols[..num_symbols]);
+        match (num_symbols, special_4_symbols) {
+            (1, _) => Ok(vec![
+                TableEntry {
+                    bits: 0,
+                    value: symbols[0]
+                };
+                TABLE_SIZE
+            ]),
+            (2, _) => {
+                let mut ret = Vec::new_with_capacity(TABLE_SIZE)?;
+                symbols[0..2].sort_unstable();
+                for _ in 0..(TABLE_SIZE >> 1) {
+                    ret.push(TableEntry {
+                        bits: 1,
+                        value: symbols[0],
+                    });
+                    ret.push(TableEntry {
+                        bits: 1,
+                        value: symbols[1],
+                    });
+                }
+                Ok(ret)
+            }
+            (3, _) => {
+                let mut ret = Vec::new_with_capacity(TABLE_SIZE)?;
+                symbols[1..3].sort_unstable();
+                for _ in 0..(TABLE_SIZE >> 2) {
+                    ret.push(TableEntry {
+                        bits: 1,
+                        value: symbols[0],
+                    });
+                    ret.push(TableEntry {
+                        bits: 2,
+                        value: symbols[1],
+                    });
+                    ret.push(TableEntry {
+                        bits: 1,
+                        value: symbols[0],
+                    });
+                    ret.push(TableEntry {
+                        bits: 2,
+                        value: symbols[2],
+                    });
+                }
+                Ok(ret)
+            }
+            (4, false) => {
+                let mut ret = Vec::new_with_capacity(TABLE_SIZE)?;
+                symbols.sort_unstable();
+                for _ in 0..(TABLE_SIZE >> 2) {
+                    ret.push(TableEntry {
+                        bits: 2,
+                        value: symbols[0],
+                    });
+                    ret.push(TableEntry {
+                        bits: 2,
+                        value: symbols[2],
+                    });
+                    ret.push(TableEntry {
+                        bits: 2,
+                        value: symbols[1],
+                    });
+                    ret.push(TableEntry {
+                        bits: 2,
+                        value: symbols[3],
+                    });
+                }
+                Ok(ret)
+            }
+            (4, true) => {
+                let mut ret = Vec::new_with_capacity(TABLE_SIZE)?;
+                symbols[2..4].sort_unstable();
+                for _ in 0..(TABLE_SIZE >> 3) {
+                    ret.push(TableEntry {
+                        bits: 1,
+                        value: symbols[0],
+                    });
+                    ret.push(TableEntry {
+                        bits: 2,
+                        value: symbols[1],
+                    });
+                    ret.push(TableEntry {
+                        bits: 1,
+                        value: symbols[0],
+                    });
+                    ret.push(TableEntry {
+                        bits: 3,
+                        value: symbols[2],
+                    });
+                    ret.push(TableEntry {
+                        bits: 1,
+                        value: symbols[0],
+                    });
+                    ret.push(TableEntry {
+                        bits: 2,
+                        value: symbols[1],
+                    });
+                    ret.push(TableEntry {
+                        bits: 1,
+                        value: symbols[0],
+                    });
+                    ret.push(TableEntry {
+                        bits: 3,
+                        value: symbols[3],
+                    });
+                }
+                Ok(ret)
+            }
+            _ => unreachable!(),
+        }
+    }
+
+    fn decode_huffman_code_lengths(
+        code_length_code_lengths: [u8; CODE_LENGTHS_CODE],
+        al_size: usize,
+        br: &mut BitReader,
+    ) -> Result<Vec<u8>> {
+        let table = Table::build(5, &code_length_code_lengths)?;
+
+        let mut symbol = 0;
+        let mut prev_code_len = DEFAULT_CODE_LENGTH;
+        let mut repeat = 0u16;
+        let mut repeat_code_len = 0;
+        let mut space = 1 << 15;
+
+        let mut code_lengths = vec![0u8; al_size];
+
+        while symbol < al_size && space > 0 {
+            let idx = br.peek(5) as usize;
+            br.consume(table[idx].bits as usize)?;
+            let code_len = table[idx].value as u8;
+            if code_len < CODE_LENGTH_REPEAT_CODE {
+                repeat = 0;
+                code_lengths[symbol] = code_len;
+                symbol += 1;
+                if code_len != 0 {
+                    prev_code_len = code_len;
+                    space -= 32768usize >> code_len;
+                }
+            } else {
+                let extra_bits = code_len - 14;
+
+                let new_len = if code_len == CODE_LENGTH_REPEAT_CODE {
+                    prev_code_len
+                } else {
+                    0
+                };
+                if repeat_code_len != new_len {
+                    repeat = 0;
+                    repeat_code_len = new_len;
+                }
+                let old_repeat = repeat;
+                if repeat > 0 {
+                    repeat -= 2;
+                    repeat <<= extra_bits;
+                }
+                repeat += br.read(extra_bits as usize)? as u16 + 3;
+                let repeat_delta = repeat - old_repeat;
+                if symbol + repeat_delta as usize > al_size {
+                    return Err(Error::InvalidHuffman);
+                }
+                for i in 0..repeat_delta {
+                    code_lengths[symbol + i as usize] = repeat_code_len;
+                }
+                symbol += repeat_delta as usize;
+                if repeat_code_len != 0 {
+                    space -= (repeat_delta as usize) << (15 - repeat_code_len);
+                }
+            }
+        }
+        if space != 0 {
+            return Err(Error::InvalidHuffman);
+        }
+        Ok(code_lengths)
+    }
+
+    #[instrument(level = "trace", ret, err)]
+    fn build(root_bits: usize, code_lengths: &[u8]) -> Result<Vec<TableEntry>> {
+        if code_lengths.len() > 1 << HUFFMAN_MAX_BITS {
+            return Err(Error::InvalidHuffman);
+        }
+        let mut counts = [0u16; HUFFMAN_MAX_BITS + 1];
+        for &v in code_lengths.iter() {
+            counts[v as usize] += 1;
+        }
+
+        /* symbols sorted by code length */
+        let mut sorted = vec![0u16; code_lengths.len()];
+
+        /* offsets in sorted table for each length */
+        let mut offset = [0; HUFFMAN_MAX_BITS + 1];
+        let mut max_length = 1;
+
+        /* generate offsets into sorted symbol table by code length */
+        {
+            let mut sum = 0;
+            for len in 1..=HUFFMAN_MAX_BITS {
+                offset[len] = sum;
+                if counts[len] != 0 {
+                    sum += counts[len];
+                    max_length = len;
+                }
+            }
+        }
+
+        /* sort symbols by length, by symbol order within each length */
+        for (symbol, len) in code_lengths.iter().enumerate() {
+            if *len != 0 {
+                sorted[offset[*len as usize] as usize] = symbol as u16;
+                offset[*len as usize] += 1;
+            }
+        }
+
+        let mut table_bits = root_bits;
+        let mut table_size = 1 << table_bits;
+        let mut table_pos = 0;
+        let mut table = vec![TableEntry { bits: 0, value: 0 }; table_size];
+
+        /* special case code with only one value */
+        if offset[HUFFMAN_MAX_BITS] == 1 {
+            for v in table.iter_mut() {
+                v.bits = 0;
+                v.value = sorted[0];
+            }
+            return Ok(table);
+        }
+
+        /* fill in root table */
+        /* let's reduce the table size to a smaller size if possible, and */
+        /* create the repetitions by memcpy if possible in the coming loop */
+        if table_bits > max_length {
+            table_bits = max_length;
+            table_size = 1 << table_bits;
+        }
+        let mut key = 0u32;
+        let mut symbol = 0;
+        let mut bits = 1u8;
+        let mut step = 2;
+        loop {
+            loop {
+                if counts[bits as usize] == 0 {
+                    break;
+                }
+                let value = sorted[symbol];
+                symbol += 1;
+                replicate_value(&mut table[key as usize..], step, TableEntry { bits, value });
+                key = get_next_key(key, bits as usize);
+                counts[bits as usize] -= 1;
+            }
+            step <<= 1;
+            bits += 1;
+            if bits as usize > table_bits {
+                break;
+            }
+        }
+
+        /* if root_bits != table_bits we only created one fraction of the */
+        /* table, and we need to replicate it now. */
+        while table.len() != table_size {
+            for i in 0..table_size {
+                table[i + table_size] = table[i];
+            }
+            table_size <<= 1;
+        }
+        trace!("table of length {}, table_size: {table_size}", table.len());
+
+        /* fill in 2nd level tables and add pointers to root table */
+        let mask = (table.len() - 1) as u32;
+        let mut low = !0u32;
+        let mut step = 2;
+        for len in root_bits + 1..=max_length {
+            loop {
+                if counts[len] == 0 {
+                    break;
+                }
+                if (key & mask) != low {
+                    table_pos += table_size;
+                    table_bits = next_table_bit_size(&counts, len, root_bits);
+                    table_size = 1 << table_bits;
+                    low = key & mask;
+                    table[low as usize].bits = (table_bits + root_bits) as u8;
+                    table[low as usize].value = (table_pos - low as usize) as u16;
+                    if table.len() < table_pos + table_size {
+                        table.resize(table_pos + table_size, TableEntry { bits: 0, value: 0 });
+                    }
+                }
+                counts[len] -= 1;
+                let bits = (len - root_bits) as u8;
+                let value = sorted[symbol];
+                symbol += 1;
+                let pos = table_pos + (key as usize >> root_bits);
+                trace!(
+                    "filling 2nd level table of len {len} starting at position {pos} ({table_pos} + {}) of {}",
+                    key as usize >> root_bits,
+                    table.len()
+                );
+                replicate_value(&mut table[pos..], step, TableEntry { bits, value });
+                key = get_next_key(key, len);
+            }
+            step <<= 1;
+        }
+        Ok(table)
+    }
+
+    #[instrument(level = "trace", skip(br), ret, err)]
+    pub fn decode(al_size: usize, br: &mut BitReader) -> Result<Table> {
+        let entries = if al_size == 1 {
+            vec![TableEntry { bits: 0, value: 0 }; TABLE_SIZE]
+        } else {
+            assert!(al_size < 1 << HUFFMAN_MAX_BITS);
+            let simple_code_or_skip = br.read(2)? as usize;
+            if simple_code_or_skip == 1 {
+                Table::decode_simple_table(al_size, br)?
+            } else {
+                let mut code_length_code_lengths = [0u8; CODE_LENGTHS_CODE];
+                let mut space = 32;
+                const STATIC_HUFF_BITS: [u8; 16] = [2, 2, 2, 3, 2, 2, 2, 4, 2, 2, 2, 3, 2, 2, 2, 4];
+                const STATIC_HUFF_VALS: [u8; 16] = [0, 4, 3, 2, 0, 4, 3, 1, 0, 4, 3, 2, 0, 4, 3, 5];
+                const CODE_LENGTH_CODE_ORDER: [u8; CODE_LENGTHS_CODE] =
+                    [1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15];
+                let mut num_codes = 0;
+                for i in simple_code_or_skip..CODE_LENGTHS_CODE {
+                    if space <= 0 {
+                        break;
+                    }
+                    let idx = br.peek(4) as usize;
+                    br.consume(STATIC_HUFF_BITS[idx] as usize)?;
+                    let v = STATIC_HUFF_VALS[idx];
+                    code_length_code_lengths[CODE_LENGTH_CODE_ORDER[i] as usize] = v;
+                    if v != 0 {
+                        space -= 32 >> v;
+                        num_codes += 1;
+                    }
+                }
+                if num_codes != 1 && space != 0 {
+                    return Err(Error::InvalidHuffman);
+                }
+                let code_lengths =
+                    Table::decode_huffman_code_lengths(code_length_code_lengths, al_size, br)?;
+                debug!(?code_lengths);
+                Table::build(TABLE_BITS, &code_lengths)?
+            }
+        };
+        Ok(Table { entries })
+    }
+
+    #[inline]
+    pub fn read(&self, br: &mut BitReader) -> u32 {
+        let mut pos = br.peek(TABLE_BITS) as usize;
+        let mut n_bits = self.entries[pos].bits as usize;
+        if n_bits > TABLE_BITS {
+            br.consume_optimistic(TABLE_BITS);
+            n_bits -= TABLE_BITS;
+            pos += self.entries[pos].value as usize;
+            pos += br.peek(n_bits) as usize;
+        }
+        br.consume_optimistic(self.entries[pos].bits as usize);
+        self.entries[pos].value as u32
+    }
+}
+
+#[derive(Debug)]
+pub struct HuffmanCodes {
+    tables: Vec<Table>,
+}
+
+impl HuffmanCodes {
+    pub fn decode(num: usize, br: &mut BitReader) -> Result<HuffmanCodes> {
+        let alphabet_sizes: Vec<u16> = (0..num)
+            .map(|_| Ok(decode_varint16(br)? + 1))
+            .collect::<Result<_>>()?;
+        let max = *alphabet_sizes.iter().max().unwrap();
+        if max as usize > (1 << HUFFMAN_MAX_BITS) {
+            return Err(Error::AlphabetTooLargeHuff(max as usize));
+        }
+        let tables = alphabet_sizes
+            .iter()
+            .map(|sz| Table::decode(*sz as usize, br))
+            .collect::<Result<_>>()?;
+        Ok(HuffmanCodes { tables })
+    }
+
+    #[inline]
+    pub fn read(&self, br: &mut BitReader, ctx: usize) -> u32 {
+        self.tables[ctx].read(br)
+    }
+
+    pub fn single_symbol(&self, ctx: usize) -> Option<u32> {
+        if let TableEntry { bits: 0, value } = self.tables[ctx].entries[0] {
+            Some(value as u32)
+        } else {
+            None
+        }
+    }
+}
+
+#[cfg(test)]
+impl Table {
+    fn new_single_symbol(sym: u16) -> Table {
+        Table {
+            entries: vec![
+                TableEntry {
+                    bits: 0,
+                    value: sym
+                };
+                TABLE_SIZE
+            ],
+        }
+    }
+}
+
+#[cfg(test)]
+impl HuffmanCodes {
+    /// Builds Huffman histogram of 256 8-bit symbols.
+    pub(super) fn byte_histogram() -> HuffmanCodes {
+        let mut br = BitReader::new(&[0b11101111, 0b00111111, 0, 1, 0, 0b10100000, 0b0110]);
+        HuffmanCodes::decode(1, &mut br).unwrap()
+    }
+
+    pub(super) fn byte_histogram_rle() -> HuffmanCodes {
+        let mut histogram = Self::byte_histogram();
+        histogram.tables.push(Table::new_single_symbol(1));
+        histogram
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use test_log::test;
+
+    #[test]
+    fn byte_histogram() {
+        let codes = HuffmanCodes::byte_histogram();
+
+        let expected_arr = [8u8, 13, 21, 34, 55, 89, 144, 233];
+        let bits = expected_arr.map(|v| v.reverse_bits());
+        let mut br = BitReader::new(&bits);
+
+        for expected in expected_arr {
+            assert_eq!(codes.read(&mut br, 0), expected as u32);
+        }
+    }
+
+    #[test]
+    fn long_code() {
+        // This correctly sums to 4096 table entries
+        const CODE: [u8; 520] = [
+            3, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 7, 8, 8, 8, 8, 8, 8, 8, 9, 9, 8, 9, 9, 9, 9, 9,
+            9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+            9, 9, 9, 9, 9, 9, 9, 8, 9, 9, 8, 9, 9, 9, 9, 9, 8, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8, 8, 8, 8,
+            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 8, 9, 8, 8, 8, 8, 9, 9, 9, 9, 8, 8, 9, 9, 9, 9, 9, 9,
+            9, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+            9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 9, 9, 9, 9,
+            9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 4, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 10, 7, 9, 9, 11, 12, 12,
+        ];
+        assert!(Table::build(TABLE_BITS, &CODE).is_ok());
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/entropy_coding/hybrid_uint.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/entropy_coding/hybrid_uint.rs
new file mode 100644
index 0000000..edca6b5
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/entropy_coding/hybrid_uint.rs
@@ -0,0 +1,83 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::bit_reader::BitReader;
+use crate::error::Error;
+
+use crate::util::CeilLog2;
+
+#[derive(Debug)]
+pub struct HybridUint {
+    split_token: u32,
+    split_exponent: u32,
+    msb_in_token: u32,
+    lsb_in_token: u32,
+}
+
+impl HybridUint {
+    pub(super) fn is_split_exponent_zero(&self) -> bool {
+        self.split_exponent == 0
+    }
+
+    pub fn decode(log_alpha_size: usize, br: &mut BitReader) -> Result<HybridUint, Error> {
+        let split_exponent = br.read((log_alpha_size + 1).ceil_log2())? as u32;
+        let split_token = 1u32 << split_exponent;
+        let msb_in_token;
+        let lsb_in_token;
+        if split_exponent != log_alpha_size as u32 {
+            let nbits = (split_exponent + 1).ceil_log2() as usize;
+            msb_in_token = br.read(nbits)? as u32;
+            if msb_in_token > split_exponent {
+                return Err(Error::InvalidUintConfig(split_exponent, msb_in_token, None));
+            }
+            let nbits = (split_exponent - msb_in_token + 1).ceil_log2() as usize;
+            lsb_in_token = br.read(nbits)? as u32;
+        } else {
+            msb_in_token = 0;
+            lsb_in_token = 0;
+        }
+        if lsb_in_token + msb_in_token > split_exponent {
+            return Err(Error::InvalidUintConfig(
+                split_exponent,
+                msb_in_token,
+                Some(lsb_in_token),
+            ));
+        }
+        Ok(HybridUint {
+            split_token,
+            split_exponent,
+            msb_in_token,
+            lsb_in_token,
+        })
+    }
+
+    #[inline]
+    pub fn read(&self, symbol: u32, br: &mut BitReader) -> u32 {
+        if symbol < self.split_token {
+            return symbol;
+        }
+        let bits_in_token = self.lsb_in_token + self.msb_in_token;
+        let nbits =
+            self.split_exponent - bits_in_token + ((symbol - self.split_token) >> bits_in_token);
+        // TODO(tirr-c): Assert `nbits <= 31`.
+        let low = symbol & ((1 << self.lsb_in_token) - 1);
+        let symbol_nolow = symbol >> self.lsb_in_token;
+        let bits = br.read_optimistic(nbits as usize) as u32;
+        let hi = (symbol_nolow & ((1 << self.msb_in_token) - 1)) | (1 << self.msb_in_token);
+        (((hi << nbits) | bits) << self.lsb_in_token) | low
+    }
+}
+
+#[cfg(test)]
+impl HybridUint {
+    pub fn new(split_exponent: u32, msb_in_token: u32, lsb_in_token: u32) -> Self {
+        Self {
+            split_token: 1 << split_exponent,
+            split_exponent,
+            msb_in_token,
+            lsb_in_token,
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/entropy_coding/mod.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/entropy_coding/mod.rs
new file mode 100644
index 0000000..8326873
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/entropy_coding/mod.rs
@@ -0,0 +1,10 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+pub mod ans;
+pub mod context_map;
+pub mod decode;
+pub mod huffman;
+pub mod hybrid_uint;
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/error.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/error.rs
new file mode 100644
index 0000000..f361afe2
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/error.rs
@@ -0,0 +1,264 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::collections::TryReserveError;
+
+use thiserror::Error;
+
+use crate::{
+    api::{JxlColorType, JxlDataFormat},
+    entropy_coding::huffman::HUFFMAN_MAX_BITS,
+    features::spline::Point,
+    image::DataTypeTag,
+};
+
+#[derive(Error, Debug)]
+#[non_exhaustive]
+pub enum Error {
+    #[error("Invalid raw quantization table")]
+    InvalidRawQuantTable,
+    #[error("Invalid distance band {0}: {1}")]
+    InvalidDistanceBand(usize, f32),
+    #[error("Invalid AFV bands")]
+    InvalidAFVBands,
+    #[error("Invalid quantization table weight: {0}")]
+    InvalidQuantizationTableWeight(f32),
+    #[error("Read out of bounds; size hint: {0}")]
+    OutOfBounds(usize),
+    #[error("Section is too short")]
+    SectionTooShort,
+    #[error("Non-zero padding bits")]
+    NonZeroPadding,
+    #[error("Invalid signature")]
+    InvalidSignature,
+    #[error("Invalid exponent_bits_per_sample: {0}")]
+    InvalidExponent(u32),
+    #[error("Invalid mantissa_bits: {0}")]
+    InvalidMantissa(i32),
+    #[error("Invalid bits_per_sample: {0}")]
+    InvalidBitsPerSample(u32),
+    #[error("Invalid enum value {0} for {1}")]
+    InvalidEnum(u32, String),
+    #[error("Value of dim_shift {0} is too large")]
+    DimShiftTooLarge(u32),
+    #[error("Float is NaN or Inf")]
+    FloatNaNOrInf,
+    #[error("Invalid gamma value: {0}")]
+    InvalidGamma(f32),
+    #[error("Invalid color encoding: no ICC and unknown TF / ColorSpace")]
+    InvalidColorEncoding,
+    #[error("Invalid color space: should be one of RGB, Gray or XYB")]
+    InvalidColorSpace,
+    #[error("Only perceptual rendering intent implemented for XYB ICC profile.")]
+    InvalidRenderingIntent,
+    #[error("Invalid intensity_target: {0}")]
+    InvalidIntensityTarget(f32),
+    #[error("Invalid min_nits: {0}")]
+    InvalidMinNits(f32),
+    #[error("Invalid linear_below {1}, relative_to_max_display is {0}")]
+    InvalidLinearBelow(bool, f32),
+    #[error("Overflow when computing a bitstream size")]
+    SizeOverflow,
+    #[error("Invalid ISOBMMF container")]
+    InvalidBox,
+    #[error("ICC is too large")]
+    IccTooLarge,
+    #[error("Invalid ICC stream: unexpected end of stream")]
+    IccEndOfStream,
+    #[error("Invalid ICC stream")]
+    InvalidIccStream,
+    #[error("Invalid HybridUintConfig: {0} {1} {2:?}")]
+    InvalidUintConfig(u32, u32, Option<u32>),
+    #[error("LZ77 enabled when explicitly disallowed")]
+    Lz77Disallowed,
+    #[error("LZ77 repeat symbol encountered without decoding any symbols")]
+    UnexpectedLz77Repeat,
+    #[error("Huffman alphabet too large: {0}, max is {max}", max = 1 << HUFFMAN_MAX_BITS)]
+    AlphabetTooLargeHuff(usize),
+    #[error("Invalid Huffman code")]
+    InvalidHuffman,
+    #[error("Invalid ANS histogram")]
+    InvalidAnsHistogram,
+    #[error("ANS stream checksum mismatch")]
+    AnsChecksumMismatch,
+    #[error("Integer too large: nbits {0} > 29")]
+    IntegerTooLarge(u32),
+    #[error("Invalid context map: context id {0} > 255")]
+    InvalidContextMap(u32),
+    #[error("Invalid context map: number of histogram {0}, number of distinct histograms {1}")]
+    InvalidContextMapHole(u32, u32),
+    #[error(
+        "Invalid permutation: skipped elements {skip} and encoded elements {end} don't fit in permutation of size {size}"
+    )]
+    InvalidPermutationSize { size: u32, skip: u32, end: u32 },
+    #[error(
+        "Invalid permutation: Lehmer code {lehmer} out of bounds in permutation of size {size} at index {idx}"
+    )]
+    InvalidPermutationLehmerCode { size: u32, idx: u32, lehmer: u32 },
+    #[error("Invalid quant encoding mode")]
+    InvalidQuantEncodingMode,
+    #[error("Invalid quant encoding with mode {mode} and required size {required_size}")]
+    InvalidQuantEncoding { mode: u8, required_size: usize },
+    // FrameHeader format errors
+    #[error("Invalid extra channel upsampling: upsampling: {0} dim_shift: {1} ec_upsampling: {2}")]
+    InvalidEcUpsampling(u32, u32, u32),
+    #[error("Num_ds: {0} should be smaller than num_passes: {1}")]
+    NumPassesTooLarge(u32, u32),
+    #[error("Non-patch reference frame with a crop")]
+    NonPatchReferenceWithCrop,
+    #[error("Non-444 chroma subsampling is not allowed when adaptive DC smoothing is enabled")]
+    Non444ChromaSubsampling,
+    #[error("Non-444 chroma subsampling is not allowed for bigger than 8x8 transforms")]
+    InvalidBlockSizeForChromaSubsampling,
+    #[error("Out of memory: {0}")]
+    OutOfMemory(#[from] TryReserveError),
+    #[error("Out of memory when allocating image of byte size {0}x{1}")]
+    ImageOutOfMemory(usize, usize),
+    #[error("Image size too large: {0}x{1}")]
+    ImageSizeTooLarge(usize, usize),
+    #[error("Invalid image size: {0}x{1}")]
+    InvalidImageSize(usize, usize),
+    // Generic arithmetic overflow. Prefer using other errors if possible.
+    #[error("Arithmetic overflow")]
+    ArithmeticOverflow,
+    #[error("Empty frame sequence")]
+    NoFrames,
+    #[error(
+        "Pipeline channel type mismatch: stage {0} channel {1}, expected {2:?} but found {3:?}"
+    )]
+    PipelineChannelTypeMismatch(String, usize, DataTypeTag, DataTypeTag),
+    #[error("Invalid stage {0} after extend stage")]
+    PipelineInvalidStageAfterExtend(String),
+    #[error("Channel {0} was not used in the render pipeline")]
+    PipelineChannelUnused(usize),
+    #[error("Trying to copy rects of different size, src: {0}x{1} dst {2}x{3}")]
+    CopyOfDifferentSize(usize, usize, usize, usize),
+    #[error("LF quantization factor is too small: {0}")]
+    LfQuantFactorTooSmall(f32),
+    #[error("HF quantization factor is too small: {0}")]
+    HfQuantFactorTooSmall(f32),
+    #[error("Invalid modular mode predictor: {0}")]
+    InvalidPredictor(u32),
+    #[error("Invalid modular mode property: {0}")]
+    InvalidProperty(u32),
+    #[error("Invalid alpha channel for blending: {0}, limit is {1}")]
+    PatchesInvalidAlphaChannel(usize, usize),
+    #[error("Invalid patch blend mode: {0}, limit is {1}")]
+    PatchesInvalidBlendMode(u8, u8),
+    #[error("Invalid Patch: negative {0}-coordinate: {1} base {0},  {2} delta {0}")]
+    PatchesInvalidDelta(String, usize, i32),
+    #[error(
+        "Invalid position specified in reference frame in {0}-coordinate: {0}0 + {0}size = {1} + {2} > {3} = reference_frame {0}size"
+    )]
+    PatchesInvalidPosition(String, usize, usize, usize),
+    #[error("Patches invalid reference frame at index {0}")]
+    PatchesInvalidReference(usize),
+    #[error("Invalid Patch {0}: at {1} + {2} > {3}")]
+    PatchesOutOfBounds(String, usize, usize, usize),
+    #[error("Patches cannot use frames saved post color transforms")]
+    PatchesPostColorTransform(),
+    #[error("Too many {0}: {1}, limit is {2}")]
+    PatchesTooMany(String, usize, usize),
+    #[error("Reference too large: {0}, limit is {1}")]
+    PatchesRefTooLarge(usize, usize),
+    #[error("Point list is empty")]
+    PointListEmpty,
+    #[error("Too large area for spline: {0}, limit is {1}")]
+    SplinesAreaTooLarge(u64, u64),
+    #[error("Too large manhattan_distance reached: {0}, limit is {1}")]
+    SplinesDistanceTooLarge(u64, u64),
+    #[error("Too many splines: {0}, limit is {1}")]
+    SplinesTooMany(u32, u32),
+    #[error("Spline has adjacent coinciding control points: point[{0}]: {1:?}, point[{2}]: {3:?}")]
+    SplineAdjacentCoincidingControlPoints(usize, Point, usize, Point),
+    #[error("Too many control points for splines: {0}, limit is {1}")]
+    SplinesTooManyControlPoints(u32, u32),
+    #[error(
+        "Spline point outside valid bounds: coordinates: {0:?}, out of bounds: {1}, bounds: {2:?}"
+    )]
+    SplinesPointOutOfRange(Point, i32, std::ops::Range<i32>),
+    #[error("Spline coordinates out of bounds: {0}, limit is {1}")]
+    SplinesCoordinatesLimit(i32, i32),
+    #[error("Spline delta-delta is out of bounds: {0}, limit is {1}")]
+    SplinesDeltaLimit(i64, i64),
+    #[error("Modular tree too large: {0}, limit is {1}")]
+    TreeTooLarge(usize, usize),
+    #[error("Modular tree too tall: {0}, limit is {1}")]
+    TreeTooTall(usize, usize),
+    #[error("Modular tree multiplier too large: {0}, limit is {1}")]
+    TreeMultiplierTooLarge(u32, u32),
+    #[error("Modular tree multiplier too large: {0}, multiplier log is {1}")]
+    TreeMultiplierBitsTooLarge(u32, u32),
+    #[error(
+        "Modular tree splits on property {0} at value {1}, which is outside the possible range of [{2}, {3}]"
+    )]
+    TreeSplitOnEmptyRange(u8, i32, i32, i32),
+    #[error("Modular stream requested a global tree but there isn't one")]
+    NoGlobalTree,
+    #[error("Invalid transform id")]
+    InvalidTransformId,
+    #[error("Invalid RCT type {0}")]
+    InvalidRCT(u32),
+    #[error("Invalid channel range: {0}..{1}, {2} total channels")]
+    InvalidChannelRange(usize, usize, usize),
+    #[error("Invalid transform: mixing different channels (different shape or different shift)")]
+    MixingDifferentChannels,
+    #[error("Invalid transform: squeezing meta-channels needs an in-place transform")]
+    MetaSqueezeRequiresInPlace,
+    #[error("Invalid transform: too many squeezes (shift > 30)")]
+    TooManySqueezes,
+    #[error("Invalid BlockConextMap: too big: num_lf_context: {0}, num_qf_thresholds: {1}")]
+    BlockContextMapSizeTooBig(usize, usize),
+    #[error("Invalid BlockConextMap: too many distinct contexts.")]
+    TooManyBlockContexts,
+    #[error("Base color correlation out of range.")]
+    BaseColorCorrelationOutOfRange,
+    #[error("Invalid EPF sharpness param {0}")]
+    InvalidEpfValue(i32),
+    #[error("Invalid VarDCT transform type {0}")]
+    InvalidVarDCTTransform(usize),
+    #[error("Invalid VarDCT transform map")]
+    InvalidVarDCTTransformMap,
+    #[error("VarDCT transform overflows HF group")]
+    HFBlockOutOfBounds,
+    #[error("Invalid AC: nonzeros {0} is too large for {1} 8x8 blocks")]
+    InvalidNumNonZeros(usize, usize),
+    #[error("Invalid AC: {0} nonzeros after decoding block")]
+    EndOfBlockResidualNonZeros(usize),
+    #[error("Unknown transfer function for ICC profile")]
+    TransferFunctionUnknown,
+    #[error("Attempting to write out of Bounds when writing ICC")]
+    IccWriteOutOfBounds,
+    #[error("Invalid tag string when writing ICC: {0}")]
+    IccInvalidTagString(String),
+    #[error("Invalid text for ICC MLuc string, not ascii: {0}")]
+    IccMlucTextNotAscii(String),
+    #[error("ICC value is out of range / NaN: {0}")]
+    IccValueOutOfRangeS15Fixed16(f32),
+    #[error("Y value is too small: {0}")]
+    IccInvalidWhitePointY(f32),
+    #[error("{2}: wx: {0}, wy: {1}")]
+    IccInvalidWhitePoint(f32, f32, String),
+    #[error("Determinant is zero or too small, matrix is close to singular: |det| = {0}.")]
+    MatrixInversionFailed(f64),
+    #[error("Unsupported transfer function when writing ICC")]
+    IccUnsupportedTransferFunction,
+    #[error("Table size too large when writing ICC: {0}")]
+    IccTableSizeExceeded(usize),
+    #[error("Invalid CMS configuration: requested ICC but no CMS is configured")]
+    ICCOutputNoCMS,
+    #[error("I/O error: {0}")]
+    IOError(#[from] std::io::Error),
+    #[error("Wrong buffer count: {0} buffers given, {1} buffers expected")]
+    WrongBufferCount(usize, usize),
+    #[error("Image is not grayscale, but grayscale output was requested")]
+    NotGrayscale,
+    #[error("Invalid output buffer byte size {0}x{1} for {2}x{3} image with type {4:?} {5:?}")]
+    InvalidOutputBufferSize(usize, usize, usize, usize, JxlColorType, JxlDataFormat),
+    #[error("Attempting to save channels with different downsample amounts: {0:?} and {1:?}")]
+    SaveDifferentDownsample((u8, u8), (u8, u8)),
+}
+
+pub type Result<T, E = Error> = std::result::Result<T, E>;
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/features/blending.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/features/blending.rs
new file mode 100644
index 0000000..6266716
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/features/blending.rs
@@ -0,0 +1,783 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(clippy::needless_range_loop)]
+
+use crate::headers::extra_channels::{ExtraChannel, ExtraChannelInfo};
+
+use super::patches::{PatchBlendMode, PatchBlending};
+
+#[inline]
+fn maybe_clamp(v: f32, clamp: bool) -> f32 {
+    if clamp { v.clamp(0.0, 1.0) } else { v }
+}
+
+pub fn perform_blending<T: AsRef<[f32]>, V: AsMut<[f32]>>(
+    bg: &mut [V],
+    fg: &[T],
+    color_blending: &PatchBlending,
+    ec_blending: &[PatchBlending],
+    extra_channel_info: &[ExtraChannelInfo],
+) {
+    let has_alpha = extra_channel_info
+        .iter()
+        .any(|info| info.ec_type == ExtraChannel::Alpha);
+    let num_ec = extra_channel_info.len();
+    let xsize = bg[0].as_mut().len();
+
+    let mut tmp = vec![vec![0.0f32; xsize]; 3 + num_ec];
+
+    for i in 0..num_ec {
+        let alpha = ec_blending[i].alpha_channel;
+        let clamp = ec_blending[i].clamp;
+        let alpha_associated = extra_channel_info[alpha].alpha_associated();
+
+        match ec_blending[i].mode {
+            PatchBlendMode::Add => {
+                for x in 0..xsize {
+                    tmp[3 + i][x] = bg[3 + i].as_mut()[x] + fg[3 + i].as_ref()[x];
+                }
+            }
+            PatchBlendMode::BlendAbove => {
+                if i == alpha {
+                    for x in 0..xsize {
+                        let fa = maybe_clamp(fg[3 + alpha].as_ref()[x], clamp);
+                        tmp[3 + i][x] = 1.0 - (1.0 - fa) * (1.0 - bg[3 + i].as_mut()[x]);
+                    }
+                } else if alpha_associated {
+                    for x in 0..xsize {
+                        let fa = maybe_clamp(fg[3 + alpha].as_ref()[x], clamp);
+                        tmp[3 + i][x] = fg[3 + i].as_ref()[x] + bg[3 + i].as_mut()[x] * (1.0 - fa);
+                    }
+                } else {
+                    for x in 0..xsize {
+                        let fa = maybe_clamp(fg[3 + alpha].as_ref()[x], clamp);
+                        let new_a = 1.0 - (1.0 - fa) * (1.0 - bg[3 + alpha].as_mut()[x]);
+                        let rnew_a = if new_a > 0.0 { 1.0 / new_a } else { 0.0 };
+                        tmp[3 + i][x] = (fg[3 + i].as_ref()[x] * fa
+                            + bg[3 + i].as_mut()[x] * bg[3 + alpha].as_mut()[x] * (1.0 - fa))
+                            * rnew_a;
+                    }
+                }
+            }
+            PatchBlendMode::BlendBelow => {
+                if i == alpha {
+                    for x in 0..xsize {
+                        let ba = maybe_clamp(bg[3 + alpha].as_mut()[x], clamp);
+                        tmp[3 + i][x] = 1.0 - (1.0 - ba) * (1.0 - fg[3 + i].as_ref()[x]);
+                    }
+                } else if alpha_associated {
+                    for x in 0..xsize {
+                        let ba = maybe_clamp(bg[3 + alpha].as_mut()[x], clamp);
+                        tmp[3 + i][x] = bg[3 + i].as_mut()[x] + fg[3 + i].as_ref()[x] * (1.0 - ba);
+                    }
+                } else {
+                    for x in 0..xsize {
+                        let ba = maybe_clamp(bg[3 + alpha].as_mut()[x], clamp);
+                        let new_a = 1.0 - (1.0 - ba) * (1.0 - fg[3 + alpha].as_ref()[x]);
+                        let rnew_a = if new_a > 0.0 { 1.0 / new_a } else { 0.0 };
+                        tmp[3 + i][x] = (bg[3 + i].as_mut()[x] * ba
+                            + fg[3 + i].as_ref()[x] * fg[3 + alpha].as_ref()[x] * (1.0 - ba))
+                            * rnew_a;
+                    }
+                }
+            }
+            PatchBlendMode::AlphaWeightedAddAbove => {
+                if i == alpha {
+                    tmp[3 + i].copy_from_slice(bg[3 + i].as_mut());
+                } else if clamp {
+                    for x in 0..xsize {
+                        tmp[3 + i][x] = bg[3 + i].as_mut()[x]
+                            + fg[3 + i].as_ref()[x] * fg[3 + alpha].as_ref()[x].clamp(0.0, 1.0);
+                    }
+                } else {
+                    for x in 0..xsize {
+                        tmp[3 + i][x] = bg[3 + i].as_mut()[x]
+                            + fg[3 + i].as_ref()[x] * fg[3 + alpha].as_ref()[x];
+                    }
+                }
+            }
+            PatchBlendMode::AlphaWeightedAddBelow => {
+                if i == alpha {
+                    tmp[3 + i].copy_from_slice(fg[3 + i].as_ref());
+                } else if clamp {
+                    for x in 0..xsize {
+                        tmp[3 + i][x] = fg[3 + i].as_ref()[x]
+                            + bg[3 + i].as_mut()[x] * bg[3 + alpha].as_mut()[x].clamp(0.0, 1.0);
+                    }
+                } else {
+                    for x in 0..xsize {
+                        tmp[3 + i][x] = fg[3 + i].as_ref()[x]
+                            + bg[3 + i].as_mut()[x] * bg[3 + alpha].as_mut()[x];
+                    }
+                }
+            }
+            PatchBlendMode::Mul => {
+                if clamp {
+                    for x in 0..xsize {
+                        tmp[3 + i][x] =
+                            bg[3 + i].as_mut()[x] * fg[3 + i].as_ref()[x].clamp(0.0, 1.0);
+                    }
+                } else {
+                    for x in 0..xsize {
+                        tmp[3 + i][x] = bg[3 + i].as_mut()[x] * fg[3 + i].as_ref()[x];
+                    }
+                }
+            }
+            PatchBlendMode::Replace => {
+                tmp[3 + i].copy_from_slice(fg[3 + i].as_ref());
+            }
+            PatchBlendMode::None => {
+                tmp[3 + i].copy_from_slice(bg[3 + i].as_mut());
+            }
+        }
+    }
+
+    let alpha = color_blending.alpha_channel;
+    let clamp = color_blending.clamp;
+
+    match color_blending.mode {
+        PatchBlendMode::Add => {
+            for c in 0..3 {
+                for x in 0..xsize {
+                    tmp[c][x] = bg[c].as_mut()[x] + fg[c].as_ref()[x];
+                }
+            }
+        }
+        PatchBlendMode::AlphaWeightedAddAbove => {
+            for c in 0..3 {
+                if !has_alpha {
+                    for x in 0..xsize {
+                        tmp[c][x] = bg[c].as_mut()[x] + fg[c].as_ref()[x];
+                    }
+                } else if clamp {
+                    for x in 0..xsize {
+                        tmp[c][x] = bg[c].as_mut()[x]
+                            + fg[c].as_ref()[x] * fg[3 + alpha].as_ref()[x].clamp(0.0, 1.0);
+                    }
+                } else {
+                    for x in 0..xsize {
+                        tmp[c][x] =
+                            bg[c].as_mut()[x] + fg[c].as_ref()[x] * fg[3 + alpha].as_ref()[x];
+                    }
+                }
+            }
+        }
+        PatchBlendMode::AlphaWeightedAddBelow => {
+            for c in 0..3 {
+                if !has_alpha {
+                    for x in 0..xsize {
+                        tmp[c][x] = bg[c].as_mut()[x] + fg[c].as_ref()[x];
+                    }
+                } else if clamp {
+                    for x in 0..xsize {
+                        tmp[c][x] = fg[c].as_ref()[x]
+                            + bg[c].as_mut()[x] * bg[3 + alpha].as_mut()[x].clamp(0.0, 1.0);
+                    }
+                } else {
+                    for x in 0..xsize {
+                        tmp[c][x] =
+                            fg[c].as_ref()[x] + bg[c].as_mut()[x] * bg[3 + alpha].as_mut()[x];
+                    }
+                }
+            }
+        }
+        PatchBlendMode::BlendAbove => {
+            if !has_alpha {
+                for c in 0..3 {
+                    tmp[c].copy_from_slice(fg[c].as_ref());
+                }
+            } else if extra_channel_info[alpha].alpha_associated() {
+                for x in 0..xsize {
+                    let fa = maybe_clamp(fg[3 + alpha].as_ref()[x], clamp);
+                    for c in 0..3 {
+                        tmp[c][x] = fg[c].as_ref()[x] + bg[c].as_mut()[x] * (1.0 - fa);
+                    }
+                    tmp[3 + alpha][x] = 1.0 - (1.0 - fa) * (1.0 - bg[3 + alpha].as_mut()[x]);
+                }
+            } else {
+                for x in 0..xsize {
+                    let fa = maybe_clamp(fg[3 + alpha].as_ref()[x], clamp);
+                    let new_a = 1.0 - (1.0 - fa) * (1.0 - bg[3 + alpha].as_mut()[x]);
+                    let rnew_a = if new_a > 0.0 { 1.0 / new_a } else { 0.0 };
+                    for c in 0..3 {
+                        tmp[c][x] = (fg[c].as_ref()[x] * fa
+                            + bg[c].as_mut()[x] * bg[3 + alpha].as_mut()[x] * (1.0 - fa))
+                            * rnew_a;
+                    }
+                    tmp[3 + alpha][x] = new_a;
+                }
+            }
+        }
+        PatchBlendMode::BlendBelow => {
+            if !has_alpha {
+                for c in 0..3 {
+                    tmp[c].copy_from_slice(bg[c].as_mut());
+                }
+            } else if extra_channel_info[alpha].alpha_associated() {
+                for x in 0..xsize {
+                    let ba = maybe_clamp(bg[3 + alpha].as_mut()[x], clamp);
+                    for c in 0..3 {
+                        tmp[c][x] = bg[c].as_mut()[x] + fg[c].as_ref()[x] * (1.0 - ba);
+                    }
+                    tmp[3 + alpha][x] = 1.0 - (1.0 - ba) * (1.0 - fg[3 + alpha].as_ref()[x]);
+                }
+            } else {
+                for x in 0..xsize {
+                    let ba = maybe_clamp(bg[3 + alpha].as_mut()[x], clamp);
+                    let new_a = 1.0 - (1.0 - ba) * (1.0 - fg[3 + alpha].as_ref()[x]);
+                    let rnew_a = if new_a > 0.0 { 1.0 / new_a } else { 0.0 };
+                    for c in 0..3 {
+                        tmp[c][x] = (bg[c].as_mut()[x] * ba
+                            + fg[c].as_ref()[x] * fg[3 + alpha].as_ref()[x] * (1.0 - ba))
+                            * rnew_a;
+                    }
+                    tmp[3 + alpha][x] = new_a;
+                }
+            }
+        }
+        PatchBlendMode::Mul => {
+            for c in 0..3 {
+                for x in 0..xsize {
+                    tmp[c][x] = bg[c].as_mut()[x] * maybe_clamp(fg[c].as_ref()[x], clamp);
+                }
+            }
+        }
+        PatchBlendMode::Replace => {
+            for c in 0..3 {
+                tmp[c].copy_from_slice(fg[c].as_ref());
+            }
+        }
+        PatchBlendMode::None => {
+            for c in 0..3 {
+                tmp[c].copy_from_slice(bg[c].as_mut());
+            }
+        }
+    }
+    for i in 0..(3 + num_ec) {
+        bg[i].as_mut().copy_from_slice(&tmp[i]);
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    fn clamp(x: f32) -> f32 {
+        x.clamp(0.0, 1.0)
+    }
+
+    mod perform_blending_tests {
+        use super::{super::*, *};
+        use crate::{headers::bit_depth::BitDepth, util::test::assert_all_almost_abs_eq};
+        use test_log::test;
+
+        const ABS_DELTA: f32 = 1e-6;
+
+        // Helper for expected value calculations based on C++ logic
+
+        // Alpha compositing formula: Ao = As + Ab * (1 - As)
+        // Used for kBlend modes for the alpha channel itself.
+        fn expected_alpha_blend(fg_a: f32, bg_a: f32) -> f32 {
+            fg_a + bg_a * (1.0 - fg_a)
+        }
+
+        // Color compositing for kBlend, premultiplied alpha: Co = Cs_premult + Cb_premult * (1 - As)
+        fn expected_color_blend_premultiplied(c_fg: f32, c_bg: f32, fg_a: f32) -> f32 {
+            c_fg + c_bg * (1.0 - fg_a)
+        }
+
+        // Color compositing for kBlend, non-premultiplied alpha: Co = (Cs * As + Cb * Ab * (1 - As)) / Ao_blend
+        fn expected_color_blend_non_premultiplied(
+            c_fg: f32,
+            fg_a: f32, // Foreground color and its alpha
+            c_bg: f32,
+            bg_a: f32,            // Background color and its alpha
+            alpha_blend_out: f32, // The resulting alpha from expected_alpha_blend(fg_a, bg_a)
+        ) -> f32 {
+            if alpha_blend_out.abs() < ABS_DELTA {
+                // Avoid division by zero
+                0.0
+            } else {
+                (c_fg * fg_a + c_bg * bg_a * (1.0 - fg_a)) / alpha_blend_out
+            }
+        }
+
+        // For kAlphaWeightedAdd modes: Co = Cb + Cs * As
+        fn expected_alpha_weighted_add(c_bg: f32, c_fg: f32, fg_a: f32) -> f32 {
+            c_bg + c_fg * fg_a
+        }
+
+        // For kMul mode: Co = Cb * Cs
+        fn expected_mul_blend(c_bg: f32, c_fg: f32) -> f32 {
+            c_bg * c_fg
+        }
+
+        #[test]
+        fn test_color_replace_fg_over_bg() {
+            let mut bg_r = [0.1];
+            let mut bg_g = [0.2];
+            let mut bg_b = [0.3];
+            let fg_r = [0.7];
+            let fg_g = [0.8];
+            let fg_b = [0.9];
+
+            let mut bg_channels: [&mut [f32]; 3] = [&mut bg_r, &mut bg_g, &mut bg_b];
+            let fg_channels: [&[f32]; 3] = [&fg_r, &fg_g, &fg_b];
+
+            let color_blending = PatchBlending {
+                mode: PatchBlendMode::Replace,
+                alpha_channel: 0, // Not used for Replace
+                clamp: false,
+            };
+
+            let ec_blending: [PatchBlending; 0] = [];
+            let extra_channel_info: [ExtraChannelInfo; 0] = [];
+
+            perform_blending(
+                &mut bg_channels,
+                &fg_channels,
+                &color_blending,
+                &ec_blending,
+                &extra_channel_info,
+            );
+
+            // Expected: output color is fg color
+            assert_all_almost_abs_eq(&bg_r, &fg_r, ABS_DELTA);
+            assert_all_almost_abs_eq(&bg_g, &fg_g, ABS_DELTA);
+            assert_all_almost_abs_eq(&bg_b, &fg_b, ABS_DELTA);
+        }
+
+        #[test]
+        fn test_color_add() {
+            let mut bg_r = [0.1];
+            let mut bg_g = [0.2];
+            let mut bg_b = [0.3];
+            let fg_r = [0.7];
+            let fg_g = [0.6];
+            let fg_b = [0.5];
+            let expected_r = [bg_r[0] + fg_r[0]];
+            let expected_g = [bg_g[0] + fg_g[0]];
+            let expected_b = [bg_b[0] + fg_b[0]];
+
+            let mut bg_channels: [&mut [f32]; 3] = [&mut bg_r, &mut bg_g, &mut bg_b];
+            let fg_channels: [&[f32]; 3] = [&fg_r, &fg_g, &fg_b];
+
+            let color_blending = PatchBlending {
+                mode: PatchBlendMode::Add,
+                alpha_channel: 0, // Not used
+                clamp: false,
+            };
+            let ec_blending: [PatchBlending; 0] = [];
+            let extra_channel_info: [ExtraChannelInfo; 0] = [];
+
+            perform_blending(
+                &mut bg_channels,
+                &fg_channels,
+                &color_blending,
+                &ec_blending,
+                &extra_channel_info,
+            );
+
+            assert_all_almost_abs_eq(&bg_r, &expected_r, ABS_DELTA);
+            assert_all_almost_abs_eq(&bg_g, &expected_g, ABS_DELTA);
+            assert_all_almost_abs_eq(&bg_b, &expected_b, ABS_DELTA);
+        }
+
+        #[test]
+        fn test_color_blend_above_premultiplied_alpha() {
+            // BG: R=0.1, G=0.2, B=0.3, A=0.8 (premultiplied)
+            // FG: R=0.4, G=0.3, B=0.2, A=0.5 (premultiplied)
+            let mut bg_r = [0.1];
+            let mut bg_g = [0.2];
+            let mut bg_b = [0.3];
+            let mut bg_a = [0.8];
+            let fg_r = [0.4];
+            let fg_g = [0.3];
+            let fg_b = [0.2];
+            let fg_a = [0.5];
+            let fga = fg_a[0]; // Not clamped
+            let bga = bg_a[0];
+
+            // Expected alpha: Ao = Afg + Abg * (1 - Afg)
+            let expected_a_val = expected_alpha_blend(fga, bga);
+            // Expected color: Co = Cfg_premult + Cbg_premult * (1 - Afg)
+            let expected_r_val = expected_color_blend_premultiplied(fg_r[0], bg_r[0], fga);
+            let expected_g_val = expected_color_blend_premultiplied(fg_g[0], bg_g[0], fga);
+            let expected_b_val = expected_color_blend_premultiplied(fg_b[0], bg_b[0], fga);
+
+            let mut bg_channels: [&mut [f32]; 4] = [&mut bg_r, &mut bg_g, &mut bg_b, &mut bg_a];
+            let fg_channels: [&[f32]; 4] = [&fg_r, &fg_g, &fg_b, &fg_a];
+
+            let color_blending = PatchBlending {
+                mode: PatchBlendMode::BlendAbove,
+                alpha_channel: 0, // EC0 is the alpha channel
+                clamp: false,
+            };
+            // EC0 (alpha) blending rule.
+            // For BlendAbove color mode, the alpha channel itself is also blended using source-over.
+            // So this ec_blending rule for alpha will be effectively overridden by color blending's alpha calculation.
+            let ec_blending = [PatchBlending {
+                mode: PatchBlendMode::Replace, // Arbitrary, will be overwritten by color blend
+                alpha_channel: 0,
+                clamp: false,
+            }];
+            let extra_channel_info = [ExtraChannelInfo::new(
+                false,
+                ExtraChannel::Alpha,
+                BitDepth::f32(), // Assuming f32
+                0,
+                "alpha".to_string(),
+                true, // alpha_associated = true (premultiplied)
+                None,
+                None,
+            )];
+
+            perform_blending(
+                &mut bg_channels,
+                &fg_channels,
+                &color_blending,
+                &ec_blending,
+                &extra_channel_info,
+            );
+
+            assert_all_almost_abs_eq(&bg_a, &[expected_a_val], ABS_DELTA);
+            assert_all_almost_abs_eq(&bg_r, &[expected_r_val], ABS_DELTA);
+            assert_all_almost_abs_eq(&bg_g, &[expected_g_val], ABS_DELTA);
+            assert_all_almost_abs_eq(&bg_b, &[expected_b_val], ABS_DELTA);
+        }
+
+        #[test]
+        fn test_color_blend_above_non_premultiplied_alpha() {
+            // BG: R=0.1, G=0.2, B=0.3 (unpremult), A=0.8
+            // FG: R=0.7, G=0.6, B=0.5 (unpremult), A=0.5
+            let mut bg_r = [0.1];
+            let mut bg_g = [0.2];
+            let mut bg_b = [0.3];
+            let mut bg_a = [0.8];
+            let fg_r = [0.7];
+            let fg_g = [0.6];
+            let fg_b = [0.5];
+            let fg_a = [0.5];
+            let fga = fg_a[0];
+            let bga = bg_a[0];
+
+            // Expected alpha: Ao = Afg + Abg * (1 - Afg)
+            let expected_a_val = expected_alpha_blend(fga, bga);
+            // Expected color: Co = (Cfg_unpremult * Afg + Cbg_unpremult * Abg * (1 - Afg)) / Ao_blend
+            let expected_r_val =
+                expected_color_blend_non_premultiplied(fg_r[0], fga, bg_r[0], bga, expected_a_val);
+            let expected_g_val =
+                expected_color_blend_non_premultiplied(fg_g[0], fga, bg_g[0], bga, expected_a_val);
+            let expected_b_val =
+                expected_color_blend_non_premultiplied(fg_b[0], fga, bg_b[0], bga, expected_a_val);
+
+            let mut bg_channels: [&mut [f32]; 4] = [&mut bg_r, &mut bg_g, &mut bg_b, &mut bg_a];
+            let fg_channels: [&[f32]; 4] = [&fg_r, &fg_g, &fg_b, &fg_a];
+
+            let color_blending = PatchBlending {
+                mode: PatchBlendMode::BlendAbove,
+                alpha_channel: 0, // EC0
+                clamp: false,
+            };
+            let ec_blending = [PatchBlending {
+                // This will be overwritten for the alpha channel by color blending
+                mode: PatchBlendMode::Replace,
+                alpha_channel: 0,
+                clamp: false,
+            }];
+            let extra_channel_info = [ExtraChannelInfo::new(
+                false,
+                ExtraChannel::Alpha,
+                BitDepth::f32(),
+                0,
+                "alpha".to_string(),
+                false, // alpha_associated = false (non-premultiplied)
+                None,
+                None,
+            )];
+
+            perform_blending(
+                &mut bg_channels,
+                &fg_channels,
+                &color_blending,
+                &ec_blending,
+                &extra_channel_info,
+            );
+
+            assert_all_almost_abs_eq(&bg_a, &[expected_a_val], ABS_DELTA);
+            assert_all_almost_abs_eq(&bg_r, &[expected_r_val], ABS_DELTA);
+            assert_all_almost_abs_eq(&bg_g, &[expected_g_val], ABS_DELTA);
+            assert_all_almost_abs_eq(&bg_b, &[expected_b_val], ABS_DELTA);
+        }
+
+        #[test]
+        fn test_color_alpha_weighted_add_above() {
+            let mut bg_r = [0.1];
+            let mut bg_g = [0.2];
+            let mut bg_b = [0.3];
+            let mut bg_a = [0.8]; // bg alpha used by ec_blending
+            let fg_r = [0.7];
+            let fg_g = [0.6];
+            let fg_b = [0.5];
+            let fg_a = [0.5]; // fg alpha used for weighting
+            let fga_for_weighting = fg_a[0]; // Not clamped as color_blending.clamp is false
+
+            // Expected color: Co = Cbg + Cfg * Afg_for_weighting
+            let expected_r_val = expected_alpha_weighted_add(bg_r[0], fg_r[0], fga_for_weighting);
+            let expected_g_val = expected_alpha_weighted_add(bg_g[0], fg_g[0], fga_for_weighting);
+            let expected_b_val = expected_alpha_weighted_add(bg_b[0], fg_b[0], fga_for_weighting);
+
+            // Expected alpha (EC0): Blended according to ec_blending[0].
+            // Mode is BlendAbove, alpha_channel is 0 (itself).
+            // C++: PerformAlphaBlending(bg[3+0], bg[3+0], fg[3+0], fg[3+0], tmp.Row(3+0), ...)
+            // This means it's the "alpha channel blends itself" case: Ao = Afg + Abg * (1 - Afg)
+            // fg_alpha_for_ec0 = fg_a[0], bg_alpha_for_ec0 = bg_a[0]. ec_blending[0].clamp is false.
+            let expected_a_val = expected_alpha_blend(fg_a[0], bg_a[0]);
+
+            let mut bg_channels: [&mut [f32]; 4] = [&mut bg_r, &mut bg_g, &mut bg_b, &mut bg_a];
+            let fg_channels: [&[f32]; 4] = [&fg_r, &fg_g, &fg_b, &fg_a];
+
+            let color_blending = PatchBlending {
+                mode: PatchBlendMode::AlphaWeightedAddAbove,
+                alpha_channel: 0, // EC0 is alpha
+                clamp: false,
+            };
+            // For AlphaWeightedAdd color mode, the alpha channel (EC0) value is determined by its ec_blending rule.
+            // Let's make EC0 blend itself using BlendAbove mode.
+            let ec_blending = [PatchBlending {
+                mode: PatchBlendMode::BlendAbove, // Alpha channel EC0 blends itself
+                alpha_channel: 0,                 //  using itself as alpha reference
+                clamp: false,
+            }];
+            let extra_channel_info = [ExtraChannelInfo::new(
+                false,
+                ExtraChannel::Alpha,
+                BitDepth::f32(),
+                0,
+                "alpha".to_string(),
+                true, // alpha_associated (doesn't directly affect AWA color, but affects EC0's own blend)
+                None,
+                None,
+            )];
+
+            perform_blending(
+                &mut bg_channels,
+                &fg_channels,
+                &color_blending,
+                &ec_blending,
+                &extra_channel_info,
+            );
+
+            assert_all_almost_abs_eq(&bg_r, &[expected_r_val], ABS_DELTA);
+            assert_all_almost_abs_eq(&bg_g, &[expected_g_val], ABS_DELTA);
+            assert_all_almost_abs_eq(&bg_b, &[expected_b_val], ABS_DELTA);
+            assert_all_almost_abs_eq(&bg_a, &[expected_a_val], ABS_DELTA);
+        }
+
+        #[test]
+        fn test_color_mul_with_clamp() {
+            let mut bg_r = [0.5];
+            let mut bg_g = [0.8];
+            let mut bg_b = [1.0];
+            let fg_r = [1.5];
+            let fg_g = [-0.2];
+            let fg_b = [0.5]; // fg values will be clamped
+            let expected_r = [expected_mul_blend(bg_r[0], clamp(fg_r[0]))]; // 0.5 * 1.0 = 0.5
+            let expected_g = [expected_mul_blend(bg_g[0], clamp(fg_g[0]))]; // 0.8 * 0.0 = 0.0
+            let expected_b = [expected_mul_blend(bg_b[0], clamp(fg_b[0]))]; // 1.0 * 0.5 = 0.5
+
+            let mut bg_channels: [&mut [f32]; 3] = [&mut bg_r, &mut bg_g, &mut bg_b];
+            let fg_channels: [&[f32]; 3] = [&fg_r, &fg_g, &fg_b];
+
+            let color_blending = PatchBlending {
+                mode: PatchBlendMode::Mul,
+                alpha_channel: 0, // Not used
+                clamp: true,      // Clamp fg values
+            };
+            let ec_blending: [PatchBlending; 0] = [];
+            let extra_channel_info: [ExtraChannelInfo; 0] = [];
+
+            perform_blending(
+                &mut bg_channels,
+                &fg_channels,
+                &color_blending,
+                &ec_blending,
+                &extra_channel_info,
+            );
+
+            assert_all_almost_abs_eq(&bg_r, &expected_r, ABS_DELTA);
+            assert_all_almost_abs_eq(&bg_g, &expected_g, ABS_DELTA);
+            assert_all_almost_abs_eq(&bg_b, &expected_b, ABS_DELTA);
+        }
+
+        #[test]
+        fn test_ec_blend_data_with_separate_alpha_premultiplied() {
+            // Color: Replace FG over BG (to keep it simple)
+            // EC0: Data channel
+            // EC1: Alpha channel for EC0
+            let mut bg_r = [0.1];
+            let mut bg_g = [0.1];
+            let mut bg_b = [0.1];
+            let mut bg_ec0 = [0.2];
+            let mut bg_ec1_alpha = [0.9]; // EC1 is alpha for EC0
+
+            let fg_r = [0.5];
+            let fg_g = [0.5];
+            let fg_b = [0.5];
+            let fg_ec0 = [0.6];
+            let fg_ec1_alpha = [0.4];
+
+            // EC1 (Alpha channel for EC0) blending: BlendAbove, uses itself as alpha.
+            // fg_alpha = fg_ec1_alpha[0], bg_alpha = bg_ec1_alpha[0]
+            let expected_out_ec1_alpha = expected_alpha_blend(fg_ec1_alpha[0], bg_ec1_alpha[0]);
+
+            // EC0 (Data channel) blending: BlendAbove, uses EC1 as alpha.
+            // fg_alpha_for_ec0 = fg_ec1_alpha[0] (not clamped as ec_blending[0].clamp is false)
+            // is_premultiplied = extra_channel_info[ec_blending[0].alpha_channel (is 1)].alpha_associated = true.
+            // Formula: out = fg_data + bg_data * (1.f - fg_alpha_of_data)
+            let expected_out_ec0 =
+                expected_color_blend_premultiplied(fg_ec0[0], bg_ec0[0], fg_ec1_alpha[0]);
+
+            let mut bg_channels: [&mut [f32]; 5] = [
+                &mut bg_r,
+                &mut bg_g,
+                &mut bg_b,
+                &mut bg_ec0,
+                &mut bg_ec1_alpha,
+            ];
+            let fg_channels: [&[f32]; 5] = [&fg_r, &fg_g, &fg_b, &fg_ec0, &fg_ec1_alpha];
+
+            let color_blending = PatchBlending {
+                // Simple color replace
+                mode: PatchBlendMode::Replace,
+                alpha_channel: 0,
+                clamp: false,
+            };
+
+            let ec_blending = [
+                PatchBlending {
+                    // EC0 (data) uses EC1 as alpha
+                    mode: PatchBlendMode::BlendAbove,
+                    alpha_channel: 1, // EC1 is alpha for EC0
+                    clamp: false,
+                },
+                PatchBlending {
+                    // EC1 (alpha) blends itself
+                    mode: PatchBlendMode::BlendAbove,
+                    alpha_channel: 1, // EC1 uses itself as alpha
+                    clamp: false,
+                },
+            ];
+            let extra_channel_info = [
+                ExtraChannelInfo::new(
+                    false,
+                    ExtraChannel::Unknown,
+                    BitDepth::f32(),
+                    0,
+                    "ec0".to_string(),
+                    false,
+                    None,
+                    None,
+                ), // EC0 data
+                ExtraChannelInfo::new(
+                    false,
+                    ExtraChannel::Alpha,
+                    BitDepth::f32(),
+                    0,
+                    "alpha_for_ec0".to_string(),
+                    true, // EC1 is premultiplied alpha
+                    None,
+                    None,
+                ), // EC1 alpha
+            ];
+
+            perform_blending(
+                &mut bg_channels,
+                &fg_channels,
+                &color_blending,
+                &ec_blending,
+                &extra_channel_info,
+            );
+
+            // Expected Color (Replace)
+            assert_all_almost_abs_eq(&bg_r, &fg_r, ABS_DELTA);
+            assert_all_almost_abs_eq(&bg_g, &fg_g, ABS_DELTA);
+            assert_all_almost_abs_eq(&bg_b, &fg_b, ABS_DELTA);
+
+            assert_all_almost_abs_eq(&bg_ec1_alpha, &[expected_out_ec1_alpha], ABS_DELTA);
+
+            assert_all_almost_abs_eq(&bg_ec0, &[expected_out_ec0], ABS_DELTA);
+        }
+
+        #[test]
+        fn test_no_alpha_channel_blend_above_falls_back_to_copy_fg() {
+            let mut bg_r = [0.1];
+            let mut bg_g = [0.2];
+            let mut bg_b = [0.3];
+            let fg_r = [0.7];
+            let fg_g = [0.8];
+            let fg_b = [0.9];
+
+            let mut bg_channels: [&mut [f32]; 3] = [&mut bg_r, &mut bg_g, &mut bg_b];
+            let fg_channels: [&[f32]; 3] = [&fg_r, &fg_g, &fg_b];
+
+            let color_blending = PatchBlending {
+                mode: PatchBlendMode::BlendAbove,
+                alpha_channel: 0, // Irrelevant as no alpha EIs
+                clamp: false,
+            };
+
+            let ec_blending: [PatchBlending; 0] = [];
+            // No ExtraChannelInfo means has_alpha will be false.
+            let extra_channel_info: [ExtraChannelInfo; 0] = [];
+
+            perform_blending(
+                &mut bg_channels,
+                &fg_channels,
+                &color_blending,
+                &ec_blending,
+                &extra_channel_info,
+            );
+
+            // Expected: output color is fg color due to fallback
+            assert_all_almost_abs_eq(&bg_r, &fg_r, ABS_DELTA);
+            assert_all_almost_abs_eq(&bg_g, &fg_g, ABS_DELTA);
+            assert_all_almost_abs_eq(&bg_b, &fg_b, ABS_DELTA);
+        }
+
+        #[test]
+        fn test_empty_pixels() {
+            let mut bg_r: [f32; 0] = [];
+            let mut bg_g: [f32; 0] = [];
+            let mut bg_b: [f32; 0] = [];
+            let fg_r: [f32; 0] = [];
+            let fg_g: [f32; 0] = [];
+            let fg_b: [f32; 0] = [];
+
+            let mut bg_channels: [&mut [f32]; 3] = [&mut bg_r, &mut bg_g, &mut bg_b];
+            let fg_channels: [&[f32]; 3] = [&fg_r, &fg_g, &fg_b];
+
+            let color_blending = PatchBlending {
+                mode: PatchBlendMode::Replace,
+                alpha_channel: 0,
+                clamp: false,
+            };
+            let ec_blending: [PatchBlending; 0] = [];
+            let extra_channel_info: [ExtraChannelInfo; 0] = [];
+
+            perform_blending(
+                &mut bg_channels,
+                &fg_channels,
+                &color_blending,
+                &ec_blending,
+                &extra_channel_info,
+            );
+
+            // Expect output slices to also be empty and unchanged.
+            assert_eq!(bg_r.len(), 0);
+            assert_eq!(bg_g.len(), 0);
+            assert_eq!(bg_b.len(), 0);
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/features/epf.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/features/epf.rs
new file mode 100644
index 0000000..2dccedc0
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/features/epf.rs
@@ -0,0 +1,68 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{
+    error::{Error, Result},
+    frame::{HfMetadata, LfGlobalState},
+    headers::frame_header::{Encoding, FrameHeader},
+    image::Image,
+};
+
+use jxl_transforms::transform_map::*;
+
+pub fn create_sigma_image(
+    frame_header: &FrameHeader,
+    lf_global: &LfGlobalState,
+    hf_meta: &Option<HfMetadata>,
+) -> Result<Image<f32>> {
+    let size_blocks = frame_header.size_blocks();
+    let rf = &frame_header.restoration_filter;
+    let sigma_xsize = size_blocks.0;
+    let sigma_ysize = size_blocks.1;
+    // We might over-read the sigma row slightly when applying EPF, so ensure that there is enough
+    // space to avoid having the out-of-bounds read from the row causing a panic (the value does
+    // not affect any pixels that are actually visualized, so we don't need to set it to anything
+    // special below).
+    let mut sigma_image = Image::<f32>::new((sigma_xsize + 2, sigma_ysize))?;
+    #[allow(clippy::excessive_precision)]
+    const INV_SIGMA_NUM: f32 = -1.1715728752538099024;
+    if frame_header.encoding == Encoding::VarDCT {
+        let hf_meta = hf_meta.as_ref().unwrap();
+        let quant_params = lf_global.quant_params.as_ref().unwrap();
+        let quant_scale = 1.0 / quant_params.inv_global_scale();
+        for by in 0..size_blocks.1 {
+            let raw_quant_row = hf_meta.raw_quant_map.row(by);
+            let transform_row = hf_meta.transform_map.row(by);
+            for bx in 0..size_blocks.0 {
+                let raw_quant = raw_quant_row[bx];
+                let raw_transform_id = transform_row[bx];
+                let transform_id = raw_transform_id & 127;
+                let is_first_block = raw_transform_id >= 128;
+                if !is_first_block {
+                    continue;
+                }
+                let transform_type = HfTransformType::from_usize(transform_id as usize)
+                    .ok_or(Error::InvalidVarDCTTransform(transform_id as usize))?;
+                let cx = covered_blocks_x(transform_type) as usize;
+                let cy = covered_blocks_y(transform_type) as usize;
+                let sigma_quant =
+                    rf.epf_quant_mul / (quant_scale * raw_quant as f32 * INV_SIGMA_NUM);
+                for iy in 0..cy {
+                    for ix in 0..cx {
+                        let sharpness = hf_meta.epf_map.row(by + iy)[bx + ix] as usize;
+                        let sigma = (sigma_quant * rf.epf_sharp_lut[sharpness]).min(-1e-4);
+                        sigma_image.row_mut(by + iy)[bx + ix] = 1.0 / sigma;
+                    }
+                }
+            }
+        }
+    } else {
+        // TODO(szabadka): Instead of allocating an image, return an enum with image and f32
+        // variants.
+        let sigma = INV_SIGMA_NUM / rf.epf_sigma_for_modular;
+        sigma_image.fill(sigma);
+    }
+    Ok(sigma_image)
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/features/mod.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/features/mod.rs
new file mode 100644
index 0000000..fbbfd2ae
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/features/mod.rs
@@ -0,0 +1,10 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+pub mod blending;
+pub mod epf;
+pub mod noise;
+pub mod patches;
+pub mod spline;
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/features/noise.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/features/noise.rs
new file mode 100644
index 0000000..5770a19
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/features/noise.rs
@@ -0,0 +1,40 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{bit_reader::BitReader, error::Result};
+#[derive(Debug, PartialEq, Default, Clone, Copy)]
+pub struct Noise {
+    pub lut: [f32; 8],
+}
+
+impl Noise {
+    pub fn read(br: &mut BitReader) -> Result<Noise> {
+        let mut noise = Noise::default();
+        for l in &mut noise.lut {
+            *l = (br.read(10)? as f32) / ((1 << 10) as f32);
+        }
+        Ok(noise)
+    }
+    pub fn strength(&self, vx: f32) -> f32 {
+        let k_scale = (self.lut.len() - 2) as f32;
+        let scaled_vx = f32::max(0.0, vx * k_scale);
+        let pre_floor_x = scaled_vx.floor();
+        let pre_frac_x = scaled_vx - pre_floor_x;
+        let floor_x = if scaled_vx >= k_scale + 1.0 {
+            k_scale
+        } else {
+            pre_floor_x
+        };
+        let frac_x = if scaled_vx >= k_scale + 1.0 {
+            1.0
+        } else {
+            pre_frac_x
+        };
+        let floor_x_int = floor_x as usize;
+        let low = self.lut[floor_x_int];
+        let hi = self.lut[floor_x_int + 1];
+        ((hi - low) * frac_x + low).clamp(0.0, 1.0)
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/features/patches.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/features/patches.rs
new file mode 100644
index 0000000..b73a2d73
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/features/patches.rs
@@ -0,0 +1,2034 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use num_derive::FromPrimitive;
+use num_traits::FromPrimitive;
+
+use crate::{
+    bit_reader::BitReader,
+    entropy_coding::decode::Histograms,
+    entropy_coding::decode::SymbolReader,
+    error::{Error, Result},
+    features::blending::perform_blending,
+    frame::{DecoderState, ReferenceFrame},
+    headers::extra_channels::ExtraChannelInfo,
+    util::{NewWithCapacity, slice, tracing_wrappers::*},
+};
+
+// Context numbers as specified in Section C.4.5, Listing C.2:
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+#[repr(usize)]
+pub enum PatchContext {
+    NumRefPatch = 0,
+    ReferenceFrame = 1,
+    PatchSize = 2,
+    PatchReferencePosition = 3,
+    PatchPosition = 4,
+    PatchBlendMode = 5,
+    PatchOffset = 6,
+    PatchCount = 7,
+    PatchAlphaChannel = 8,
+    PatchClamp = 9,
+}
+
+impl PatchContext {
+    const NUM: usize = 10;
+}
+
+/// Blend modes
+#[derive(Debug, PartialEq, Eq, Clone, Copy, FromPrimitive)]
+#[repr(u8)]
+pub enum PatchBlendMode {
+    // The new values are the old ones. Useful to skip some channels.
+    None = 0,
+    // The new values (in the crop) replace the old ones: sample = new
+    Replace = 1,
+    // The new values (in the crop) get added to the old ones: sample = old + new
+    Add = 2,
+    // The new values (in the crop) get multiplied by the old ones:
+    // sample = old * new
+    // This blend mode is only supported if BlendColorSpace is kEncoded. The
+    // range of the new value matters for multiplication purposes, and its
+    // nominal range of 0..1 is computed the same way as this is done for the
+    // alpha values in kBlend and kAlphaWeightedAdd.
+    Mul = 3,
+    // The new values (in the crop) replace the old ones if alpha>0:
+    // For first alpha channel:
+    // alpha = old + new * (1 - old)
+    // For other channels if !alpha_associated:
+    // sample = ((1 - new_alpha) * old * old_alpha + new_alpha * new) / alpha
+    // For other channels if alpha_associated:
+    // sample = (1 - new_alpha) * old + new
+    // The alpha formula applies to the alpha used for the division in the other
+    // channels formula, and applies to the alpha channel itself if its
+    // blend_channel value matches itself.
+    // If using kBlendAbove, new is the patch and old is the original image; if
+    // using kBlendBelow, the meaning is inverted.
+    BlendAbove = 4,
+    BlendBelow = 5,
+    // The new values (in the crop) are added to the old ones if alpha>0:
+    // For first alpha channel: sample = sample = old + new * (1 - old)
+    // For other channels: sample = old + alpha * new
+    AlphaWeightedAddAbove = 6,
+    AlphaWeightedAddBelow = 7,
+}
+
+impl PatchBlendMode {
+    pub const NUM_BLEND_MODES: u8 = 8;
+
+    #[cfg(test)]
+    fn try_from(i: u8) -> Result<PatchBlendMode> {
+        match i {
+            0 => Ok(PatchBlendMode::None),
+            1 => Ok(PatchBlendMode::Replace),
+            2 => Ok(PatchBlendMode::Add),
+            3 => Ok(PatchBlendMode::Mul),
+            4 => Ok(PatchBlendMode::BlendAbove),
+            5 => Ok(PatchBlendMode::BlendBelow),
+            6 => Ok(PatchBlendMode::AlphaWeightedAddAbove),
+            7 => Ok(PatchBlendMode::AlphaWeightedAddBelow),
+            _ => Err(Error::PatchesInvalidBlendMode(
+                i,
+                PatchBlendMode::NUM_BLEND_MODES,
+            )),
+        }
+    }
+
+    #[cfg(test)]
+    fn random<R: rand::Rng>(rng: &mut R) -> Self {
+        use rand::distr::{Distribution, Uniform};
+        Self::try_from(
+            Uniform::new_inclusive(
+                PatchBlendMode::None as u8,
+                PatchBlendMode::AlphaWeightedAddBelow as u8,
+            )
+            .unwrap()
+            .sample(rng),
+        )
+        .unwrap()
+    }
+
+    pub fn uses_alpha(self) -> bool {
+        matches!(
+            self,
+            Self::BlendAbove
+                | Self::BlendBelow
+                | Self::AlphaWeightedAddAbove
+                | Self::AlphaWeightedAddBelow
+        )
+    }
+
+    pub fn uses_clamp(self) -> bool {
+        self.uses_alpha() || self == Self::Mul
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct PatchBlending {
+    pub mode: PatchBlendMode,
+    pub alpha_channel: usize,
+    pub clamp: bool,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct PatchReferencePosition {
+    // Not using `ref` like in the spec here, because it is a keyword.
+    reference: usize,
+    x0: usize,
+    y0: usize,
+    xsize: usize,
+    ysize: usize,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct PatchPosition {
+    x: usize,
+    y: usize,
+    ref_pos_idx: usize,
+}
+
+#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
+struct PatchTreeNode {
+    left_child: isize,
+    right_child: isize,
+    y_center: usize,
+    start: usize,
+    num: usize,
+}
+
+#[derive(Clone, Debug, Default, PartialEq, Eq)]
+pub struct PatchesDictionary {
+    pub positions: Vec<PatchPosition>,
+    pub ref_positions: Vec<PatchReferencePosition>,
+    blendings: Vec<PatchBlending>,
+    blendings_stride: usize,
+    patch_tree: Vec<PatchTreeNode>,
+    // Number of patches for each row.
+    num_patches: Vec<usize>,
+    sorted_patches_y0: Vec<(usize, usize)>,
+    sorted_patches_y1: Vec<(usize, usize)>,
+}
+
+impl PatchesDictionary {
+    #[cfg(test)]
+    pub fn random<R: rand::Rng>(
+        size: (usize, usize),
+        num_extra_channels: usize,
+        alpha_channel: usize,
+        reference_frames: usize,
+        rng: &mut R,
+    ) -> Self {
+        use rand::distr::{Distribution, Uniform};
+        let width_dist = Uniform::new_inclusive(0, size.0 - 1).unwrap();
+        let height_dist = Uniform::new_inclusive(0, size.1 - 1).unwrap();
+        let num_refs = Uniform::new_inclusive(1, 5).unwrap().sample(rng);
+        let ref_dist = Uniform::new_inclusive(0, num_refs - 1).unwrap();
+        let ref_frame_dist = Uniform::new_inclusive(0, reference_frames - 1).unwrap();
+        let num_patches = Uniform::new_inclusive(num_refs, 10).unwrap().sample(rng);
+        let mut result = PatchesDictionary {
+            positions: (0..num_patches)
+                .map(|_| PatchPosition {
+                    x: width_dist.sample(rng),
+                    y: height_dist.sample(rng),
+                    ref_pos_idx: ref_dist.sample(rng),
+                })
+                .collect(),
+            ref_positions: (0..num_refs)
+                .map(|_| {
+                    let mut result = PatchReferencePosition {
+                        reference: ref_frame_dist.sample(rng),
+                        x0: width_dist.sample(rng),
+                        y0: height_dist.sample(rng),
+                        xsize: 0,
+                        ysize: 0,
+                    };
+                    result.xsize = Uniform::new_inclusive(1, size.0 - result.x0)
+                        .unwrap()
+                        .sample(rng);
+                    result.ysize = Uniform::new_inclusive(1, size.1 - result.y0)
+                        .unwrap()
+                        .sample(rng);
+                    result
+                })
+                .collect(),
+            blendings: (0..num_patches)
+                .map(|_| PatchBlending {
+                    mode: PatchBlendMode::random(rng),
+                    alpha_channel,
+                    clamp: Uniform::new_inclusive(0, 1).unwrap().sample(rng) == 0,
+                })
+                .collect(),
+            blendings_stride: num_extra_channels + 1,
+            patch_tree: vec![],
+            num_patches: vec![],
+            sorted_patches_y0: vec![],
+            sorted_patches_y1: vec![],
+        };
+        result.compute_patch_tree().unwrap();
+        result
+    }
+
+    fn compute_patch_tree(&mut self) -> Result<()> {
+        #[derive(Debug, Clone, Copy)]
+        struct PatchInterval {
+            idx: usize,
+            y0: usize,
+            y1: usize,
+        }
+
+        self.patch_tree.clear();
+        self.num_patches.clear();
+        self.sorted_patches_y0.clear();
+        self.sorted_patches_y1.clear();
+
+        if self.positions.is_empty() {
+            return Ok(());
+        }
+
+        // Create a y-interval for each patch.
+        let mut intervals: Vec<PatchInterval> = Vec::new_with_capacity(self.positions.len())?;
+        for (i, pos) in self.positions.iter().enumerate() {
+            let ref_pos = self.ref_positions[pos.ref_pos_idx];
+            if ref_pos.xsize > 0 && ref_pos.ysize > 0 {
+                intervals.push(PatchInterval {
+                    idx: i,
+                    y0: pos.y,
+                    y1: pos.y + self.ref_positions[pos.ref_pos_idx].ysize,
+                });
+            }
+        }
+
+        let intervals_len = intervals.len();
+        let sort_by_y0 = |intervals: &mut Vec<PatchInterval>, start: usize, end: usize| {
+            intervals[start..end].sort_unstable_by_key(|i| i.y0);
+        };
+        let sort_by_y1 = |intervals: &mut Vec<PatchInterval>, start: usize, end: usize| {
+            intervals[start..end].sort_unstable_by_key(|i| i.y1);
+        };
+
+        // Count the number of patches for each row.
+        sort_by_y1(&mut intervals, 0, intervals_len);
+        self.num_patches
+            .resize(intervals.last().map_or(0, |iv| iv.y1), 0); //Safe last()
+        for iv in &intervals {
+            for y in iv.y0..iv.y1 {
+                self.num_patches[y] += 1;
+            }
+        }
+
+        let root = PatchTreeNode {
+            start: 0,
+            num: intervals.len(),
+            ..Default::default()
+        };
+        self.patch_tree.push(root);
+
+        let mut next = 0;
+        while next < self.patch_tree.len() {
+            let node = &mut self.patch_tree[next]; // Borrow mutably *before* accessing fields
+            let start = node.start;
+            let end = node.start + node.num;
+
+            // Choose the y_center for this node to be the median of interval starts.
+            sort_by_y0(&mut intervals, start, end);
+            let middle_idx = start + node.num / 2;
+            node.y_center = intervals[middle_idx].y0;
+
+            // Divide the intervals in [start, end) into three groups:
+            let mut right_start = middle_idx;
+            while right_start < end && intervals[right_start].y0 == node.y_center {
+                right_start += 1;
+            }
+
+            sort_by_y1(&mut intervals, start, right_start);
+            let mut left_end = right_start;
+            while left_end > start && intervals[left_end - 1].y1 > node.y_center {
+                left_end -= 1;
+            }
+
+            // Fill in sorted_patches_y0_ and sorted_patches_y1_ for the current node.
+            node.num = right_start - left_end;
+            node.start = self.sorted_patches_y0.len();
+
+            self.sorted_patches_y1
+                .try_reserve(right_start.saturating_sub(left_end))?;
+            self.sorted_patches_y0
+                .try_reserve(right_start.saturating_sub(left_end))?;
+            for i in (left_end..right_start).rev() {
+                self.sorted_patches_y1
+                    .push((intervals[i].y1, intervals[i].idx));
+            }
+            sort_by_y0(&mut intervals, left_end, right_start);
+            for interval in intervals.iter().take(right_start).skip(left_end) {
+                self.sorted_patches_y0.push((interval.y0, interval.idx));
+            }
+
+            // Create the left and right nodes (if not empty).
+            // We modify left_child/right_child on the *original* node in patch_tree,
+            // so we have to do the assignment *before* we push the new nodes.
+            self.patch_tree[next].left_child = -1;
+            self.patch_tree[next].right_child = -1;
+
+            if left_end > start {
+                let mut left = PatchTreeNode::default();
+                left.start = start;
+                left.num = left_end - left.start;
+                self.patch_tree[next].left_child = self.patch_tree.len() as isize;
+                self.patch_tree.try_reserve(1)?;
+                self.patch_tree.push(left);
+            }
+            if right_start < end {
+                let mut right = PatchTreeNode::default();
+                right.start = right_start;
+                right.num = end - right.start;
+                self.patch_tree[next].right_child = self.patch_tree.len() as isize;
+                self.patch_tree.try_reserve(1)?;
+                self.patch_tree.push(right);
+            }
+
+            next += 1;
+        }
+        Ok(())
+    }
+
+    #[instrument(level = "debug", skip(br), ret, err)]
+    pub fn read(
+        br: &mut BitReader,
+        xsize: usize,
+        ysize: usize,
+        num_extra_channels: usize,
+        reference_frames: &[Option<ReferenceFrame>],
+    ) -> Result<PatchesDictionary> {
+        let blendings_stride = num_extra_channels + 1;
+        let patches_histograms = Histograms::decode(PatchContext::NUM, br, true)?;
+        let mut patches_reader = SymbolReader::new(&patches_histograms, br, None)?;
+        let num_ref_patch = patches_reader.read_unsigned(
+            &patches_histograms,
+            br,
+            PatchContext::NumRefPatch as usize,
+        ) as usize;
+        let num_pixels = xsize * ysize;
+        let max_ref_patches = 1024 + num_pixels / 4;
+        let max_patches = max_ref_patches * 4;
+        let max_blending_infos = max_patches * 4;
+        if num_ref_patch > max_ref_patches {
+            return Err(Error::PatchesTooMany(
+                "reference patches".to_string(),
+                num_ref_patch,
+                max_ref_patches,
+            ));
+        }
+        let mut total_patches = 0;
+        let mut next_size = 1;
+        let mut positions: Vec<PatchPosition> = Vec::new();
+        let mut blendings = Vec::new();
+        let mut ref_positions = Vec::new_with_capacity(num_ref_patch)?;
+        for _ in 0..num_ref_patch {
+            let reference = patches_reader.read_unsigned(
+                &patches_histograms,
+                br,
+                PatchContext::ReferenceFrame as usize,
+            ) as usize;
+            if reference >= DecoderState::MAX_STORED_FRAMES {
+                return Err(Error::PatchesRefTooLarge(
+                    reference,
+                    DecoderState::MAX_STORED_FRAMES,
+                ));
+            }
+
+            let x0 = patches_reader.read_unsigned(
+                &patches_histograms,
+                br,
+                PatchContext::PatchReferencePosition as usize,
+            ) as usize;
+            let y0 = patches_reader.read_unsigned(
+                &patches_histograms,
+                br,
+                PatchContext::PatchReferencePosition as usize,
+            ) as usize;
+            let ref_pos_xsize = patches_reader.read_unsigned(
+                &patches_histograms,
+                br,
+                PatchContext::PatchSize as usize,
+            ) as usize
+                + 1;
+            let ref_pos_ysize = patches_reader.read_unsigned(
+                &patches_histograms,
+                br,
+                PatchContext::PatchSize as usize,
+            ) as usize
+                + 1;
+            let reference_frame = &reference_frames[reference];
+            // TODO(firsching): make sure this check is correct in the presence of downsampled extra channels (also in libjxl).
+            match reference_frame {
+                None => return Err(Error::PatchesInvalidReference(reference)),
+                Some(reference) => {
+                    if !reference.saved_before_color_transform {
+                        return Err(Error::PatchesPostColorTransform());
+                    }
+                    if x0 + ref_pos_xsize > reference.frame[0].size().0 {
+                        return Err(Error::PatchesInvalidPosition(
+                            "x".to_string(),
+                            x0,
+                            ref_pos_xsize,
+                            reference.frame[0].size().0,
+                        ));
+                    }
+                    if y0 + ref_pos_ysize > reference.frame[0].size().1 {
+                        return Err(Error::PatchesInvalidPosition(
+                            "y".to_string(),
+                            y0,
+                            ref_pos_ysize,
+                            reference.frame[0].size().1,
+                        ));
+                    }
+                }
+            }
+
+            let id_count = patches_reader.read_unsigned(
+                &patches_histograms,
+                br,
+                PatchContext::PatchCount as usize,
+            ) as usize
+                + 1;
+            if id_count > max_patches + 1 {
+                return Err(Error::PatchesTooMany(
+                    "patches".to_string(),
+                    id_count,
+                    max_patches,
+                ));
+            }
+            total_patches += id_count;
+
+            if total_patches > max_patches {
+                return Err(Error::PatchesTooMany(
+                    "patches".to_string(),
+                    total_patches,
+                    max_patches,
+                ));
+            }
+
+            if next_size < total_patches {
+                next_size *= 2;
+                next_size = std::cmp::min(next_size, max_patches);
+            }
+            if next_size * blendings_stride > max_blending_infos {
+                return Err(Error::PatchesTooMany(
+                    "blending_info".to_string(),
+                    total_patches,
+                    max_patches,
+                ));
+            }
+            positions.try_reserve(next_size.saturating_sub(positions.len()))?;
+            blendings.try_reserve(
+                (next_size * PatchBlendMode::NUM_BLEND_MODES as usize)
+                    .saturating_sub(blendings.len()),
+            )?;
+
+            for i in 0..id_count {
+                let mut pos = PatchPosition {
+                    x: 0,
+                    y: 0,
+                    ref_pos_idx: ref_positions.len(),
+                };
+                if i == 0 {
+                    // Read initial position
+                    pos.x = patches_reader.read_unsigned(
+                        &patches_histograms,
+                        br,
+                        PatchContext::PatchPosition as usize,
+                    ) as usize;
+                    pos.y = patches_reader.read_unsigned(
+                        &patches_histograms,
+                        br,
+                        PatchContext::PatchPosition as usize,
+                    ) as usize;
+                } else {
+                    // Read offsets and calculate new position
+                    let delta_x = patches_reader.read_signed(
+                        &patches_histograms,
+                        br,
+                        PatchContext::PatchOffset as usize,
+                    );
+                    if delta_x < 0 && (-delta_x as usize) > positions.last().unwrap().x {
+                        return Err(Error::PatchesInvalidDelta(
+                            "x".to_string(),
+                            positions.last().unwrap().x,
+                            delta_x,
+                        ));
+                    }
+                    pos.x = (positions.last().unwrap().x as i32 + delta_x) as usize;
+
+                    let delta_y = patches_reader.read_signed(
+                        &patches_histograms,
+                        br,
+                        PatchContext::PatchOffset as usize,
+                    );
+                    if delta_y < 0 && (-delta_y as usize) > positions.last().unwrap().y {
+                        return Err(Error::PatchesInvalidDelta(
+                            "y".to_string(),
+                            positions.last().unwrap().y,
+                            delta_y,
+                        ));
+                    }
+                    pos.y = (positions.last().unwrap().y as i32 + delta_y) as usize;
+                }
+
+                if pos.x + ref_pos_xsize > xsize {
+                    return Err(Error::PatchesOutOfBounds(
+                        "x".to_string(),
+                        pos.x,
+                        ref_pos_xsize,
+                        xsize,
+                    ));
+                }
+                if pos.y + ref_pos_ysize > ysize {
+                    return Err(Error::PatchesOutOfBounds(
+                        "y".to_string(),
+                        pos.y,
+                        ref_pos_ysize,
+                        ysize,
+                    ));
+                }
+
+                for _ in 0..blendings_stride {
+                    let mut alpha_channel = 0;
+                    let mut clamp = false;
+                    let maybe_blend_mode = patches_reader.read_unsigned(
+                        &patches_histograms,
+                        br,
+                        PatchContext::PatchBlendMode as usize,
+                    ) as u8;
+                    let blend_mode = match PatchBlendMode::from_u8(maybe_blend_mode) {
+                        None => {
+                            return Err(Error::PatchesInvalidBlendMode(
+                                maybe_blend_mode,
+                                PatchBlendMode::NUM_BLEND_MODES,
+                            ));
+                        }
+                        Some(blend_mode) => blend_mode,
+                    };
+
+                    if PatchBlendMode::uses_alpha(blend_mode) && blendings_stride > 2 {
+                        alpha_channel = patches_reader.read_unsigned(
+                            &patches_histograms,
+                            br,
+                            PatchContext::PatchAlphaChannel as usize,
+                        ) as usize;
+                        if alpha_channel >= num_extra_channels {
+                            return Err(Error::PatchesInvalidAlphaChannel(
+                                alpha_channel,
+                                num_extra_channels,
+                            ));
+                        }
+                    }
+
+                    if PatchBlendMode::uses_clamp(blend_mode) {
+                        clamp = patches_reader.read_unsigned(
+                            &patches_histograms,
+                            br,
+                            PatchContext::PatchClamp as usize,
+                        ) != 0;
+                    }
+                    blendings.push(PatchBlending {
+                        mode: blend_mode,
+                        alpha_channel,
+                        clamp,
+                    });
+                }
+                positions.push(pos);
+            }
+
+            ref_positions.push(PatchReferencePosition {
+                reference,
+                x0,
+                y0,
+                xsize: ref_pos_xsize,
+                ysize: ref_pos_ysize,
+            })
+        }
+
+        let mut patches_dict = PatchesDictionary {
+            positions,
+            blendings,
+            ref_positions,
+            blendings_stride,
+            num_patches: vec![],
+            sorted_patches_y0: vec![],
+            sorted_patches_y1: vec![],
+            patch_tree: vec![],
+        };
+        patches_dict.compute_patch_tree()?;
+        Ok(patches_dict)
+    }
+
+    pub fn set_patches_for_row(&self, y: usize, patches_for_row_result: &mut Vec<usize>) {
+        patches_for_row_result.clear();
+        if self.num_patches.len() <= y || self.num_patches[y] == 0 {
+            return;
+        }
+
+        let mut tree_idx: isize = 0;
+        loop {
+            if tree_idx == -1 {
+                break;
+            }
+
+            // Safe access using get() and unwrap_or().  No need for the assert.
+            let node = self.patch_tree.get(tree_idx as usize).unwrap_or_else(|| {
+                // TODO(firsching): Handle panic differently?
+                panic!("Invalid tree_idx: {tree_idx}");
+            });
+
+            if y <= node.y_center {
+                for i in 0..node.num {
+                    let p = self.sorted_patches_y0[node.start + i];
+                    if y < p.0 {
+                        break;
+                    }
+                    patches_for_row_result.push(p.1);
+                }
+                tree_idx = if y < node.y_center {
+                    node.left_child
+                } else {
+                    -1
+                };
+            } else {
+                for i in 0..node.num {
+                    let p = self.sorted_patches_y1[node.start + i];
+                    if y >= p.0 {
+                        break;
+                    }
+                    patches_for_row_result.push(p.1);
+                }
+                tree_idx = node.right_child;
+            }
+        }
+
+        // Ensure that the relative order of patches is preserved.
+        patches_for_row_result.sort();
+    }
+
+    pub fn add_one_row(
+        &self,
+        row: &mut [&mut [f32]],
+        row_pos: (usize, usize),
+        xsize: usize,
+        extra_channel_info: &[ExtraChannelInfo],
+        reference_frames: &[Option<ReferenceFrame>],
+        patches_for_row_result: &mut Vec<usize>,
+    ) {
+        // TODO(zond): Allocate a buffer for this when building the stage instead of when executing it.
+        let mut out = row
+            .iter_mut()
+            .map(|s| &mut s[..xsize])
+            .collect::<Vec<&mut [f32]>>();
+        let num_ec = extra_channel_info.len();
+        assert!(num_ec + 1 == self.blendings_stride);
+        let dummy_fg = vec![0f32];
+        let mut fg = vec![dummy_fg.as_slice(); 3 + num_ec];
+        self.set_patches_for_row(row_pos.1, &mut *patches_for_row_result);
+        for pos_idx in patches_for_row_result.iter() {
+            let pos = &self.positions[*pos_idx];
+            assert!(row_pos.1 >= pos.y); // assert patch starts at or before current row
+            if pos.x >= row_pos.0 + out[0].len() {
+                // if patch starts before end of current chunk, continue
+                continue;
+            }
+
+            let ref_pos = &self.ref_positions[pos.ref_pos_idx];
+            assert!(pos.y + ref_pos.ysize > row_pos.1); // assert patch ends after current row
+            if pos.x + ref_pos.xsize < row_pos.0 {
+                // if patch ends before current chunk, continue
+                continue;
+            }
+
+            let (ref_x0, out_x0, ref_xsize) = if pos.x < row_pos.0 {
+                // if patch starts before current chunk
+                // crop the first part of the patch and use the first part of the chunk
+                (
+                    ref_pos.x0 + row_pos.0 - pos.x,
+                    0,
+                    ref_pos.xsize + pos.x - row_pos.0,
+                )
+            } else {
+                // otherwise
+                // use the first part of the patch and crop the first part of the chunk
+                (ref_pos.x0, pos.x - row_pos.0, ref_pos.xsize)
+            };
+            let (ref_x1, out_x1) = if out[0].len() - out_x0 < ref_xsize {
+                // if rest of chunk is smaller than patch
+                // crop the last part of the patch and use the last part of the chunk
+                (ref_x0 + out[0].len() - out_x0, out[0].len())
+            } else {
+                // otherwise
+                // use the last part of the patch and crop the last part of the chunk
+                (ref_x0 + ref_xsize, out_x0 + ref_xsize)
+            };
+            let ref_pos_y = ref_pos.y0 + row_pos.1 - pos.y;
+
+            for (c, fg_ptr) in fg.iter_mut().enumerate().take(3) {
+                *fg_ptr = &(reference_frames[ref_pos.reference].as_ref().unwrap().frame[c]
+                    .row(ref_pos_y)[ref_x0..ref_x1]);
+            }
+            for i in 0..num_ec {
+                fg[3 + i] = &(reference_frames[ref_pos.reference].as_ref().unwrap().frame[3 + i]
+                    .row(ref_pos_y)[ref_x0..ref_x1]);
+            }
+
+            let blending_idx = pos_idx * self.blendings_stride;
+            perform_blending(
+                &mut slice!(&mut out, .., out_x0..out_x1),
+                &fg,
+                &self.blendings[blending_idx],
+                &self.blendings[blending_idx + 1..],
+                extra_channel_info,
+            );
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+
+    mod read_patches_tests {
+        use super::super::*;
+        use test_log::test;
+
+        #[test]
+        fn read_single_patch_dict() -> Result<()> {
+            let mut br = BitReader::new(&[0x12, 0x4a, 0x8c, 0x63, 0x13, 0x01, 0xa6, 0x53, 0x01]);
+            let got_dict = PatchesDictionary::read(
+                &mut br,
+                1024,
+                1024,
+                0,
+                &[Some(ReferenceFrame::blank(1024, 1024, 1, true).unwrap())],
+            )?;
+            let want_dict = PatchesDictionary {
+                positions: vec![PatchPosition {
+                    x: 10,
+                    y: 20,
+                    ref_pos_idx: 0,
+                }],
+                ref_positions: vec![PatchReferencePosition {
+                    reference: 0,
+                    x0: 0,
+                    y0: 0,
+                    xsize: 1,
+                    ysize: 1,
+                }],
+                blendings: vec![PatchBlending {
+                    mode: PatchBlendMode::Add,
+                    alpha_channel: 0,
+                    clamp: false,
+                }],
+                blendings_stride: 1,
+                num_patches: vec![
+                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+                ],
+                patch_tree: vec![PatchTreeNode {
+                    left_child: -1,
+                    right_child: -1,
+                    y_center: 20,
+                    start: 0,
+                    num: 1,
+                }],
+                sorted_patches_y0: vec![(20, 0)],
+                sorted_patches_y1: vec![(21, 0)],
+            };
+            assert_eq!(got_dict, want_dict);
+            Ok(())
+        }
+
+        #[test]
+        fn read_multi_patch_dict() -> Result<()> {
+            let mut br = BitReader::new(&[
+                0x12, 0xc6, 0x26, 0x3f, 0x08, 0x4e, 0xb6, 0x0d, 0xf2, 0xde, 0xb6, 0x6d,
+            ]);
+            let got_dict = PatchesDictionary::read(
+                &mut br,
+                1024,
+                1024,
+                2,
+                &[Some(ReferenceFrame::blank(1024, 1024, 1, true).unwrap())],
+            )?;
+            let want_dict = PatchesDictionary {
+                positions: vec![
+                    PatchPosition {
+                        x: 0,
+                        y: 0,
+                        ref_pos_idx: 0,
+                    },
+                    PatchPosition {
+                        x: 5,
+                        y: 5,
+                        ref_pos_idx: 1,
+                    },
+                ],
+                ref_positions: vec![
+                    PatchReferencePosition {
+                        reference: 0,
+                        x0: 0,
+                        y0: 0,
+                        xsize: 2,
+                        ysize: 1,
+                    },
+                    PatchReferencePosition {
+                        reference: 0,
+                        x0: 0,
+                        y0: 0,
+                        xsize: 1,
+                        ysize: 2,
+                    },
+                ],
+                blendings: vec![
+                    PatchBlending {
+                        mode: PatchBlendMode::BlendAbove,
+                        alpha_channel: 1,
+                        clamp: false,
+                    },
+                    PatchBlending {
+                        mode: PatchBlendMode::Mul,
+                        alpha_channel: 0,
+                        clamp: true,
+                    },
+                    PatchBlending {
+                        mode: PatchBlendMode::Mul,
+                        alpha_channel: 0,
+                        clamp: true,
+                    },
+                    PatchBlending {
+                        mode: PatchBlendMode::Mul,
+                        alpha_channel: 0,
+                        clamp: true,
+                    },
+                    PatchBlending {
+                        mode: PatchBlendMode::Mul,
+                        alpha_channel: 0,
+                        clamp: true,
+                    },
+                    PatchBlending {
+                        mode: PatchBlendMode::Mul,
+                        alpha_channel: 0,
+                        clamp: true,
+                    },
+                ],
+                blendings_stride: 3,
+                num_patches: vec![1, 0, 0, 0, 0, 1, 1],
+                patch_tree: vec![
+                    PatchTreeNode {
+                        left_child: 1,
+                        right_child: -1,
+                        y_center: 5,
+                        start: 0,
+                        num: 1,
+                    },
+                    PatchTreeNode {
+                        left_child: -1,
+                        right_child: -1,
+                        y_center: 0,
+                        start: 1,
+                        num: 1,
+                    },
+                ],
+                sorted_patches_y0: vec![(5, 1), (0, 0)],
+                sorted_patches_y1: vec![(7, 1), (1, 0)],
+            };
+            assert_eq!(got_dict, want_dict);
+            Ok(())
+        }
+
+        #[test]
+        fn read_large_patch_dict() -> Result<()> {
+            let mut br = BitReader::new(&[
+                0x12, 0x4e, 0x50, 0x76, 0xeb, 0x41, 0x0d, 0x7e, 0xe5, 0x8e, 0xd2, 0x5d, 0x01,
+            ]);
+            let got_dict = PatchesDictionary::read(
+                &mut br,
+                1024,
+                1024,
+                1,
+                &[Some(ReferenceFrame::blank(1024, 1024, 1, true).unwrap())],
+            )?;
+            let want_dict = PatchesDictionary {
+                positions: vec![PatchPosition {
+                    x: 2,
+                    y: 3,
+                    ref_pos_idx: 0,
+                }],
+                ref_positions: vec![PatchReferencePosition {
+                    reference: 0,
+                    x0: 0,
+                    y0: 0,
+                    xsize: 300,
+                    ysize: 200,
+                }],
+                blendings: vec![
+                    PatchBlending {
+                        mode: PatchBlendMode::AlphaWeightedAddBelow,
+                        alpha_channel: 0,
+                        clamp: false,
+                    },
+                    PatchBlending {
+                        mode: PatchBlendMode::Mul,
+                        alpha_channel: 0,
+                        clamp: false,
+                    },
+                ],
+                blendings_stride: 2,
+                num_patches: vec![
+                    0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+                    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+                    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+                    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+                    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+                    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+                    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+                    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+                ],
+                patch_tree: vec![PatchTreeNode {
+                    left_child: -1,
+                    right_child: -1,
+                    y_center: 3,
+                    start: 0,
+                    num: 1,
+                }],
+                sorted_patches_y0: vec![(3, 0)],
+                sorted_patches_y1: vec![(203, 0)],
+            };
+            assert_eq!(got_dict, want_dict);
+            Ok(())
+        }
+
+        #[test]
+        fn read_clamped_patch_dict() -> Result<()> {
+            let mut br = BitReader::new(&[0x12, 0xc6, 0x26, 0x1f, 0x70, 0xce, 0x06]);
+            let got_dict = PatchesDictionary::read(
+                &mut br,
+                1024,
+                1024,
+                0,
+                &[Some(ReferenceFrame::blank(1024, 1024, 1, true).unwrap())],
+            )?;
+            let want_dict = PatchesDictionary {
+                positions: vec![PatchPosition {
+                    x: 4,
+                    y: 4,
+                    ref_pos_idx: 0,
+                }],
+                ref_positions: vec![PatchReferencePosition {
+                    reference: 0,
+                    x0: 0,
+                    y0: 0,
+                    xsize: 1,
+                    ysize: 1,
+                }],
+                blendings: vec![PatchBlending {
+                    mode: PatchBlendMode::Mul,
+                    alpha_channel: 0,
+                    clamp: true,
+                }],
+                blendings_stride: 1,
+                num_patches: vec![0, 0, 0, 0, 1],
+                patch_tree: vec![PatchTreeNode {
+                    left_child: -1,
+                    right_child: -1,
+                    y_center: 4,
+                    start: 0,
+                    num: 1,
+                }],
+                sorted_patches_y0: vec![(4, 0)],
+                sorted_patches_y1: vec![(5, 0)],
+            };
+            assert_eq!(got_dict, want_dict);
+            Ok(())
+        }
+
+        #[test]
+        fn read_dup_patch_dict() -> Result<()> {
+            let mut br = BitReader::new(&[0x12, 0x0a, 0x8d, 0x88, 0x03, 0x31, 0xd7, 0x35]);
+            let got_dict = PatchesDictionary::read(
+                &mut br,
+                1024,
+                1024,
+                0,
+                &[Some(ReferenceFrame::blank(1024, 1024, 1, true).unwrap())],
+            )?;
+            let want_dict = PatchesDictionary {
+                positions: vec![
+                    PatchPosition {
+                        x: 0,
+                        y: 0,
+                        ref_pos_idx: 0,
+                    },
+                    PatchPosition {
+                        x: 5,
+                        y: 5,
+                        ref_pos_idx: 0,
+                    },
+                ],
+                ref_positions: vec![PatchReferencePosition {
+                    reference: 0,
+                    x0: 0,
+                    y0: 0,
+                    xsize: 1,
+                    ysize: 1,
+                }],
+                blendings: vec![
+                    PatchBlending {
+                        mode: PatchBlendMode::Add,
+                        alpha_channel: 0,
+                        clamp: false,
+                    },
+                    PatchBlending {
+                        mode: PatchBlendMode::Add,
+                        alpha_channel: 0,
+                        clamp: false,
+                    },
+                ],
+                blendings_stride: 1,
+                num_patches: vec![1, 0, 0, 0, 0, 1],
+                patch_tree: vec![
+                    PatchTreeNode {
+                        left_child: 1,
+                        right_child: -1,
+                        y_center: 5,
+                        start: 0,
+                        num: 1,
+                    },
+                    PatchTreeNode {
+                        left_child: -1,
+                        right_child: -1,
+                        y_center: 0,
+                        start: 1,
+                        num: 1,
+                    },
+                ],
+                sorted_patches_y0: vec![(5, 1), (0, 0)],
+                sorted_patches_y1: vec![(6, 1), (1, 0)],
+            };
+            assert_eq!(got_dict, want_dict);
+            Ok(())
+        }
+    }
+
+    mod set_patches_for_row_tests {
+        use super::super::*;
+        use test_log::test;
+
+        // Helper to create a PatchesDictionary for tests
+        fn create_dictionary(
+            positions: Vec<PatchPosition>,
+            ref_positions: Vec<PatchReferencePosition>,
+        ) -> PatchesDictionary {
+            // Using default/empty blendings for these tests as they don't affect get_patches_for_row
+            let mut dict = PatchesDictionary {
+                positions,
+                ref_positions,
+                ..Default::default()
+            };
+            dict.compute_patch_tree().unwrap();
+            dict
+        }
+
+        #[test]
+        fn test_no_patches() {
+            let dict = create_dictionary(vec![], vec![]);
+            let mut patches_for_row_result = vec![];
+            dict.set_patches_for_row(0, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![] as Vec<usize>);
+            dict.set_patches_for_row(10, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![] as Vec<usize>);
+        }
+
+        #[test]
+        fn test_single_patch_hit() {
+            let ref_positions = vec![PatchReferencePosition {
+                reference: 0,
+                x0: 0,
+                y0: 0,
+                xsize: 10,
+                ysize: 5,
+            }];
+            let positions = vec![PatchPosition {
+                x: 0,
+                y: 10,
+                ref_pos_idx: 0,
+            }];
+            let dict = create_dictionary(positions, ref_positions);
+            let mut patches_for_row_result = vec![];
+
+            // Patch covers rows 10, 11, 12, 13, 14
+            dict.set_patches_for_row(10, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![0]); // First row of patch
+            dict.set_patches_for_row(12, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![0]); // Middle row of patch
+            dict.set_patches_for_row(14, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![0]); // Last row of patch
+        }
+
+        #[test]
+        fn test_single_patch_miss() {
+            let ref_positions = vec![PatchReferencePosition {
+                reference: 0,
+                x0: 0,
+                y0: 0,
+                xsize: 10,
+                ysize: 5,
+            }]; // Covers y=10 to y=14
+            let positions = vec![PatchPosition {
+                x: 0,
+                y: 10,
+                ref_pos_idx: 0,
+            }];
+            let dict = create_dictionary(positions, ref_positions);
+            let mut patches_for_row_result = vec![];
+
+            dict.set_patches_for_row(9, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![] as Vec<usize>); // Row before patch
+            dict.set_patches_for_row(15, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![] as Vec<usize>); // Row after patch
+        }
+
+        #[test]
+        fn test_single_patch_height_one() {
+            let ref_positions = vec![PatchReferencePosition {
+                reference: 0,
+                x0: 0,
+                y0: 0,
+                xsize: 10,
+                ysize: 1,
+            }]; // Covers y=5 only
+            let positions = vec![PatchPosition {
+                x: 0,
+                y: 5,
+                ref_pos_idx: 0,
+            }];
+            let dict = create_dictionary(positions, ref_positions);
+            let mut patches_for_row_result = vec![];
+
+            dict.set_patches_for_row(4, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![] as Vec<usize>);
+            dict.set_patches_for_row(5, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![0]);
+            dict.set_patches_for_row(6, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![] as Vec<usize>);
+        }
+
+        #[test]
+        fn test_multiple_patches_non_overlapping() {
+            let ref_positions = vec![
+                PatchReferencePosition {
+                    reference: 0,
+                    x0: 0,
+                    y0: 0,
+                    xsize: 10,
+                    ysize: 3,
+                }, // Patch 0: rows 5,6,7
+                PatchReferencePosition {
+                    reference: 0,
+                    x0: 0,
+                    y0: 0,
+                    xsize: 10,
+                    ysize: 2,
+                }, // Patch 1: rows 10,11
+            ];
+            let positions = vec![
+                PatchPosition {
+                    x: 0,
+                    y: 5,
+                    ref_pos_idx: 0,
+                },
+                PatchPosition {
+                    x: 0,
+                    y: 10,
+                    ref_pos_idx: 1,
+                },
+            ];
+            let dict = create_dictionary(positions, ref_positions);
+            let mut patches_for_row_result = vec![];
+
+            dict.set_patches_for_row(4, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![] as Vec<usize>);
+            dict.set_patches_for_row(5, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![0]);
+            dict.set_patches_for_row(7, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![0]);
+            dict.set_patches_for_row(8, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![] as Vec<usize>); // Between patches
+            dict.set_patches_for_row(9, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![] as Vec<usize>); // Between patches
+            dict.set_patches_for_row(10, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![1]);
+            dict.set_patches_for_row(11, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![1]);
+            dict.set_patches_for_row(12, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![] as Vec<usize>);
+        }
+
+        #[test]
+        fn test_multiple_patches_overlapping() {
+            let ref_positions = vec![
+                PatchReferencePosition {
+                    reference: 0,
+                    x0: 0,
+                    y0: 0,
+                    xsize: 10,
+                    ysize: 5,
+                }, // Patch 0: rows 10-14
+                PatchReferencePosition {
+                    reference: 0,
+                    x0: 0,
+                    y0: 0,
+                    xsize: 10,
+                    ysize: 4,
+                }, // Patch 1: rows 12-15
+            ];
+            let positions = vec![
+                PatchPosition {
+                    x: 0,
+                    y: 10,
+                    ref_pos_idx: 0,
+                }, // idx 0
+                PatchPosition {
+                    x: 0,
+                    y: 12,
+                    ref_pos_idx: 1,
+                }, // idx 1
+            ];
+            let dict = create_dictionary(positions, ref_positions);
+            let mut patches_for_row_result = vec![];
+
+            dict.set_patches_for_row(10, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![0]); // Only patch 0
+            dict.set_patches_for_row(11, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![0]); // Only patch 0
+            dict.set_patches_for_row(12, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![0, 1]); // Both patches (sorted indices)
+            dict.set_patches_for_row(13, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![0, 1]); // Both patches
+            dict.set_patches_for_row(14, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![0, 1]); // Patch 0 ends, Patch 1 continues
+            dict.set_patches_for_row(15, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![1]); // Only patch 1
+            dict.set_patches_for_row(16, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![] as Vec<usize>);
+        }
+
+        #[test]
+        fn test_multiple_patches_adjacent() {
+            let ref_positions = vec![
+                PatchReferencePosition {
+                    reference: 0,
+                    x0: 0,
+                    y0: 0,
+                    xsize: 10,
+                    ysize: 2,
+                }, // Patch 0: rows 5,6
+                PatchReferencePosition {
+                    reference: 0,
+                    x0: 0,
+                    y0: 0,
+                    xsize: 10,
+                    ysize: 3,
+                }, // Patch 1: rows 7,8,9
+            ];
+            let positions = vec![
+                PatchPosition {
+                    x: 0,
+                    y: 5,
+                    ref_pos_idx: 0,
+                },
+                PatchPosition {
+                    x: 0,
+                    y: 7,
+                    ref_pos_idx: 1,
+                },
+            ];
+            let dict = create_dictionary(positions, ref_positions);
+            let mut patches_for_row_result = vec![];
+
+            dict.set_patches_for_row(4, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![] as Vec<usize>);
+            dict.set_patches_for_row(5, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![0]);
+            dict.set_patches_for_row(6, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![0]);
+            dict.set_patches_for_row(7, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![1]); // Patch 0 ends, Patch 1 starts
+            dict.set_patches_for_row(8, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![1]);
+            dict.set_patches_for_row(9, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![1]);
+            dict.set_patches_for_row(10, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![] as Vec<usize>);
+        }
+
+        #[test]
+        fn test_multiple_patches_same_start_different_heights() {
+            let ref_positions = vec![
+                PatchReferencePosition {
+                    reference: 0,
+                    x0: 0,
+                    y0: 0,
+                    xsize: 10,
+                    ysize: 2,
+                }, // Patch 0: rows 3,4
+                PatchReferencePosition {
+                    reference: 0,
+                    x0: 0,
+                    y0: 0,
+                    xsize: 10,
+                    ysize: 4,
+                }, // Patch 1: rows 3,4,5,6
+            ];
+            let positions = vec![
+                PatchPosition {
+                    x: 0,
+                    y: 3,
+                    ref_pos_idx: 0,
+                }, // idx 0
+                PatchPosition {
+                    x: 0,
+                    y: 3,
+                    ref_pos_idx: 1,
+                }, // idx 1
+            ];
+            let dict = create_dictionary(positions, ref_positions);
+            let mut patches_for_row_result = vec![];
+
+            dict.set_patches_for_row(2, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![] as Vec<usize>);
+            dict.set_patches_for_row(3, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![0, 1]); // Both cover
+            dict.set_patches_for_row(4, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![0, 1]); // Both cover
+            dict.set_patches_for_row(5, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![1]); // Only patch 1 (longer)
+            dict.set_patches_for_row(6, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![1]); // Only patch 1
+            dict.set_patches_for_row(7, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![] as Vec<usize>);
+        }
+
+        #[test]
+        fn test_patches_out_of_order_definition() {
+            // Define patches in a non-sorted order of their y positions
+            // get_patches_for_row should still return sorted indices if multiple apply.
+            let ref_positions = vec![
+                PatchReferencePosition {
+                    reference: 0,
+                    x0: 0,
+                    y0: 0,
+                    xsize: 5,
+                    ysize: 3,
+                }, // Patch 0 (idx 0): rows 10,11,12
+                PatchReferencePosition {
+                    reference: 0,
+                    x0: 0,
+                    y0: 0,
+                    xsize: 5,
+                    ysize: 3,
+                }, // Patch 1 (idx 1): rows 5,6,7
+                PatchReferencePosition {
+                    reference: 0,
+                    x0: 0,
+                    y0: 0,
+                    xsize: 5,
+                    ysize: 3,
+                }, // Patch 2 (idx 2): rows 10,11,12 (overlaps with 0)
+            ];
+            let positions = vec![
+                PatchPosition {
+                    x: 0,
+                    y: 10,
+                    ref_pos_idx: 0,
+                }, // Patch 0
+                PatchPosition {
+                    x: 0,
+                    y: 5,
+                    ref_pos_idx: 1,
+                }, // Patch 1
+                PatchPosition {
+                    x: 0,
+                    y: 10,
+                    ref_pos_idx: 2,
+                }, // Patch 2
+            ];
+            let dict = create_dictionary(positions, ref_positions);
+            let mut patches_for_row_result = vec![];
+
+            dict.set_patches_for_row(4, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![] as Vec<usize>);
+            dict.set_patches_for_row(5, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![1]);
+            dict.set_patches_for_row(6, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![1]);
+            dict.set_patches_for_row(7, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![1]);
+            dict.set_patches_for_row(8, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![] as Vec<usize>);
+            dict.set_patches_for_row(9, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![] as Vec<usize>);
+            dict.set_patches_for_row(10, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![0, 2]); // Patches 0 and 2, indices sorted
+            dict.set_patches_for_row(11, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![0, 2]);
+            dict.set_patches_for_row(12, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![0, 2]);
+            dict.set_patches_for_row(13, &mut patches_for_row_result);
+            assert_eq!(patches_for_row_result, vec![] as Vec<usize>);
+        }
+    }
+
+    mod add_one_row_tests {
+        use super::super::*;
+        use crate::{
+            headers::{bit_depth::BitDepth, extra_channels::ExtraChannel},
+            image::Image,
+            util::test::assert_all_almost_abs_eq,
+        };
+
+        const MAX_ABS_DELTA: f32 = 1e-6; // Adjusted for typical f32 comparisons
+
+        fn create_reference_frame(
+            width: usize,
+            height: usize,
+            channel_values: &[f32],
+        ) -> Result<Option<ReferenceFrame>> {
+            let mut frame_channels = Vec::new();
+            for v in channel_values.iter() {
+                let img = Image::new_with_value((width, height), *v)?;
+                frame_channels.push(img);
+            }
+            Ok(Some(ReferenceFrame {
+                frame: frame_channels,
+                saved_before_color_transform: true,
+            }))
+        }
+
+        fn create_reference_frame_single_row<const N: usize>(
+            rows: &[[f32; N]],
+        ) -> Result<Option<ReferenceFrame>> {
+            let mut frame_channels = Vec::new();
+            for v in rows.iter() {
+                let mut img = Image::new((N, 1))?;
+                img.row_mut(0).copy_from_slice(v);
+                frame_channels.push(img);
+            }
+            Ok(Some(ReferenceFrame {
+                frame: frame_channels,
+                saved_before_color_transform: true,
+            }))
+        }
+
+        #[test]
+        fn test_add_one_row_simple_replace() -> Result<()> {
+            let xsize = 10;
+
+            let ref_frames = vec![create_reference_frame(xsize, 1, &[1.0; 3])?];
+            let extra_channel_info: Vec<ExtraChannelInfo> = Vec::new();
+
+            let ref_positions = vec![PatchReferencePosition {
+                reference: 0, // Points to main_ref_frame
+                x0: 2,
+                y0: 0,
+                xsize: 3,
+                ysize: 1,
+            }];
+            let positions = vec![PatchPosition {
+                x: 2,
+                y: 0,
+                ref_pos_idx: 0,
+            }];
+            let blendings = vec![PatchBlending {
+                mode: PatchBlendMode::Replace,
+                alpha_channel: 0,
+                clamp: false, // Clamping set to false
+            }];
+            let mut patches_dict = PatchesDictionary {
+                positions,
+                ref_positions,
+                blendings,
+                blendings_stride: 1 + extra_channel_info.len(),
+                patch_tree: Vec::new(),
+                num_patches: Vec::new(),
+                sorted_patches_y0: Vec::new(),
+                sorted_patches_y1: Vec::new(),
+            };
+            patches_dict.compute_patch_tree()?;
+
+            let mut r_data: Vec<f32> = vec![0.0; xsize];
+            let mut g_data: Vec<f32> = vec![0.0; xsize];
+            let mut b_data: Vec<f32> = vec![0.0; xsize];
+            let mut row_slices: Vec<&mut [f32]> = vec![&mut r_data, &mut g_data, &mut b_data];
+
+            let expected_r = vec![0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0];
+
+            patches_dict.add_one_row(
+                &mut row_slices,
+                (0, 0),
+                xsize,
+                &extra_channel_info,
+                &ref_frames, // Pass the Vec<ReferenceFrame>
+                &mut vec![],
+            );
+
+            assert_all_almost_abs_eq(&r_data, &expected_r, MAX_ABS_DELTA);
+            assert_all_almost_abs_eq(&g_data, &expected_r, MAX_ABS_DELTA);
+            assert_all_almost_abs_eq(&b_data, &expected_r, MAX_ABS_DELTA);
+            Ok(())
+        }
+
+        #[test]
+        fn test_add_one_row_simple_add() -> Result<()> {
+            let xsize = 10;
+            let y_coord = 0;
+
+            let ref_frames = vec![create_reference_frame(xsize, 1, &[0.2; 3])?];
+            let extra_channel_info: Vec<ExtraChannelInfo> = Vec::new();
+
+            let ref_positions = vec![PatchReferencePosition {
+                reference: 0,
+                x0: 2,
+                y0: 0,
+                xsize: 3,
+                ysize: 1,
+            }];
+            let positions = vec![PatchPosition {
+                x: 2,
+                y: 0,
+                ref_pos_idx: 0,
+            }];
+            let blendings = vec![PatchBlending {
+                mode: PatchBlendMode::Add,
+                alpha_channel: 0,
+                clamp: false, // Clamping set to false
+            }];
+            let mut patches_dict = PatchesDictionary {
+                positions,
+                ref_positions,
+                blendings,
+                blendings_stride: 1 + extra_channel_info.len(),
+                patch_tree: Vec::new(),
+                num_patches: Vec::new(),
+                sorted_patches_y0: Vec::new(),
+                sorted_patches_y1: Vec::new(),
+            };
+            patches_dict.compute_patch_tree()?;
+
+            let mut r_data: Vec<f32> = vec![0.5; xsize];
+            let mut g_data: Vec<f32> = vec![0.5; xsize];
+            let mut b_data: Vec<f32> = vec![0.5; xsize];
+            let mut row_slices: Vec<&mut [f32]> = vec![&mut r_data, &mut g_data, &mut b_data];
+
+            let mut expected_r: Vec<f32> = vec![0.5; xsize];
+            for r in expected_r.iter_mut().take(5).skip(2) {
+                *r = 0.5 + 0.2
+            }
+
+            patches_dict.add_one_row(
+                &mut row_slices,
+                (0, y_coord),
+                xsize,
+                &extra_channel_info,
+                &ref_frames,
+                &mut vec![],
+            );
+
+            assert_all_almost_abs_eq(&r_data, &expected_r, MAX_ABS_DELTA);
+            assert_all_almost_abs_eq(&g_data, &expected_r, MAX_ABS_DELTA);
+            assert_all_almost_abs_eq(&b_data, &expected_r, MAX_ABS_DELTA);
+            Ok(())
+        }
+
+        #[test]
+        fn test_add_one_row_overlapping_replace() -> Result<()> {
+            let xsize = 10;
+            let y_coord = 0;
+
+            let main_ref_frame1 = create_reference_frame(xsize, 1, &[1.0; 3])?;
+            let main_ref_frame2 = create_reference_frame(xsize, 1, &[2.0; 3])?;
+
+            let ref_frames = vec![main_ref_frame1, main_ref_frame2];
+            let extra_channel_info: Vec<ExtraChannelInfo> = Vec::new();
+
+            let ref_positions = vec![
+                PatchReferencePosition {
+                    reference: 0, // Points to main_ref_frame1
+                    x0: 0,
+                    y0: 0,
+                    xsize: 4,
+                    ysize: 1,
+                },
+                PatchReferencePosition {
+                    reference: 1, // Points to main_ref_frame2
+                    x0: 0,
+                    y0: 0,
+                    xsize: 3,
+                    ysize: 1,
+                },
+            ];
+            let positions = vec![
+                PatchPosition {
+                    x: 2,
+                    y: 0,
+                    ref_pos_idx: 0,
+                }, // P1: canvas [2..6] with 1.0
+                PatchPosition {
+                    x: 4,
+                    y: 0,
+                    ref_pos_idx: 1,
+                }, // P2: canvas [4..7] with 2.0
+            ];
+            let blendings = vec![
+                PatchBlending {
+                    mode: PatchBlendMode::Replace,
+                    alpha_channel: 0,
+                    clamp: false, // Clamping set to false
+                }, // For P1
+                PatchBlending {
+                    mode: PatchBlendMode::Replace,
+                    alpha_channel: 0,
+                    clamp: false, // Clamping set to false
+                }, // For P2
+            ];
+            let mut patches_dict = PatchesDictionary {
+                positions,
+                ref_positions,
+                blendings,
+                blendings_stride: 1 + extra_channel_info.len(),
+                patch_tree: Vec::new(),
+                num_patches: Vec::new(),
+                sorted_patches_y0: Vec::new(),
+                sorted_patches_y1: Vec::new(),
+            };
+            patches_dict.compute_patch_tree()?;
+
+            let mut r_data: Vec<f32> = vec![0.0; xsize];
+            let mut g_data: Vec<f32> = vec![0.0; xsize];
+            let mut b_data: Vec<f32> = vec![0.0; xsize];
+            let mut row_slices: Vec<&mut [f32]> = vec![&mut r_data, &mut g_data, &mut b_data];
+
+            let expected_r: Vec<f32> = vec![0.0, 0.0, 1.0, 1.0, 2.0, 2.0, 2.0, 0.0, 0.0, 0.0];
+
+            patches_dict.add_one_row(
+                &mut row_slices,
+                (0, y_coord),
+                xsize,
+                &extra_channel_info,
+                &ref_frames,
+                &mut vec![],
+            );
+
+            assert_all_almost_abs_eq(&r_data, &expected_r, MAX_ABS_DELTA);
+            assert_all_almost_abs_eq(&g_data, &expected_r, MAX_ABS_DELTA);
+            assert_all_almost_abs_eq(&b_data, &expected_r, MAX_ABS_DELTA);
+            Ok(())
+        }
+
+        #[test]
+        fn test_add_one_row_blend_above_ec_alpha_non_associated() -> Result<()> {
+            let xsize = 1;
+            let y_coord = 0;
+
+            let initial_color_val = 0.1;
+            let initial_ec0_alpha = 0.4;
+            let ref_color_val = 0.8;
+            let ref_ec0_alpha_val = 0.5;
+
+            let ec_info = vec![ExtraChannelInfo::new(
+                true,
+                ExtraChannel::Alpha,
+                BitDepth::f32(),
+                0,
+                "AlphaEC".to_string(),
+                false, // alpha_associated = false
+                None,
+                None,
+            )];
+
+            let main_ref_frame = create_reference_frame(
+                xsize,
+                1,
+                &[
+                    ref_color_val,
+                    ref_color_val,
+                    ref_color_val,
+                    ref_ec0_alpha_val,
+                ],
+            )?;
+
+            let ref_frames = vec![main_ref_frame];
+
+            let ref_positions = vec![PatchReferencePosition {
+                reference: 0,
+                x0: 0,
+                y0: 0,
+                xsize: 1,
+                ysize: 1,
+            }];
+            let positions = vec![PatchPosition {
+                x: 0,
+                y: 0,
+                ref_pos_idx: 0,
+            }];
+            let blendings = vec![
+                PatchBlending {
+                    mode: PatchBlendMode::BlendAbove,
+                    alpha_channel: 0, // Alpha for color is EC0
+                    clamp: false,     // Clamping set to false
+                }, // Color
+                PatchBlending {
+                    mode: PatchBlendMode::BlendAbove,
+                    alpha_channel: 0, // Alpha for EC0 is EC0 itself
+                    clamp: false,     // Clamping set to false
+                }, // EC0
+            ];
+            let mut patches_dict = PatchesDictionary {
+                positions,
+                ref_positions,
+                blendings,
+                blendings_stride: 1 + ec_info.len(), // Color + 1 EC
+                patch_tree: Vec::new(),
+                num_patches: Vec::new(),
+                sorted_patches_y0: Vec::new(),
+                sorted_patches_y1: Vec::new(),
+            };
+            patches_dict.compute_patch_tree()?;
+
+            let mut r_data = vec![initial_color_val; xsize];
+            let mut g_data = vec![initial_color_val; xsize];
+            let mut b_data = vec![initial_color_val; xsize];
+            let mut ec0_data = vec![initial_ec0_alpha; xsize];
+            let mut row_slices: Vec<&mut [f32]> =
+                vec![&mut r_data, &mut g_data, &mut b_data, &mut ec0_data];
+
+            // Calculations based on C++ logic for non-associated alpha:
+            // OutputAlpha = OldAlpha + PatchAlpha * (1 - OldAlpha)
+            // OutputColor = (OldColor * OldAlpha * (1 - PatchAlpha) + PatchColor * PatchAlpha) / OutputAlpha
+            // (If OutputAlpha is very small, OutputColor is 0)
+            let canvas_alpha_val = initial_ec0_alpha; // old_alpha
+            let patch_alpha_val = ref_ec0_alpha_val; // ref_alpha
+
+            let expected_ec0 = canvas_alpha_val + patch_alpha_val * (1.0 - canvas_alpha_val);
+
+            let canvas_color_val = initial_color_val; // old_color
+            let patch_color_val = ref_color_val; // ref_color (straight)
+
+            let expected_color = if expected_ec0.abs() < 1e-5 {
+                // Threshold similar to kSmallAlpha
+                0.0
+            } else {
+                (canvas_color_val * canvas_alpha_val * (1.0 - patch_alpha_val)
+                    + patch_color_val * patch_alpha_val)
+                    / expected_ec0
+            };
+
+            patches_dict.add_one_row(
+                &mut row_slices,
+                (0, y_coord),
+                xsize,
+                &ec_info,
+                &ref_frames,
+                &mut vec![],
+            );
+
+            assert_all_almost_abs_eq(&r_data, &vec![expected_color], MAX_ABS_DELTA);
+            assert_all_almost_abs_eq(&g_data, &vec![expected_color], MAX_ABS_DELTA);
+            assert_all_almost_abs_eq(&b_data, &vec![expected_color], MAX_ABS_DELTA);
+            assert_all_almost_abs_eq(&ec0_data, &vec![expected_ec0], MAX_ABS_DELTA);
+            Ok(())
+        }
+
+        #[test]
+        fn test_add_one_row_blend_above_ec_alpha_associated() -> Result<()> {
+            let xsize = 1;
+            let y_coord = 0;
+
+            let initial_color_val = 0.1; // Canvas color, assumed associated
+            let initial_ec0_alpha = 0.4; // Canvas alpha
+            let ref_color_val = 0.8; // Patch color, straight (non-associated)
+            let ref_ec0_alpha_val = 0.5; // Patch alpha
+
+            let ec_info = vec![ExtraChannelInfo::new(
+                true,
+                ExtraChannel::Alpha,
+                BitDepth::f32(),
+                0,
+                "AlphaEC".to_string(),
+                true, // alpha_associated = true
+                None,
+                None,
+            )];
+
+            let main_ref_frame = create_reference_frame(
+                xsize,
+                1,
+                &[
+                    ref_color_val,
+                    ref_color_val,
+                    ref_color_val,
+                    ref_ec0_alpha_val,
+                ],
+            )?;
+
+            let ref_frames = vec![main_ref_frame];
+
+            let ref_positions = vec![PatchReferencePosition {
+                reference: 0,
+                x0: 0,
+                y0: 0,
+                xsize: 1,
+                ysize: 1,
+            }];
+            let positions = vec![PatchPosition {
+                x: 0,
+                y: 0,
+                ref_pos_idx: 0,
+            }];
+            let blendings = vec![
+                PatchBlending {
+                    mode: PatchBlendMode::BlendAbove,
+                    alpha_channel: 0,
+                    clamp: false, // Clamping set to false
+                }, // Color
+                PatchBlending {
+                    mode: PatchBlendMode::BlendAbove,
+                    alpha_channel: 0,
+                    clamp: false, // Clamping set to false
+                }, // EC0
+            ];
+            let mut patches_dict = PatchesDictionary {
+                positions,
+                ref_positions,
+                blendings,
+                blendings_stride: 1 + ec_info.len(),
+                patch_tree: Vec::new(),
+                num_patches: Vec::new(),
+                sorted_patches_y0: Vec::new(),
+                sorted_patches_y1: Vec::new(),
+            };
+            patches_dict.compute_patch_tree()?;
+
+            let mut r_data = vec![initial_color_val; xsize];
+            let mut g_data = vec![initial_color_val; xsize];
+            let mut b_data = vec![initial_color_val; xsize];
+            let mut ec0_data = vec![initial_ec0_alpha; xsize];
+            let mut row_slices: Vec<&mut [f32]> =
+                vec![&mut r_data, &mut g_data, &mut b_data, &mut ec0_data];
+
+            let expected_ec0 = ref_ec0_alpha_val + initial_ec0_alpha * (1.0 - ref_ec0_alpha_val);
+
+            let expected_color = ref_color_val + initial_color_val * (1.0 - ref_ec0_alpha_val);
+
+            patches_dict.add_one_row(
+                &mut row_slices,
+                (0, y_coord),
+                xsize,
+                &ec_info,
+                &ref_frames,
+                &mut vec![],
+            );
+
+            assert_all_almost_abs_eq(&ec0_data, &vec![expected_ec0], MAX_ABS_DELTA);
+            assert_all_almost_abs_eq(&r_data, &vec![expected_color], MAX_ABS_DELTA);
+            assert_all_almost_abs_eq(&g_data, &vec![expected_color], MAX_ABS_DELTA);
+            assert_all_almost_abs_eq(&b_data, &vec![expected_color], MAX_ABS_DELTA);
+            Ok(())
+        }
+
+        #[test]
+        fn test_add_one_row_mul_blend() -> Result<()> {
+            let xsize = 2;
+            let y_coord = 0;
+
+            let initial_vals = [0.5, 2.0];
+            let ref_vals = [0.8, 0.7];
+
+            let main_ref_frame = create_reference_frame_single_row(&[ref_vals; 3])?;
+            let dummy_ref_frame1 = create_reference_frame_single_row(&[[0.0; 2]; 3])?;
+            let dummy_ref_frame2 = create_reference_frame_single_row(&[[0.0; 2]; 3])?;
+
+            let ref_frames = vec![main_ref_frame, dummy_ref_frame1, dummy_ref_frame2];
+            let extra_channel_info: Vec<ExtraChannelInfo> = Vec::new();
+
+            let ref_positions = vec![PatchReferencePosition {
+                reference: 0,
+                x0: 0,
+                y0: 0,
+                xsize,
+                ysize: 1,
+            }];
+            let positions = vec![PatchPosition {
+                x: 0,
+                y: 0,
+                ref_pos_idx: 0,
+            }];
+
+            // Test Mul (always without clamp as per new instruction)
+            let blendings = vec![PatchBlending {
+                mode: PatchBlendMode::Mul,
+                alpha_channel: 0,
+                clamp: false, // Clamping set to false
+            }];
+            let mut dict = PatchesDictionary {
+                positions: positions.clone(),
+                ref_positions: ref_positions.clone(),
+                blendings,
+                blendings_stride: 1, // Only color channels
+                patch_tree: Vec::new(),
+                num_patches: Vec::new(),
+                sorted_patches_y0: Vec::new(),
+                sorted_patches_y1: Vec::new(),
+            };
+            dict.compute_patch_tree()?;
+
+            let mut r_data = initial_vals;
+            let mut g_data = initial_vals;
+            let mut b_data = initial_vals;
+            let mut slices: Vec<&mut [f32]> = vec![&mut r_data, &mut g_data, &mut b_data];
+            dict.add_one_row(
+                &mut slices,
+                (0, y_coord),
+                xsize,
+                &extra_channel_info,
+                &ref_frames,
+                &mut vec![],
+            );
+
+            let expected_vals = [0.5 * 0.8, 2.0 * 0.7]; // [0.4, 1.4]
+            assert_all_almost_abs_eq(&r_data, &expected_vals, MAX_ABS_DELTA);
+            assert_all_almost_abs_eq(&g_data, &expected_vals, MAX_ABS_DELTA);
+            assert_all_almost_abs_eq(&b_data, &expected_vals, MAX_ABS_DELTA);
+
+            Ok(())
+        }
+
+        #[test]
+        fn test_add_one_row_none_blend() -> Result<()> {
+            let xsize = 5;
+            let y_coord = 0;
+
+            let main_ref_frame = create_reference_frame(xsize, 1, &[100.0; 3])?;
+            let dummy_ref_frame1 = create_reference_frame(xsize, 1, &[0.0; 3])?;
+            let dummy_ref_frame2 = create_reference_frame(xsize, 1, &[0.0; 3])?;
+
+            let ref_frames = vec![main_ref_frame, dummy_ref_frame1, dummy_ref_frame2];
+            let extra_channel_info: Vec<ExtraChannelInfo> = Vec::new();
+
+            let ref_positions = vec![PatchReferencePosition {
+                reference: 0,
+                x0: 0,
+                y0: 0,
+                xsize: 3,
+                ysize: 1,
+            }];
+            let positions = vec![PatchPosition {
+                x: 1,
+                y: 0,
+                ref_pos_idx: 0,
+            }];
+            let blendings = vec![PatchBlending {
+                mode: PatchBlendMode::None,
+                alpha_channel: 0,
+                clamp: false, // Clamping set to false
+            }];
+
+            let mut patches_dict = PatchesDictionary {
+                positions,
+                ref_positions,
+                blendings,
+                blendings_stride: 1, // Only color channels
+                patch_tree: Vec::new(),
+                num_patches: Vec::new(),
+                sorted_patches_y0: Vec::new(),
+                sorted_patches_y1: Vec::new(),
+            };
+            patches_dict.compute_patch_tree()?;
+
+            let initial_data: Vec<f32> = (0..xsize).map(|i| i as f32 * 0.1 + 0.05).collect();
+            let mut r_data = initial_data.clone();
+            let mut g_data = initial_data.clone();
+            let mut b_data = initial_data.clone();
+            let mut row_slices: Vec<&mut [f32]> = vec![&mut r_data, &mut g_data, &mut b_data];
+
+            patches_dict.add_one_row(
+                &mut row_slices,
+                (0, y_coord),
+                xsize,
+                &extra_channel_info,
+                &ref_frames,
+                &mut vec![],
+            );
+
+            assert_all_almost_abs_eq(&r_data, &initial_data, MAX_ABS_DELTA);
+            assert_all_almost_abs_eq(&g_data, &initial_data, MAX_ABS_DELTA);
+            assert_all_almost_abs_eq(&b_data, &initial_data, MAX_ABS_DELTA);
+            Ok(())
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/features/spline.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/features/spline.rs
new file mode 100644
index 0000000..449cb142
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/features/spline.rs
@@ -0,0 +1,1956 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::{
+    f32::consts::{FRAC_1_SQRT_2, PI, SQRT_2},
+    iter::{self, zip},
+    ops,
+};
+
+use crate::{
+    bit_reader::BitReader,
+    entropy_coding::decode::{Histograms, SymbolReader, unpack_signed},
+    error::{Error, Result},
+    frame::color_correlation_map::ColorCorrelationParams,
+    util::{CeilLog2, NewWithCapacity, fast_cos, fast_erff, tracing_wrappers::*},
+};
+const MAX_NUM_CONTROL_POINTS: u32 = 1 << 20;
+const MAX_NUM_CONTROL_POINTS_PER_PIXEL_RATIO: u32 = 2;
+const DELTA_LIMIT: i64 = 1 << 30;
+const SPLINE_POS_LIMIT: i32 = 1 << 23;
+
+const QUANTIZATION_ADJUSTMENT_CONTEXT: usize = 0;
+const STARTING_POSITION_CONTEXT: usize = 1;
+const NUM_SPLINES_CONTEXT: usize = 2;
+const NUM_CONTROL_POINTS_CONTEXT: usize = 3;
+const CONTROL_POINTS_CONTEXT: usize = 4;
+const DCT_CONTEXT: usize = 5;
+const NUM_SPLINE_CONTEXTS: usize = 6;
+const DESIRED_RENDERING_DISTANCE: f32 = 1.0;
+
+#[derive(Debug, Clone, Copy, Default)]
+pub struct Point {
+    pub x: f32,
+    pub y: f32,
+}
+
+impl Point {
+    fn new(x: f32, y: f32) -> Self {
+        Point { x, y }
+    }
+    fn abs(&self) -> f32 {
+        self.x.hypot(self.y)
+    }
+}
+
+impl PartialEq for Point {
+    fn eq(&self, other: &Self) -> bool {
+        (self.x - other.x).abs() < 1e-3 && (self.y - other.y).abs() < 1e-3
+    }
+}
+
+impl ops::Add<Point> for Point {
+    type Output = Point;
+    fn add(self, rhs: Point) -> Point {
+        Point {
+            x: self.x + rhs.x,
+            y: self.y + rhs.y,
+        }
+    }
+}
+
+impl ops::Sub<Point> for Point {
+    type Output = Point;
+    fn sub(self, rhs: Point) -> Point {
+        Point {
+            x: self.x - rhs.x,
+            y: self.y - rhs.y,
+        }
+    }
+}
+
+impl ops::Mul<f32> for Point {
+    type Output = Point;
+    fn mul(self, rhs: f32) -> Point {
+        Point {
+            x: self.x * rhs,
+            y: self.y * rhs,
+        }
+    }
+}
+
+impl ops::Div<f32> for Point {
+    type Output = Point;
+    fn div(self, rhs: f32) -> Point {
+        let inv = 1.0 / rhs;
+        Point {
+            x: self.x * inv,
+            y: self.y * inv,
+        }
+    }
+}
+
+#[derive(Default, Debug)]
+pub struct Spline {
+    control_points: Vec<Point>,
+    // X, Y, B.
+    color_dct: [Dct32; 3],
+    // Splines are drawn by normalized Gaussian splatting. This controls the
+    // Gaussian's parameter along the spline.
+    sigma_dct: Dct32,
+    // The estimated area in pixels covered by the spline.
+    estimated_area_reached: u64,
+}
+
+impl Spline {
+    pub fn validate_adjacent_point_coincidence(&self) -> Result<()> {
+        if let Some(((index, p0), p1)) = zip(
+            self.control_points
+                .iter()
+                .take(self.control_points.len() - 1)
+                .enumerate(),
+            self.control_points.iter().skip(1),
+        )
+        .find(|((_, p0), p1)| **p0 == **p1)
+        {
+            return Err(Error::SplineAdjacentCoincidingControlPoints(
+                index,
+                *p0,
+                index + 1,
+                *p1,
+            ));
+        }
+        Ok(())
+    }
+}
+
+#[derive(Debug, Default, Clone)]
+pub struct QuantizedSpline {
+    // Double delta-encoded.
+    pub control_points: Vec<(i64, i64)>,
+    pub color_dct: [[i32; 32]; 3],
+    pub sigma_dct: [i32; 32],
+}
+
+fn inv_adjusted_quant(adjustment: i32) -> f32 {
+    if adjustment >= 0 {
+        1.0 / (1.0 + 0.125 * adjustment as f32)
+    } else {
+        1.0 - 0.125 * adjustment as f32
+    }
+}
+
+fn validate_spline_point_pos<T: num_traits::ToPrimitive>(x: T, y: T) -> Result<()> {
+    let xi = x.to_i32().unwrap();
+    let yi = y.to_i32().unwrap();
+    let ok_range = -(1i32 << 23)..(1i32 << 23);
+    if !ok_range.contains(&xi) {
+        return Err(Error::SplinesPointOutOfRange(
+            Point {
+                x: xi as f32,
+                y: yi as f32,
+            },
+            xi,
+            ok_range,
+        ));
+    }
+    if !ok_range.contains(&yi) {
+        return Err(Error::SplinesPointOutOfRange(
+            Point {
+                x: xi as f32,
+                y: yi as f32,
+            },
+            yi,
+            ok_range,
+        ));
+    }
+    Ok(())
+}
+
+const CHANNEL_WEIGHT: [f32; 4] = [0.0042, 0.075, 0.07, 0.3333];
+
+fn area_limit(image_size: u64) -> u64 {
+    (1024 * image_size + (1u64 << 32)).min(1u64 << 42)
+}
+
+impl QuantizedSpline {
+    #[instrument(level = "debug", skip(br), ret, err)]
+    pub fn read(
+        br: &mut BitReader,
+        splines_histograms: &Histograms,
+        splines_reader: &mut SymbolReader,
+        max_control_points: u32,
+        total_num_control_points: &mut u32,
+    ) -> Result<QuantizedSpline> {
+        let num_control_points =
+            splines_reader.read_unsigned(splines_histograms, br, NUM_CONTROL_POINTS_CONTEXT);
+        *total_num_control_points += num_control_points;
+        if *total_num_control_points > max_control_points {
+            return Err(Error::SplinesTooManyControlPoints(
+                *total_num_control_points,
+                max_control_points,
+            ));
+        }
+        let mut control_points = Vec::new_with_capacity(num_control_points as usize)?;
+        for _ in 0..num_control_points {
+            let x =
+                splines_reader.read_signed(splines_histograms, br, CONTROL_POINTS_CONTEXT) as i64;
+            let y =
+                splines_reader.read_signed(splines_histograms, br, CONTROL_POINTS_CONTEXT) as i64;
+            control_points.push((x, y));
+            // Add check that double deltas are not outrageous (not in spec).
+            let max_delta_delta = x.abs().max(y.abs());
+            if max_delta_delta >= DELTA_LIMIT {
+                return Err(Error::SplinesDeltaLimit(max_delta_delta, DELTA_LIMIT));
+            }
+        }
+        // Decode DCTs and populate the QuantizedSpline struct
+        let mut color_dct = [[0; 32]; 3];
+        let mut sigma_dct = [0; 32];
+
+        let mut decode_dct = |dct: &mut [i32; 32]| -> Result<()> {
+            for value in dct.iter_mut() {
+                *value = splines_reader.read_signed(splines_histograms, br, DCT_CONTEXT);
+            }
+            Ok(())
+        };
+
+        for channel in &mut color_dct {
+            decode_dct(channel)?;
+        }
+        decode_dct(&mut sigma_dct)?;
+
+        Ok(QuantizedSpline {
+            control_points,
+            color_dct,
+            sigma_dct,
+        })
+    }
+
+    pub fn dequantize(
+        &self,
+        starting_point: &Point,
+        quantization_adjustment: i32,
+        y_to_x: f32,
+        y_to_b: f32,
+        image_size: u64,
+    ) -> Result<Spline> {
+        let area_limit = area_limit(image_size);
+
+        let mut result = Spline {
+            control_points: Vec::new_with_capacity(self.control_points.len() + 1)?,
+            ..Default::default()
+        };
+
+        let px = starting_point.x.round();
+        let py = starting_point.y.round();
+        validate_spline_point_pos(px, py)?;
+
+        let mut current_x = px as i32;
+        let mut current_y = py as i32;
+        result
+            .control_points
+            .push(Point::new(current_x as f32, current_y as f32));
+
+        let mut current_delta_x = 0i32;
+        let mut current_delta_y = 0i32;
+        let mut manhattan_distance = 0u64;
+
+        for &(dx, dy) in &self.control_points {
+            current_delta_x += dx as i32;
+            current_delta_y += dy as i32;
+            validate_spline_point_pos(current_delta_x, current_delta_y)?;
+
+            manhattan_distance +=
+                current_delta_x.unsigned_abs() as u64 + current_delta_y.unsigned_abs() as u64;
+
+            if manhattan_distance > area_limit {
+                return Err(Error::SplinesDistanceTooLarge(
+                    manhattan_distance,
+                    area_limit,
+                ));
+            }
+
+            current_x += current_delta_x;
+            current_y += current_delta_y;
+            validate_spline_point_pos(current_x, current_y)?;
+
+            result
+                .control_points
+                .push(Point::new(current_x as f32, current_y as f32));
+        }
+
+        let inv_quant = inv_adjusted_quant(quantization_adjustment);
+
+        for (c, weight) in CHANNEL_WEIGHT.iter().enumerate().take(3) {
+            for i in 0..32 {
+                let inv_dct_factor = if i == 0 { FRAC_1_SQRT_2 } else { 1.0 };
+                result.color_dct[c].0[i] =
+                    self.color_dct[c][i] as f32 * inv_dct_factor * weight * inv_quant;
+            }
+        }
+
+        for i in 0..32 {
+            result.color_dct[0].0[i] += y_to_x * result.color_dct[1].0[i];
+            result.color_dct[2].0[i] += y_to_b * result.color_dct[1].0[i];
+        }
+
+        let mut width_estimate = 0;
+        let mut color = [0u64; 3];
+
+        for (c, color_val) in color.iter_mut().enumerate() {
+            for i in 0..32 {
+                *color_val += (inv_quant * self.color_dct[c][i].abs() as f32).ceil() as u64;
+            }
+        }
+
+        color[0] += y_to_x.abs().ceil() as u64 * color[1];
+        color[2] += y_to_b.abs().ceil() as u64 * color[1];
+
+        let max_color = color[0].max(color[1]).max(color[2]);
+        let logcolor = 1u64.max((1u64 + max_color).ceil_log2());
+
+        let weight_limit =
+            (((area_limit as f32 / logcolor as f32) / manhattan_distance.max(1) as f32).sqrt())
+                .ceil();
+
+        for i in 0..32 {
+            let inv_dct_factor = if i == 0 { FRAC_1_SQRT_2 } else { 1.0 };
+            result.sigma_dct.0[i] =
+                self.sigma_dct[i] as f32 * inv_dct_factor * CHANNEL_WEIGHT[3] * inv_quant;
+
+            let weight_f = (inv_quant * self.sigma_dct[i].abs() as f32).ceil();
+            let weight = weight_limit.min(weight_f.max(1.0)) as u64;
+            width_estimate += weight * weight * logcolor;
+        }
+
+        result.estimated_area_reached = width_estimate * manhattan_distance;
+
+        Ok(result)
+    }
+}
+
+#[derive(Debug, Clone, Copy, Default)]
+struct SplineSegment {
+    center_x: f32,
+    center_y: f32,
+    maximum_distance: f32,
+    inv_sigma: f32,
+    sigma_over_4_times_intensity: f32,
+    color: [f32; 3],
+}
+
+#[derive(Debug, Default, Clone)]
+pub struct Splines {
+    pub quantization_adjustment: i32,
+    pub splines: Vec<QuantizedSpline>,
+    pub starting_points: Vec<Point>,
+    segments: Vec<SplineSegment>,
+    segment_indices: Vec<usize>,
+    segment_y_start: Vec<u64>,
+}
+
+fn draw_centripetal_catmull_rom_spline(points: &[Point]) -> Result<Vec<Point>> {
+    if points.is_empty() {
+        return Ok(vec![]);
+    }
+    if points.len() == 1 {
+        return Ok(vec![points[0]]);
+    }
+    const NUM_POINTS: usize = 16;
+    // Create a view of points with one prepended and one appended point.
+    let extended_points = iter::once(points[0] + (points[0] - points[1]))
+        .chain(points.iter().cloned())
+        .chain(iter::once(
+            points[points.len() - 1] + (points[points.len() - 1] - points[points.len() - 2]),
+        ));
+    // Pair each point with the sqrt of the distance to the next point.
+    let points_and_deltas = extended_points
+        .chain(iter::once(Point::default()))
+        .scan(Point::default(), |previous, p| {
+            let result = Some((*previous, (p - *previous).abs().sqrt()));
+            *previous = p;
+            result
+        })
+        .skip(1);
+    // Window the points with a [Point; 4] window.
+    let windowed_points = points_and_deltas
+        .scan([(Point::default(), 0.0); 4], |window, p| {
+            (window[0], window[1], window[2], window[3]) =
+                (window[1], window[2], window[3], (p.0, p.1));
+            Some([window[0], window[1], window[2], window[3]])
+        })
+        .skip(3);
+    // Create the points necessary per window, and flatten the result.
+    let result = windowed_points
+        .flat_map(|p| {
+            let mut window_result = [Point::default(); NUM_POINTS];
+            window_result[0] = p[1].0;
+            let mut t = [0.0; 4];
+            for k in 0..3 {
+                // TODO(from libjxl): Restrict d[k] with reasonable limit and spec it.
+                t[k + 1] = t[k] + p[k].1;
+            }
+            for (i, window_point) in window_result.iter_mut().enumerate().skip(1) {
+                let tt = p[0].1 + ((i as f32) / (NUM_POINTS as f32)) * p[1].1;
+                let mut a = [Point::default(); 3];
+                for k in 0..3 {
+                    // TODO(from libjxl): Reciprocal multiplication would be faster.
+                    a[k] = p[k].0 + (p[k + 1].0 - p[k].0) * ((tt - t[k]) / p[k].1);
+                }
+                let mut b = [Point::default(); 2];
+                for k in 0..2 {
+                    b[k] = a[k] + (a[k + 1] - a[k]) * ((tt - t[k]) / (p[k].1 + p[k + 1].1));
+                }
+                *window_point = b[0] + (b[1] - b[0]) * ((tt - t[1]) / p[1].1);
+            }
+            window_result
+        })
+        .chain(iter::once(points[points.len() - 1]))
+        .collect();
+    Ok(result)
+}
+
+fn for_each_equally_spaced_point<F: FnMut(Point, f32)>(
+    points: &[Point],
+    desired_distance: f32,
+    mut f: F,
+) {
+    if points.is_empty() {
+        return;
+    }
+    let mut accumulated_distance = 0.0;
+    f(points[0], desired_distance);
+    if points.len() == 1 {
+        return;
+    }
+    for index in 0..(points.len() - 1) {
+        let mut current = points[index];
+        let next = points[index + 1];
+        let segment = next - current;
+        let segment_length = segment.abs();
+        let unit_step = segment / segment_length;
+        if accumulated_distance + segment_length >= desired_distance {
+            current = current + unit_step * (desired_distance - accumulated_distance);
+            f(current, desired_distance);
+            accumulated_distance -= desired_distance;
+        }
+        accumulated_distance += segment_length;
+        while accumulated_distance >= desired_distance {
+            current = current + unit_step * desired_distance;
+            f(current, desired_distance);
+            accumulated_distance -= desired_distance;
+        }
+    }
+    f(points[points.len() - 1], accumulated_distance);
+}
+
+/// Precomputed multipliers for DCT: PI / 32.0 * i for i in 0..32
+const DCT_MULTIPLIERS: [f32; 32] = [
+    PI / 32.0 * 0.0,
+    PI / 32.0 * 1.0,
+    PI / 32.0 * 2.0,
+    PI / 32.0 * 3.0,
+    PI / 32.0 * 4.0,
+    PI / 32.0 * 5.0,
+    PI / 32.0 * 6.0,
+    PI / 32.0 * 7.0,
+    PI / 32.0 * 8.0,
+    PI / 32.0 * 9.0,
+    PI / 32.0 * 10.0,
+    PI / 32.0 * 11.0,
+    PI / 32.0 * 12.0,
+    PI / 32.0 * 13.0,
+    PI / 32.0 * 14.0,
+    PI / 32.0 * 15.0,
+    PI / 32.0 * 16.0,
+    PI / 32.0 * 17.0,
+    PI / 32.0 * 18.0,
+    PI / 32.0 * 19.0,
+    PI / 32.0 * 20.0,
+    PI / 32.0 * 21.0,
+    PI / 32.0 * 22.0,
+    PI / 32.0 * 23.0,
+    PI / 32.0 * 24.0,
+    PI / 32.0 * 25.0,
+    PI / 32.0 * 26.0,
+    PI / 32.0 * 27.0,
+    PI / 32.0 * 28.0,
+    PI / 32.0 * 29.0,
+    PI / 32.0 * 30.0,
+    PI / 32.0 * 31.0,
+];
+
+/// Precomputed cosine values for DCT at a given t value.
+/// Computed once and reused for all 4 DCT evaluations (3 color channels + sigma).
+struct PrecomputedCosines([f32; 32]);
+
+impl PrecomputedCosines {
+    /// Precompute cosines for a given t value.
+    /// Call this once per point, then use with continuous_idct_fast for each DCT.
+    #[inline]
+    fn new(t: f32) -> Self {
+        let tandhalf = t + 0.5;
+        PrecomputedCosines(core::array::from_fn(|i| {
+            fast_cos(DCT_MULTIPLIERS[i] * tandhalf)
+        }))
+    }
+}
+
+#[derive(Default, Clone, Copy, Debug)]
+struct Dct32([f32; 32]);
+
+impl Dct32 {
+    /// Fast continuous IDCT using precomputed cosines.
+    /// This avoids recomputing 32 cosines for each of the 4 DCT calls per point.
+    #[inline]
+    fn continuous_idct_fast(&self, precomputed: &PrecomputedCosines) -> f32 {
+        // Compute dot product of coeffs and precomputed cosines
+        // Using iterator for auto-vectorization
+        zip(self.0, precomputed.0)
+            .map(|(coeff, cos)| coeff * cos)
+            .sum::<f32>()
+            * SQRT_2
+    }
+}
+
+impl Splines {
+    #[cfg(test)]
+    pub fn create(
+        quantization_adjustment: i32,
+        splines: Vec<QuantizedSpline>,
+        starting_points: Vec<Point>,
+    ) -> Splines {
+        Splines {
+            quantization_adjustment,
+            splines,
+            starting_points,
+            segments: vec![],
+            segment_indices: vec![],
+            segment_y_start: vec![],
+        }
+    }
+    pub fn draw_segments(&self, row: &mut [&mut [f32]], row_pos: (usize, usize), xsize: usize) {
+        let first_segment_index_pos = self.segment_y_start[row_pos.1];
+        let last_segment_index_pos = self.segment_y_start[row_pos.1 + 1];
+        for segment_index_pos in first_segment_index_pos..last_segment_index_pos {
+            self.draw_segment(
+                row,
+                row_pos,
+                xsize,
+                &self.segments[self.segment_indices[segment_index_pos as usize]],
+            );
+        }
+    }
+    fn draw_segment(
+        &self,
+        row: &mut [&mut [f32]],
+        row_pos: (usize, usize),
+        xsize: usize,
+        segment: &SplineSegment,
+    ) {
+        let (x0, y) = row_pos;
+        let x1 = x0 + xsize;
+        let clamped_x0 = x0.max((segment.center_x - segment.maximum_distance).round() as usize);
+        // one-past-the-end
+        let clamped_x1 = x1.min((segment.center_x + segment.maximum_distance).round() as usize + 1);
+        for x in clamped_x0..clamped_x1 {
+            self.draw_segment_at(row, (x, y), x0, segment);
+        }
+    }
+    fn draw_segment_at(
+        &self,
+        row: &mut [&mut [f32]],
+        pixel_pos: (usize, usize),
+        row_x0: usize,
+        segment: &SplineSegment,
+    ) {
+        let (x, y) = pixel_pos;
+        let inv_sigma = segment.inv_sigma;
+        let half = 0.5f32;
+        let one_over_2s2 = 0.353_553_38_f32;
+        let sigma_over_4_times_intensity = segment.sigma_over_4_times_intensity;
+        let dx = x as f32 - segment.center_x;
+        let dy = y as f32 - segment.center_y;
+        let sqd = dx * dx + dy * dy;
+        let distance = sqd.sqrt();
+        let one_dimensional_factor = fast_erff((distance * half + one_over_2s2) * inv_sigma)
+            - fast_erff((distance * half - one_over_2s2) * inv_sigma);
+        let local_intensity =
+            sigma_over_4_times_intensity * one_dimensional_factor * one_dimensional_factor;
+        for (channel_index, row) in row.iter_mut().enumerate() {
+            let cm = segment.color[channel_index];
+            let inp = row[x - row_x0];
+            row[x - row_x0] = cm * local_intensity + inp;
+        }
+    }
+
+    fn add_segment(
+        &mut self,
+        center: &Point,
+        intensity: f32,
+        color: [f32; 3],
+        sigma: f32,
+        high_precision: bool,
+        segments_by_y: &mut Vec<(u64, usize)>,
+    ) {
+        if sigma.is_infinite()
+            || sigma == 0.0
+            || (1.0 / sigma).is_infinite()
+            || intensity.is_infinite()
+        {
+            return;
+        }
+        let distance_exp: f32 = if high_precision { 5.0 } else { 3.0 };
+        let max_color = [0.01, color[0], color[1], color[2]]
+            .iter()
+            .map(|chan| (chan * intensity).abs())
+            .max_by(|a, b| a.total_cmp(b))
+            .unwrap();
+        let max_distance =
+            (-2.0 * sigma * sigma * (0.1f32.ln() * distance_exp - max_color.ln())).sqrt();
+        let segment = SplineSegment {
+            center_x: center.x,
+            center_y: center.y,
+            color,
+            inv_sigma: 1.0 / sigma,
+            sigma_over_4_times_intensity: 0.25 * sigma * intensity,
+            maximum_distance: max_distance,
+        };
+        let y0 = (center.y - max_distance).round() as i64;
+        let y1 = (center.y + max_distance).round() as i64 + 1;
+        for y in 0.max(y0)..y1 {
+            segments_by_y.push((y as u64, self.segments.len()));
+        }
+        self.segments.push(segment);
+    }
+
+    fn add_segments_from_points(
+        &mut self,
+        spline: &Spline,
+        points_to_draw: &[(Point, f32)],
+        length: f32,
+        desired_distance: f32,
+        high_precision: bool,
+        segments_by_y: &mut Vec<(u64, usize)>,
+    ) {
+        let inv_length = 1.0 / length;
+        for (point_index, (point, multiplier)) in points_to_draw.iter().enumerate() {
+            let progress = (point_index as f32 * desired_distance * inv_length).min(1.0);
+            let t = (32.0 - 1.0) * progress;
+
+            // Precompute cosines once for this point (saves 3x cosine computations)
+            let precomputed = PrecomputedCosines::new(t);
+
+            // Use precomputed cosines for all 4 DCT evaluations
+            let mut color = [0.0; 3];
+            for (index, coeffs) in spline.color_dct.iter().enumerate() {
+                color[index] = coeffs.continuous_idct_fast(&precomputed);
+            }
+            let sigma = spline.sigma_dct.continuous_idct_fast(&precomputed);
+
+            self.add_segment(
+                point,
+                *multiplier,
+                color,
+                sigma,
+                high_precision,
+                segments_by_y,
+            );
+        }
+    }
+
+    pub fn initialize_draw_cache(
+        &mut self,
+        image_xsize: u64,
+        image_ysize: u64,
+        color_correlation_params: &ColorCorrelationParams,
+        high_precision: bool,
+    ) -> Result<()> {
+        let mut total_estimated_area_reached = 0u64;
+        let mut splines = Vec::new();
+        let area_limit = area_limit(image_xsize * image_ysize);
+        for (index, qspline) in self.splines.iter().enumerate() {
+            let spline = qspline.dequantize(
+                &self.starting_points[index],
+                self.quantization_adjustment,
+                color_correlation_params.y_to_x_lf(),
+                color_correlation_params.y_to_b_lf(),
+                image_xsize * image_ysize,
+            )?;
+            total_estimated_area_reached += spline.estimated_area_reached;
+            if total_estimated_area_reached > area_limit {
+                return Err(Error::SplinesAreaTooLarge(
+                    total_estimated_area_reached,
+                    area_limit,
+                ));
+            }
+            spline.validate_adjacent_point_coincidence()?;
+            splines.push(spline);
+        }
+
+        if total_estimated_area_reached
+            > (8 * image_xsize * image_ysize + (1u64 << 25)).min(1u64 << 30)
+        {
+            warn!(
+                "Large total_estimated_area_reached, expect slower decoding:{}",
+                total_estimated_area_reached
+            );
+        }
+
+        let mut segments_by_y = Vec::new();
+
+        self.segments.clear();
+        for spline in splines {
+            let mut points_to_draw = Vec::<(Point, f32)>::new();
+            let intermediate_points = draw_centripetal_catmull_rom_spline(&spline.control_points)?;
+            for_each_equally_spaced_point(
+                &intermediate_points,
+                DESIRED_RENDERING_DISTANCE,
+                |p, d| points_to_draw.push((p, d)),
+            );
+            let length = (points_to_draw.len() - 2) as f32 * DESIRED_RENDERING_DISTANCE
+                + points_to_draw[points_to_draw.len() - 1].1;
+            if length <= 0.0 {
+                continue;
+            }
+            self.add_segments_from_points(
+                &spline,
+                &points_to_draw,
+                length,
+                DESIRED_RENDERING_DISTANCE,
+                high_precision,
+                &mut segments_by_y,
+            );
+        }
+
+        // TODO(from libjxl): Consider linear sorting here.
+        segments_by_y.sort_by_key(|segment| segment.0);
+
+        self.segment_indices.clear();
+        self.segment_indices.try_reserve(segments_by_y.len())?;
+        self.segment_indices.resize(segments_by_y.len(), 0);
+
+        self.segment_y_start.clear();
+        self.segment_y_start.try_reserve(image_ysize as usize + 1)?;
+        self.segment_y_start.resize(image_ysize as usize + 1, 0);
+
+        for (i, segment) in segments_by_y.iter().enumerate() {
+            self.segment_indices[i] = segment.1;
+            let y = segment.0;
+            if y < image_ysize {
+                self.segment_y_start[y as usize + 1] += 1;
+            }
+        }
+        for y in 0..image_ysize {
+            self.segment_y_start[y as usize + 1] += self.segment_y_start[y as usize];
+        }
+        Ok(())
+    }
+
+    #[instrument(level = "debug", skip(br), ret, err)]
+    pub fn read(br: &mut BitReader, num_pixels: u32) -> Result<Splines> {
+        trace!(pos = br.total_bits_read());
+        let splines_histograms = Histograms::decode(NUM_SPLINE_CONTEXTS, br, true)?;
+        let mut splines_reader = SymbolReader::new(&splines_histograms, br, None)?;
+        let num_splines =
+            1 + splines_reader.read_unsigned(&splines_histograms, br, NUM_SPLINES_CONTEXT);
+        let max_control_points =
+            MAX_NUM_CONTROL_POINTS.min(num_pixels / MAX_NUM_CONTROL_POINTS_PER_PIXEL_RATIO);
+        if num_splines > max_control_points {
+            return Err(Error::SplinesTooMany(num_splines, max_control_points));
+        }
+
+        let mut starting_points = Vec::new();
+        let mut last_x = 0;
+        let mut last_y = 0;
+        for i in 0..num_splines {
+            let unsigned_x =
+                splines_reader.read_unsigned(&splines_histograms, br, STARTING_POSITION_CONTEXT);
+            let unsigned_y =
+                splines_reader.read_unsigned(&splines_histograms, br, STARTING_POSITION_CONTEXT);
+
+            let (x, y) = if i != 0 {
+                (
+                    unpack_signed(unsigned_x) + last_x,
+                    unpack_signed(unsigned_y) + last_y,
+                )
+            } else {
+                (unsigned_x as i32, unsigned_y as i32)
+            };
+            // It is not in spec, but reasonable limit to avoid overflows.
+            let max_coordinate = x.abs().max(y.abs());
+            if max_coordinate >= SPLINE_POS_LIMIT {
+                return Err(Error::SplinesCoordinatesLimit(
+                    max_coordinate,
+                    SPLINE_POS_LIMIT,
+                ));
+            }
+
+            starting_points.push(Point {
+                x: x as f32,
+                y: y as f32,
+            });
+
+            last_x = x;
+            last_y = y;
+        }
+
+        let quantization_adjustment =
+            splines_reader.read_signed(&splines_histograms, br, QUANTIZATION_ADJUSTMENT_CONTEXT);
+
+        let mut splines = Vec::new();
+        let mut num_control_points = 0u32;
+        for _ in 0..num_splines {
+            splines.push(QuantizedSpline::read(
+                br,
+                &splines_histograms,
+                &mut splines_reader,
+                max_control_points,
+                &mut num_control_points,
+            )?);
+        }
+        splines_reader.check_final_state(&splines_histograms, br)?;
+        Ok(Splines {
+            quantization_adjustment,
+            splines,
+            starting_points,
+            ..Splines::default()
+        })
+    }
+}
+
+#[cfg(test)]
+#[allow(clippy::excessive_precision)]
+mod test_splines {
+    use std::{f32::consts::SQRT_2, iter::zip};
+    use test_log::test;
+
+    use crate::{
+        error::{Error, Result},
+        features::spline::SplineSegment,
+        frame::color_correlation_map::ColorCorrelationParams,
+        util::test::{assert_all_almost_abs_eq, assert_almost_abs_eq, assert_almost_eq},
+    };
+
+    use super::{
+        DCT_MULTIPLIERS, DESIRED_RENDERING_DISTANCE, Dct32, Point, PrecomputedCosines,
+        QuantizedSpline, Spline, Splines, draw_centripetal_catmull_rom_spline,
+        for_each_equally_spaced_point,
+    };
+    use crate::util::fast_cos;
+
+    impl Dct32 {
+        /// Original continuous_idct for testing - validates correctness against golden values.
+        fn continuous_idct(&self, t: f32) -> f32 {
+            let tandhalf = t + 0.5;
+            zip(DCT_MULTIPLIERS, self.0)
+                .map(|(multiplier, coeff)| SQRT_2 * coeff * fast_cos(multiplier * tandhalf))
+                .sum()
+        }
+    }
+
+    #[test]
+    fn dequantize() -> Result<(), Error> {
+        // Golden data generated by libjxl.
+        let quantized_and_dequantized = [
+            (
+                QuantizedSpline {
+                    control_points: vec![
+                        (109, 105),
+                        (-247, -261),
+                        (168, 427),
+                        (-46, -360),
+                        (-61, 181),
+                    ],
+                    color_dct: [
+                        [
+                            12223, 9452, 5524, 16071, 1048, 17024, 14833, 7690, 21952, 2405, 2571,
+                            2190, 1452, 2500, 18833, 1667, 5857, 21619, 1310, 20000, 10429, 11667,
+                            7976, 18786, 12976, 18548, 14786, 12238, 8667, 3405, 19929, 8429,
+                        ],
+                        [
+                            177, 712, 127, 999, 969, 356, 105, 12, 1132, 309, 353, 415, 1213, 156,
+                            988, 524, 316, 1100, 64, 36, 816, 1285, 183, 889, 839, 1099, 79, 1316,
+                            287, 105, 689, 841,
+                        ],
+                        [
+                            780, -201, -38, -695, -563, -293, -88, 1400, -357, 520, 979, 431, -118,
+                            590, -971, -127, 157, 206, 1266, 204, -320, -223, 704, -687, -276,
+                            -716, 787, -1121, 40, 292, 249, -10,
+                        ],
+                    ],
+                    sigma_dct: [
+                        139, 65, 133, 5, 137, 272, 88, 178, 71, 256, 254, 82, 126, 252, 152, 53,
+                        281, 15, 8, 209, 285, 156, 73, 56, 36, 287, 86, 244, 270, 94, 224, 156,
+                    ],
+                },
+                Spline {
+                    control_points: vec![
+                        Point { x: 109.0, y: 54.0 },
+                        Point { x: 218.0, y: 159.0 },
+                        Point { x: 80.0, y: 3.0 },
+                        Point { x: 110.0, y: 274.0 },
+                        Point { x: 94.0, y: 185.0 },
+                        Point { x: 17.0, y: 277.0 },
+                    ],
+                    color_dct: [
+                        Dct32([
+                            36.300457,
+                            39.69839859,
+                            23.20079994,
+                            67.49819946,
+                            4.401599884,
+                            71.50080109,
+                            62.29859924,
+                            32.29800034,
+                            92.19839478,
+                            10.10099983,
+                            10.79819965,
+                            9.197999954,
+                            6.098399639,
+                            10.5,
+                            79.09859467,
+                            7.001399517,
+                            24.59939957,
+                            90.79979706,
+                            5.501999855,
+                            84.0,
+                            43.80179977,
+                            49.00139999,
+                            33.49919891,
+                            78.90119934,
+                            54.49919891,
+                            77.90159607,
+                            62.10119629,
+                            51.39959717,
+                            36.40139771,
+                            14.30099964,
+                            83.70179749,
+                            35.40179825,
+                        ]),
+                        Dct32([
+                            9.386842728,
+                            53.40000153,
+                            9.525000572,
+                            74.92500305,
+                            72.67500305,
+                            26.70000076,
+                            7.875000477,
+                            0.9000000358,
+                            84.90000153,
+                            23.17500114,
+                            26.47500038,
+                            31.12500191,
+                            90.9750061,
+                            11.70000076,
+                            74.1000061,
+                            39.30000305,
+                            23.70000076,
+                            82.5,
+                            4.800000191,
+                            2.700000048,
+                            61.20000076,
+                            96.37500763,
+                            13.72500038,
+                            66.67500305,
+                            62.92500305,
+                            82.42500305,
+                            5.925000191,
+                            98.70000458,
+                            21.52500153,
+                            7.875000477,
+                            51.67500305,
+                            63.07500076,
+                        ]),
+                        Dct32([
+                            47.99487305,
+                            39.33000183,
+                            6.865000725,
+                            26.27500153,
+                            33.2650032,
+                            6.190000534,
+                            1.715000629,
+                            98.90000153,
+                            59.91000366,
+                            59.57500458,
+                            95.00499725,
+                            61.29500198,
+                            82.71500397,
+                            53.0,
+                            6.130004883,
+                            30.41000366,
+                            34.69000244,
+                            96.91999817,
+                            93.4200058,
+                            16.97999954,
+                            38.80000305,
+                            80.76500702,
+                            63.00499725,
+                            18.5850029,
+                            43.60500336,
+                            32.30500412,
+                            61.01499939,
+                            20.23000336,
+                            24.32500076,
+                            28.31500053,
+                            69.10500336,
+                            62.375,
+                        ]),
+                    ],
+                    sigma_dct: Dct32([
+                        32.75933838,
+                        21.66449928,
+                        44.32889938,
+                        1.666499972,
+                        45.66209793,
+                        90.6576004,
+                        29.33039856,
+                        59.32740021,
+                        23.66429901,
+                        85.32479858,
+                        84.6581955,
+                        27.33059883,
+                        41.99580002,
+                        83.99160004,
+                        50.66159821,
+                        17.66489983,
+                        93.65729523,
+                        4.999499798,
+                        2.666399956,
+                        69.65969849,
+                        94.9905014,
+                        51.99480057,
+                        24.33090019,
+                        18.66479874,
+                        11.99880028,
+                        95.65709686,
+                        28.66379929,
+                        81.32519531,
+                        89.99099731,
+                        31.3302002,
+                        74.65919495,
+                        51.99480057,
+                    ]),
+                    estimated_area_reached: 19843491681,
+                },
+            ),
+            (
+                QuantizedSpline {
+                    control_points: vec![
+                        (24, -32),
+                        (-178, -7),
+                        (226, 151),
+                        (121, -172),
+                        (-184, 39),
+                        (-201, -182),
+                        (301, 404),
+                    ],
+                    color_dct: [
+                        [
+                            5051, 6881, 5238, 1571, 9952, 19762, 2048, 13524, 16405, 2310, 1286,
+                            4714, 16857, 21429, 12500, 15524, 1857, 5595, 6286, 17190, 15405,
+                            20738, 310, 16071, 10952, 16286, 15571, 8452, 6929, 3095, 9905, 5690,
+                        ],
+                        [
+                            899, 1059, 836, 388, 1291, 247, 235, 203, 1073, 747, 1283, 799, 356,
+                            1281, 1231, 561, 477, 720, 309, 733, 1013, 477, 779, 1183, 32, 1041,
+                            1275, 367, 88, 1047, 321, 931,
+                        ],
+                        [
+                            -78, 244, -883, 943, -682, 752, 107, 262, -75, 557, -202, -575, -231,
+                            -731, -605, 732, 682, 650, 592, -14, -1035, 913, -188, -95, 286, -574,
+                            -509, 67, 86, -1056, 592, 380,
+                        ],
+                    ],
+                    sigma_dct: [
+                        308, 8, 125, 7, 119, 237, 209, 60, 277, 215, 126, 186, 90, 148, 211, 136,
+                        188, 142, 140, 124, 272, 140, 274, 165, 24, 209, 76, 254, 185, 83, 11, 141,
+                    ],
+                },
+                Spline {
+                    control_points: vec![
+                        Point { x: 172.0, y: 309.0 },
+                        Point { x: 196.0, y: 277.0 },
+                        Point { x: 42.0, y: 238.0 },
+                        Point { x: 114.0, y: 350.0 },
+                        Point { x: 307.0, y: 290.0 },
+                        Point { x: 316.0, y: 269.0 },
+                        Point { x: 124.0, y: 66.0 },
+                        Point { x: 233.0, y: 267.0 },
+                    ],
+                    color_dct: [
+                        Dct32([
+                            15.00070381,
+                            28.90019989,
+                            21.99959946,
+                            6.598199844,
+                            41.79839706,
+                            83.00039673,
+                            8.601599693,
+                            56.80079651,
+                            68.90100098,
+                            9.701999664,
+                            5.401199818,
+                            19.79879951,
+                            70.79940033,
+                            90.00180054,
+                            52.5,
+                            65.20079803,
+                            7.799399853,
+                            23.49899864,
+                            26.40119934,
+                            72.19799805,
+                            64.7009964,
+                            87.09959412,
+                            1.301999927,
+                            67.49819946,
+                            45.99839783,
+                            68.40119934,
+                            65.39820099,
+                            35.49839783,
+                            29.10179901,
+                            12.9989996,
+                            41.60099792,
+                            23.89799881,
+                        ]),
+                        Dct32([
+                            47.67667389,
+                            79.42500305,
+                            62.70000076,
+                            29.10000038,
+                            96.82500458,
+                            18.52500153,
+                            17.625,
+                            15.22500038,
+                            80.4750061,
+                            56.02500153,
+                            96.2250061,
+                            59.92500305,
+                            26.70000076,
+                            96.07500458,
+                            92.32500458,
+                            42.07500076,
+                            35.77500153,
+                            54.00000381,
+                            23.17500114,
+                            54.97500229,
+                            75.9750061,
+                            35.77500153,
+                            58.42500305,
+                            88.7250061,
+                            2.400000095,
+                            78.07500458,
+                            95.625,
+                            27.52500153,
+                            6.600000381,
+                            78.52500153,
+                            24.07500076,
+                            69.82500458,
+                        ]),
+                        Dct32([
+                            43.81587219,
+                            96.50500488,
+                            0.8899993896,
+                            95.11000061,
+                            49.0850029,
+                            71.16500092,
+                            25.11499977,
+                            33.56500244,
+                            75.2250061,
+                            95.01499939,
+                            82.08500671,
+                            19.67500305,
+                            10.53000069,
+                            44.90500259,
+                            49.9750061,
+                            93.31500244,
+                            83.51499939,
+                            99.5,
+                            64.61499786,
+                            53.99500275,
+                            3.525009155,
+                            99.68499756,
+                            45.2650032,
+                            82.07500458,
+                            22.42000008,
+                            37.89500427,
+                            59.99499893,
+                            32.21500015,
+                            12.62000084,
+                            4.605003357,
+                            65.51499939,
+                            96.42500305,
+                        ]),
+                    ],
+                    sigma_dct: Dct32([
+                        72.58903503,
+                        2.666399956,
+                        41.66249847,
+                        2.333099842,
+                        39.66270065,
+                        78.99209595,
+                        69.65969849,
+                        19.99799919,
+                        92.32409668,
+                        71.65950012,
+                        41.99580002,
+                        61.9937973,
+                        29.99699974,
+                        49.32839966,
+                        70.32630157,
+                        45.3288002,
+                        62.66040039,
+                        47.32859802,
+                        46.66199875,
+                        41.32920074,
+                        90.6576004,
+                        46.66199875,
+                        91.32419586,
+                        54.99449921,
+                        7.999199867,
+                        69.65969849,
+                        25.3307991,
+                        84.6581955,
+                        61.66049957,
+                        27.66390038,
+                        3.66629982,
+                        46.99530029,
+                    ]),
+                    estimated_area_reached: 25829781306,
+                },
+            ),
+            (
+                QuantizedSpline {
+                    control_points: vec![
+                        (157, -89),
+                        (-244, 41),
+                        (-58, 168),
+                        (429, -185),
+                        (-361, 198),
+                        (230, -269),
+                        (-416, 203),
+                        (167, 65),
+                        (460, -344),
+                    ],
+                    color_dct: [
+                        [
+                            5691, 15429, 1000, 2524, 5595, 4048, 18881, 1357, 14381, 3952, 22595,
+                            15167, 20857, 2500, 905, 14548, 5452, 19500, 19143, 9643, 10929, 6048,
+                            9476, 7143, 11952, 21524, 6643, 22310, 15500, 11476, 5310, 10452,
+                        ],
+                        [
+                            470, 880, 47, 1203, 1295, 211, 475, 8, 907, 528, 325, 1145, 769, 1035,
+                            633, 905, 57, 72, 1216, 780, 1, 696, 47, 637, 843, 580, 1144, 477, 669,
+                            479, 256, 643,
+                        ],
+                        [
+                            1169, -301, 1041, -725, -43, -22, 774, 134, -822, 499, 456, -287, -713,
+                            -776, 76, 449, 750, 580, -207, -643, 956, -426, 377, -64, 101, -250,
+                            -164, 259, 169, -240, 430, -22,
+                        ],
+                    ],
+                    sigma_dct: [
+                        354, 5, 75, 56, 140, 226, 84, 187, 151, 70, 257, 288, 137, 99, 100, 159,
+                        79, 176, 59, 210, 278, 68, 171, 65, 230, 263, 69, 199, 107, 107, 170, 202,
+                    ],
+                },
+                Spline {
+                    control_points: vec![
+                        Point { x: 100.0, y: 186.0 },
+                        Point { x: 257.0, y: 97.0 },
+                        Point { x: 170.0, y: 49.0 },
+                        Point { x: 25.0, y: 169.0 },
+                        Point { x: 309.0, y: 104.0 },
+                        Point { x: 232.0, y: 237.0 },
+                        Point { x: 385.0, y: 101.0 },
+                        Point { x: 122.0, y: 168.0 },
+                        Point { x: 26.0, y: 300.0 },
+                        Point { x: 390.0, y: 88.0 },
+                    ],
+                    color_dct: [
+                        Dct32([
+                            16.90140724,
+                            64.80179596,
+                            4.199999809,
+                            10.60079956,
+                            23.49899864,
+                            17.00160027,
+                            79.30019379,
+                            5.699399948,
+                            60.40019608,
+                            16.59840012,
+                            94.89899445,
+                            63.70139694,
+                            87.59939575,
+                            10.5,
+                            3.80099988,
+                            61.10159683,
+                            22.89839935,
+                            81.8999939,
+                            80.40059662,
+                            40.50059891,
+                            45.90179825,
+                            25.40159988,
+                            39.79919815,
+                            30.00059891,
+                            50.19839859,
+                            90.40079498,
+                            27.90059853,
+                            93.70199585,
+                            65.09999847,
+                            48.19919968,
+                            22.30200005,
+                            43.89839935,
+                        ]),
+                        Dct32([
+                            24.92551422,
+                            66.0,
+                            3.525000095,
+                            90.2250061,
+                            97.12500763,
+                            15.82500076,
+                            35.625,
+                            0.6000000238,
+                            68.02500153,
+                            39.60000229,
+                            24.37500191,
+                            85.875,
+                            57.67500305,
+                            77.625,
+                            47.47500229,
+                            67.875,
+                            4.275000095,
+                            5.400000095,
+                            91.20000458,
+                            58.50000381,
+                            0.07500000298,
+                            52.20000076,
+                            3.525000095,
+                            47.77500153,
+                            63.22500229,
+                            43.5,
+                            85.80000305,
+                            35.77500153,
+                            50.17500305,
+                            35.92500305,
+                            19.20000076,
+                            48.22500229,
+                        ]),
+                        Dct32([
+                            82.78805542,
+                            44.93000031,
+                            76.39500427,
+                            39.4750061,
+                            94.11500549,
+                            14.2850008,
+                            89.80500031,
+                            9.980000496,
+                            10.48500061,
+                            74.52999878,
+                            56.29500198,
+                            65.78500366,
+                            7.765003204,
+                            23.30500031,
+                            52.79500198,
+                            99.30500031,
+                            56.77500153,
+                            46.0,
+                            76.71000671,
+                            13.49000549,
+                            66.99499512,
+                            22.38000107,
+                            29.91499901,
+                            43.29500198,
+                            70.2950058,
+                            26.0,
+                            74.31999969,
+                            53.90499878,
+                            62.00500488,
+                            19.12500381,
+                            49.30000305,
+                            46.68500137,
+                        ]),
+                    ],
+                    sigma_dct: Dct32([
+                        83.43025208,
+                        1.666499972,
+                        24.99749947,
+                        18.66479874,
+                        46.66199875,
+                        75.32579803,
+                        27.99720001,
+                        62.32709885,
+                        50.32830048,
+                        23.33099937,
+                        85.65809631,
+                        95.99040222,
+                        45.66209793,
+                        32.99670029,
+                        33.32999802,
+                        52.99469757,
+                        26.33069992,
+                        58.66079712,
+                        19.66469955,
+                        69.99299622,
+                        92.65740204,
+                        22.6644001,
+                        56.99430084,
+                        21.66449928,
+                        76.65899658,
+                        87.65789795,
+                        22.99769974,
+                        66.3266983,
+                        35.6631012,
+                        35.6631012,
+                        56.6609993,
+                        67.32659912,
+                    ]),
+                    estimated_area_reached: 47263284396,
+                },
+            ),
+        ];
+        for (quantized, want_dequantized) in quantized_and_dequantized {
+            let got_dequantized = quantized.dequantize(
+                &want_dequantized.control_points[0],
+                0,
+                0.0,
+                1.0,
+                2u64 << 30,
+            )?;
+            assert_eq!(
+                got_dequantized.control_points.len(),
+                want_dequantized.control_points.len()
+            );
+            assert_all_almost_abs_eq(
+                got_dequantized
+                    .control_points
+                    .iter()
+                    .map(|p| p.x)
+                    .collect::<Vec<f32>>(),
+                want_dequantized
+                    .control_points
+                    .iter()
+                    .map(|p| p.x)
+                    .collect::<Vec<f32>>(),
+                1e-6,
+            );
+            assert_all_almost_abs_eq(
+                got_dequantized
+                    .control_points
+                    .iter()
+                    .map(|p| p.y)
+                    .collect::<Vec<f32>>(),
+                want_dequantized
+                    .control_points
+                    .iter()
+                    .map(|p| p.y)
+                    .collect::<Vec<f32>>(),
+                1e-6,
+            );
+            for index in 0..got_dequantized.color_dct.len() {
+                assert_all_almost_abs_eq(
+                    got_dequantized.color_dct[index].0,
+                    want_dequantized.color_dct[index].0,
+                    1e-4,
+                );
+            }
+            assert_all_almost_abs_eq(
+                got_dequantized.sigma_dct.0,
+                want_dequantized.sigma_dct.0,
+                1e-4,
+            );
+            assert_eq!(
+                got_dequantized.estimated_area_reached,
+                want_dequantized.estimated_area_reached,
+            );
+        }
+        Ok(())
+    }
+
+    #[test]
+    fn centripetal_catmull_rom_spline() -> Result<(), Error> {
+        let control_points = vec![Point { x: 1.0, y: 2.0 }, Point { x: 4.0, y: 3.0 }];
+        let want_result = [
+            Point { x: 1.0, y: 2.0 },
+            Point {
+                x: 1.187500119,
+                y: 2.0625,
+            },
+            Point { x: 1.375, y: 2.125 },
+            Point {
+                x: 1.562499881,
+                y: 2.1875,
+            },
+            Point {
+                x: 1.750000119,
+                y: 2.25,
+            },
+            Point {
+                x: 1.9375,
+                y: 2.3125,
+            },
+            Point { x: 2.125, y: 2.375 },
+            Point {
+                x: 2.312500238,
+                y: 2.4375,
+            },
+            Point {
+                x: 2.500000238,
+                y: 2.5,
+            },
+            Point {
+                x: 2.6875,
+                y: 2.5625,
+            },
+            Point {
+                x: 2.875000477,
+                y: 2.625,
+            },
+            Point {
+                x: 3.062499762,
+                y: 2.6875,
+            },
+            Point { x: 3.25, y: 2.75 },
+            Point {
+                x: 3.4375,
+                y: 2.8125,
+            },
+            Point {
+                x: 3.624999762,
+                y: 2.875,
+            },
+            Point {
+                x: 3.812500238,
+                y: 2.9375,
+            },
+            Point { x: 4.0, y: 3.0 },
+        ];
+        let got_result = draw_centripetal_catmull_rom_spline(&control_points)?;
+        assert_all_almost_abs_eq(
+            got_result.iter().map(|p| p.x).collect::<Vec<f32>>(),
+            want_result.iter().map(|p| p.x).collect::<Vec<f32>>(),
+            1e-10,
+        );
+        Ok(())
+    }
+
+    #[test]
+    fn equally_spaced_points() -> Result<(), Error> {
+        let desired_rendering_distance = 10.0f32;
+        let segments = [
+            Point { x: 0.0, y: 0.0 },
+            Point { x: 5.0, y: 0.0 },
+            Point { x: 35.0, y: 0.0 },
+            Point { x: 35.0, y: 10.0 },
+        ];
+        let want_results = [
+            (Point { x: 0.0, y: 0.0 }, desired_rendering_distance),
+            (Point { x: 10.0, y: 0.0 }, desired_rendering_distance),
+            (Point { x: 20.0, y: 0.0 }, desired_rendering_distance),
+            (Point { x: 30.0, y: 0.0 }, desired_rendering_distance),
+            (Point { x: 35.0, y: 5.0 }, desired_rendering_distance),
+            (Point { x: 35.0, y: 10.0 }, 5.0f32),
+        ];
+        let mut got_results = Vec::<(Point, f32)>::new();
+        for_each_equally_spaced_point(&segments, desired_rendering_distance, |p, d| {
+            got_results.push((p, d))
+        });
+        assert_all_almost_abs_eq(
+            got_results.iter().map(|(p, _)| p.x).collect::<Vec<f32>>(),
+            want_results.iter().map(|(p, _)| p.x).collect::<Vec<f32>>(),
+            1e-9,
+        );
+        assert_all_almost_abs_eq(
+            got_results.iter().map(|(p, _)| p.y).collect::<Vec<f32>>(),
+            want_results.iter().map(|(p, _)| p.y).collect::<Vec<f32>>(),
+            1e-9,
+        );
+        assert_all_almost_abs_eq(
+            got_results.iter().map(|(_, d)| *d).collect::<Vec<f32>>(),
+            want_results.iter().map(|(_, d)| *d).collect::<Vec<f32>>(),
+            1e-9,
+        );
+        Ok(())
+    }
+
+    #[test]
+    fn dct32() -> Result<(), Error> {
+        let mut dct = Dct32::default();
+        for (i, coeff) in dct.0.iter_mut().enumerate() {
+            *coeff = 0.05f32 * i as f32;
+        }
+        // Golden numbers come from libjxl.
+        let want_out = [
+            16.7353153229,
+            -18.6041717529,
+            7.9931735992,
+            -7.1250801086,
+            4.6699867249,
+            -4.3367614746,
+            3.2450540066,
+            -3.0694460869,
+            2.4446771145,
+            -2.3350939751,
+            1.9243829250,
+            -1.8484034538,
+            1.5531382561,
+            -1.4964176416,
+            1.2701368332,
+            -1.2254891396,
+            1.0434474945,
+            -1.0067725182,
+            0.8544843197,
+            -0.8232427835,
+            0.6916543841,
+            -0.6642799377,
+            0.5473306179,
+            -0.5226536393,
+            0.4161090851,
+            -0.3933961987,
+            0.2940555215,
+            -0.2726306915,
+            0.1781132221,
+            -0.1574717760,
+            0.0656886101,
+            -0.0454511642,
+        ];
+        for (t, want) in want_out.iter().enumerate() {
+            let got_out = dct.continuous_idct(t as f32);
+            assert_almost_abs_eq(got_out, *want, 1e-4);
+        }
+        Ok(())
+    }
+
+    #[test]
+    fn dct32_fast_matches_original() {
+        // Verify that continuous_idct_fast produces the same results as continuous_idct
+        let mut dct = Dct32::default();
+        for (i, coeff) in dct.0.iter_mut().enumerate() {
+            *coeff = 0.05f32 * i as f32;
+        }
+
+        for t in 0..32 {
+            let t_val = t as f32;
+            let original = dct.continuous_idct(t_val);
+            let precomputed = PrecomputedCosines::new(t_val);
+            let fast = dct.continuous_idct_fast(&precomputed);
+            assert_almost_abs_eq(fast, original, 1e-5);
+        }
+    }
+
+    fn verify_segment_almost_equal(seg1: &SplineSegment, seg2: &SplineSegment) {
+        assert_almost_eq(seg1.center_x, seg2.center_x, 1e-2, 1e-4);
+        assert_almost_eq(seg1.center_y, seg2.center_y, 1e-2, 1e-4);
+        for (got, want) in zip(seg1.color.iter(), seg2.color.iter()) {
+            assert_almost_eq(*got, *want, 1e-2, 1e-4);
+        }
+        assert_almost_eq(seg1.inv_sigma, seg2.inv_sigma, 1e-2, 1e-4);
+        assert_almost_eq(seg1.maximum_distance, seg2.maximum_distance, 1e-2, 1e-4);
+        assert_almost_eq(
+            seg1.sigma_over_4_times_intensity,
+            seg2.sigma_over_4_times_intensity,
+            1e-2,
+            1e-4,
+        );
+    }
+
+    #[test]
+    fn spline_segments_add_segment() -> Result<(), Error> {
+        let mut splines = Splines::default();
+        let mut segments_by_y = Vec::<(u64, usize)>::new();
+
+        splines.add_segment(
+            &Point { x: 10.0, y: 20.0 },
+            0.5,
+            [0.5, 0.6, 0.7],
+            0.8,
+            true,
+            &mut segments_by_y,
+        );
+        // Golden numbers come from libjxl.
+        let want_segment = SplineSegment {
+            center_x: 10.0,
+            center_y: 20.0,
+            color: [0.5, 0.6, 0.7],
+            inv_sigma: 1.25,
+            maximum_distance: 3.65961,
+            sigma_over_4_times_intensity: 0.1,
+        };
+        assert_eq!(splines.segments.len(), 1);
+        verify_segment_almost_equal(&splines.segments[0], &want_segment);
+        let want_segments_by_y = [
+            (16, 0),
+            (17, 0),
+            (18, 0),
+            (19, 0),
+            (20, 0),
+            (21, 0),
+            (22, 0),
+            (23, 0),
+            (24, 0),
+        ];
+        for (got, want) in zip(segments_by_y.iter(), want_segments_by_y.iter()) {
+            assert_eq!(got.0, want.0);
+            assert_eq!(got.1, want.1);
+        }
+        Ok(())
+    }
+
+    #[test]
+    fn spline_segments_add_segments_from_points() -> Result<(), Error> {
+        let mut splines = Splines::default();
+        let mut segments_by_y = Vec::<(u64, usize)>::new();
+        let mut color_dct = [Dct32::default(); 3];
+        for (channel_index, channel_dct) in color_dct.iter_mut().enumerate() {
+            for (coeff_index, coeff) in channel_dct.0.iter_mut().enumerate() {
+                *coeff = 0.1 * channel_index as f32 + 0.05 * coeff_index as f32;
+            }
+        }
+        let mut sigma_dct = Dct32::default();
+        for (coeff_index, coeff) in sigma_dct.0.iter_mut().enumerate() {
+            *coeff = 0.06 * coeff_index as f32;
+        }
+        let spline = Spline {
+            control_points: vec![],
+            color_dct,
+            sigma_dct,
+            estimated_area_reached: 0,
+        };
+        let points_to_draw = vec![
+            (Point { x: 10.0, y: 20.0 }, 1.0),
+            (Point { x: 11.0, y: 21.0 }, 1.0),
+            (Point { x: 12.0, y: 21.0 }, 1.0),
+        ];
+        splines.add_segments_from_points(
+            &spline,
+            &points_to_draw,
+            SQRT_2 + 1.0,
+            DESIRED_RENDERING_DISTANCE,
+            true,
+            &mut segments_by_y,
+        );
+        // Golden numbers come from libjxl.
+        let want_segments = [
+            SplineSegment {
+                center_x: 10.0,
+                center_y: 20.0,
+                color: [16.73531532, 19.68646049, 22.63760757],
+                inv_sigma: 0.04979490861,
+                maximum_distance: 108.6400299,
+                sigma_over_4_times_intensity: 5.020593643,
+            },
+            SplineSegment {
+                center_x: 11.0,
+                center_y: 21.0,
+                color: [-0.8199231625, -0.7960500717, -0.7721766233],
+                inv_sigma: -1.016355753,
+                maximum_distance: 4.680418015,
+                sigma_over_4_times_intensity: -0.2459768653,
+            },
+            SplineSegment {
+                center_x: 12.0,
+                center_y: 21.0,
+                color: [-0.7767754197, -0.7544237971, -0.7320720553],
+                inv_sigma: -1.072811365,
+                maximum_distance: 4.423510075,
+                sigma_over_4_times_intensity: -0.2330325693,
+            },
+        ];
+        assert_eq!(splines.segments.len(), want_segments.len());
+        for (got, want) in zip(splines.segments.iter(), want_segments.iter()) {
+            verify_segment_almost_equal(got, want);
+        }
+        let want_segments_by_y: Vec<(u64, usize)> = (0..=129)
+            .map(|c| (c, 0))
+            .chain((16..=26).map(|c| (c, 1)))
+            .chain((17..=25).map(|c| (c, 2)))
+            .collect();
+        for (got, want) in zip(segments_by_y.iter(), want_segments_by_y.iter()) {
+            assert_eq!(got.0, want.0);
+            assert_eq!(got.1, want.1);
+        }
+        Ok(())
+    }
+
+    #[test]
+    fn init_draw_cache() -> Result<(), Error> {
+        let mut splines = Splines {
+            splines: vec![
+                QuantizedSpline {
+                    control_points: vec![
+                        (109, 105),
+                        (-247, -261),
+                        (168, 427),
+                        (-46, -360),
+                        (-61, 181),
+                    ],
+                    color_dct: [
+                        [
+                            12223, 9452, 5524, 16071, 1048, 17024, 14833, 7690, 21952, 2405, 2571,
+                            2190, 1452, 2500, 18833, 1667, 5857, 21619, 1310, 20000, 10429, 11667,
+                            7976, 18786, 12976, 18548, 14786, 12238, 8667, 3405, 19929, 8429,
+                        ],
+                        [
+                            177, 712, 127, 999, 969, 356, 105, 12, 1132, 309, 353, 415, 1213, 156,
+                            988, 524, 316, 1100, 64, 36, 816, 1285, 183, 889, 839, 1099, 79, 1316,
+                            287, 105, 689, 841,
+                        ],
+                        [
+                            780, -201, -38, -695, -563, -293, -88, 1400, -357, 520, 979, 431, -118,
+                            590, -971, -127, 157, 206, 1266, 204, -320, -223, 704, -687, -276,
+                            -716, 787, -1121, 40, 292, 249, -10,
+                        ],
+                    ],
+                    sigma_dct: [
+                        139, 65, 133, 5, 137, 272, 88, 178, 71, 256, 254, 82, 126, 252, 152, 53,
+                        281, 15, 8, 209, 285, 156, 73, 56, 36, 287, 86, 244, 270, 94, 224, 156,
+                    ],
+                },
+                QuantizedSpline {
+                    control_points: vec![
+                        (24, -32),
+                        (-178, -7),
+                        (226, 151),
+                        (121, -172),
+                        (-184, 39),
+                        (-201, -182),
+                        (301, 404),
+                    ],
+                    color_dct: [
+                        [
+                            5051, 6881, 5238, 1571, 9952, 19762, 2048, 13524, 16405, 2310, 1286,
+                            4714, 16857, 21429, 12500, 15524, 1857, 5595, 6286, 17190, 15405,
+                            20738, 310, 16071, 10952, 16286, 15571, 8452, 6929, 3095, 9905, 5690,
+                        ],
+                        [
+                            899, 1059, 836, 388, 1291, 247, 235, 203, 1073, 747, 1283, 799, 356,
+                            1281, 1231, 561, 477, 720, 309, 733, 1013, 477, 779, 1183, 32, 1041,
+                            1275, 367, 88, 1047, 321, 931,
+                        ],
+                        [
+                            -78, 244, -883, 943, -682, 752, 107, 262, -75, 557, -202, -575, -231,
+                            -731, -605, 732, 682, 650, 592, -14, -1035, 913, -188, -95, 286, -574,
+                            -509, 67, 86, -1056, 592, 380,
+                        ],
+                    ],
+                    sigma_dct: [
+                        308, 8, 125, 7, 119, 237, 209, 60, 277, 215, 126, 186, 90, 148, 211, 136,
+                        188, 142, 140, 124, 272, 140, 274, 165, 24, 209, 76, 254, 185, 83, 11, 141,
+                    ],
+                },
+            ],
+            starting_points: vec![Point { x: 10.0, y: 20.0 }, Point { x: 5.0, y: 40.0 }],
+            ..Default::default()
+        };
+        splines.initialize_draw_cache(
+            1 << 15,
+            1 << 15,
+            &ColorCorrelationParams {
+                color_factor: 1,
+                base_correlation_x: 0.0,
+                base_correlation_b: 0.0,
+                ytox_lf: 0,
+                ytob_lf: 0,
+            },
+            true,
+        )?;
+        assert_eq!(splines.segments.len(), 1940);
+        let want_segments_sample = [
+            (
+                22,
+                SplineSegment {
+                    center_x: 25.77652359,
+                    center_y: 35.33295059,
+                    color: [-524.996582, -509.9048462, 43.3883667],
+                    inv_sigma: -0.00197347207,
+                    maximum_distance: 3021.377197,
+                    sigma_over_4_times_intensity: -126.6802902,
+                },
+            ),
+            (
+                474,
+                SplineSegment {
+                    center_x: -16.45600891,
+                    center_y: 78.81845856,
+                    color: [-117.6707535, -133.5515594, 343.5632629],
+                    inv_sigma: -0.002631845651,
+                    maximum_distance: 2238.376221,
+                    sigma_over_4_times_intensity: -94.9903717,
+                },
+            ),
+            (
+                835,
+                SplineSegment {
+                    center_x: -71.93701172,
+                    center_y: 230.0635529,
+                    color: [44.79507446, 298.9411621, -395.3574524],
+                    inv_sigma: 0.01869126037,
+                    maximum_distance: 316.4499207,
+                    sigma_over_4_times_intensity: 13.3752346,
+                },
+            ),
+            (
+                1066,
+                SplineSegment {
+                    center_x: -126.2593002,
+                    center_y: -22.97857094,
+                    color: [-136.4196625, 194.757019, -98.18778992],
+                    inv_sigma: 0.007531851064,
+                    maximum_distance: 769.2540283,
+                    sigma_over_4_times_intensity: 33.19237137,
+                },
+            ),
+            (
+                1328,
+                SplineSegment {
+                    center_x: 73.70871735,
+                    center_y: 56.31413269,
+                    color: [-13.44394779, 162.6139221, 93.78419495],
+                    inv_sigma: 0.003664178308,
+                    maximum_distance: 1572.710327,
+                    sigma_over_4_times_intensity: 68.2281189,
+                },
+            ),
+            (
+                1545,
+                SplineSegment {
+                    center_x: 77.48892975,
+                    center_y: -92.33877563,
+                    color: [-220.6807556, 66.13040924, -32.26184082],
+                    inv_sigma: 0.03166157752,
+                    maximum_distance: 183.6748352,
+                    sigma_over_4_times_intensity: 7.89600563,
+                },
+            ),
+            (
+                1774,
+                SplineSegment {
+                    center_x: -16.43594933,
+                    center_y: -144.8626556,
+                    color: [57.31535339, -46.36843109, 92.14952087],
+                    inv_sigma: -0.01524505392,
+                    maximum_distance: 371.4827271,
+                    sigma_over_4_times_intensity: -16.39876175,
+                },
+            ),
+            (
+                1929,
+                SplineSegment {
+                    center_x: 61.19338608,
+                    center_y: -10.70717049,
+                    color: [-69.78807068, 300.6082458, -476.5135803],
+                    inv_sigma: 0.003229281865,
+                    maximum_distance: 1841.37854,
+                    sigma_over_4_times_intensity: 77.41659546,
+                },
+            ),
+        ];
+        for (index, segment) in want_segments_sample {
+            verify_segment_almost_equal(&segment, &splines.segments[index]);
+        }
+        Ok(())
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/adaptive_lf_smoothing.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/adaptive_lf_smoothing.rs
new file mode 100644
index 0000000..50c31ea
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/adaptive_lf_smoothing.rs
@@ -0,0 +1,95 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::error::Result;
+use crate::image::Image;
+use num_traits::abs;
+
+#[allow(clippy::excessive_precision)]
+const W_SIDE: f32 = 0.20345139757231578;
+#[allow(clippy::excessive_precision)]
+const W_CORNER: f32 = 0.0334829185968739;
+const W_CENTER: f32 = 1.0 - 4.0 * (W_SIDE + W_CORNER);
+
+fn compute_pixel_channel(
+    dc_factor: f32,
+    gap: f32,
+    x: usize,
+    row_top: &[f32],
+    row: &[f32],
+    row_bottom: &[f32],
+) -> (f32, f32, f32) {
+    let tl = row_top[x - 1];
+    let tc = row_top[x];
+    let tr = row_top[x + 1];
+    let ml = row[x - 1];
+    let mc = row[x];
+    let mr = row[x + 1];
+    let bl = row_bottom[x - 1];
+    let bc = row_bottom[x];
+    let br = row_bottom[x + 1];
+    let corner = tl + tr + bl + br;
+    let side = ml + mr + tc + bc;
+    let sm = corner * W_CORNER + side * W_SIDE + mc * W_CENTER;
+    (mc, sm, gap.max(abs((mc - sm) / dc_factor)))
+}
+
+pub fn adaptive_lf_smoothing(lf_factors: [f32; 3], lf_image: &mut [Image<f32>; 3]) -> Result<()> {
+    let xsize = lf_image[0].size().0;
+    let ysize = lf_image[0].size().1;
+    if ysize <= 2 || xsize <= 2 {
+        return Ok(());
+    }
+    let mut smoothed: [Image<f32>; 3] = [
+        Image::<f32>::new((xsize, ysize))?,
+        Image::<f32>::new((xsize, ysize))?,
+        Image::<f32>::new((xsize, ysize))?,
+    ];
+    for c in 0..3 {
+        for y in [0, ysize - 1] {
+            smoothed[c].row_mut(y).copy_from_slice(lf_image[c].row(y));
+        }
+    }
+    for y in 1..ysize - 1 {
+        for x in [0, xsize - 1] {
+            for c in 0..3 {
+                smoothed[c].row_mut(y)[x] = lf_image[c].row(y)[x];
+            }
+        }
+        for x in 1..xsize - 1 {
+            let gap = 0.5;
+            let (mc_x, sm_x, gap) = compute_pixel_channel(
+                lf_factors[0],
+                gap,
+                x,
+                lf_image[0].row(y - 1),
+                lf_image[0].row(y),
+                lf_image[0].row(y + 1),
+            );
+            let (mc_y, sm_y, gap) = compute_pixel_channel(
+                lf_factors[1],
+                gap,
+                x,
+                lf_image[1].row(y - 1),
+                lf_image[1].row(y),
+                lf_image[1].row(y + 1),
+            );
+            let (mc_b, sm_b, gap) = compute_pixel_channel(
+                lf_factors[2],
+                gap,
+                x,
+                lf_image[2].row(y - 1),
+                lf_image[2].row(y),
+                lf_image[2].row(y + 1),
+            );
+            let factor = (3.0 - 4.0 * gap).max(0.0);
+            smoothed[0].row_mut(y)[x] = (sm_x - mc_x) * factor + mc_x;
+            smoothed[1].row_mut(y)[x] = (sm_y - mc_y) * factor + mc_y;
+            smoothed[2].row_mut(y)[x] = (sm_b - mc_b) * factor + mc_b;
+        }
+    }
+    *lf_image = smoothed;
+    Ok(())
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/block_context_map.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/block_context_map.rs
new file mode 100644
index 0000000..c48e1e2
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/block_context_map.rs
@@ -0,0 +1,149 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{
+    bit_reader::BitReader,
+    entropy_coding::{context_map::*, decode::unpack_signed},
+    error::{Error, Result},
+    frame::coeff_order::NUM_ORDERS,
+    util::ShiftRightCeil,
+};
+
+pub const NON_ZERO_BUCKETS: usize = 37;
+pub const ZERO_DENSITY_CONTEXT_COUNT: usize = 458;
+
+pub const COEFF_FREQ_CONTEXT: [usize; 64] = [
+    0xBAD, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19,
+    19, 20, 20, 21, 21, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27,
+    27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30,
+];
+
+pub const COEFF_NUM_NONZERO_CONTEXT: [usize; 64] = [
+    0xBAD, 0, 31, 62, 62, 93, 93, 93, 93, 123, 123, 123, 123, 152, 152, 152, 152, 152, 152, 152,
+    152, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 206, 206, 206, 206, 206, 206,
+    206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206,
+    206, 206, 206, 206, 206, 206,
+];
+
+#[inline]
+pub fn zero_density_context(
+    nonzeros_left: usize,
+    k: usize,
+    log_num_blocks: usize,
+    prev: usize,
+) -> usize {
+    let nonzeros_left_norm = nonzeros_left.shrc(log_num_blocks);
+    let k_norm = k >> log_num_blocks;
+    debug_assert!((1..64).contains(&k_norm));
+    debug_assert!((1..64).contains(&nonzeros_left_norm));
+    (COEFF_NUM_NONZERO_CONTEXT[nonzeros_left_norm & 63] + COEFF_FREQ_CONTEXT[k_norm & 63]) * 2
+        + prev
+}
+
+#[derive(Debug)]
+pub struct BlockContextMap {
+    pub lf_thresholds: [Vec<i32>; 3],
+    pub qf_thresholds: Vec<u32>,
+    pub context_map: Vec<u8>,
+    pub num_lf_contexts: usize,
+    pub num_contexts: usize,
+}
+
+impl BlockContextMap {
+    pub fn num_ac_contexts(&self) -> usize {
+        self.num_contexts * (NON_ZERO_BUCKETS + ZERO_DENSITY_CONTEXT_COUNT)
+    }
+    pub fn read(br: &mut BitReader) -> Result<BlockContextMap, Error> {
+        if br.read(1)? == 1 {
+            Ok(BlockContextMap {
+                lf_thresholds: [vec![], vec![], vec![]],
+                qf_thresholds: vec![],
+                context_map: vec![
+                    0, 1, 2, 2, 3, 3, 4, 5, 6, 6, 6, 6, 6, //
+                    7, 8, 9, 9, 10, 11, 12, 13, 14, 14, 14, 14, 14, //
+                    7, 8, 9, 9, 10, 11, 12, 13, 14, 14, 14, 14, 14, //
+                ],
+                num_lf_contexts: 1,
+                num_contexts: 15,
+            })
+        } else {
+            let mut num_lf_contexts: usize = 1;
+            let mut lf_thresholds: [Vec<i32>; 3] = [vec![], vec![], vec![]];
+            for thr in lf_thresholds.iter_mut() {
+                let num_lf_thresholds = br.read(4)? as usize;
+                let mut v: Vec<i32> = vec![0; num_lf_thresholds];
+                for val in v.iter_mut() {
+                    let uval = match br.read(2)? {
+                        0 => br.read(4)?,
+                        1 => br.read(8)? + 16,
+                        2 => br.read(16)? + 272,
+                        _ => br.read(32)? + 65808,
+                    };
+                    *val = unpack_signed(uval as u32)
+                }
+                *thr = v;
+                num_lf_contexts *= num_lf_thresholds + 1;
+            }
+            let num_qf_thresholds = br.read(4)? as usize;
+            let mut qf_thresholds: Vec<u32> = vec![0; num_qf_thresholds];
+            for val in qf_thresholds.iter_mut() {
+                *val = match br.read(2)? {
+                    0 => br.read(2)?,
+                    1 => br.read(3)? + 4,
+                    2 => br.read(5)? + 12,
+                    _ => br.read(8)? + 44,
+                } as u32
+                    + 1;
+            }
+            if num_lf_contexts * (num_qf_thresholds + 1) > 64 {
+                return Err(Error::BlockContextMapSizeTooBig(
+                    num_lf_contexts,
+                    num_qf_thresholds,
+                ));
+            }
+            let context_map_size = 3 * NUM_ORDERS * num_lf_contexts * (num_qf_thresholds + 1);
+            let context_map = decode_context_map(context_map_size, br)?;
+            assert_eq!(context_map.len(), context_map_size);
+            let num_contexts = *context_map.iter().max().unwrap() as usize + 1;
+            if num_contexts > 16 {
+                Err(Error::TooManyBlockContexts)
+            } else {
+                Ok(BlockContextMap {
+                    lf_thresholds,
+                    qf_thresholds,
+                    context_map,
+                    num_lf_contexts,
+                    num_contexts,
+                })
+            }
+        }
+    }
+    pub fn block_context(&self, lf_idx: usize, qf: u32, shape_id: usize, c: usize) -> usize {
+        let mut qf_idx: usize = 0;
+        for t in &self.qf_thresholds {
+            if qf > *t {
+                qf_idx += 1;
+            }
+        }
+        let mut idx = if c < 2 { c ^ 1 } else { 2 };
+        idx = idx * NUM_ORDERS + shape_id;
+        idx = idx * (self.qf_thresholds.len() + 1) + qf_idx;
+        idx = idx * self.num_lf_contexts + lf_idx;
+        self.context_map[idx] as usize
+    }
+    pub fn nonzero_context(&self, nonzeros: usize, block_context: usize) -> usize {
+        let context: usize = if nonzeros < 8 {
+            nonzeros
+        } else if nonzeros < 64 {
+            4 + nonzeros / 2
+        } else {
+            36
+        };
+        context * self.num_contexts + block_context
+    }
+    pub fn zero_density_context_offset(&self, block_context: usize) -> usize {
+        self.num_contexts * NON_ZERO_BUCKETS + ZERO_DENSITY_CONTEXT_COUNT * block_context
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/coeff_order.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/coeff_order.rs
new file mode 100644
index 0000000..8b4036a8
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/coeff_order.rs
@@ -0,0 +1,153 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{
+    BLOCK_DIM, BLOCK_SIZE,
+    bit_reader::BitReader,
+    entropy_coding::decode::SymbolReader,
+    error::Result,
+    frame::Histograms,
+    headers::permutation::Permutation,
+    util::{CeilLog2, tracing_wrappers::*},
+};
+
+use jxl_transforms::transform_map::*;
+
+use std::mem;
+
+pub const NUM_ORDERS: usize = 13;
+
+pub const TRANSFORM_TYPE_LUT: [HfTransformType; NUM_ORDERS] = [
+    HfTransformType::DCT,
+    HfTransformType::IDENTITY, // a.k.a. "Hornuss"
+    HfTransformType::DCT16X16,
+    HfTransformType::DCT32X32,
+    HfTransformType::DCT8X16,
+    HfTransformType::DCT8X32,
+    HfTransformType::DCT16X32,
+    HfTransformType::DCT64X64,
+    HfTransformType::DCT32X64,
+    HfTransformType::DCT128X128,
+    HfTransformType::DCT64X128,
+    HfTransformType::DCT256X256,
+    HfTransformType::DCT128X256,
+];
+
+pub const NUM_PERMUTATION_CONTEXTS: usize = 8;
+
+pub fn natural_coeff_order(transform: HfTransformType) -> Vec<u32> {
+    let cx = covered_blocks_x(transform) as usize;
+    let cy = covered_blocks_y(transform) as usize;
+    let xsize: usize = cx * BLOCK_DIM;
+    assert!(cx >= cy);
+    // We compute the zigzag order for a cx x cx block, then discard all the
+    // lines that are not multiple of the ratio between cx and cy.
+    let xs = cx / cy;
+    let xsm = xs - 1;
+    let xss = xs.ceil_log2();
+    let mut out: Vec<u32> = vec![0; cx * cy * BLOCK_SIZE];
+    // First half of the block
+    let mut cur = cx * cy;
+    for i in 0..xsize {
+        for j in 0..(i + 1) {
+            let mut x = j;
+            let mut y = i - j;
+            if i % 2 != 0 {
+                mem::swap(&mut x, &mut y);
+            }
+            if (y & xsm) != 0 {
+                continue;
+            }
+            y >>= xss;
+            let val;
+            if x < cx && y < cy {
+                val = y * cx + x;
+            } else {
+                val = cur;
+                cur += 1;
+            }
+            out[val] = (y * xsize + x) as u32;
+        }
+    }
+    // Second half
+    for ir in 1..xsize {
+        let ip = xsize - ir;
+        let i = ip - 1;
+        for j in 0..(i + 1) {
+            let mut x = xsize - 1 - (i - j);
+            let mut y = xsize - 1 - j;
+            if !i.is_multiple_of(2) {
+                mem::swap(&mut x, &mut y);
+            }
+            if (y & xsm) != 0 {
+                continue;
+            }
+            y >>= xss;
+            let val = cur;
+            cur += 1;
+            out[val] = (y * xsize + x) as u32;
+        }
+    }
+    out
+}
+
+pub fn decode_coeff_orders(used_orders: u32, br: &mut BitReader) -> Result<Vec<Permutation>> {
+    // TODO(szabadka): Compute natural coefficient orders only for those transform that are used.
+    let all_component_orders = 3 * NUM_ORDERS;
+    let mut permutations: Vec<Permutation> = (0..all_component_orders)
+        .map(|o| Permutation(natural_coeff_order(TRANSFORM_TYPE_LUT[o / 3])))
+        .collect();
+    if used_orders == 0 {
+        return Ok(permutations);
+    }
+    let histograms = Histograms::decode(NUM_PERMUTATION_CONTEXTS, br, true)?;
+    let mut reader = SymbolReader::new(&histograms, br, None)?;
+    for (ord, transform_type) in TRANSFORM_TYPE_LUT.iter().enumerate() {
+        if used_orders & (1 << ord) == 0 {
+            continue;
+        }
+        debug!(?transform_type);
+        let num_blocks = covered_blocks_x(*transform_type) * covered_blocks_y(*transform_type);
+        for c in 0..3 {
+            let size = num_blocks * BLOCK_SIZE as u32;
+            let permutation = Permutation::decode(size, num_blocks, &histograms, br, &mut reader)?;
+            let index = 3 * ord + c;
+            permutations[index].compose(&permutation);
+        }
+    }
+    reader.check_final_state(&histograms, br)?;
+    Ok(permutations)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    // Golden data generated from libjxl's `ComputeNaturalCoeffOrder` for DCT (8x8).
+    const COEFF_ORDER_1X1: [u32; 64] = [
+        0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27,
+        20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
+        58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63,
+    ];
+
+    // Golden data generated from libjxl's `ComputeNaturalCoeffOrder` for DCT8X16 (16x8).
+    const COEFF_ORDER_2X1: [u32; 128] = [
+        0, 1, 16, 2, 3, 17, 32, 18, 4, 5, 19, 33, 48, 34, 20, 6, 7, 21, 35, 49, 64, 50, 36, 22, 8,
+        9, 23, 37, 51, 65, 80, 66, 52, 38, 24, 10, 11, 25, 39, 53, 67, 81, 96, 82, 68, 54, 40, 26,
+        12, 13, 27, 41, 55, 69, 83, 97, 112, 98, 84, 70, 56, 42, 28, 14, 15, 29, 43, 57, 71, 85,
+        99, 113, 114, 100, 86, 72, 58, 44, 30, 31, 45, 59, 73, 87, 101, 115, 116, 102, 88, 74, 60,
+        46, 47, 61, 75, 89, 103, 117, 118, 104, 90, 76, 62, 63, 77, 91, 105, 119, 120, 106, 92, 78,
+        79, 93, 107, 121, 122, 108, 94, 95, 109, 123, 124, 110, 111, 125, 126, 127,
+    ];
+
+    #[test]
+    fn test_natural_coeff_order() {
+        let order_1x1 = natural_coeff_order(HfTransformType::DCT);
+        assert_eq!(order_1x1, COEFF_ORDER_1X1);
+
+        let order_2x1 = natural_coeff_order(HfTransformType::DCT8X16);
+        assert_eq!(order_2x1, COEFF_ORDER_2X1);
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/color_correlation_map.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/color_correlation_map.rs
new file mode 100644
index 0000000..0c513b7
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/color_correlation_map.rs
@@ -0,0 +1,91 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{
+    BLOCK_DIM,
+    bit_reader::BitReader,
+    error::{Error, Result},
+};
+use std::default::Default;
+
+pub const COLOR_TILE_DIM: usize = 64;
+
+const _: () = assert!(COLOR_TILE_DIM.is_multiple_of(BLOCK_DIM));
+
+pub const COLOR_TILE_DIM_IN_BLOCKS: usize = COLOR_TILE_DIM / BLOCK_DIM;
+
+pub const DEFAULT_COLOR_FACTOR: u32 = 84;
+
+#[derive(Debug, Copy, Clone)]
+pub struct ColorCorrelationParams {
+    pub color_factor: u32,
+    pub base_correlation_x: f32,
+    pub base_correlation_b: f32,
+    pub ytox_lf: i32,
+    pub ytob_lf: i32,
+}
+
+impl Default for ColorCorrelationParams {
+    fn default() -> Self {
+        Self {
+            color_factor: DEFAULT_COLOR_FACTOR,
+            base_correlation_x: 0.0,
+            base_correlation_b: 1.0,
+            ytox_lf: 0,
+            ytob_lf: 0,
+        }
+    }
+}
+
+impl ColorCorrelationParams {
+    pub fn read(br: &mut BitReader) -> Result<ColorCorrelationParams, Error> {
+        if br.read(1)? == 1 {
+            Ok(Self::default())
+        } else {
+            let color_factor = match br.read(2)? {
+                0 => DEFAULT_COLOR_FACTOR,
+                1 => 256,
+                2 => (br.read(8)? + 2) as u32,
+                _ => (br.read(16)? + 258) as u32,
+            };
+            use crate::util::f16;
+            let val_x = f16::from_bits(br.read(16)? as u16);
+            let val_b = f16::from_bits(br.read(16)? as u16);
+            if !val_x.is_finite() || !val_b.is_finite() {
+                return Err(Error::FloatNaNOrInf);
+            }
+            let base_correlation_x = val_x.to_f32();
+            let base_correlation_b = val_b.to_f32();
+            if base_correlation_x > 4.0 || base_correlation_b > 4.0 {
+                return Err(Error::BaseColorCorrelationOutOfRange);
+            }
+            let ytox_lf = br.read(8)? as i32 - 128;
+            let ytob_lf = br.read(8)? as i32 - 128;
+            Ok(ColorCorrelationParams {
+                color_factor,
+                base_correlation_x,
+                base_correlation_b,
+                ytox_lf,
+                ytob_lf,
+            })
+        }
+    }
+
+    pub fn y_to_x(&self, factor: i32) -> f32 {
+        self.base_correlation_x + (factor as f32) / (self.color_factor as f32)
+    }
+
+    pub fn y_to_x_lf(&self) -> f32 {
+        self.y_to_x(self.ytox_lf)
+    }
+
+    pub fn y_to_b(&self, factor: i32) -> f32 {
+        self.base_correlation_b + (factor as f32) / (self.color_factor as f32)
+    }
+
+    pub fn y_to_b_lf(&self) -> f32 {
+        self.y_to_b(self.ytob_lf)
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/decode.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/decode.rs
new file mode 100644
index 0000000..aa6f33e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/decode.rs
@@ -0,0 +1,493 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::sync::Arc;
+
+use super::render::pipeline;
+use super::{
+    block_context_map::BlockContextMap,
+    coeff_order::decode_coeff_orders,
+    color_correlation_map::ColorCorrelationParams,
+    group::{VarDctBuffers, decode_vardct_group},
+    modular::{FullModularImage, ModularStreamId, Tree, decode_hf_metadata, decode_vardct_lf},
+    quant_weights::DequantMatrices,
+    quantizer::{LfQuantFactors, QuantizerParams},
+};
+use crate::error::Error;
+#[cfg(test)]
+use crate::render::SimpleRenderPipeline;
+use crate::render::buffer_splitter::BufferSplitter;
+use crate::{
+    GROUP_DIM,
+    bit_reader::BitReader,
+    entropy_coding::decode::Histograms,
+    error::Result,
+    features::{noise::Noise, patches::PatchesDictionary, spline::Splines},
+    frame::{
+        DecoderState, Frame, HfGlobalState, HfMetadata, LfGlobalState, PassState, coeff_order,
+    },
+    headers::{
+        color_encoding::ColorSpace,
+        frame_header::{Encoding, FrameHeader},
+        toc::Toc,
+    },
+    image::Image,
+    render::RenderPipeline,
+    util::{CeilLog2, Xorshift128Plus, tracing_wrappers::*},
+};
+use jxl_transforms::transform_map::*;
+
+impl Frame {
+    pub fn from_header_and_toc(
+        frame_header: FrameHeader,
+        toc: Toc,
+        mut decoder_state: DecoderState,
+    ) -> Result<Self> {
+        if frame_header.is_visible() {
+            decoder_state.visible_frame_index += 1;
+            decoder_state.nonvisible_frame_index = 0;
+        } else {
+            decoder_state.nonvisible_frame_index += 1;
+        }
+        let image_metadata = &decoder_state.file_header.image_metadata;
+        let is_gray = !frame_header.do_ycbcr
+            && !image_metadata.xyb_encoded
+            && image_metadata.color_encoding.color_space == ColorSpace::Gray;
+        let color_channels = if is_gray { 1 } else { 3 };
+        let size_blocks = frame_header.size_blocks();
+        let lf_image = if frame_header.encoding == Encoding::VarDCT {
+            if frame_header.has_lf_frame() {
+                decoder_state.lf_frames[frame_header.lf_level as usize]
+                    .as_ref()
+                    .map(|[a, b, c]| {
+                        Ok::<_, Error>([a.try_clone()?, b.try_clone()?, c.try_clone()?])
+                    })
+                    .transpose()?
+            } else {
+                Some([
+                    Image::new(size_blocks)?,
+                    Image::new(size_blocks)?,
+                    Image::new(size_blocks)?,
+                ])
+            }
+        } else {
+            None
+        };
+        let quant_lf = Image::new(size_blocks)?;
+        let size_color_tiles = (size_blocks.0.div_ceil(8), size_blocks.1.div_ceil(8));
+        let hf_meta = if frame_header.encoding == Encoding::VarDCT {
+            Some(HfMetadata {
+                ytox_map: Image::new(size_color_tiles)?,
+                ytob_map: Image::new(size_color_tiles)?,
+                raw_quant_map: Image::new(size_blocks)?,
+                transform_map: Image::new_with_value(
+                    size_blocks,
+                    HfTransformType::INVALID_TRANSFORM,
+                )?,
+                epf_map: Image::new(size_blocks)?,
+                used_hf_types: 0,
+            })
+        } else {
+            None
+        };
+
+        let reference_frame_data = if frame_header.can_be_referenced {
+            let image_size = &decoder_state.file_header.size;
+            let image_size = (image_size.xsize() as usize, image_size.ysize() as usize);
+            let sz = if frame_header.save_before_ct {
+                frame_header.size_upsampled()
+            } else {
+                image_size
+            };
+
+            let num_ref_channels = 3 + image_metadata.extra_channel_info.len();
+            Some(
+                (0..num_ref_channels)
+                    .map(|_| Image::new(sz))
+                    .collect::<Result<Vec<_>>>()?,
+            )
+        } else {
+            None
+        };
+
+        let lf_frame_data = if frame_header.lf_level != 0 {
+            Some(
+                (0..3)
+                    .map(|_| Image::new(frame_header.size_upsampled()))
+                    .collect::<Result<Vec<_>, _>>()?
+                    .try_into()
+                    .unwrap(),
+            )
+        } else {
+            None
+        };
+
+        Ok(Self {
+            #[cfg(test)]
+            use_simple_pipeline: decoder_state.use_simple_pipeline,
+            header: frame_header,
+            color_channels,
+            toc,
+            lf_global: None,
+            hf_global: None,
+            lf_image,
+            quant_lf,
+            hf_meta,
+            decoder_state,
+            render_pipeline: None,
+            reference_frame_data,
+            lf_frame_data,
+            lf_global_was_rendered: false,
+            vardct_buffers: None,
+        })
+    }
+    /// Given a bit reader pointing at the end of the TOC, returns a vector of `BitReader`s, each
+    /// of which reads a specific section.
+    pub fn sections<'a>(&self, br: &'a mut BitReader) -> Result<Vec<BitReader<'a>>> {
+        debug!(toc = ?self.toc);
+        let ret = self
+            .toc
+            .entries
+            .iter()
+            .scan(br, |br, count| Some(br.split_at(*count as usize)))
+            .collect::<Result<Vec<_>>>()?;
+        if !self.toc.permuted {
+            return Ok(ret);
+        }
+        let mut inv_perm = vec![0; ret.len()];
+        for (i, pos) in self.toc.permutation.iter().enumerate() {
+            inv_perm[*pos as usize] = i;
+        }
+        let mut shuffled_ret = ret.clone();
+        for (br, pos) in ret.into_iter().zip(inv_perm.into_iter()) {
+            shuffled_ret[pos] = br;
+        }
+        Ok(shuffled_ret)
+    }
+    #[instrument(level = "debug", skip_all)]
+    pub fn decode_lf_global(&mut self, br: &mut BitReader) -> Result<()> {
+        debug!(section_size = br.total_bits_available());
+        assert!(self.lf_global.is_none());
+        trace!(pos = br.total_bits_read());
+
+        let patches = if self.header.has_patches() {
+            info!("decoding patches");
+            Some(PatchesDictionary::read(
+                br,
+                self.header.size_padded().0,
+                self.header.size_padded().1,
+                self.decoder_state.extra_channel_info().len(),
+                &self.decoder_state.reference_frames[..],
+            )?)
+        } else {
+            None
+        };
+
+        let splines = if self.header.has_splines() {
+            info!("decoding splines");
+            Some(Splines::read(br, self.header.width * self.header.height)?)
+        } else {
+            None
+        };
+
+        let noise = if self.header.has_noise() {
+            info!("decoding noise");
+            Some(Noise::read(br)?)
+        } else {
+            None
+        };
+
+        let lf_quant = LfQuantFactors::new(br)?;
+        debug!(?lf_quant);
+
+        let quant_params = if self.header.encoding == Encoding::VarDCT {
+            info!("decoding VarDCT quantizer params");
+            Some(QuantizerParams::read(br)?)
+        } else {
+            None
+        };
+        debug!(?quant_params);
+
+        let block_context_map = if self.header.encoding == Encoding::VarDCT {
+            info!("decoding block context map");
+            Some(BlockContextMap::read(br)?)
+        } else {
+            None
+        };
+        debug!(?block_context_map);
+
+        let color_correlation_params = if self.header.encoding == Encoding::VarDCT {
+            info!("decoding color correlation params");
+            Some(ColorCorrelationParams::read(br)?)
+        } else {
+            None
+        };
+        debug!(?color_correlation_params);
+
+        let tree = if br.read(1)? == 1 {
+            let size_limit = (1024
+                + self.header.width as usize
+                    * self.header.height as usize
+                    * (self.color_channels + self.decoder_state.extra_channel_info().len())
+                    / 16)
+                .min(1 << 22);
+            Some(Tree::read(br, size_limit)?)
+        } else {
+            None
+        };
+
+        let modular_global = FullModularImage::read(
+            &self.header,
+            &self.decoder_state.file_header.image_metadata,
+            self.modular_color_channels(),
+            &tree,
+            br,
+        )?;
+
+        self.lf_global = Some(LfGlobalState {
+            patches: patches.map(Arc::new),
+            splines,
+            noise,
+            lf_quant,
+            quant_params,
+            block_context_map,
+            color_correlation_params,
+            tree,
+            modular_global,
+        });
+
+        Ok(())
+    }
+
+    #[instrument(level = "debug", skip(self, br))]
+    pub fn decode_lf_group(&mut self, group: usize, br: &mut BitReader) -> Result<()> {
+        debug!(section_size = br.total_bits_available());
+        let lf_global = self.lf_global.as_mut().unwrap();
+        if self.header.encoding == Encoding::VarDCT && !self.header.has_lf_frame() {
+            info!("decoding VarDCT LF with group id {}", group);
+            decode_vardct_lf(
+                group,
+                &self.header,
+                &self.decoder_state.file_header.image_metadata,
+                &lf_global.tree,
+                lf_global.color_correlation_params.as_ref().unwrap(),
+                lf_global.quant_params.as_ref().unwrap(),
+                &lf_global.lf_quant,
+                lf_global.block_context_map.as_ref().unwrap(),
+                self.lf_image.as_mut().unwrap(),
+                &mut self.quant_lf,
+                br,
+            )?;
+        }
+        lf_global.modular_global.read_stream(
+            ModularStreamId::ModularLF(group),
+            &self.header,
+            &lf_global.tree,
+            br,
+        )?;
+        if self.header.encoding == Encoding::VarDCT {
+            info!("decoding HF metadata with group id {}", group);
+            let hf_meta = self.hf_meta.as_mut().unwrap();
+            decode_hf_metadata(
+                group,
+                &self.header,
+                &self.decoder_state.file_header.image_metadata,
+                &lf_global.tree,
+                hf_meta,
+                br,
+            )?;
+        }
+        Ok(())
+    }
+
+    #[instrument(level = "debug", skip_all)]
+    pub fn decode_hf_global(&mut self, br: &mut BitReader) -> Result<()> {
+        debug!(section_size = br.total_bits_available());
+        if self.header.encoding == Encoding::Modular {
+            return Ok(());
+        }
+        let lf_global = self.lf_global.as_mut().unwrap();
+        let mut dequant_matrices = DequantMatrices::decode(&self.header, lf_global, br)?;
+        dequant_matrices.ensure_computed(self.hf_meta.as_ref().unwrap().used_hf_types)?;
+        let block_context_map = lf_global.block_context_map.as_mut().unwrap();
+        let num_histo_bits = self.header.num_groups().ceil_log2();
+        let num_histograms: u32 = br.read(num_histo_bits)? as u32 + 1;
+        info!(
+            "Processing HFGlobal section with {} passes and {} histograms",
+            self.header.passes.num_passes, num_histograms
+        );
+        let mut passes: Vec<PassState> = vec![];
+        #[allow(unused_variables)]
+        for i in 0..self.header.passes.num_passes as usize {
+            let used_orders = match br.read(2)? {
+                0 => 0x5f,
+                1 => 0x13,
+                2 => 0,
+                _ => br.read(coeff_order::NUM_ORDERS)?,
+            } as u32;
+            debug!(used_orders);
+            let coeff_orders = decode_coeff_orders(used_orders, br)?;
+            assert_eq!(coeff_orders.len(), 3 * coeff_order::NUM_ORDERS);
+            let num_contexts = num_histograms as usize * block_context_map.num_ac_contexts();
+            info!(
+                "Deconding histograms for pass {} with {} contexts",
+                i, num_contexts
+            );
+            let histograms = Histograms::decode(num_contexts, br, true)?;
+            debug!("Found {} histograms", histograms.num_histograms());
+            passes.push(PassState {
+                coeff_orders,
+                histograms,
+            });
+        }
+        let hf_coefficients = if passes.len() <= 1 {
+            None
+        } else {
+            let xs = GROUP_DIM * GROUP_DIM;
+            let ys = self.header.num_groups();
+            Some((
+                Image::new((xs, ys))?,
+                Image::new((xs, ys))?,
+                Image::new((xs, ys))?,
+            ))
+        };
+        self.hf_global = Some(HfGlobalState {
+            num_histograms,
+            passes,
+            dequant_matrices,
+            hf_coefficients,
+        });
+        Ok(())
+    }
+
+    #[instrument(level = "debug", skip(self, br, buffer_splitter))]
+    pub fn decode_hf_group(
+        &mut self,
+        group: usize,
+        pass: usize,
+        mut br: BitReader,
+        buffer_splitter: &mut BufferSplitter,
+    ) -> Result<()> {
+        debug!(section_size = br.total_bits_available());
+        if self.header.has_noise() {
+            // TODO(sboukortt): consider making this a dedicated stage
+            let num_channels = self.header.num_extra_channels as usize + 3;
+
+            let group_dim = self.header.group_dim() as u32;
+            let xsize_groups = self.header.size_groups().0;
+            let gx = (group % xsize_groups) as u32;
+            let gy = (group / xsize_groups) as u32;
+            // TODO(sboukortt): test upsampling+noise
+            let upsampling = self.header.upsampling;
+            let x0 = gx * upsampling * group_dim;
+            let y0 = gy * upsampling * group_dim;
+            let x1 = ((x0 + upsampling * group_dim) as usize).min(self.header.size_upsampled().0);
+            let y1 = ((y0 + upsampling * group_dim) as usize).min(self.header.size_upsampled().1);
+            let xsize = x1 - x0 as usize;
+            let ysize = y1 - y0 as usize;
+            let mut rng = Xorshift128Plus::new_with_seeds(
+                self.decoder_state.visible_frame_index as u32,
+                self.decoder_state.nonvisible_frame_index as u32,
+                x0,
+                y0,
+            );
+            let bits_to_float = |bits: u32| f32::from_bits((bits >> 9) | 0x3F800000);
+            for i in 0..3 {
+                let mut buf = pipeline!(self, p, p.get_buffer(num_channels + i)?);
+                const FLOATS_PER_BATCH: usize =
+                    Xorshift128Plus::N * std::mem::size_of::<u64>() / std::mem::size_of::<f32>();
+                let mut batch = [0u64; Xorshift128Plus::N];
+
+                for y in 0..ysize {
+                    let row = buf.row_mut(y);
+                    for batch_index in 0..xsize.div_ceil(FLOATS_PER_BATCH) {
+                        rng.fill(&mut batch);
+                        let batch_size =
+                            (xsize - batch_index * FLOATS_PER_BATCH).min(FLOATS_PER_BATCH);
+                        for i in 0..batch_size {
+                            let x = FLOATS_PER_BATCH * batch_index + i;
+                            let k = i / 2;
+                            let high_bytes = i % 2 != 0;
+                            let bits = if high_bytes {
+                                ((batch[k] & 0xFFFFFFFF00000000) >> 32) as u32
+                            } else {
+                                (batch[k] & 0xFFFFFFFF) as u32
+                            };
+                            row[x] = bits_to_float(bits);
+                        }
+                    }
+                }
+                pipeline!(
+                    self,
+                    p,
+                    p.set_buffer_for_group(num_channels + i, group, 1, buf, buffer_splitter)?
+                )
+            }
+        }
+
+        let lf_global = self.lf_global.as_mut().unwrap();
+        if self.header.encoding == Encoding::VarDCT {
+            info!("Decoding VarDCT group {group}, pass {pass}");
+            let hf_global = self.hf_global.as_mut().unwrap();
+            let hf_meta = self.hf_meta.as_mut().unwrap();
+            let mut pixels = [
+                pipeline!(self, p, p.get_buffer(0))?,
+                pipeline!(self, p, p.get_buffer(1))?,
+                pipeline!(self, p, p.get_buffer(2))?,
+            ];
+            let buffers = self.vardct_buffers.get_or_insert_with(VarDctBuffers::new);
+            decode_vardct_group(
+                group,
+                pass,
+                &self.header,
+                lf_global,
+                hf_global,
+                hf_meta,
+                &self.lf_image,
+                &self.quant_lf,
+                &self
+                    .decoder_state
+                    .file_header
+                    .transform_data
+                    .opsin_inverse_matrix
+                    .quant_biases,
+                &mut pixels,
+                &mut br,
+                buffers,
+            )?;
+            if self.decoder_state.enable_output
+                && pass + 1 == self.header.passes.num_passes as usize
+            {
+                for (c, img) in pixels.into_iter().enumerate() {
+                    pipeline!(
+                        self,
+                        p,
+                        p.set_buffer_for_group(c, group, 1, img, buffer_splitter)?
+                    );
+                }
+            }
+        }
+        lf_global.modular_global.read_stream(
+            ModularStreamId::ModularHF { group, pass },
+            &self.header,
+            &lf_global.tree,
+            &mut br,
+        )?;
+        lf_global.modular_global.process_output(
+            2 + pass,
+            group,
+            &self.header,
+            &mut |chan, group, num_passes, image| {
+                pipeline!(
+                    self,
+                    p,
+                    p.set_buffer_for_group(chan, group, num_passes, image, buffer_splitter)?
+                );
+                Ok(())
+            },
+        )?;
+        Ok(())
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/group.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/group.rs
new file mode 100644
index 0000000..5b8d02d
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/group.rs
@@ -0,0 +1,564 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use num_traits::Float;
+
+use jxl_transforms::{transform::*, transform_map::*};
+
+use crate::{
+    BLOCK_DIM, BLOCK_SIZE, GROUP_DIM,
+    bit_reader::BitReader,
+    entropy_coding::decode::SymbolReader,
+    error::{Error, Result},
+    frame::{
+        HfGlobalState, HfMetadata, LfGlobalState, block_context_map::*,
+        color_correlation_map::COLOR_TILE_DIM_IN_BLOCKS, quant_weights::DequantMatrices,
+    },
+    headers::frame_header::FrameHeader,
+    image::{Image, ImageRect, Rect},
+    util::{CeilLog2, ShiftRightCeil, tracing_wrappers::*},
+};
+use jxl_simd::{F32SimdVec, I32SimdVec, SimdDescriptor, SimdMask, simd_function};
+
+const LF_BUFFER_SIZE: usize = 32 * 32;
+
+/// Reusable buffers for VarDCT group decoding to avoid repeated allocations.
+pub struct VarDctBuffers {
+    pub scratch: Vec<f32>,
+    pub transform_buffer: [Vec<f32>; 3],
+}
+
+impl VarDctBuffers {
+    pub fn new() -> Self {
+        Self {
+            scratch: vec![0.0; LF_BUFFER_SIZE],
+            transform_buffer: [
+                vec![0.0; MAX_COEFF_AREA],
+                vec![0.0; MAX_COEFF_AREA],
+                vec![0.0; MAX_COEFF_AREA],
+            ],
+        }
+    }
+
+    /// Reset buffers to zero for reuse.
+    pub fn reset(&mut self) {
+        self.scratch.fill(0.0);
+        for buf in &mut self.transform_buffer {
+            buf.fill(0.0);
+        }
+    }
+}
+
+impl Default for VarDctBuffers {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+#[inline]
+fn predict_num_nonzeros(nzeros_map: &Image<u32>, bx: usize, by: usize) -> usize {
+    if bx == 0 {
+        if by == 0 {
+            32
+        } else {
+            nzeros_map.row(by - 1)[0] as usize
+        }
+    } else if by == 0 {
+        nzeros_map.row(by)[bx - 1] as usize
+    } else {
+        (nzeros_map.row(by - 1)[bx] + nzeros_map.row(by)[bx - 1]).div_ceil(2) as usize
+    }
+}
+
+#[inline(always)]
+fn adjust_quant_bias<D: SimdDescriptor>(
+    d: D,
+    c: usize,
+    quant_i: D::I32Vec,
+    biases: &[f32; 4],
+) -> D::F32Vec {
+    let quant = quant_i.as_f32();
+    let adjusted = quant - D::F32Vec::splat(d, biases[3]) / quant;
+    D::I32Vec::splat(d, 2)
+        .gt(quant_i.abs())
+        .if_then_else_f32(quant_i.as_f32() * D::F32Vec::splat(d, biases[c]), adjusted)
+}
+
+#[allow(clippy::too_many_arguments)]
+#[inline(always)]
+fn dequant_lane<D: SimdDescriptor>(
+    d: D,
+    scaled_dequant_x: f32,
+    scaled_dequant_y: f32,
+    scaled_dequant_b: f32,
+    dequant_matrices: &[f32],
+    size: usize,
+    k: usize,
+    x_cc_mul: f32,
+    b_cc_mul: f32,
+    biases: &[f32; 4],
+    qblock: &[&[i32]; 3],
+    block: &mut [Vec<f32>; 3],
+) {
+    let x_mul = D::F32Vec::load(d, &dequant_matrices[k..]) * D::F32Vec::splat(d, scaled_dequant_x);
+    let y_mul =
+        D::F32Vec::load(d, &dequant_matrices[size + k..]) * D::F32Vec::splat(d, scaled_dequant_y);
+    let b_mul = D::F32Vec::load(d, &dequant_matrices[2 * size + k..])
+        * D::F32Vec::splat(d, scaled_dequant_b);
+
+    let quantized_x = D::I32Vec::load(d, &qblock[0][k..]);
+    let quantized_y = D::I32Vec::load(d, &qblock[1][k..]);
+    let quantized_b = D::I32Vec::load(d, &qblock[2][k..]);
+
+    let dequant_x_cc = adjust_quant_bias(d, 0, quantized_x, biases) * x_mul;
+    let dequant_y = adjust_quant_bias(d, 1, quantized_y, biases) * y_mul;
+    let dequant_b_cc = adjust_quant_bias(d, 2, quantized_b, biases) * b_mul;
+
+    let dequant_x = D::F32Vec::splat(d, x_cc_mul).mul_add(dequant_y, dequant_x_cc);
+    let dequant_b = D::F32Vec::splat(d, b_cc_mul).mul_add(dequant_y, dequant_b_cc);
+    dequant_x.store(&mut block[0][k..]);
+    dequant_y.store(&mut block[1][k..]);
+    dequant_b.store(&mut block[2][k..]);
+}
+
+#[allow(clippy::too_many_arguments)]
+#[inline(always)]
+fn dequant_block<D: SimdDescriptor>(
+    d: D,
+    hf_type: HfTransformType,
+    inv_global_scale: f32,
+    quant: u32,
+    x_dm_multiplier: f32,
+    b_dm_multiplier: f32,
+    x_cc_mul: f32,
+    b_cc_mul: f32,
+    size: usize,
+    dequant_matrices: &DequantMatrices,
+    covered_blocks: usize,
+    biases: &[f32; 4],
+    qblock: &[&[i32]; 3],
+    block: &mut [Vec<f32>; 3],
+) {
+    let scaled_dequant_y = inv_global_scale / (quant as f32);
+
+    let scaled_dequant_x = scaled_dequant_y * x_dm_multiplier;
+    let scaled_dequant_b = scaled_dequant_y * b_dm_multiplier;
+
+    let matrices = dequant_matrices.matrix(hf_type, 0);
+
+    assert!(BLOCK_SIZE.is_multiple_of(D::F32Vec::LEN));
+    for k in (0..covered_blocks * BLOCK_SIZE).step_by(D::F32Vec::LEN) {
+        dequant_lane(
+            d,
+            scaled_dequant_x,
+            scaled_dequant_y,
+            scaled_dequant_b,
+            matrices,
+            size,
+            k,
+            x_cc_mul,
+            b_cc_mul,
+            biases,
+            qblock,
+            block,
+        );
+    }
+}
+
+#[allow(clippy::too_many_arguments)]
+#[inline(always)]
+fn dequant_and_transform_to_pixels<D: SimdDescriptor>(
+    d: D,
+    quant_biases: &[f32; 4],
+    x_dm_multiplier: f32,
+    b_dm_multiplier: f32,
+    pixels: &mut [Image<f32>; 3],
+    scratch: &mut [f32],
+    inv_global_scale: f32,
+    transform_buffer: &mut [Vec<f32>; 3],
+    hshift: [usize; 3],
+    vshift: [usize; 3],
+    by: usize,
+    sby: [usize; 3],
+    bx: usize,
+    sbx: [usize; 3],
+    x_cc_mul: f32,
+    b_cc_mul: f32,
+    raw_quant: u32,
+    lf_rects: &Option<[ImageRect<f32>; 3]>,
+    transform_type: HfTransformType,
+    block_rect: Rect,
+    num_blocks: usize,
+    num_coeffs: usize,
+    qblock: &[&[i32]; 3],
+    dequant_matrices: &DequantMatrices,
+) -> Result<(), Error> {
+    dequant_block::<D>(
+        d,
+        transform_type,
+        inv_global_scale,
+        raw_quant,
+        x_dm_multiplier,
+        b_dm_multiplier,
+        x_cc_mul,
+        b_cc_mul,
+        num_coeffs,
+        dequant_matrices,
+        num_blocks,
+        quant_biases,
+        qblock,
+        transform_buffer,
+    );
+    for c in [1, 0, 2] {
+        if (sbx[c] << hshift[c]) != bx || (sby[c] << vshift[c] != by) {
+            continue;
+        }
+        let lf = &mut scratch[..];
+        {
+            let xs = covered_blocks_x(transform_type) as usize;
+            let ys = covered_blocks_y(transform_type) as usize;
+            let rect = lf_rects.as_ref().unwrap()[c];
+            for (y, lf) in lf.chunks_exact_mut(xs).enumerate().take(ys) {
+                lf.copy_from_slice(&rect.row(y)[0..xs]);
+            }
+        }
+        transform_to_pixels(transform_type, lf, &mut transform_buffer[c]);
+        let downsampled_rect = Rect {
+            origin: (
+                block_rect.origin.0 >> hshift[c],
+                block_rect.origin.1 >> vshift[c],
+            ),
+            size: block_rect.size,
+        };
+        let mut output_rect = pixels[c].get_rect_mut(downsampled_rect);
+        for i in 0..downsampled_rect.size.1 {
+            let offset = i * downsampled_rect.size.0;
+            output_rect
+                .row(i)
+                .copy_from_slice(&transform_buffer[c][offset..offset + downsampled_rect.size.0]);
+        }
+    }
+    Ok(())
+}
+
+simd_function!(
+    dequant_and_transform_to_pixels_dispatch,
+    d: D,
+    #[allow(clippy::too_many_arguments)]
+    pub fn dequant_and_transform_to_pixels_fwd(
+        quant_biases: &[f32; 4],
+        x_dm_multiplier: f32,
+        b_dm_multiplier: f32,
+        pixels: &mut [Image<f32>; 3],
+        scratch: &mut [f32],
+        inv_global_scale: f32,
+        transform_buffer: &mut [Vec<f32>; 3],
+        hshift: [usize; 3],
+        vshift: [usize; 3],
+        by: usize,
+        sby: [usize; 3],
+        bx: usize,
+        sbx: [usize; 3],
+        x_cc_mul: f32,
+        b_cc_mul: f32,
+        raw_quant: u32,
+        lf_rects: &Option<[ImageRect<f32>; 3]>,
+        transform_type: HfTransformType,
+        block_rect: Rect,
+        num_blocks: usize,
+        num_coeffs: usize,
+        qblock: &[&[i32]; 3],
+        dequant_matrices: &DequantMatrices,
+    ) -> Result<(), Error> {
+        dequant_and_transform_to_pixels(
+            d,
+            quant_biases,
+            x_dm_multiplier,
+            b_dm_multiplier,
+            pixels,
+            scratch,
+            inv_global_scale,
+            transform_buffer,
+            hshift,
+            vshift,
+            by,
+            sby,
+            bx,
+            sbx,
+            x_cc_mul,
+            b_cc_mul,
+            raw_quant,
+            lf_rects,
+            transform_type,
+            block_rect,
+            num_blocks,
+            num_coeffs,
+            qblock,
+            dequant_matrices,
+        )
+    }
+);
+
+#[allow(clippy::too_many_arguments)]
+#[allow(clippy::type_complexity)]
+pub fn decode_vardct_group(
+    group: usize,
+    pass: usize,
+    frame_header: &FrameHeader,
+    lf_global: &mut LfGlobalState,
+    hf_global: &mut HfGlobalState,
+    hf_meta: &HfMetadata,
+    lf_image: &Option<[Image<f32>; 3]>,
+    quant_lf: &Image<u8>,
+    quant_biases: &[f32; 4],
+    pixels: &mut [Image<f32>; 3],
+    br: &mut BitReader,
+    buffers: &mut VarDctBuffers,
+) -> Result<(), Error> {
+    let x_dm_multiplier = (1.0 / (1.25)).powf(frame_header.x_qm_scale as f32 - 2.0);
+    let b_dm_multiplier = (1.0 / (1.25)).powf(frame_header.b_qm_scale as f32 - 2.0);
+
+    let num_histo_bits = hf_global.num_histograms.ceil_log2();
+    let histogram_index: usize = br.read(num_histo_bits as usize)? as usize;
+    debug!(?histogram_index);
+    let mut reader = SymbolReader::new(&hf_global.passes[pass].histograms, br, None)?;
+    let block_group_rect = frame_header.block_group_rect(group);
+    debug!(?block_group_rect);
+    // Reset and use pooled buffers
+    buffers.reset();
+    let scratch = &mut buffers.scratch;
+    let color_correlation_params = lf_global.color_correlation_params.as_ref().unwrap();
+    let cmap_rect = Rect {
+        origin: (
+            block_group_rect.origin.0 / COLOR_TILE_DIM_IN_BLOCKS,
+            block_group_rect.origin.1 / COLOR_TILE_DIM_IN_BLOCKS,
+        ),
+        size: (
+            block_group_rect.size.0.div_ceil(COLOR_TILE_DIM_IN_BLOCKS),
+            block_group_rect.size.1.div_ceil(COLOR_TILE_DIM_IN_BLOCKS),
+        ),
+    };
+    let quant_params = lf_global.quant_params.as_ref().unwrap();
+    let inv_global_scale = quant_params.inv_global_scale();
+    let ytox_map = hf_meta.ytox_map.get_rect(cmap_rect);
+    let ytob_map = hf_meta.ytob_map.get_rect(cmap_rect);
+    let transform_map = hf_meta.transform_map.get_rect(block_group_rect);
+    let raw_quant_map = hf_meta.raw_quant_map.get_rect(block_group_rect);
+    let mut num_nzeros: [Image<u32>; 3] = [
+        Image::new((
+            block_group_rect.size.0 >> frame_header.hshift(0),
+            block_group_rect.size.1 >> frame_header.vshift(0),
+        ))?,
+        Image::new((
+            block_group_rect.size.0 >> frame_header.hshift(1),
+            block_group_rect.size.1 >> frame_header.vshift(1),
+        ))?,
+        Image::new((
+            block_group_rect.size.0 >> frame_header.hshift(2),
+            block_group_rect.size.1 >> frame_header.vshift(2),
+        ))?,
+    ];
+    let quant_lf_rect = quant_lf.get_rect(block_group_rect);
+    let block_context_map = lf_global.block_context_map.as_mut().unwrap();
+    let context_offset = histogram_index * block_context_map.num_ac_contexts();
+    let mut coeffs_storage;
+    let coeffs = match hf_global.hf_coefficients.as_mut() {
+        Some(hf_coefficients) => [
+            hf_coefficients.0.row_mut(group),
+            hf_coefficients.1.row_mut(group),
+            hf_coefficients.2.row_mut(group),
+        ],
+        None => {
+            coeffs_storage = vec![0; 3 * GROUP_DIM * GROUP_DIM];
+            let (coeffs_x, coeffs_y_b) = coeffs_storage.split_at_mut(GROUP_DIM * GROUP_DIM);
+            let (coeffs_y, coeffs_b) = coeffs_y_b.split_at_mut(GROUP_DIM * GROUP_DIM);
+            [coeffs_x, coeffs_y, coeffs_b]
+        }
+    };
+    let shift_for_pass = if pass < frame_header.passes.shift.len() {
+        frame_header.passes.shift[pass]
+    } else {
+        0
+    };
+    let mut coeffs_offset = 0;
+    let transform_buffer = &mut buffers.transform_buffer;
+
+    let hshift = [
+        frame_header.hshift(0),
+        frame_header.hshift(1),
+        frame_header.hshift(2),
+    ];
+    let vshift = [
+        frame_header.vshift(0),
+        frame_header.vshift(1),
+        frame_header.vshift(2),
+    ];
+    let lf = match lf_image.as_ref() {
+        None => None,
+        Some(lf_planes) => {
+            let r: [Rect; 3] = core::array::from_fn(|i| Rect {
+                origin: (
+                    block_group_rect.origin.0 >> hshift[i],
+                    block_group_rect.origin.1 >> vshift[i],
+                ),
+                size: (
+                    block_group_rect.size.0 >> hshift[i],
+                    block_group_rect.size.1 >> vshift[i],
+                ),
+            });
+
+            let [lf_x, lf_y, lf_b] = lf_planes.each_ref();
+            Some([
+                lf_x.get_rect(r[0]),
+                lf_y.get_rect(r[1]),
+                lf_b.get_rect(r[2]),
+            ])
+        }
+    };
+    for by in 0..block_group_rect.size.1 {
+        let sby = [by >> vshift[0], by >> vshift[1], by >> vshift[2]];
+        let ty = by / COLOR_TILE_DIM_IN_BLOCKS;
+
+        let row_cmap_x = ytox_map.row(ty);
+        let row_cmap_b = ytob_map.row(ty);
+
+        for bx in 0..block_group_rect.size.0 {
+            let sbx = [bx >> hshift[0], bx >> hshift[1], bx >> hshift[2]];
+            let tx = bx / COLOR_TILE_DIM_IN_BLOCKS;
+            let x_cc_mul = color_correlation_params.y_to_x(row_cmap_x[tx] as i32);
+            let b_cc_mul = color_correlation_params.y_to_b(row_cmap_b[tx] as i32);
+            let raw_quant = raw_quant_map.row(by)[bx] as u32;
+            let quant_lf = quant_lf_rect.row(by)[bx] as usize;
+            let raw_transform_id = transform_map.row(by)[bx];
+            let transform_id = raw_transform_id & 127;
+            let is_first_block = raw_transform_id >= 128;
+            if !is_first_block {
+                continue;
+            }
+            let lf_rects = match lf.as_ref() {
+                None => None,
+                Some(lf) => {
+                    let [lf_x, lf_y, lf_b] = lf.each_ref();
+                    Some([
+                        lf_x.rect(Rect {
+                            origin: (sbx[0], sby[0]),
+                            size: (lf_x.size().0 - sbx[0], lf_x.size().1 - sby[0]),
+                        }),
+                        lf_y.rect(Rect {
+                            origin: (sbx[1], sby[1]),
+                            size: (lf_y.size().0 - sbx[1], lf_y.size().1 - sby[1]),
+                        }),
+                        lf_b.rect(Rect {
+                            origin: (sbx[2], sby[2]),
+                            size: (lf_b.size().0 - sbx[2], lf_b.size().1 - sby[2]),
+                        }),
+                    ])
+                }
+            };
+
+            let transform_type = HfTransformType::from_usize(transform_id as usize)
+                .ok_or(Error::InvalidVarDCTTransform(transform_id as usize))?;
+            let cx = covered_blocks_x(transform_type) as usize;
+            let cy = covered_blocks_y(transform_type) as usize;
+            let shape_id = block_shape_id(transform_type) as usize;
+            let block_size = (cx * BLOCK_DIM, cy * BLOCK_DIM);
+            let block_rect = Rect {
+                origin: (bx * BLOCK_DIM, by * BLOCK_DIM),
+                size: block_size,
+            };
+            let num_blocks = cx * cy;
+            let num_coeffs = num_blocks * BLOCK_SIZE;
+            let log_num_blocks = num_blocks.ilog2() as usize;
+            let pass_info = &hf_global.passes[pass];
+            for c in [1, 0, 2] {
+                if (sbx[c] << hshift[c]) != bx || (sby[c] << vshift[c] != by) {
+                    continue;
+                }
+                trace!(
+                    "Decoding block ({},{}) channel {} with {}x{} block transform {} (shape id {})",
+                    sbx[c], sby[c], c, cx, cy, transform_id, shape_id
+                );
+                let predicted_nzeros = predict_num_nonzeros(&num_nzeros[c], sbx[c], sby[c]);
+                let block_context =
+                    block_context_map.block_context(quant_lf, raw_quant, shape_id, c);
+                let nonzero_context = block_context_map
+                    .nonzero_context(predicted_nzeros, block_context)
+                    + context_offset;
+                let mut nonzeros =
+                    reader.read_unsigned(&pass_info.histograms, br, nonzero_context) as usize;
+                trace!(
+                    "block ({},{},{c}) predicted_nzeros: {predicted_nzeros} \
+                       nzero_ctx: {nonzero_context} (offset: {context_offset}) \
+                       nzeros: {nonzeros}",
+                    sbx[c], sby[c]
+                );
+                if nonzeros + num_blocks > num_coeffs {
+                    return Err(Error::InvalidNumNonZeros(nonzeros, num_blocks));
+                }
+                for iy in 0..cy {
+                    let nzrow = num_nzeros[c].row_mut(sby[c] + iy);
+                    for ix in 0..cx {
+                        nzrow[sbx[c] + ix] = nonzeros.shrc(log_num_blocks) as u32;
+                    }
+                }
+                let histo_offset =
+                    block_context_map.zero_density_context_offset(block_context) + context_offset;
+                let mut prev = if nonzeros > num_coeffs / 16 { 0 } else { 1 };
+                let permutation = &pass_info.coeff_orders[shape_id * 3 + c];
+                let current_coeffs = &mut coeffs[c][coeffs_offset..coeffs_offset + num_coeffs];
+                for k in num_blocks..num_coeffs {
+                    if nonzeros == 0 {
+                        break;
+                    }
+                    let ctx =
+                        histo_offset + zero_density_context(nonzeros, k, log_num_blocks, prev);
+                    let coeff =
+                        reader.read_signed(&pass_info.histograms, br, ctx) << shift_for_pass;
+                    prev = if coeff != 0 { 1 } else { 0 };
+                    nonzeros -= prev;
+                    let coeff_index = permutation[k] as usize;
+                    current_coeffs[coeff_index] += coeff;
+                }
+                if nonzeros != 0 {
+                    return Err(Error::EndOfBlockResidualNonZeros(nonzeros));
+                }
+            }
+            let qblock = [
+                &coeffs[0][coeffs_offset..],
+                &coeffs[1][coeffs_offset..],
+                &coeffs[2][coeffs_offset..],
+            ];
+            let dequant_matrices = &hf_global.dequant_matrices;
+            dequant_and_transform_to_pixels_dispatch(
+                quant_biases,
+                x_dm_multiplier,
+                b_dm_multiplier,
+                pixels,
+                scratch,
+                inv_global_scale,
+                transform_buffer,
+                hshift,
+                vshift,
+                by,
+                sby,
+                bx,
+                sbx,
+                x_cc_mul,
+                b_cc_mul,
+                raw_quant,
+                &lf_rects,
+                transform_type,
+                block_rect,
+                num_blocks,
+                num_coeffs,
+                &qblock,
+                dequant_matrices,
+            )?;
+            coeffs_offset += num_coeffs;
+        }
+    }
+    reader.check_final_state(&hf_global.passes[pass].histograms, br)?;
+    Ok(())
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/mod.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/mod.rs
new file mode 100644
index 0000000..56e6435
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/mod.rs
@@ -0,0 +1,481 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::sync::Arc;
+
+use crate::{
+    bit_reader::BitReader,
+    entropy_coding::decode::Histograms,
+    error::Result,
+    features::{noise::Noise, patches::PatchesDictionary, spline::Splines},
+    headers::{
+        FileHeader,
+        encodings::UnconditionalCoder,
+        extra_channels::ExtraChannelInfo,
+        frame_header::{Encoding, FrameHeader},
+        permutation::Permutation,
+        toc::{Toc, TocNonserialized},
+    },
+    image::Image,
+    util::tracing_wrappers::*,
+};
+use adaptive_lf_smoothing::adaptive_lf_smoothing;
+use block_context_map::BlockContextMap;
+use color_correlation_map::ColorCorrelationParams;
+use modular::{FullModularImage, Tree};
+use quant_weights::DequantMatrices;
+use quantizer::{LfQuantFactors, QuantizerParams};
+
+mod adaptive_lf_smoothing;
+mod block_context_map;
+mod coeff_order;
+pub mod color_correlation_map;
+pub mod decode;
+mod group;
+pub mod modular;
+mod quant_weights;
+pub mod quantizer;
+pub mod render;
+
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub enum Section {
+    LfGlobal,
+    Lf { group: usize },
+    HfGlobal,
+    Hf { group: usize, pass: usize },
+}
+
+pub struct LfGlobalState {
+    patches: Option<Arc<PatchesDictionary>>,
+    splines: Option<Splines>,
+    noise: Option<Noise>,
+    lf_quant: LfQuantFactors,
+    pub quant_params: Option<QuantizerParams>,
+    block_context_map: Option<BlockContextMap>,
+    color_correlation_params: Option<ColorCorrelationParams>,
+    tree: Option<Tree>,
+    modular_global: FullModularImage,
+}
+
+pub struct PassState {
+    coeff_orders: Vec<Permutation>,
+    histograms: Histograms,
+}
+
+pub struct HfGlobalState {
+    num_histograms: u32,
+    passes: Vec<PassState>,
+    dequant_matrices: DequantMatrices,
+    hf_coefficients: Option<(Image<i32>, Image<i32>, Image<i32>)>,
+}
+
+#[derive(Debug)]
+pub struct ReferenceFrame {
+    pub frame: Vec<Image<f32>>,
+    pub saved_before_color_transform: bool,
+}
+
+impl ReferenceFrame {
+    #[cfg(test)]
+    pub fn blank(
+        width: usize,
+        height: usize,
+        num_channels: usize,
+        saved_before_color_transform: bool,
+    ) -> Result<Self> {
+        let frame = (0..num_channels)
+            .map(|_| Image::new((width, height)))
+            .collect::<Result<_>>()?;
+        Ok(Self {
+            frame,
+            saved_before_color_transform,
+        })
+    }
+    #[cfg(test)]
+    pub fn random<R: rand::Rng>(
+        mut rng: &mut R,
+        width: usize,
+        height: usize,
+        num_channels: usize,
+        saved_before_color_transform: bool,
+    ) -> Result<Self> {
+        let frame = (0..num_channels)
+            .map(|_| Image::new_random((width, height), &mut rng))
+            .collect::<Result<_>>()?;
+        Ok(Self {
+            frame,
+            saved_before_color_transform,
+        })
+    }
+}
+
+#[derive(Debug)]
+pub struct DecoderState {
+    pub(super) file_header: FileHeader,
+    pub(super) reference_frames: Arc<[Option<ReferenceFrame>; Self::MAX_STORED_FRAMES]>,
+    pub(super) lf_frames: [Option<[Image<f32>; 3]>; 4],
+    pub xyb_output_linear: bool,
+    // TODO(veluca): do we really need this? ISTM it could be achieved by passing None for all the
+    // buffers, and it's not clear to me what use the decoder can make of it.
+    pub enable_output: bool,
+    pub render_spotcolors: bool,
+    #[cfg(test)]
+    pub use_simple_pipeline: bool,
+    pub visible_frame_index: usize,
+    pub nonvisible_frame_index: usize,
+    pub high_precision: bool,
+}
+
+impl DecoderState {
+    pub const MAX_STORED_FRAMES: usize = 4;
+
+    pub fn new(file_header: FileHeader) -> Self {
+        Self {
+            file_header,
+            reference_frames: Arc::new([None, None, None, None]),
+            lf_frames: [None, None, None, None],
+            xyb_output_linear: true,
+            enable_output: true,
+            render_spotcolors: true,
+            #[cfg(test)]
+            use_simple_pipeline: false,
+            visible_frame_index: 0,
+            nonvisible_frame_index: 0,
+            high_precision: false,
+        }
+    }
+
+    pub fn extra_channel_info(&self) -> &Vec<ExtraChannelInfo> {
+        &self.file_header.image_metadata.extra_channel_info
+    }
+
+    pub fn reference_frame(&self, i: usize) -> Option<&ReferenceFrame> {
+        assert!(i < Self::MAX_STORED_FRAMES);
+        self.reference_frames[i].as_ref()
+    }
+
+    #[cfg(test)]
+    pub fn set_use_simple_pipeline(&mut self, u: bool) {
+        self.use_simple_pipeline = u;
+    }
+}
+
+pub struct HfMetadata {
+    ytox_map: Image<i8>,
+    ytob_map: Image<i8>,
+    pub raw_quant_map: Image<i32>,
+    pub transform_map: Image<u8>,
+    pub epf_map: Image<u8>,
+    used_hf_types: u32,
+}
+
+pub struct Frame {
+    header: FrameHeader,
+    toc: Toc,
+    color_channels: usize,
+    lf_global: Option<LfGlobalState>,
+    hf_global: Option<HfGlobalState>,
+    lf_image: Option<[Image<f32>; 3]>,
+    quant_lf: Image<u8>,
+    hf_meta: Option<HfMetadata>,
+    decoder_state: DecoderState,
+    #[cfg(test)]
+    use_simple_pipeline: bool,
+    #[cfg(test)]
+    render_pipeline: Option<Box<dyn std::any::Any>>,
+    #[cfg(not(test))]
+    render_pipeline: Option<Box<crate::render::LowMemoryRenderPipeline>>,
+    reference_frame_data: Option<Vec<Image<f32>>>,
+    lf_frame_data: Option<[Image<f32>; 3]>,
+    lf_global_was_rendered: bool,
+    /// Reusable buffers for VarDCT group decoding.
+    vardct_buffers: Option<group::VarDctBuffers>,
+}
+
+impl Frame {
+    pub fn new(br: &mut BitReader, decoder_state: DecoderState) -> Result<Self> {
+        let mut frame_header = FrameHeader::read_unconditional(
+            &(),
+            br,
+            &decoder_state.file_header.frame_header_nonserialized(),
+        )?;
+        frame_header.postprocess(&decoder_state.file_header.frame_header_nonserialized());
+        let num_toc_entries = frame_header.num_toc_entries();
+        let toc = Toc::read_unconditional(
+            &(),
+            br,
+            &TocNonserialized {
+                num_entries: num_toc_entries as u32,
+            },
+        )
+        .unwrap();
+        br.jump_to_byte_boundary()?;
+        Self::from_header_and_toc(frame_header, toc, decoder_state)
+    }
+
+    pub fn toc(&self) -> &Toc {
+        &self.toc
+    }
+
+    pub fn header(&self) -> &FrameHeader {
+        &self.header
+    }
+
+    pub fn total_bytes_in_toc(&self) -> usize {
+        self.toc.entries.iter().map(|x| *x as usize).sum()
+    }
+
+    #[instrument(level = "debug", skip(self), ret)]
+    pub fn get_section_idx(&self, section: Section) -> usize {
+        if self.header.num_toc_entries() == 1 {
+            0
+        } else {
+            match section {
+                Section::LfGlobal => 0,
+                Section::Lf { group } => 1 + group,
+                Section::HfGlobal => self.header.num_lf_groups() + 1,
+                Section::Hf { group, pass } => {
+                    2 + self.header.num_lf_groups() + self.header.num_groups() * pass + group
+                }
+            }
+        }
+    }
+
+    pub fn finalize_lf(&mut self) -> Result<()> {
+        if self.header.should_do_adaptive_lf_smoothing() {
+            let lf_global = self.lf_global.as_mut().unwrap();
+            let lf_quant = &lf_global.lf_quant;
+            let inv_quant_lf = lf_global.quant_params.as_mut().unwrap().inv_quant_lf();
+            adaptive_lf_smoothing(
+                [
+                    inv_quant_lf * lf_quant.quant_factors[0],
+                    inv_quant_lf * lf_quant.quant_factors[1],
+                    inv_quant_lf * lf_quant.quant_factors[2],
+                ],
+                self.lf_image.as_mut().unwrap(),
+            )
+        } else {
+            Ok(())
+        }
+    }
+
+    pub fn finalize(mut self) -> Result<Option<DecoderState>> {
+        // First, drop the render pipeline to ensure that no other references to the reference
+        // frames are around.
+        self.render_pipeline = None;
+        if self.header.can_be_referenced {
+            info!("Saving frame in slot {}", self.header.save_as_reference);
+            let rf = Arc::get_mut(&mut self.decoder_state.reference_frames)
+                .expect("remaining references to reference_frames");
+            rf[self.header.save_as_reference as usize] = Some(ReferenceFrame {
+                frame: self.reference_frame_data.unwrap(),
+                saved_before_color_transform: self.header.save_before_ct,
+            });
+        }
+
+        if self.header.lf_level != 0 {
+            self.decoder_state.lf_frames[(self.header.lf_level - 1) as usize] = self.lf_frame_data;
+        }
+        let decoder_state = if self.header.is_last {
+            None
+        } else {
+            Some(self.decoder_state)
+        };
+        Ok(decoder_state)
+    }
+
+    fn modular_color_channels(&self) -> usize {
+        if self.header.encoding == Encoding::VarDCT {
+            0
+        } else {
+            self.color_channels
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use std::panic;
+
+    use crate::{
+        error::{Error, Result},
+        features::spline::Point,
+        util::test::assert_almost_abs_eq,
+    };
+    use test_log::test;
+
+    use super::Frame;
+
+    fn decode(
+        bytes: &[u8],
+        verify: impl Fn(&Frame, usize) -> Result<()> + 'static,
+    ) -> Result<usize> {
+        crate::api::tests::decode(bytes, usize::MAX, false, Some(Box::new(verify))).map(|x| x.0)
+    }
+
+    #[test]
+    fn splines() -> Result<(), Error> {
+        let verify_frame = move |frame: &Frame, _| {
+            let lf_global = frame.lf_global.as_ref().unwrap();
+            let splines = lf_global.splines.as_ref().unwrap();
+            assert_eq!(splines.quantization_adjustment, 0);
+            let expected_starting_points = [Point { x: 9.0, y: 54.0 }].to_vec();
+            assert_eq!(splines.starting_points, expected_starting_points);
+            assert_eq!(splines.splines.len(), 1);
+            let spline = splines.splines[0].clone();
+            let expected_control_points = [
+                (109, 105),
+                (-130, -261),
+                (-66, 193),
+                (227, -52),
+                (-170, 290),
+            ]
+            .to_vec();
+            assert_eq!(spline.control_points.clone(), expected_control_points);
+
+            const EXPECTED_COLOR_DCT: [[i32; 32]; 3] = [
+                {
+                    let mut row = [0; 32];
+                    row[0] = 168;
+                    row[1] = 119;
+                    row
+                },
+                {
+                    let mut row = [0; 32];
+                    row[0] = 9;
+                    row[2] = 7;
+                    row
+                },
+                {
+                    let mut row = [0; 32];
+                    row[0] = -10;
+                    row[1] = 7;
+                    row
+                },
+            ];
+            assert_eq!(spline.color_dct, EXPECTED_COLOR_DCT);
+            const EXPECTED_SIGMA_DCT: [i32; 32] = {
+                let mut dct = [0; 32];
+                dct[0] = 4;
+                dct[7] = 2;
+                dct
+            };
+            assert_eq!(spline.sigma_dct, EXPECTED_SIGMA_DCT);
+            Ok(())
+        };
+        assert_eq!(
+            decode(
+                include_bytes!("../../resources/test/splines.jxl"),
+                verify_frame
+            )?,
+            1
+        );
+        Ok(())
+    }
+
+    #[test]
+    fn noise() -> Result<(), Error> {
+        let verify_frame = |frame: &Frame, _| {
+            let lf_global = frame.lf_global.as_ref().unwrap();
+            let noise = lf_global.noise.as_ref().unwrap();
+            let want_noise = [
+                0.000000, 0.000977, 0.002930, 0.003906, 0.005859, 0.006836, 0.008789, 0.010742,
+            ];
+            for (index, noise_param) in want_noise.iter().enumerate() {
+                assert_almost_abs_eq(noise.lut[index], *noise_param, 1e-6);
+            }
+            Ok(())
+        };
+        assert_eq!(
+            decode(
+                include_bytes!("../../resources/test/8x8_noise.jxl"),
+                verify_frame,
+            )?,
+            1
+        );
+        Ok(())
+    }
+
+    #[test]
+    fn patches() -> Result<(), Error> {
+        let verify_frame = |frame: &Frame, frame_index| {
+            if frame_index == 0 {
+                assert!(!frame.header().has_patches());
+                assert!(frame.header().can_be_referenced);
+            } else if frame_index == 1 {
+                assert!(frame.header().has_patches());
+                assert!(!frame.header().can_be_referenced);
+            }
+            Ok(())
+        };
+        assert_eq!(
+            decode(
+                include_bytes!("../../resources/test/grayscale_patches_modular.jxl"),
+                verify_frame,
+            )?,
+            2
+        );
+        Ok(())
+    }
+
+    #[test]
+    fn multiple_lf_420() -> Result<(), Error> {
+        let verify_frame = |frame: &Frame, _| {
+            assert!(frame.header().is420());
+            let Some(lf_image) = &frame.lf_image else {
+                panic!("no lf_image");
+            };
+            for y in 0..146 {
+                let sample_cb_row = lf_image[0].row(y);
+                let sample_cr_row = lf_image[2].row(y);
+                for x in 0..146 {
+                    let sample_cb = sample_cb_row[x];
+                    let sample_cr = sample_cr_row[x];
+                    let no_chroma = sample_cb == 0.0 && sample_cr == 0.0;
+                    if y < 128 || x < 128 {
+                        assert!(!no_chroma);
+                    } else {
+                        assert!(no_chroma);
+                    }
+                }
+            }
+            Ok(())
+        };
+        decode(
+            include_bytes!("../../resources/test/multiple_lf_420.jxl"),
+            verify_frame,
+        )?;
+        Ok(())
+    }
+
+    #[test]
+    fn xyb_grayscale_patches() -> Result<(), Error> {
+        let verify_frame = |frame: &Frame, frame_index| {
+            if frame_index == 0 {
+                assert_eq!(
+                    frame.header.frame_type,
+                    crate::headers::frame_header::FrameType::ReferenceOnly,
+                );
+                assert_eq!(
+                    frame.header.encoding,
+                    crate::headers::frame_header::Encoding::Modular,
+                );
+                assert_eq!(frame.modular_color_channels(), 3);
+            } else {
+                assert!(frame.header.has_patches());
+                assert_eq!(frame.modular_color_channels(), 0);
+            }
+            Ok(())
+        };
+        assert_eq!(
+            decode(
+                include_bytes!("../../resources/test/grayscale_patches_var_dct.jxl"),
+                verify_frame,
+            )?,
+            2
+        );
+        Ok(())
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/borrowed_buffers.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/borrowed_buffers.rs
new file mode 100644
index 0000000..098f236
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/borrowed_buffers.rs
@@ -0,0 +1,48 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::{cell::RefMut, ops::DerefMut};
+
+use crate::{
+    error::Result,
+    frame::modular::{IMAGE_OFFSET, IMAGE_PADDING},
+    image::Image,
+};
+
+use super::{ModularBufferInfo, ModularChannel};
+
+pub fn with_buffers<T>(
+    buffers: &[ModularBufferInfo],
+    indices: &[usize],
+    grid: usize,
+    skip_empty: bool,
+    f: impl FnOnce(Vec<&mut ModularChannel>) -> Result<T>,
+) -> Result<T> {
+    let mut bufs = vec![];
+    for i in indices {
+        // Allocate buffers if they are not present.
+        let buf = &buffers[*i];
+        let b = &buf.buffer_grid[grid];
+        let mut data = b.data.borrow_mut();
+        if data.is_none() {
+            *data = Some(ModularChannel {
+                data: Image::new_with_padding(b.size, IMAGE_OFFSET, IMAGE_PADDING)?,
+                auxiliary_data: None,
+                shift: buf.info.shift,
+                bit_depth: buf.info.bit_depth,
+            });
+        }
+
+        // Skip zero-sized buffers when decoding - they don't contribute to the bitstream.
+        // This matches libjxl's behavior in DecodeGroup where zero-sized rects are skipped.
+        // The buffer is still allocated above so transforms can access it.
+        if skip_empty && (b.size.0 == 0 || b.size.1 == 0) {
+            continue;
+        }
+
+        bufs.push(RefMut::map(data, |x| x.as_mut().unwrap()));
+    }
+    f(bufs.iter_mut().map(|x| x.deref_mut()).collect())
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/decode/bitstream.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/decode/bitstream.rs
new file mode 100644
index 0000000..930603f
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/decode/bitstream.rs
@@ -0,0 +1,95 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use super::channel::decode_modular_channel;
+use crate::{
+    bit_reader::BitReader,
+    entropy_coding::decode::SymbolReader,
+    error::{Error, Result},
+    frame::modular::{ModularChannel, Tree, transforms::apply::meta_apply_local_transforms},
+    headers::{JxlHeader, modular::GroupHeader},
+};
+
+// This function will decode a header and apply local transforms if a header is not given.
+// The intended use of passing a header is for the DcGlobal section.
+pub fn decode_modular_subbitstream(
+    buffers: Vec<&mut ModularChannel>,
+    stream_id: usize,
+    header: Option<GroupHeader>,
+    global_tree: &Option<Tree>,
+    br: &mut BitReader,
+) -> Result<()> {
+    // Skip decoding if all grids are zero-sized.
+    let is_empty = buffers
+        .iter()
+        .all(|buffer| matches!(buffer.data.size(), (0, _) | (_, 0)));
+    if is_empty {
+        return Ok(());
+    }
+    let mut transform_steps = vec![];
+    let mut buffer_storage = vec![];
+
+    let buffers = buffers.into_iter().collect::<Vec<_>>();
+    let (header, mut buffers) = match header {
+        Some(h) => (h, buffers),
+        None => {
+            let h = GroupHeader::read(br)?;
+            if !h.transforms.is_empty() {
+                // Note: reassigning to `buffers` here convinces the borrow checker that the borrow of
+                // `buffer_storage` ought to outlive `buffers[..]`'s lifetime, which obviously breaks
+                // applying transforms later.
+                let new_bufs;
+                (new_bufs, transform_steps) =
+                    meta_apply_local_transforms(buffers, &mut buffer_storage, &h)?;
+                (h, new_bufs)
+            } else {
+                (h, buffers)
+            }
+        }
+    };
+
+    if header.use_global_tree && global_tree.is_none() {
+        return Err(Error::NoGlobalTree);
+    }
+    let local_tree = if !header.use_global_tree {
+        let num_local_samples = buffers
+            .iter()
+            .map(|buf| {
+                let (width, height) = buf.channel_info().size;
+                width * height
+            })
+            .sum::<usize>();
+        let size_limit = (1024 + num_local_samples).min(1 << 20);
+        Some(Tree::read(br, size_limit)?)
+    } else {
+        None
+    };
+    let tree = if header.use_global_tree {
+        global_tree.as_ref().unwrap()
+    } else {
+        local_tree.as_ref().unwrap()
+    };
+
+    let image_width = buffers
+        .iter()
+        .map(|info| info.channel_info().size.0)
+        .max()
+        .unwrap_or(0);
+    let mut reader = SymbolReader::new(&tree.histograms, br, Some(image_width))?;
+
+    for i in 0..buffers.len() {
+        decode_modular_channel(&mut buffers, i, stream_id, &header, tree, &mut reader, br)?;
+    }
+
+    reader.check_final_state(&tree.histograms, br)?;
+
+    drop(buffers);
+
+    for step in transform_steps.iter().rev() {
+        step.local_apply(&mut buffer_storage)?;
+    }
+
+    Ok(())
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/decode/channel.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/decode/channel.rs
new file mode 100644
index 0000000..daf031856
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/decode/channel.rs
@@ -0,0 +1,205 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use super::common::precompute_references;
+use crate::{
+    bit_reader::BitReader,
+    entropy_coding::decode::{Histograms, SymbolReader},
+    error::Result,
+    frame::modular::{
+        IMAGE_OFFSET, IMAGE_PADDING, ModularChannel, Tree,
+        decode::{
+            common::make_pixel,
+            specialized_trees::{TreeSpecialCase, specialize_tree},
+        },
+        predict::{PredictionData, WeightedPredictorState},
+        tree::{NUM_NONREF_PROPERTIES, PROPERTIES_PER_PREVCHAN, predict},
+    },
+    headers::modular::GroupHeader,
+    image::Image,
+    util::tracing_wrappers::*,
+};
+
+const SMALL_CHANNEL_THRESHOLD: usize = 64;
+
+// General case decoder, for small buffers for which it's not worth trying to detect tree special cases.
+#[inline(never)]
+fn decode_modular_channel_small(
+    buffers: &mut [&mut ModularChannel],
+    chan: usize,
+    stream_id: usize,
+    header: &GroupHeader,
+    tree: &Tree,
+    reader: &mut SymbolReader,
+    br: &mut BitReader,
+) -> Result<()> {
+    let size = buffers[chan].data.size();
+    let mut wp_state = WeightedPredictorState::new(&header.wp_header, size.0);
+    let mut num_ref_props = tree
+        .max_property_count()
+        .saturating_sub(NUM_NONREF_PROPERTIES);
+    // The precompute_references function stores 4 values per reference property (offset + 0,1,2,3)
+    num_ref_props = num_ref_props.div_ceil(PROPERTIES_PER_PREVCHAN) * PROPERTIES_PER_PREVCHAN;
+    let mut references = Image::<i32>::new((num_ref_props, size.0))?;
+    let num_properties = NUM_NONREF_PROPERTIES + num_ref_props;
+
+    const { assert!(IMAGE_OFFSET.1 == 2) };
+
+    for y in 0..size.1 {
+        precompute_references(buffers, chan, y, &mut references);
+        let mut property_buffer: Vec<i32> = vec![0; num_properties];
+        property_buffer[0] = chan as i32;
+        property_buffer[1] = stream_id as i32;
+        let [row, row_top, row_toptop] =
+            buffers[chan].data.distinct_full_rows_mut([y + 2, y + 1, y]);
+        let row = &mut row[IMAGE_OFFSET.0..IMAGE_OFFSET.0 + size.0];
+        let row_top = &mut row_top[IMAGE_OFFSET.0..IMAGE_OFFSET.0 + size.0];
+        let row_toptop = &mut row_toptop[IMAGE_OFFSET.0..IMAGE_OFFSET.0 + size.0];
+        for x in 0..size.0 {
+            let prediction_data = PredictionData::get_rows(row, row_top, row_toptop, x, y);
+            let prediction_result = predict(
+                &tree.nodes,
+                prediction_data,
+                size.0,
+                Some(&mut wp_state),
+                x,
+                y,
+                &references,
+                &mut property_buffer,
+            );
+            let dec = reader.read_signed(&tree.histograms, br, prediction_result.context as usize);
+            let val = make_pixel(dec, prediction_result.multiplier, prediction_result.guess);
+            row[x] = val;
+            wp_state.update_errors(val, (x, y), size.0);
+        }
+    }
+
+    Ok(())
+}
+
+pub(super) trait ModularChannelDecoder {
+    const NEEDS_TOP: bool;
+    const NEEDS_TOPTOP: bool;
+    fn init_row(&mut self, buffers: &mut [&mut ModularChannel], chan: usize, y: usize);
+    fn decode_one(
+        &mut self,
+        prediction_data: PredictionData,
+        pos: (usize, usize),
+        xsize: usize,
+        reader: &mut SymbolReader,
+        br: &mut BitReader,
+        histograms: &Histograms,
+    ) -> i32;
+}
+
+#[inline(never)]
+fn decode_modular_channel_impl<D: ModularChannelDecoder>(
+    buffers: &mut [&mut ModularChannel],
+    chan: usize,
+    mut decoder: D,
+    reader: &mut SymbolReader,
+    br: &mut BitReader,
+    histograms: &Histograms,
+) -> Result<()> {
+    let size = buffers[chan].data.size();
+    debug_assert!(size.0 >= 4);
+    debug_assert!(size.1 >= 2);
+
+    const { assert!(IMAGE_OFFSET.1 == 2) };
+
+    // Let the compiler decide whether inlining in the borders is worth it.
+    let do_decode_cold =
+        |decoder: &mut D, prediction_data, pos, reader: &mut SymbolReader, br: &mut BitReader| {
+            decoder.decode_one(prediction_data, pos, size.0, reader, br, histograms)
+        };
+
+    for y in 0..size.1 {
+        decoder.init_row(buffers, chan, y);
+        let [row, row_top, row_toptop] =
+            buffers[chan].data.distinct_full_rows_mut([y + 2, y + 1, y]);
+        let row = &mut row[IMAGE_OFFSET.0..IMAGE_OFFSET.0 + size.0];
+        let row_top = &mut row_top[IMAGE_OFFSET.0..IMAGE_OFFSET.0 + size.0];
+        let row_toptop = &mut row_toptop[IMAGE_OFFSET.0..IMAGE_OFFSET.0 + size.0];
+        let mut last = 0;
+        let mut prediction_data = PredictionData::default();
+        for x in 0..2 {
+            prediction_data = PredictionData::get_rows(row, row_top, row_toptop, x, y);
+            let val = do_decode_cold(&mut decoder, prediction_data, (x, y), reader, br);
+            row[x] = val;
+            last = val;
+        }
+        if y < 2 {
+            for x in 2..size.0 - 2 {
+                let prediction_data = PredictionData::get_rows(row, row_top, row_toptop, x, y);
+                let val = do_decode_cold(&mut decoder, prediction_data, (x, y), reader, br);
+                row[x] = val;
+            }
+        } else {
+            for (x, r) in row.iter_mut().enumerate().skip(2).take(size.0 - 4) {
+                prediction_data = prediction_data.update_for_interior_row(
+                    row_top,
+                    row_toptop,
+                    x,
+                    last,
+                    D::NEEDS_TOP,
+                    D::NEEDS_TOPTOP,
+                );
+                let val =
+                    decoder.decode_one(prediction_data, (x, y), size.0, reader, br, histograms);
+                *r = val;
+                last = val;
+            }
+        }
+        for x in size.0 - 2..size.0 {
+            prediction_data = PredictionData::get_rows(row, row_top, row_toptop, x, y);
+            let val = do_decode_cold(&mut decoder, prediction_data, (x, y), reader, br);
+            row[x] = val;
+        }
+    }
+    Ok(())
+}
+
+#[allow(clippy::too_many_arguments)]
+#[instrument(level = "debug", skip(buffers, reader, tree))]
+pub(super) fn decode_modular_channel(
+    buffers: &mut [&mut ModularChannel],
+    chan: usize,
+    stream_id: usize,
+    header: &GroupHeader,
+    tree: &Tree,
+    reader: &mut SymbolReader,
+    br: &mut BitReader,
+) -> Result<()> {
+    debug!("reading channel");
+    let size = buffers[chan].data.size();
+    if size.0 <= IMAGE_PADDING.0
+        || size.1 <= IMAGE_PADDING.1
+        || size.0 * size.1 <= SMALL_CHANNEL_THRESHOLD
+    {
+        return decode_modular_channel_small(buffers, chan, stream_id, header, tree, reader, br);
+    }
+
+    assert_eq!(buffers[chan].data.padding().1, IMAGE_PADDING.1);
+    assert!(buffers[chan].data.padding().0 >= IMAGE_PADDING.0);
+    assert_eq!(buffers[chan].data.offset(), IMAGE_OFFSET);
+
+    // We now know the channel has size at least IMAGE_PADDING.
+
+    let special_tree = specialize_tree(tree, chan, stream_id, size.0, header)?;
+    match special_tree {
+        TreeSpecialCase::NoWp(t) => {
+            decode_modular_channel_impl(buffers, chan, t, reader, br, &tree.histograms)
+        }
+        TreeSpecialCase::WpOnly(t) => {
+            decode_modular_channel_impl(buffers, chan, t, reader, br, &tree.histograms)
+        }
+        TreeSpecialCase::SingleGradientOnly(t) => {
+            decode_modular_channel_impl(buffers, chan, t, reader, br, &tree.histograms)
+        }
+        TreeSpecialCase::General(t) => {
+            decode_modular_channel_impl(buffers, chan, t, reader, br, &tree.histograms)
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/decode/common.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/decode/common.rs
new file mode 100644
index 0000000..e3107af
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/decode/common.rs
@@ -0,0 +1,87 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{
+    frame::{
+        modular::{ModularChannel, predict::clamped_gradient},
+        quantizer::NUM_QUANT_TABLES,
+    },
+    headers::frame_header::FrameHeader,
+    image::Image,
+};
+use num_traits::abs;
+
+#[derive(Debug)]
+pub enum ModularStreamId {
+    GlobalData,
+    VarDCTLF(usize),
+    ModularLF(usize),
+    LFMeta(usize),
+    QuantTable(usize),
+    ModularHF { pass: usize, group: usize },
+}
+
+impl ModularStreamId {
+    pub fn get_id(&self, frame_header: &FrameHeader) -> usize {
+        match self {
+            Self::GlobalData => 0,
+            Self::VarDCTLF(g) => 1 + g,
+            Self::ModularLF(g) => 1 + frame_header.num_lf_groups() + g,
+            Self::LFMeta(g) => 1 + frame_header.num_lf_groups() * 2 + g,
+            Self::QuantTable(q) => 1 + frame_header.num_lf_groups() * 3 + q,
+            Self::ModularHF { pass, group } => {
+                1 + frame_header.num_lf_groups() * 3
+                    + NUM_QUANT_TABLES
+                    + frame_header.num_groups() * *pass
+                    + *group
+            }
+        }
+    }
+}
+
+pub(super) fn precompute_references(
+    buffers: &mut [&mut ModularChannel],
+    chan: usize,
+    y: usize,
+    references: &mut Image<i32>,
+) {
+    references.fill(0);
+    let mut offset = 0;
+    let num_extra_props = references.size().0;
+    for i in 0..chan {
+        if offset >= num_extra_props {
+            break;
+        }
+        let j = chan - i - 1;
+        if buffers[j].data.size() != buffers[chan].data.size()
+            || buffers[j].shift != buffers[chan].shift
+        {
+            continue;
+        }
+        let ref_chan_row = buffers[j].data.row(y);
+        let ref_chan_prev = buffers[j].data.row(y.saturating_sub(1));
+        for x in 0..buffers[chan].data.size().0 {
+            let ref_row = references.row_mut(x);
+            let v = ref_chan_row[x];
+            ref_row[offset] = abs(v);
+            ref_row[offset + 1] = v;
+            let vleft = if x > 0 { ref_chan_row[x - 1] } else { 0 };
+            let vtop = if y > 0 { ref_chan_prev[x] } else { vleft };
+            let vtopleft = if x > 0 && y > 0 {
+                ref_chan_prev[x - 1]
+            } else {
+                vleft
+            };
+            let vpredicted = clamped_gradient(vleft as i64, vtop as i64, vtopleft as i64);
+            ref_row[offset + 2] = abs(v as i64 - vpredicted) as i32;
+            ref_row[offset + 3] = (v as i64 - vpredicted) as i32;
+        }
+        offset += 4;
+    }
+}
+
+pub(super) fn make_pixel(dec: i32, mul: u32, guess: i64) -> i32 {
+    (guess + (mul as i64) * (dec as i64)) as i32
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/decode/mod.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/decode/mod.rs
new file mode 100644
index 0000000..3a3e510e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/decode/mod.rs
@@ -0,0 +1,12 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+mod bitstream;
+mod channel;
+mod common;
+mod specialized_trees;
+
+pub use bitstream::decode_modular_subbitstream;
+pub use common::ModularStreamId;
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/decode/specialized_trees.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/decode/specialized_trees.rs
new file mode 100644
index 0000000..415ac3a7
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/decode/specialized_trees.rs
@@ -0,0 +1,383 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::{collections::VecDeque, ops::Range};
+
+use crate::{
+    bit_reader::BitReader,
+    entropy_coding::decode::{Histograms, SymbolReader},
+    error::Result,
+    frame::modular::{
+        ModularChannel, Predictor, Tree,
+        decode::{
+            channel::ModularChannelDecoder,
+            common::{make_pixel, precompute_references},
+        },
+        predict::{PredictionData, WeightedPredictorState},
+        tree::{NUM_NONREF_PROPERTIES, PROPERTIES_PER_PREVCHAN, TreeNode, predict},
+    },
+    headers::modular::GroupHeader,
+    image::Image,
+};
+
+// TODO(veluca): we probably want to make flatter trees eventually.
+
+pub struct NoWpTree {
+    nodes: Vec<TreeNode>,
+    references: Image<i32>,
+    property_buffer: Vec<i32>,
+}
+
+impl NoWpTree {
+    fn new(
+        nodes: Vec<TreeNode>,
+        max_property_count: usize,
+        channel: usize,
+        stream: usize,
+        xsize: usize,
+    ) -> Result<Self> {
+        let num_ref_props = max_property_count
+            .saturating_sub(NUM_NONREF_PROPERTIES)
+            .next_multiple_of(PROPERTIES_PER_PREVCHAN);
+        let references = Image::<i32>::new((num_ref_props, xsize))?;
+        let num_properties = NUM_NONREF_PROPERTIES + num_ref_props;
+        let mut property_buffer: Vec<i32> = vec![0; num_properties];
+
+        property_buffer[0] = channel as i32;
+        property_buffer[1] = stream as i32;
+
+        Ok(Self {
+            nodes,
+            references,
+            property_buffer,
+        })
+    }
+}
+
+impl ModularChannelDecoder for NoWpTree {
+    const NEEDS_TOP: bool = true;
+    const NEEDS_TOPTOP: bool = true;
+
+    fn init_row(&mut self, buffers: &mut [&mut ModularChannel], chan: usize, y: usize) {
+        precompute_references(buffers, chan, y, &mut self.references);
+        self.property_buffer[2..].fill(0);
+    }
+
+    fn decode_one(
+        &mut self,
+        prediction_data: PredictionData,
+        pos: (usize, usize),
+        xsize: usize,
+        reader: &mut SymbolReader,
+        br: &mut BitReader,
+        histograms: &Histograms,
+    ) -> i32 {
+        let prediction_result = predict(
+            &self.nodes,
+            prediction_data,
+            xsize,
+            None,
+            pos.0,
+            pos.1,
+            &self.references,
+            &mut self.property_buffer,
+        );
+        let dec = reader.read_signed(histograms, br, prediction_result.context as usize);
+        make_pixel(dec, prediction_result.multiplier, prediction_result.guess)
+    }
+}
+
+pub struct GeneralTree {
+    no_wp_tree: NoWpTree,
+    wp_state: WeightedPredictorState,
+}
+
+impl GeneralTree {
+    fn new(
+        nodes: Vec<TreeNode>,
+        max_property_count: usize,
+        header: &GroupHeader,
+        channel: usize,
+        stream: usize,
+        xsize: usize,
+    ) -> Result<Self> {
+        let wp_state = WeightedPredictorState::new(&header.wp_header, xsize);
+        Ok(Self {
+            no_wp_tree: NoWpTree::new(nodes, max_property_count, channel, stream, xsize)?,
+            wp_state,
+        })
+    }
+}
+
+impl ModularChannelDecoder for GeneralTree {
+    const NEEDS_TOP: bool = true;
+    const NEEDS_TOPTOP: bool = true;
+
+    fn init_row(&mut self, buffers: &mut [&mut ModularChannel], chan: usize, y: usize) {
+        self.no_wp_tree.init_row(buffers, chan, y);
+    }
+
+    fn decode_one(
+        &mut self,
+        prediction_data: PredictionData,
+        pos: (usize, usize),
+        xsize: usize,
+        reader: &mut SymbolReader,
+        br: &mut BitReader,
+        histograms: &Histograms,
+    ) -> i32 {
+        let prediction_result = predict(
+            &self.no_wp_tree.nodes,
+            prediction_data,
+            xsize,
+            Some(&mut self.wp_state),
+            pos.0,
+            pos.1,
+            &self.no_wp_tree.references,
+            &mut self.no_wp_tree.property_buffer,
+        );
+        let dec = reader.read_signed(histograms, br, prediction_result.context as usize);
+        let val = make_pixel(dec, prediction_result.multiplier, prediction_result.guess);
+        self.wp_state.update_errors(val, pos, xsize);
+        val
+    }
+}
+
+const LUT_MAX_SPLITVAL: i32 = 1023;
+const LUT_MIN_SPLITVAL: i32 = -1024;
+const LUT_TABLE_SIZE: usize = (LUT_MAX_SPLITVAL - LUT_MIN_SPLITVAL + 1) as usize;
+const _: () = assert!(LUT_TABLE_SIZE.is_power_of_two());
+
+pub struct WpOnlyLookup {
+    lut: [u8; LUT_TABLE_SIZE], // Lookup (wp value -> *clustered* context id)
+    wp_state: WeightedPredictorState,
+}
+
+fn make_lut(tree: &[TreeNode], histograms: &Histograms) -> Option<[u8; LUT_TABLE_SIZE]> {
+    struct RangeAndNode {
+        range: Range<i32>,
+        node: u32,
+    }
+    let mut stack = vec![RangeAndNode {
+        range: LUT_MIN_SPLITVAL..LUT_MAX_SPLITVAL + 1,
+        node: 0,
+    }];
+
+    let mut ans = [0u8; LUT_TABLE_SIZE];
+    while let Some(RangeAndNode { range, node }) = stack.pop() {
+        let v = tree[node as usize];
+        match v {
+            TreeNode::Split {
+                val, left, right, ..
+            } => {
+                let first_left = val + 1;
+                if first_left >= range.end || first_left <= range.start {
+                    return None;
+                }
+                stack.push(RangeAndNode {
+                    range: first_left..range.end,
+                    node: left,
+                });
+                stack.push(RangeAndNode {
+                    range: range.start..first_left,
+                    node: right,
+                });
+            }
+            TreeNode::Leaf {
+                offset,
+                multiplier,
+                id,
+                ..
+            } => {
+                if offset != 0 || multiplier != 1 {
+                    return None;
+                }
+                let start = range.start - LUT_MIN_SPLITVAL;
+                let end = range.end - LUT_MIN_SPLITVAL;
+                ans[start as usize..end as usize]
+                    .fill(histograms.map_context_to_cluster(id as usize) as u8);
+            }
+        }
+    }
+
+    Some(ans)
+}
+
+impl WpOnlyLookup {
+    fn new(
+        tree: &[TreeNode],
+        histograms: &Histograms,
+        header: &GroupHeader,
+        xsize: usize,
+    ) -> Option<Self> {
+        let wp_state = WeightedPredictorState::new(&header.wp_header, xsize);
+        let lut = make_lut(tree, histograms)?;
+        Some(Self { lut, wp_state })
+    }
+}
+
+impl ModularChannelDecoder for WpOnlyLookup {
+    const NEEDS_TOP: bool = true;
+    const NEEDS_TOPTOP: bool = true;
+
+    fn init_row(&mut self, _buffers: &mut [&mut ModularChannel], _chan: usize, _y: usize) {
+        // nothing to do
+    }
+
+    #[inline(always)]
+    fn decode_one(
+        &mut self,
+        prediction_data: PredictionData,
+        pos: (usize, usize),
+        xsize: usize,
+        reader: &mut SymbolReader,
+        br: &mut BitReader,
+        histograms: &Histograms,
+    ) -> i32 {
+        let (wp_pred, property) = self
+            .wp_state
+            .predict_and_property(pos, xsize, &prediction_data);
+        let ctx =
+            self.lut[(property - LUT_MIN_SPLITVAL).clamp(0, LUT_TABLE_SIZE as i32 - 1) as usize];
+        let dec = reader.read_signed_clustered(histograms, br, ctx as usize);
+        let val = dec + wp_pred as i32;
+        self.wp_state.update_errors(val, pos, xsize);
+        val
+    }
+}
+
+pub struct SingleGradientOnly {
+    ctx: usize,
+}
+
+impl ModularChannelDecoder for SingleGradientOnly {
+    const NEEDS_TOP: bool = true;
+    const NEEDS_TOPTOP: bool = false;
+
+    fn init_row(&mut self, _: &mut [&mut ModularChannel], _: usize, _: usize) {}
+
+    #[inline(always)]
+    fn decode_one(
+        &mut self,
+        prediction_data: PredictionData,
+        _: (usize, usize),
+        _: usize,
+        reader: &mut SymbolReader,
+        br: &mut BitReader,
+        histograms: &Histograms,
+    ) -> i32 {
+        let pred = Predictor::Gradient.predict_one(prediction_data, 0);
+        let dec = reader.read_signed(histograms, br, self.ctx);
+        make_pixel(dec, 1, pred)
+    }
+}
+
+#[allow(clippy::large_enum_variant)]
+pub enum TreeSpecialCase {
+    NoWp(NoWpTree),
+    WpOnly(WpOnlyLookup),
+    SingleGradientOnly(SingleGradientOnly),
+    General(GeneralTree),
+}
+
+pub fn specialize_tree(
+    tree: &Tree,
+    channel: usize,
+    stream: usize,
+    xsize: usize,
+    header: &GroupHeader,
+) -> Result<TreeSpecialCase> {
+    // TODO(veluca): consider skipping the pruning if header.uses_global_tree is true.
+    let mut pruned_tree = Vec::new();
+    let mut queue = VecDeque::new();
+    pruned_tree.try_reserve(tree.nodes.len())?;
+    queue.try_reserve(tree.nodes.len())?;
+    queue.push_front(0);
+
+    let mut uses_wp = false;
+    let mut uses_non_wp = false;
+
+    // Obtain a pruned tree without nodes that are not relevant in the current channel and stream.
+    // Proceed in BFS order, so that we know that the children of  anode will be adjacent.
+    while let Some(v) = queue.pop_front() {
+        let node = tree.nodes[v as usize];
+        match node {
+            TreeNode::Split {
+                property,
+                val,
+                left,
+                right,
+            } if property < 2 => {
+                // If the node splits on static properties, re-enqueue its correct child immediately.
+                let vv = if property == 0 { channel } else { stream };
+                queue.push_front(if vv as i32 > val { left } else { right });
+                continue;
+            }
+            TreeNode::Split {
+                property,
+                val,
+                left,
+                right,
+            } => {
+                // WeightedPredictor property.
+                uses_wp |= property == 15;
+                uses_non_wp |= property != 15;
+                let base = (queue.len() + pruned_tree.len() + 1) as u32;
+                pruned_tree.push(TreeNode::Split {
+                    property,
+                    val,
+                    left: base,
+                    right: base + 1,
+                });
+                queue.push_back(left);
+                queue.push_back(right);
+            }
+            TreeNode::Leaf { predictor, .. } => {
+                uses_wp |= predictor == Predictor::Weighted;
+                uses_non_wp |= predictor != Predictor::Weighted;
+                pruned_tree.push(node);
+            }
+        }
+    }
+
+    if let [
+        TreeNode::Leaf {
+            predictor: Predictor::Gradient,
+            multiplier: 1,
+            offset: 0,
+            id,
+        },
+    ] = &*pruned_tree
+    {
+        return Ok(TreeSpecialCase::SingleGradientOnly(SingleGradientOnly {
+            ctx: *id as usize,
+        }));
+    }
+
+    if !uses_non_wp
+        && let Some(wp) = WpOnlyLookup::new(&pruned_tree, &tree.histograms, header, xsize)
+    {
+        return Ok(TreeSpecialCase::WpOnly(wp));
+    }
+
+    if !uses_wp {
+        return Ok(TreeSpecialCase::NoWp(NoWpTree::new(
+            pruned_tree,
+            tree.max_property_count(),
+            channel,
+            stream,
+            xsize,
+        )?));
+    }
+
+    Ok(TreeSpecialCase::General(GeneralTree::new(
+        pruned_tree,
+        tree.max_property_count(),
+        header,
+        channel,
+        stream,
+        xsize,
+    )?))
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/mod.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/mod.rs
new file mode 100644
index 0000000..8f36b29
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/mod.rs
@@ -0,0 +1,851 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::{cell::RefCell, cmp::min, fmt::Debug};
+
+use crate::{
+    bit_reader::BitReader,
+    error::{Error, Result},
+    frame::{
+        ColorCorrelationParams, HfMetadata,
+        block_context_map::BlockContextMap,
+        quantizer::{self, LfQuantFactors, QuantizerParams},
+    },
+    headers::{
+        ImageMetadata, JxlHeader, bit_depth::BitDepth, frame_header::FrameHeader,
+        modular::GroupHeader,
+    },
+    image::{Image, Rect},
+    util::{CeilLog2, tracing_wrappers::*},
+};
+use jxl_transforms::transform_map::*;
+
+mod borrowed_buffers;
+pub(crate) mod decode;
+mod predict;
+mod transforms;
+mod tree;
+
+use borrowed_buffers::with_buffers;
+pub use decode::ModularStreamId;
+use decode::decode_modular_subbitstream;
+pub use predict::Predictor;
+use transforms::{TransformStepChunk, make_grids};
+pub use tree::Tree;
+
+// Two rows on top, two pixels to the left, two pixels to the right.
+const IMAGE_PADDING: (usize, usize) = (4, 2);
+const IMAGE_OFFSET: (usize, usize) = (2, 2);
+
+#[derive(Clone, PartialEq, Eq, Copy)]
+struct ChannelInfo {
+    // The index of the output channel in the render pipeline, or -1 for non-output channels.
+    output_channel_idx: isize,
+    // width, height
+    size: (usize, usize),
+    shift: Option<(usize, usize)>, // None for meta-channels
+    bit_depth: BitDepth,
+}
+
+impl Debug for ChannelInfo {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{}x{}", self.size.0, self.size.1)?;
+        if let Some(shift) = self.shift {
+            write!(f, "(shift {},{})", shift.0, shift.1)?;
+        } else {
+            write!(f, "(meta)")?;
+        }
+        write!(f, "{:?}", self.bit_depth)?;
+        if self.output_channel_idx >= 0 {
+            write!(f, "(output channel {})", self.output_channel_idx)?;
+        }
+        Ok(())
+    }
+}
+
+impl ChannelInfo {
+    fn is_meta(&self) -> bool {
+        self.shift.is_none()
+    }
+
+    fn is_meta_or_small(&self, group_dim: usize) -> bool {
+        self.is_meta() || (self.size.0 <= group_dim && self.size.1 <= group_dim)
+    }
+
+    fn is_shift_in_range(&self, min: usize, max: usize) -> bool {
+        assert!(min <= max);
+        self.shift.is_some_and(|(a, b)| {
+            let shift = a.min(b);
+            min <= shift && shift <= max
+        })
+    }
+
+    fn is_equivalent(&self, other: &ChannelInfo) -> bool {
+        self.size == other.size && self.shift == other.shift && self.bit_depth == other.bit_depth
+    }
+}
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
+enum ModularGridKind {
+    // Single big channel.
+    None,
+    // 2048x2048 image-pixels (if modular_group_shift == 1).
+    Lf,
+    // 256x256 image-pixels (if modular_group_shift == 1).
+    Hf,
+}
+
+impl ModularGridKind {
+    fn grid_dim(&self, frame_header: &FrameHeader, shift: (usize, usize)) -> (usize, usize) {
+        let group_dim = match self {
+            ModularGridKind::None => 0,
+            ModularGridKind::Lf => frame_header.lf_group_dim(),
+            ModularGridKind::Hf => frame_header.group_dim(),
+        };
+        (group_dim >> shift.0, group_dim >> shift.1)
+    }
+    fn grid_shape(&self, frame_header: &FrameHeader) -> (usize, usize) {
+        match self {
+            ModularGridKind::None => (1, 1),
+            ModularGridKind::Lf => frame_header.size_lf_groups(),
+            ModularGridKind::Hf => frame_header.size_groups(),
+        }
+    }
+}
+
+// All the information on a specific buffer needed by Modular decoding.
+#[derive(Debug)]
+pub(crate) struct ModularChannel {
+    // Actual pixel buffer.
+    pub data: Image<i32>,
+    // Holds additional information such as the weighted predictor's error channel's last row for
+    // the transform chunk that produced this buffer.
+    auxiliary_data: Option<Image<i32>>,
+    // Shift of the channel (None if this is a meta-channel).
+    shift: Option<(usize, usize)>,
+    bit_depth: BitDepth,
+}
+
+impl ModularChannel {
+    pub fn new(size: (usize, usize), bit_depth: BitDepth) -> Result<Self> {
+        Self::new_with_shift(size, Some((0, 0)), bit_depth)
+    }
+
+    fn new_with_shift(
+        size: (usize, usize),
+        shift: Option<(usize, usize)>,
+        bit_depth: BitDepth,
+    ) -> Result<Self> {
+        Ok(ModularChannel {
+            data: Image::new_with_padding(size, IMAGE_OFFSET, IMAGE_PADDING)?,
+            auxiliary_data: None,
+            shift,
+            bit_depth,
+        })
+    }
+
+    fn try_clone(&self) -> Result<Self> {
+        Ok(ModularChannel {
+            data: self.data.try_clone()?,
+            auxiliary_data: self
+                .auxiliary_data
+                .as_ref()
+                .map(Image::try_clone)
+                .transpose()?,
+            shift: self.shift,
+            bit_depth: self.bit_depth,
+        })
+    }
+
+    fn channel_info(&self) -> ChannelInfo {
+        ChannelInfo {
+            output_channel_idx: -1,
+            size: self.data.size(),
+            shift: self.shift,
+            bit_depth: self.bit_depth,
+        }
+    }
+}
+
+// Note: this type uses interior mutability to get mutable references to multiple buffers at once.
+// In principle, this is not needed, but the overhead should be minimal so using `unsafe` here is
+// probably not worth it.
+#[derive(Debug)]
+struct ModularBuffer {
+    data: RefCell<Option<ModularChannel>>,
+    // Number of times this buffer will be used, *including* when it is used for output.
+    remaining_uses: usize,
+    used_by_transforms: Vec<usize>,
+    size: (usize, usize),
+}
+
+impl ModularBuffer {
+    // Gives out a copy of the buffer + auxiliary buffer, marking the buffer as used.
+    // If this was the last usage of the buffer, does not actually copy the buffer.
+    fn get_buffer(&mut self) -> Result<ModularChannel> {
+        self.remaining_uses = self.remaining_uses.checked_sub(1).unwrap();
+        if self.remaining_uses == 0 {
+            Ok(self.data.borrow_mut().take().unwrap())
+        } else {
+            Ok(self
+                .data
+                .borrow()
+                .as_ref()
+                .map(ModularChannel::try_clone)
+                .transpose()?
+                .unwrap())
+        }
+    }
+
+    fn mark_used(&mut self) {
+        self.remaining_uses = self.remaining_uses.checked_sub(1).unwrap();
+        if self.remaining_uses == 0 {
+            *self.data.borrow_mut() = None;
+        }
+    }
+}
+
+#[derive(Debug)]
+struct ModularBufferInfo {
+    info: ChannelInfo,
+    // The index of coded channel in the bit-stream, or -1 for non-coded channels.
+    coded_channel_id: isize,
+    #[cfg_attr(not(feature = "tracing"), allow(dead_code))]
+    description: String,
+    grid_kind: ModularGridKind,
+    grid_shape: (usize, usize),
+    buffer_grid: Vec<ModularBuffer>,
+}
+
+impl ModularBufferInfo {
+    fn get_grid_idx(
+        &self,
+        output_grid_kind: ModularGridKind,
+        output_grid_pos: (usize, usize),
+    ) -> usize {
+        let grid_pos = match (output_grid_kind, self.grid_kind) {
+            (_, ModularGridKind::None) => (0, 0),
+            (ModularGridKind::Lf, ModularGridKind::Lf)
+            | (ModularGridKind::Hf, ModularGridKind::Hf) => output_grid_pos,
+            (ModularGridKind::Hf, ModularGridKind::Lf) => {
+                (output_grid_pos.0 / 8, output_grid_pos.1 / 8)
+            }
+            _ => unreachable!("invalid combination of output grid kind and buffer grid kind"),
+        };
+        self.grid_shape.0 * grid_pos.1 + grid_pos.0
+    }
+    fn get_grid_rect(
+        &self,
+        frame_header: &FrameHeader,
+        output_grid_kind: ModularGridKind,
+        output_grid_pos: (usize, usize),
+    ) -> Rect {
+        let chan_size = self.info.size;
+        if output_grid_kind == ModularGridKind::None {
+            assert_eq!(self.grid_kind, output_grid_kind);
+            return Rect {
+                origin: (0, 0),
+                size: chan_size,
+            };
+        }
+        let shift = self.info.shift.unwrap();
+        let grid_dim = output_grid_kind.grid_dim(frame_header, shift);
+        let bx = output_grid_pos.0 * grid_dim.0;
+        let by = output_grid_pos.1 * grid_dim.1;
+        let size = (
+            (chan_size.0 - bx).min(grid_dim.0),
+            (chan_size.1 - by).min(grid_dim.1),
+        );
+        let origin = match (output_grid_kind, self.grid_kind) {
+            (ModularGridKind::Lf, ModularGridKind::Lf)
+            | (ModularGridKind::Hf, ModularGridKind::Hf) => (0, 0),
+            (_, ModularGridKind::None) => (bx, by),
+            (ModularGridKind::Hf, ModularGridKind::Lf) => {
+                let lf_grid_dim = self.grid_kind.grid_dim(frame_header, shift);
+                (bx % lf_grid_dim.0, by % lf_grid_dim.1)
+            }
+            _ => unreachable!("invalid combination of output grid kind and buffer grid kind"),
+        };
+        if size.0 == 0 || size.1 == 0 {
+            Rect {
+                origin: (0, 0),
+                size: (0, 0),
+            }
+        } else {
+            Rect { origin, size }
+        }
+    }
+}
+
+/// A modular image is a sequence of channels to which one or more transforms might have been
+/// applied. We represent a modular image as a list of buffers, some of which are coded in the
+/// bitstream; other buffers are obtained as the output of one of the transformation steps.
+/// Some buffers are marked as `output`: those are the buffers corresponding to the pre-transform
+/// image channels.
+/// The buffers are internally divided in grids, matching the sizes of the groups they are coded
+/// in (with appropriate shifts), or the size of the data produced by applying the appropriate
+/// transforms to each of the groups in the input of the transforms.
+#[derive(Debug)]
+pub struct FullModularImage {
+    buffer_info: Vec<ModularBufferInfo>,
+    transform_steps: Vec<TransformStepChunk>,
+    // List of buffer indices of the channels of the modular image encoded in each kind of section.
+    // In order, LfGlobal, LfGroup, HfGroup(pass 0), ..., HfGroup(last pass).
+    section_buffer_indices: Vec<Vec<usize>>,
+    modular_color_channels: usize,
+}
+
+impl FullModularImage {
+    #[instrument(level = "debug", skip_all)]
+    pub fn read(
+        frame_header: &FrameHeader,
+        image_metadata: &ImageMetadata,
+        modular_color_channels: usize,
+        global_tree: &Option<Tree>,
+        br: &mut BitReader,
+    ) -> Result<Self> {
+        let mut channels = vec![];
+        for c in 0..modular_color_channels {
+            let shift = (frame_header.hshift(c), frame_header.vshift(c));
+            let size = frame_header.size();
+            channels.push(ChannelInfo {
+                output_channel_idx: c as isize,
+                size: (size.0.div_ceil(1 << shift.0), size.1.div_ceil(1 << shift.1)),
+                shift: Some(shift),
+                bit_depth: image_metadata.bit_depth,
+            });
+        }
+
+        for (idx, ecups) in frame_header.ec_upsampling.iter().enumerate() {
+            let shift_ec = ecups.ceil_log2();
+            let shift_color = frame_header.upsampling.ceil_log2();
+            let shift = shift_ec
+                .checked_sub(shift_color)
+                .expect("ec_upsampling >= upsampling should be checked in frame header")
+                as usize;
+            let size = frame_header.size_upsampled();
+            let size = (
+                size.0.div_ceil(*ecups as usize),
+                size.1.div_ceil(*ecups as usize),
+            );
+            channels.push(ChannelInfo {
+                output_channel_idx: 3 + idx as isize,
+                size,
+                shift: Some((shift, shift)),
+                bit_depth: image_metadata.bit_depth,
+            });
+        }
+
+        #[cfg(feature = "tracing")]
+        for (i, ch) in channels.iter().enumerate() {
+            trace!("Modular channel {i}: {ch:?}");
+        }
+
+        if channels.is_empty() {
+            return Ok(Self {
+                buffer_info: vec![],
+                transform_steps: vec![],
+                section_buffer_indices: vec![vec![]; 2 + frame_header.passes.num_passes as usize],
+                modular_color_channels,
+            });
+        }
+
+        trace!("reading modular header");
+        let header = GroupHeader::read(br)?;
+
+        let (mut buffer_info, transform_steps) =
+            transforms::apply::meta_apply_transforms(&channels, &header)?;
+
+        // Assign each (channel, group) pair present in the bitstream to the section in which it
+        // will be decoded.
+        let mut section_buffer_indices: Vec<Vec<usize>> = vec![];
+
+        let mut sorted_buffers: Vec<_> = buffer_info
+            .iter()
+            .enumerate()
+            .filter_map(|(i, b)| {
+                if b.coded_channel_id >= 0 {
+                    Some((b.coded_channel_id, i))
+                } else {
+                    None
+                }
+            })
+            .collect();
+
+        sorted_buffers.sort_by_key(|x| x.0);
+
+        section_buffer_indices.push(
+            sorted_buffers
+                .iter()
+                .take_while(|x| {
+                    buffer_info[x.1]
+                        .info
+                        .is_meta_or_small(frame_header.group_dim())
+                })
+                .map(|x| x.1)
+                .collect(),
+        );
+
+        section_buffer_indices.push(
+            sorted_buffers
+                .iter()
+                .skip_while(|x| {
+                    buffer_info[x.1]
+                        .info
+                        .is_meta_or_small(frame_header.group_dim())
+                })
+                .filter(|x| buffer_info[x.1].info.is_shift_in_range(3, usize::MAX))
+                .map(|x| x.1)
+                .collect(),
+        );
+
+        for pass in 0..frame_header.passes.num_passes as usize {
+            let (min_shift, max_shift) = frame_header.passes.downsampling_bracket(pass);
+            section_buffer_indices.push(
+                sorted_buffers
+                    .iter()
+                    .skip_while(|x| {
+                        buffer_info[x.1]
+                            .info
+                            .is_meta_or_small(frame_header.group_dim())
+                    })
+                    .filter(|x| {
+                        buffer_info[x.1]
+                            .info
+                            .is_shift_in_range(min_shift, max_shift)
+                    })
+                    .map(|x| x.1)
+                    .collect(),
+            );
+        }
+
+        // Ensure that the channel list in each group is sorted by actual channel ID.
+        for list in section_buffer_indices.iter_mut() {
+            list.sort_by_key(|x| buffer_info[*x].coded_channel_id);
+        }
+
+        trace!(?section_buffer_indices);
+        #[cfg(feature = "tracing")]
+        for (section, indices) in section_buffer_indices.iter().enumerate() {
+            let section_name = match section {
+                0 => "LF global".to_string(),
+                1 => "LF groups".to_string(),
+                _ => format!("HF groups, pass {}", section - 2),
+            };
+            trace!("Coded modular channels in {section_name}");
+            for i in indices {
+                let bi = &buffer_info[*i];
+                trace!(
+                    "Channel {i} {:?} coded id: {}",
+                    bi.info, bi.coded_channel_id
+                );
+            }
+        }
+
+        let transform_steps = make_grids(
+            frame_header,
+            transform_steps,
+            &section_buffer_indices,
+            &mut buffer_info,
+        );
+
+        #[cfg(feature = "tracing")]
+        for (i, bi) in buffer_info.iter().enumerate() {
+            trace!(
+                "Channel {i} {:?} coded_id: {} '{}' {:?} grid {:?}",
+                bi.info, bi.coded_channel_id, bi.description, bi.grid_kind, bi.grid_shape
+            );
+            for (pos, buf) in bi.buffer_grid.iter().enumerate() {
+                trace!(
+                    "Channel {i} grid {pos} ({}, {})  size: {:?}, uses: {}, used_by: {:?}",
+                    pos % bi.grid_shape.0,
+                    pos / bi.grid_shape.0,
+                    buf.size,
+                    buf.remaining_uses,
+                    buf.used_by_transforms
+                );
+            }
+        }
+
+        #[cfg(feature = "tracing")]
+        for (i, ts) in transform_steps.iter().enumerate() {
+            trace!("Transform {i}: {ts:?}");
+        }
+
+        with_buffers(&buffer_info, &section_buffer_indices[0], 0, true, |bufs| {
+            decode_modular_subbitstream(
+                bufs,
+                ModularStreamId::GlobalData.get_id(frame_header),
+                Some(header),
+                global_tree,
+                br,
+            )
+        })?;
+
+        Ok(FullModularImage {
+            buffer_info,
+            transform_steps,
+            section_buffer_indices,
+            modular_color_channels,
+        })
+    }
+
+    #[allow(clippy::type_complexity)]
+    #[instrument(level = "debug", skip(self, frame_header, global_tree, br), ret)]
+    pub fn read_stream(
+        &mut self,
+        stream: ModularStreamId,
+        frame_header: &FrameHeader,
+        global_tree: &Option<Tree>,
+        br: &mut BitReader,
+    ) -> Result<()> {
+        if self.buffer_info.is_empty() {
+            info!("No modular channels to decode");
+            return Ok(());
+        }
+        let (section_id, grid) = match stream {
+            ModularStreamId::ModularLF(group) => (1, group),
+            ModularStreamId::ModularHF { pass, group } => (2 + pass, group),
+            _ => {
+                unreachable!(
+                    "read_stream should only be used for streams that are part of the main Modular image"
+                );
+            }
+        };
+
+        with_buffers(
+            &self.buffer_info,
+            &self.section_buffer_indices[section_id],
+            grid,
+            true,
+            |bufs| {
+                decode_modular_subbitstream(
+                    bufs,
+                    stream.get_id(frame_header),
+                    None,
+                    global_tree,
+                    br,
+                )
+            },
+        )?;
+        Ok(())
+    }
+
+    pub fn process_output(
+        &mut self,
+        section_id: usize,
+        grid: usize,
+        frame_header: &FrameHeader,
+        pass_to_pipeline: &mut dyn FnMut(usize, usize, usize, Image<i32>) -> Result<()>,
+    ) -> Result<()> {
+        let mut maybe_output = |bi: &mut ModularBufferInfo, grid: usize| -> Result<()> {
+            if bi.info.output_channel_idx >= 0 {
+                let chan = bi.info.output_channel_idx as usize;
+                debug!("Rendering channel {chan:?}, grid position {grid}");
+                let buf = bi.buffer_grid[grid].get_buffer()?;
+                // TODO(veluca): figure out what to do with passes here.
+                if chan == 0 && self.modular_color_channels == 1 {
+                    for i in 0..2 {
+                        pass_to_pipeline(i, grid, 1, buf.data.try_clone()?)?;
+                    }
+                    pass_to_pipeline(2, grid, 1, buf.data)?;
+                } else {
+                    pass_to_pipeline(chan, grid, 1, buf.data)?;
+                }
+            }
+            Ok(())
+        };
+
+        let mut new_ready_transform_chunks = vec![];
+        for buf in self.section_buffer_indices[section_id].iter().copied() {
+            maybe_output(&mut self.buffer_info[buf], grid)?;
+            let new_chunks = self.buffer_info[buf].buffer_grid[grid]
+                .used_by_transforms
+                .to_vec();
+            trace!("Buffer {buf} grid position {grid} used by chunks {new_chunks:?}");
+            new_ready_transform_chunks.extend(new_chunks);
+        }
+
+        trace!(?new_ready_transform_chunks);
+
+        while let Some(tfm) = new_ready_transform_chunks.pop() {
+            trace!("tfm = {tfm} chunk = {:?}", self.transform_steps[tfm]);
+            for (new_buf, new_grid) in
+                self.transform_steps[tfm].dep_ready(frame_header, &mut self.buffer_info)?
+            {
+                maybe_output(&mut self.buffer_info[new_buf], new_grid)?;
+                let new_chunks = self.buffer_info[new_buf].buffer_grid[new_grid]
+                    .used_by_transforms
+                    .to_vec();
+                trace!("Buffer {new_buf} grid position {new_grid} used by chunks {new_chunks:?}");
+                new_ready_transform_chunks.extend(new_chunks);
+            }
+        }
+
+        Ok(())
+    }
+}
+
+#[allow(clippy::too_many_arguments)]
+fn dequant_lf(
+    r: Rect,
+    lf: &mut [Image<f32>; 3],
+    quant_lf: &mut Image<u8>,
+    input: [&Image<i32>; 3],
+    color_correlation_params: &ColorCorrelationParams,
+    quant_params: &QuantizerParams,
+    lf_quant: &LfQuantFactors,
+    mul: f32,
+    frame_header: &FrameHeader,
+    bctx: &BlockContextMap,
+) -> Result<()> {
+    let inv_quant_lf = (quantizer::GLOBAL_SCALE_DENOM as f32)
+        / (quant_params.global_scale as f32 * quant_params.quant_lf as f32);
+    let lf_factors = lf_quant.quant_factors.map(|factor| factor * inv_quant_lf);
+
+    if frame_header.is444() {
+        let [lf0, lf1, lf2] = lf;
+        let mut lf_rects = (
+            lf0.get_rect_mut(r),
+            lf1.get_rect_mut(r),
+            lf2.get_rect_mut(r),
+        );
+
+        let fac_x = lf_factors[0] * mul;
+        let fac_y = lf_factors[1] * mul;
+        let fac_b = lf_factors[2] * mul;
+        let cfl_fac_x = color_correlation_params.y_to_x_lf();
+        let cfl_fac_b = color_correlation_params.y_to_b_lf();
+        for y in 0..r.size.1 {
+            let quant_row_x = input[1].row(y);
+            let quant_row_y = input[0].row(y);
+            let quant_row_b = input[2].row(y);
+            let dec_row_x = lf_rects.0.row(y);
+            let dec_row_y = lf_rects.1.row(y);
+            let dec_row_b = lf_rects.2.row(y);
+            for x in 0..r.size.0 {
+                let in_x = quant_row_x[x] as f32 * fac_x;
+                let in_y = quant_row_y[x] as f32 * fac_y;
+                let in_b = quant_row_b[x] as f32 * fac_b;
+                dec_row_y[x] = in_y;
+                dec_row_x[x] = in_y * cfl_fac_x + in_x;
+                dec_row_b[x] = in_y * cfl_fac_b + in_b;
+            }
+        }
+    } else {
+        for (c, lf_rect) in lf.iter_mut().enumerate() {
+            let rect = Rect {
+                origin: (
+                    r.origin.0 >> frame_header.hshift(c),
+                    r.origin.1 >> frame_header.vshift(c),
+                ),
+                size: (
+                    r.size.0 >> frame_header.hshift(c),
+                    r.size.1 >> frame_header.vshift(c),
+                ),
+            };
+            let mut lf_rect = lf_rect.get_rect_mut(rect);
+            let fac = lf_factors[c] * mul;
+            let ch = input[if c < 2 { c ^ 1 } else { c }];
+            for y in 0..rect.size.1 {
+                let quant_row = ch.row(y);
+                let row = lf_rect.row(y);
+                for x in 0..rect.size.0 {
+                    row[x] = quant_row[x] as f32 * fac;
+                }
+            }
+        }
+    }
+    let mut quant_lf_rect = quant_lf.get_rect_mut(r);
+    if bctx.num_lf_contexts <= 1 {
+        for y in 0..r.size.1 {
+            quant_lf_rect.row(y).fill(0);
+        }
+    } else {
+        for y in 0..r.size.1 {
+            let qlf_row_val = quant_lf_rect.row(y);
+            let quant_row_x = input[1].row(y >> frame_header.vshift(0));
+            let quant_row_y = input[0].row(y >> frame_header.vshift(1));
+            let quant_row_b = input[2].row(y >> frame_header.vshift(2));
+            for x in 0..r.size.0 {
+                let bucket_x = bctx.lf_thresholds[0]
+                    .iter()
+                    .filter(|&t| quant_row_x[x >> frame_header.hshift(0)] > *t)
+                    .count();
+                let bucket_y = bctx.lf_thresholds[1]
+                    .iter()
+                    .filter(|&t| quant_row_y[x >> frame_header.hshift(1)] > *t)
+                    .count();
+                let bucket_b = bctx.lf_thresholds[2]
+                    .iter()
+                    .filter(|&t| quant_row_b[x >> frame_header.hshift(2)] > *t)
+                    .count();
+                let mut bucket = bucket_x;
+                bucket *= bctx.lf_thresholds[2].len() + 1;
+                bucket += bucket_b;
+                bucket *= bctx.lf_thresholds[1].len() + 1;
+                bucket += bucket_y;
+                qlf_row_val[x] = bucket as u8;
+            }
+        }
+    }
+    Ok(())
+}
+
+#[allow(clippy::too_many_arguments)]
+pub fn decode_vardct_lf(
+    group: usize,
+    frame_header: &FrameHeader,
+    image_metadata: &ImageMetadata,
+    global_tree: &Option<Tree>,
+    color_correlation_params: &ColorCorrelationParams,
+    quant_params: &QuantizerParams,
+    lf_quant: &LfQuantFactors,
+    bctx: &BlockContextMap,
+    lf_image: &mut [Image<f32>; 3],
+    quant_lf: &mut Image<u8>,
+    br: &mut BitReader,
+) -> Result<()> {
+    let extra_precision = br.read(2)?;
+    debug!(?extra_precision);
+    let mul = 1.0 / (1 << extra_precision) as f32;
+    let stream_id = ModularStreamId::VarDCTLF(group).get_id(frame_header);
+    debug!(?stream_id);
+    let r = frame_header.lf_group_rect(group);
+    debug!(?r);
+    let shrink_rect = |size: (usize, usize), c| {
+        (
+            size.0 >> frame_header.hshift(c),
+            size.1 >> frame_header.vshift(c),
+        )
+    };
+    let mut buffers = [
+        ModularChannel::new(shrink_rect(r.size, 1), image_metadata.bit_depth)?,
+        ModularChannel::new(shrink_rect(r.size, 0), image_metadata.bit_depth)?,
+        ModularChannel::new(shrink_rect(r.size, 2), image_metadata.bit_depth)?,
+    ];
+    decode_modular_subbitstream(
+        buffers.iter_mut().collect(),
+        stream_id,
+        None,
+        global_tree,
+        br,
+    )?;
+    dequant_lf(
+        r,
+        lf_image,
+        quant_lf,
+        [&buffers[0].data, &buffers[1].data, &buffers[2].data],
+        color_correlation_params,
+        quant_params,
+        lf_quant,
+        mul,
+        frame_header,
+        bctx,
+    )
+}
+
+pub fn decode_hf_metadata(
+    group: usize,
+    frame_header: &FrameHeader,
+    image_metadata: &ImageMetadata,
+    global_tree: &Option<Tree>,
+    hf_meta: &mut HfMetadata,
+    br: &mut BitReader,
+) -> Result<()> {
+    let stream_id = ModularStreamId::LFMeta(group).get_id(frame_header);
+    debug!(?stream_id);
+    let r = frame_header.lf_group_rect(group);
+    debug!(?r);
+    let upper_bound = r.size.0 * r.size.1;
+    let count_num_bits = upper_bound.ceil_log2();
+    let count: usize = br.read(count_num_bits)? as usize + 1;
+    debug!(?count);
+    let cr = Rect {
+        origin: (r.origin.0 >> 3, r.origin.1 >> 3),
+        size: (r.size.0.div_ceil(8), r.size.1.div_ceil(8)),
+    };
+    let mut buffers = [
+        ModularChannel::new_with_shift(cr.size, Some((3, 3)), image_metadata.bit_depth)?,
+        ModularChannel::new_with_shift(cr.size, Some((3, 3)), image_metadata.bit_depth)?,
+        ModularChannel::new((count, 2), image_metadata.bit_depth)?,
+        ModularChannel::new(r.size, image_metadata.bit_depth)?,
+    ];
+    decode_modular_subbitstream(
+        buffers.iter_mut().collect(),
+        stream_id,
+        None,
+        global_tree,
+        br,
+    )?;
+    let ytox_image = &buffers[0].data;
+    let ytob_image = &buffers[1].data;
+    let mut ytox_map_rect = hf_meta.ytox_map.get_rect_mut(cr);
+    let mut ytob_map_rect = hf_meta.ytob_map.get_rect_mut(cr);
+    let i8min: i32 = i8::MIN.into();
+    let i8max: i32 = i8::MAX.into();
+    for y in 0..cr.size.1 {
+        let row_in_x = ytox_image.row(y);
+        let row_in_b = ytob_image.row(y);
+        let row_out_x = ytox_map_rect.row(y);
+        let row_out_b = ytob_map_rect.row(y);
+        for x in 0..cr.size.0 {
+            row_out_x[x] = row_in_x[x].clamp(i8min, i8max) as i8;
+            row_out_b[x] = row_in_b[x].clamp(i8min, i8max) as i8;
+        }
+    }
+    let transform_image = &buffers[2].data;
+    let epf_image = &buffers[3].data;
+    let mut transform_map_rect = hf_meta.transform_map.get_rect_mut(r);
+    let mut raw_quant_map_rect = hf_meta.raw_quant_map.get_rect_mut(r);
+    let mut epf_map_rect = hf_meta.epf_map.get_rect_mut(r);
+    let mut num: usize = 0;
+    let mut used_hf_types: u32 = 0;
+    for y in 0..r.size.1 {
+        let epf_row_in = epf_image.row(y);
+        let epf_row_out = epf_map_rect.row(y);
+        for x in 0..r.size.0 {
+            let epf_val = epf_row_in[x];
+            if !(0..8).contains(&epf_val) {
+                return Err(Error::InvalidEpfValue(epf_val));
+            }
+            epf_row_out[x] = epf_val as u8;
+            if transform_map_rect.row(y)[x] != HfTransformType::INVALID_TRANSFORM {
+                continue;
+            }
+            if num >= count {
+                return Err(Error::InvalidVarDCTTransformMap);
+            }
+            let raw_transform = transform_image.row(0)[num];
+            let raw_quant = 1 + transform_image.row(1)[num].clamp(0, 255);
+            used_hf_types |= 1 << raw_transform;
+            let transform_type = HfTransformType::from_usize(raw_transform as usize)
+                .ok_or(Error::InvalidVarDCTTransform(raw_transform as usize))?;
+            let cx = covered_blocks_x(transform_type) as usize;
+            let cy = covered_blocks_y(transform_type) as usize;
+            if (cx > 1 || cy > 1) && !frame_header.is444() {
+                return Err(Error::InvalidBlockSizeForChromaSubsampling);
+            }
+            let next_group = ((x / 32 + 1) * 32, (y / 32 + 1) * 32);
+            if x + cx > min(r.size.0, next_group.0) || y + cy > min(r.size.1, next_group.1) {
+                return Err(Error::HFBlockOutOfBounds);
+            }
+            let transform_id = raw_transform as u8;
+            for iy in 0..cy {
+                for ix in 0..cx {
+                    transform_map_rect.row(y + iy)[x + ix] = if iy == 0 && ix == 0 {
+                        transform_id + 128 // Set highest bit to signal first block.
+                    } else {
+                        transform_id
+                    };
+                    raw_quant_map_rect.row(y + iy)[x + ix] = raw_quant;
+                }
+            }
+            num += 1;
+        }
+    }
+    hf_meta.used_hf_types |= used_hf_types;
+    Ok(())
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/predict.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/predict.rs
new file mode 100644
index 0000000..c7926d8
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/predict.rs
@@ -0,0 +1,589 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{
+    error::{Error, Result},
+    headers::modular::WeightedHeader,
+    image::Image,
+    util::floor_log2_nonzero,
+};
+use num_derive::FromPrimitive;
+use num_traits::FromPrimitive;
+
+#[repr(u8)]
+#[derive(Debug, FromPrimitive, Clone, Copy, PartialEq, Eq)]
+pub enum Predictor {
+    Zero = 0,
+    West = 1,
+    North = 2,
+    AverageWestAndNorth = 3,
+    Select = 4,
+    Gradient = 5,
+    Weighted = 6,
+    NorthEast = 7,
+    NorthWest = 8,
+    WestWest = 9,
+    AverageWestAndNorthWest = 10,
+    AverageNorthAndNorthWest = 11,
+    AverageNorthAndNorthEast = 12,
+    AverageAll = 13,
+}
+
+impl Predictor {
+    pub fn requires_full_row(&self) -> bool {
+        matches!(
+            self,
+            Predictor::Weighted
+                | Predictor::NorthEast
+                | Predictor::AverageNorthAndNorthEast
+                | Predictor::AverageAll
+        )
+    }
+}
+
+impl TryFrom<u32> for Predictor {
+    type Error = Error;
+
+    fn try_from(value: u32) -> Result<Self> {
+        Self::from_u32(value).ok_or(Error::InvalidPredictor(value))
+    }
+}
+
+#[derive(Debug, Clone, Copy, Default)]
+pub struct PredictionData {
+    pub left: i32,
+    pub top: i32,
+    pub toptop: i32,
+    pub topleft: i32,
+    pub topright: i32,
+    pub leftleft: i32,
+    pub toprightright: i32,
+}
+
+impl PredictionData {
+    #[inline]
+    pub fn update_for_interior_row(
+        self,
+        row_top: &[i32],
+        row_toptop: &[i32],
+        x: usize,
+        cur: i32,
+        needs_top: bool,
+        needs_toptop: bool,
+    ) -> PredictionData {
+        debug_assert!(x > 1);
+        debug_assert!(x + 2 < row_top.len());
+        let left = cur;
+        let top = self.topright;
+        let topleft = self.top;
+        let topright = self.toprightright;
+        let leftleft = self.left;
+        let toptop = if needs_toptop { row_toptop[x] } else { 0 };
+        let toprightright = if needs_top { row_top[x + 2] } else { 0 };
+        Self {
+            left,
+            top,
+            toptop,
+            topleft,
+            topright,
+            leftleft,
+            toprightright,
+        }
+    }
+
+    pub fn get_rows(row: &[i32], row_top: &[i32], row_toptop: &[i32], x: usize, y: usize) -> Self {
+        let left = if x > 0 {
+            row[x - 1]
+        } else if y > 0 {
+            row_top[0]
+        } else {
+            0
+        };
+        let top = if y > 0 { row_top[x] } else { left };
+        let topleft = if x > 0 && y > 0 { row_top[x - 1] } else { left };
+        let topright = if x + 1 < row.len() && y > 0 {
+            row_top[x + 1]
+        } else {
+            top
+        };
+        let leftleft = if x > 1 { row[x - 2] } else { left };
+        let toptop = if y > 1 { row_toptop[x] } else { top };
+        let toprightright = if x + 2 < row.len() && y > 0 {
+            row_top[x + 2]
+        } else {
+            topright
+        };
+        Self {
+            left,
+            top,
+            toptop,
+            topleft,
+            topright,
+            leftleft,
+            toprightright,
+        }
+    }
+
+    pub fn get(rect: &Image<i32>, x: usize, y: usize) -> Self {
+        Self::get_rows(
+            rect.row(y),
+            rect.row(y.saturating_sub(1)),
+            rect.row(y.saturating_sub(2)),
+            x,
+            y,
+        )
+    }
+
+    #[allow(clippy::too_many_arguments)]
+    pub fn get_with_neighbors(
+        rect: &Image<i32>,
+        rect_left: Option<&Image<i32>>,
+        rect_top: Option<&Image<i32>>,
+        rect_top_left: Option<&Image<i32>>,
+        rect_right: Option<&Image<i32>>,
+        rect_top_right: Option<&Image<i32>>,
+        x: usize,
+        y: usize,
+        xsize: usize,
+        ysize: usize,
+    ) -> Self {
+        let left = if x > 0 {
+            rect.row(y)[x - 1]
+        } else if let Some(l) = rect_left {
+            l.row(y)[xsize - 1]
+        } else if y > 0 {
+            rect.row(y - 1)[0]
+        } else if let Some(t) = rect_top {
+            t.row(ysize - 1)[0]
+        } else {
+            0
+        };
+        let top = if y > 0 {
+            rect.row(y - 1)[x]
+        } else if let Some(t) = rect_top {
+            t.row(ysize - 1)[x]
+        } else {
+            left
+        };
+        let topleft = if x > 0 {
+            if y > 0 {
+                rect.row(y - 1)[x - 1]
+            } else if let Some(t) = rect_top {
+                t.row(ysize - 1)[x - 1]
+            } else {
+                left
+            }
+        } else if y > 0 {
+            if let Some(l) = rect_left {
+                l.row(y - 1)[xsize - 1]
+            } else {
+                left
+            }
+        } else if let Some(tl) = rect_top_left {
+            tl.row(ysize - 1)[xsize - 1]
+        } else {
+            left
+        };
+        let topright = if x + 1 < rect.size().0 {
+            if y > 0 {
+                rect.row(y - 1)[x + 1]
+            } else if let Some(t) = rect_top {
+                t.row(ysize - 1)[x + 1]
+            } else {
+                top
+            }
+        } else if y > 0 {
+            if let Some(r) = rect_right {
+                r.row(y - 1)[0]
+            } else {
+                top
+            }
+        } else if let Some(tr) = rect_top_right {
+            tr.row(ysize - 1)[0]
+        } else {
+            top
+        };
+        let leftleft = if x > 1 {
+            rect.row(y)[x - 2]
+        } else if let Some(l) = rect_left {
+            l.row(y)[xsize + x - 2]
+        } else {
+            left
+        };
+        let toptop = if y > 1 {
+            rect.row(y - 2)[x]
+        } else if let Some(t) = rect_top {
+            t.row(ysize + y - 2)[x]
+        } else {
+            top
+        };
+        let toprightright = if x + 2 < rect.size().0 {
+            if y > 0 {
+                rect.row(y - 1)[x + 2]
+            } else if let Some(t) = rect_top {
+                t.row(ysize - 1)[x + 2]
+            } else {
+                topright
+            }
+        } else if y > 0 {
+            if let Some(r) = rect_right {
+                r.row(y - 1)[x + 2 - rect.size().0]
+            } else {
+                topright
+            }
+        } else if let Some(tr) = rect_top_right {
+            tr.row(ysize - 1)[x + 2 - rect.size().0]
+        } else {
+            topright
+        };
+        Self {
+            left,
+            top,
+            toptop,
+            topleft,
+            topright,
+            leftleft,
+            toprightright,
+        }
+    }
+}
+
+pub fn clamped_gradient(left: i64, top: i64, topleft: i64) -> i64 {
+    // Same code/logic as libjxl.
+    let min = left.min(top);
+    let max = left.max(top);
+    let grad = left + top - topleft;
+    let grad_clamp_max = if topleft < min { max } else { grad };
+    if topleft > max { min } else { grad_clamp_max }
+}
+
+impl Predictor {
+    pub const NUM_PREDICTORS: u32 = Predictor::AverageAll as u32 + 1;
+
+    #[inline]
+    pub fn predict_one(
+        &self,
+        PredictionData {
+            left,
+            top,
+            toptop,
+            topleft,
+            topright,
+            leftleft,
+            toprightright,
+        }: PredictionData,
+        wp_pred: i64,
+    ) -> i64 {
+        match self {
+            Predictor::Zero => 0,
+            Predictor::West => left as i64,
+            Predictor::North => top as i64,
+            Predictor::Select => Self::select(left as i64, top as i64, topleft as i64),
+            Predictor::Gradient => clamped_gradient(left as i64, top as i64, topleft as i64),
+            Predictor::Weighted => wp_pred,
+            Predictor::WestWest => leftleft as i64,
+            Predictor::NorthEast => topright as i64,
+            Predictor::NorthWest => topleft as i64,
+            Predictor::AverageWestAndNorth => (top as i64 + left as i64) / 2,
+            Predictor::AverageWestAndNorthWest => (left as i64 + topleft as i64) / 2,
+            Predictor::AverageNorthAndNorthWest => (top as i64 + topleft as i64) / 2,
+            Predictor::AverageNorthAndNorthEast => (top as i64 + topright as i64) / 2,
+            Predictor::AverageAll => {
+                (6 * top as i64 - 2 * toptop as i64
+                    + 7 * left as i64
+                    + leftleft as i64
+                    + toprightright as i64
+                    + 3 * topright as i64
+                    + 8)
+                    / 16
+            }
+        }
+    }
+
+    fn select(left: i64, top: i64, topleft: i64) -> i64 {
+        let p = left + top - topleft;
+        if (p - left).abs() < (p - top).abs() {
+            left
+        } else {
+            top
+        }
+    }
+}
+
+const NUM_PREDICTORS: usize = 4;
+const PRED_EXTRA_BITS: i64 = 3;
+const PREDICTION_ROUND: i64 = ((1 << PRED_EXTRA_BITS) >> 1) - 1;
+// Allows to approximate division by a number from 1 to 64.
+//  for (int i = 0; i < 64; i++) divlookup[i] = (1 << 24) / (i + 1);
+const DIVLOOKUP: [u32; 64] = [
+    16777216, 8388608, 5592405, 4194304, 3355443, 2796202, 2396745, 2097152, 1864135, 1677721,
+    1525201, 1398101, 1290555, 1198372, 1118481, 1048576, 986895, 932067, 883011, 838860, 798915,
+    762600, 729444, 699050, 671088, 645277, 621378, 599186, 578524, 559240, 541200, 524288, 508400,
+    493447, 479349, 466033, 453438, 441505, 430185, 419430, 409200, 399457, 390167, 381300, 372827,
+    364722, 356962, 349525, 342392, 335544, 328965, 322638, 316551, 310689, 305040, 299593, 294337,
+    289262, 284359, 279620, 275036, 270600, 266305, 262144,
+];
+
+fn add_bits(x: i32) -> i64 {
+    (x as i64) << PRED_EXTRA_BITS
+}
+
+fn error_weight(x: u32, maxweight: u32) -> u32 {
+    let shift = floor_log2_nonzero(x + 1) as i32 - 5;
+    if shift < 0 {
+        4u32 + maxweight * DIVLOOKUP[x as usize & 63]
+    } else {
+        4u32 + ((maxweight * DIVLOOKUP[(x as usize >> shift) & 63]) >> shift)
+    }
+}
+
+fn weighted_average(pixels: &[i64; NUM_PREDICTORS], weights: &mut [u32; NUM_PREDICTORS]) -> i64 {
+    let log_weight = floor_log2_nonzero(weights.iter().fold(0u32, |sum, el| sum + *el));
+    let weight_sum = weights.iter_mut().fold(0, |sum, el| {
+        *el >>= log_weight - 4;
+        sum + *el
+    });
+    let sum = weights
+        .iter()
+        .enumerate()
+        .fold(((weight_sum >> 1) - 1) as i64, |sum, (i, weight)| {
+            sum + pixels[i] * *weight as i64
+        });
+    (sum * DIVLOOKUP[(weight_sum - 1) as usize] as i64) >> 24
+}
+
+#[derive(Debug)]
+pub struct WeightedPredictorState {
+    prediction: [i64; NUM_PREDICTORS],
+    pred: i64,
+    // Position-major layout: errors for same position are contiguous
+    // Layout: [pos0: p0,p1,p2,p3] [pos1: p0,p1,p2,p3] ...
+    pred_errors_buffer: Vec<u32>,
+    error: Vec<i32>,
+    wp_header: WeightedHeader,
+}
+
+impl WeightedPredictorState {
+    pub fn new(wp_header: &WeightedHeader, xsize: usize) -> WeightedPredictorState {
+        let num_errors = (xsize + 2) * 2;
+        WeightedPredictorState {
+            prediction: [0; NUM_PREDICTORS],
+            pred: 0,
+            // Position-major layout: errors for same position are contiguous
+            // Layout: [pos0: p0,p1,p2,p3] [pos1: p0,p1,p2,p3] ...
+            // This gives better cache locality when accessing all predictors for a position
+            pred_errors_buffer: vec![0; num_errors * NUM_PREDICTORS],
+            error: vec![0; num_errors],
+            wp_header: wp_header.clone(),
+        }
+    }
+
+    /// Get all predictor errors for a given position (contiguous in memory)
+    #[inline(always)]
+    fn get_errors_at_pos(&self, pos: usize) -> &[u32; NUM_PREDICTORS] {
+        let start = pos * NUM_PREDICTORS;
+        self.pred_errors_buffer[start..start + NUM_PREDICTORS]
+            .try_into()
+            .unwrap()
+    }
+
+    /// Get mutable reference to all predictor errors for a given position
+    #[inline(always)]
+    fn get_errors_at_pos_mut(&mut self, pos: usize) -> &mut [u32; NUM_PREDICTORS] {
+        let start = pos * NUM_PREDICTORS;
+        (&mut self.pred_errors_buffer[start..start + NUM_PREDICTORS])
+            .try_into()
+            .unwrap()
+    }
+
+    pub fn save_state(&self, wp_image: &mut Image<i32>, xsize: usize) {
+        wp_image
+            .row_mut(0)
+            .copy_from_slice(&self.error[xsize + 2..]);
+    }
+
+    pub fn restore_state(&mut self, wp_image: &Image<i32>, xsize: usize) {
+        self.error[xsize + 2..].copy_from_slice(wp_image.row(0));
+    }
+
+    #[inline(always)]
+    pub fn update_errors(&mut self, correct_val: i32, pos: (usize, usize), xsize: usize) {
+        let (cur_row, prev_row) = if pos.1 & 1 != 0 {
+            (0, xsize + 2)
+        } else {
+            (xsize + 2, 0)
+        };
+        let val = add_bits(correct_val);
+        self.error[cur_row + pos.0] = (self.pred - val) as i32;
+
+        // Compute errors for all predictors
+        let mut errs = [0u32; NUM_PREDICTORS];
+        for (err, &pred) in errs.iter_mut().zip(self.prediction.iter()) {
+            *err = (((pred - val).abs() + PREDICTION_ROUND) >> PRED_EXTRA_BITS) as u32;
+        }
+
+        // Write to current position (contiguous access)
+        *self.get_errors_at_pos_mut(cur_row + pos.0) = errs;
+
+        // Update previous row position (contiguous access)
+        let prev_errors = self.get_errors_at_pos_mut(prev_row + pos.0 + 1);
+        for i in 0..NUM_PREDICTORS {
+            prev_errors[i] = prev_errors[i].wrapping_add(errs[i]);
+        }
+    }
+
+    #[inline(always)]
+    pub fn predict_and_property(
+        &mut self,
+        pos: (usize, usize),
+        xsize: usize,
+        data: &PredictionData,
+    ) -> (i64, i32) {
+        let (cur_row, prev_row) = if pos.1 & 1 != 0 {
+            (0, xsize + 2)
+        } else {
+            (xsize + 2, 0)
+        };
+        let pos_n = prev_row + pos.0;
+        let pos_ne = if pos.0 < xsize - 1 { pos_n + 1 } else { pos_n };
+        let pos_nw = if pos.0 > 0 { pos_n - 1 } else { pos_n };
+        // Get errors at the 3 neighboring positions (contiguous access per position)
+        let errors_n = self.get_errors_at_pos(pos_n);
+        let errors_ne = self.get_errors_at_pos(pos_ne);
+        let errors_nw = self.get_errors_at_pos(pos_nw);
+
+        let mut weights = [0u32; NUM_PREDICTORS];
+        for i in 0..NUM_PREDICTORS {
+            weights[i] = error_weight(
+                errors_n[i]
+                    .wrapping_add(errors_ne[i])
+                    .wrapping_add(errors_nw[i]),
+                self.wp_header.w(i).unwrap(),
+            );
+        }
+        let n = add_bits(data.top);
+        let w = add_bits(data.left);
+        let ne = add_bits(data.topright);
+        let nw = add_bits(data.topleft);
+        let nn = add_bits(data.toptop);
+
+        let te_w = if pos.0 == 0 {
+            0
+        } else {
+            self.error[cur_row + pos.0 - 1] as i64
+        };
+        let te_n = self.error[pos_n] as i64;
+        let te_nw = self.error[pos_nw] as i64;
+        let sum_wn = te_n + te_w;
+        let te_ne = self.error[pos_ne] as i64;
+
+        let mut p = te_w;
+        if te_n.abs() > p.abs() {
+            p = te_n;
+        }
+        if te_nw.abs() > p.abs() {
+            p = te_nw;
+        }
+        if te_ne.abs() > p.abs() {
+            p = te_ne;
+        }
+
+        self.prediction[0] = w + ne - n;
+        self.prediction[1] = n - (((sum_wn + te_ne) * self.wp_header.p1c as i64) >> 5);
+        self.prediction[2] = w - (((sum_wn + te_nw) * self.wp_header.p2c as i64) >> 5);
+        self.prediction[3] = n
+            - ((te_nw * (self.wp_header.p3ca as i64)
+                + (te_n * (self.wp_header.p3cb as i64))
+                + (te_ne * (self.wp_header.p3cc as i64))
+                + ((nn - n) * (self.wp_header.p3cd as i64))
+                + ((nw - w) * (self.wp_header.p3ce as i64)))
+                >> 5);
+
+        self.pred = weighted_average(&self.prediction, &mut weights);
+
+        if ((te_n ^ te_w) | (te_n ^ te_nw)) <= 0 {
+            let mx = w.max(ne.max(n));
+            let mn = w.min(ne.min(n));
+            self.pred = mn.max(mx.min(self.pred));
+        }
+        ((self.pred + PREDICTION_ROUND) >> PRED_EXTRA_BITS, p as i32)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::headers::modular::{GroupHeader, WeightedHeader};
+
+    use super::{PredictionData, WeightedPredictorState};
+
+    struct SimpleRandom {
+        out: i64,
+    }
+
+    impl SimpleRandom {
+        fn new() -> SimpleRandom {
+            SimpleRandom { out: 1 }
+        }
+        fn next(&mut self) -> i64 {
+            self.out = self.out * 48271 % 0x7fffffff;
+            self.out
+        }
+    }
+
+    fn step(
+        rng: &mut SimpleRandom,
+        state: &mut WeightedPredictorState,
+        xsize: usize,
+        ysize: usize,
+    ) -> (i64, i32) {
+        let pos = (rng.next() as usize % xsize, rng.next() as usize % ysize);
+        let res = state.predict_and_property(
+            pos,
+            xsize,
+            &PredictionData {
+                top: rng.next() as i32 % 256,
+                left: rng.next() as i32 % 256,
+                topright: rng.next() as i32 % 256,
+                topleft: rng.next() as i32 % 256,
+                toptop: rng.next() as i32 % 256,
+                leftleft: 0,
+                toprightright: 0,
+            },
+        );
+        state.update_errors((rng.next() % 256) as i32, pos, xsize);
+        res
+    }
+
+    #[test]
+    fn predict_and_update_errors() {
+        let mut rng = SimpleRandom::new();
+        let header = GroupHeader {
+            use_global_tree: false,
+            wp_header: WeightedHeader {
+                all_default: true,
+                p1c: rng.next() as u32 % 32,
+                p2c: rng.next() as u32 % 32,
+                p3ca: rng.next() as u32 % 32,
+                p3cb: rng.next() as u32 % 32,
+                p3cc: rng.next() as u32 % 32,
+                p3cd: rng.next() as u32 % 32,
+                p3ce: rng.next() as u32 % 32,
+                w0: rng.next() as u32 % 16,
+                w1: rng.next() as u32 % 16,
+                w2: rng.next() as u32 % 16,
+                w3: rng.next() as u32 % 16,
+            },
+            transforms: Vec::new(),
+        };
+        let xsize = 8;
+        let ysize = 8;
+        let mut state = WeightedPredictorState::new(&header.wp_header, xsize);
+        // The golden number results are generated by using the libjxl predictor with the same input numbers.
+        assert_eq!(step(&mut rng, &mut state, xsize, ysize), (135i64, 0i32));
+        assert_eq!(step(&mut rng, &mut state, xsize, ysize), (110i64, -60i32));
+        assert_eq!(step(&mut rng, &mut state, xsize, ysize), (165i64, 0i32));
+        assert_eq!(step(&mut rng, &mut state, xsize, ysize), (153i64, -60i32));
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/transforms/apply.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/transforms/apply.rs
new file mode 100644
index 0000000..2440619
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/transforms/apply.rs
@@ -0,0 +1,988 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::{cell::Ref, fmt::Debug};
+
+use num_traits::FromPrimitive;
+
+use crate::{
+    error::{Error, Result},
+    frame::modular::{
+        ChannelInfo, ModularBufferInfo, ModularChannel, ModularGridKind, Predictor,
+        borrowed_buffers::with_buffers,
+    },
+    headers::{
+        self,
+        frame_header::FrameHeader,
+        modular::{TransformId, WeightedHeader},
+    },
+    image::Rect,
+    util::tracing_wrappers::*,
+};
+use std::cell::RefMut;
+use std::ops::Deref;
+use std::ops::DerefMut;
+
+use super::{RctOp, RctPermutation};
+
+#[derive(Debug, Clone)]
+pub enum TransformStep {
+    Rct {
+        buf_in: [usize; 3],
+        buf_out: [usize; 3],
+        op: RctOp,
+        perm: RctPermutation,
+    },
+    Palette {
+        buf_in: usize,
+        buf_pal: usize,
+        buf_out: Vec<usize>,
+        num_colors: usize,
+        num_deltas: usize,
+        predictor: Predictor,
+        wp_header: WeightedHeader,
+    },
+    HSqueeze {
+        buf_in: [usize; 2],
+        buf_out: usize,
+    },
+    VSqueeze {
+        buf_in: [usize; 2],
+        buf_out: usize,
+    },
+}
+
+#[derive(Debug)]
+pub struct TransformStepChunk {
+    pub(super) step: TransformStep,
+    // Grid position this transform should produce.
+    // Note that this is a lie for Palette with AverageAll or Weighted, as the transform with
+    // position (0, y) will produce the entire row of blocks (*, y) (and there will be no
+    // transforms with position (x, y) with x > 0).
+    pub(super) grid_pos: (usize, usize),
+    // Number of inputs that are not yet available.
+    pub(super) incomplete_deps: usize,
+}
+
+impl TransformStepChunk {
+    // Marks that one dependency of this transform is ready, and potentially runs the transform,
+    // returning the new buffers that are now ready.
+    #[instrument(level = "trace", skip_all)]
+    pub fn dep_ready(
+        &mut self,
+        frame_header: &FrameHeader,
+        buffers: &mut [ModularBufferInfo],
+    ) -> Result<Vec<(usize, usize)>> {
+        self.incomplete_deps = self.incomplete_deps.checked_sub(1).unwrap();
+        if self.incomplete_deps > 0 {
+            trace!(
+                "skipping transform chunk because incomplete_deps = {}",
+                self.incomplete_deps
+            );
+            return Ok(vec![]);
+        }
+        let buf_out: &[usize] = match &self.step {
+            TransformStep::Rct { buf_out, .. } => buf_out,
+            TransformStep::Palette { buf_out, .. } => buf_out,
+            TransformStep::HSqueeze { buf_out, .. } | TransformStep::VSqueeze { buf_out, .. } => {
+                &[*buf_out]
+            }
+        };
+
+        let out_grid_kind = buffers[buf_out[0]].grid_kind;
+        let out_grid = buffers[buf_out[0]].get_grid_idx(out_grid_kind, self.grid_pos);
+        let out_size = buffers[buf_out[0]].info.size;
+        for bo in buf_out {
+            assert_eq!(out_grid_kind, buffers[*bo].grid_kind);
+            assert_eq!(out_size, buffers[*bo].info.size);
+        }
+
+        match &self.step {
+            TransformStep::Rct {
+                buf_in,
+                buf_out,
+                op,
+                perm,
+            } => {
+                for i in 0..3 {
+                    assert_eq!(out_grid_kind, buffers[buf_in[i]].grid_kind);
+                    assert_eq!(out_size, buffers[buf_in[i]].info.size);
+                    // Optimistically move the buffers to the output if possible.
+                    // If not, creates buffers in the output that are a copy of the input buffers.
+                    // This should be rare.
+                    *buffers[buf_out[i]].buffer_grid[out_grid].data.borrow_mut() =
+                        Some(buffers[buf_in[i]].buffer_grid[out_grid].get_buffer()?);
+                }
+                with_buffers(buffers, buf_out, out_grid, false, |mut bufs| {
+                    super::rct::do_rct_step(&mut bufs, *op, *perm);
+                    Ok(())
+                })?;
+                Ok(buf_out.iter().map(|x| (*x, out_grid)).collect())
+            }
+            TransformStep::Palette {
+                buf_in,
+                buf_pal,
+                buf_out,
+                ..
+            } if buffers[*buf_in].info.size.0 == 0 => {
+                // Nothing to do, just bookkeeping.
+                buffers[*buf_in].buffer_grid[out_grid].mark_used();
+                buffers[*buf_pal].buffer_grid[0].mark_used();
+                with_buffers(buffers, buf_out, out_grid, false, |_| Ok(()))?;
+                Ok(buf_out.iter().map(|x| (*x, out_grid)).collect())
+            }
+            TransformStep::Palette {
+                buf_in,
+                buf_pal,
+                buf_out,
+                num_colors,
+                num_deltas,
+                predictor,
+                ..
+            } if !predictor.requires_full_row() => {
+                assert_eq!(out_grid_kind, buffers[*buf_in].grid_kind);
+                assert_eq!(out_size, buffers[*buf_in].info.size);
+
+                {
+                    let img_in =
+                        Ref::map(buffers[*buf_in].buffer_grid[out_grid].data.borrow(), |x| {
+                            x.as_ref().unwrap()
+                        });
+                    let img_pal = Ref::map(buffers[*buf_pal].buffer_grid[0].data.borrow(), |x| {
+                        x.as_ref().unwrap()
+                    });
+                    // Ensure that the output buffers are present.
+                    // TODO(szabadka): Extend the callback to support many grid points.
+                    with_buffers(buffers, buf_out, out_grid, false, |_| Ok(()))?;
+                    let grid_shape = buffers[buf_out[0]].grid_shape;
+                    let grid_x = out_grid % grid_shape.0;
+                    let grid_y = out_grid / grid_shape.0;
+                    let border = if *predictor == Predictor::Zero { 0 } else { 1 };
+                    let grid_x0 = grid_x.saturating_sub(border);
+                    let grid_y0 = grid_y.saturating_sub(border);
+                    let grid_x1 = grid_x + 1;
+                    let grid_y1 = grid_y + 1;
+                    let mut out_bufs = vec![];
+                    for i in buf_out {
+                        for gy in grid_y0..grid_y1 {
+                            for gx in grid_x0..grid_x1 {
+                                let grid = gy * grid_shape.0 + gx;
+                                let buf = &buffers[*i];
+                                let b = &buf.buffer_grid[grid];
+                                let data = b.data.borrow_mut();
+                                out_bufs.push(RefMut::map(data, |x| x.as_mut().unwrap()));
+                            }
+                        }
+                    }
+                    let mut out_buf_refs: Vec<&mut ModularChannel> =
+                        out_bufs.iter_mut().map(|x| x.deref_mut()).collect();
+                    super::palette::do_palette_step_one_group(
+                        &img_in,
+                        &img_pal,
+                        &mut out_buf_refs,
+                        grid_x - grid_x0,
+                        grid_y - grid_y0,
+                        grid_x1 - grid_x0,
+                        grid_y1 - grid_y0,
+                        *num_colors,
+                        *num_deltas,
+                        *predictor,
+                    );
+                }
+                buffers[*buf_in].buffer_grid[out_grid].mark_used();
+                buffers[*buf_pal].buffer_grid[0].mark_used();
+                Ok(buf_out.iter().map(|x| (*x, out_grid)).collect())
+            }
+            TransformStep::Palette {
+                buf_in,
+                buf_pal,
+                buf_out,
+                num_colors,
+                num_deltas,
+                predictor,
+                wp_header,
+            } => {
+                assert_eq!(out_grid_kind, buffers[*buf_in].grid_kind);
+                assert_eq!(out_size, buffers[*buf_in].info.size);
+                let mut generated_chunks = Vec::<(usize, usize)>::new();
+                let grid_shape = buffers[buf_out[0]].grid_shape;
+                {
+                    assert_eq!(out_grid % grid_shape.0, 0);
+                    let grid_y = out_grid / grid_shape.0;
+                    let grid_y0 = grid_y.saturating_sub(1);
+                    let grid_y1 = grid_y + 1;
+                    let mut in_bufs = vec![];
+                    for grid_x in 0..grid_shape.0 {
+                        let grid = grid_y * grid_shape.0 + grid_x;
+                        in_bufs.push(Ref::map(
+                            buffers[*buf_in].buffer_grid[grid].data.borrow(),
+                            |x| x.as_ref().unwrap(),
+                        ));
+                        // Ensure that the output buffers are present.
+                        // TODO(szabadka): Extend the callback to support many grid points.
+                        with_buffers(buffers, buf_out, out_grid + grid_x, false, |_| Ok(()))?;
+                    }
+                    let in_buf_refs: Vec<&ModularChannel> =
+                        in_bufs.iter().map(|x| x.deref()).collect();
+                    let img_pal = Ref::map(buffers[*buf_pal].buffer_grid[0].data.borrow(), |x| {
+                        x.as_ref().unwrap()
+                    });
+                    let mut out_bufs = vec![];
+                    for i in buf_out {
+                        for grid_y in grid_y0..grid_y1 {
+                            for grid_x in 0..grid_shape.0 {
+                                let grid = grid_y * grid_shape.0 + grid_x;
+                                let buf = &buffers[*i];
+                                let b = &buf.buffer_grid[grid];
+                                let data = b.data.borrow_mut();
+                                out_bufs.push(RefMut::map(data, |x| x.as_mut().unwrap()));
+                            }
+                        }
+                    }
+                    let mut out_buf_refs: Vec<&mut ModularChannel> =
+                        out_bufs.iter_mut().map(|x| x.deref_mut()).collect();
+                    super::palette::do_palette_step_group_row(
+                        &in_buf_refs,
+                        &img_pal,
+                        &mut out_buf_refs,
+                        grid_y - grid_y0,
+                        grid_shape.0,
+                        *num_colors,
+                        *num_deltas,
+                        *predictor,
+                        wp_header,
+                    )?;
+                }
+                buffers[*buf_pal].buffer_grid[0].mark_used();
+                for grid_x in 0..grid_shape.0 {
+                    buffers[*buf_in].buffer_grid[out_grid + grid_x].mark_used();
+                    for buf in buf_out {
+                        generated_chunks.push((*buf, out_grid + grid_x));
+                    }
+                }
+                Ok(generated_chunks)
+            }
+            TransformStep::HSqueeze { buf_in, buf_out } => {
+                let buf_avg = &buffers[buf_in[0]];
+                let buf_res = &buffers[buf_in[1]];
+                let in_grid = buf_avg.get_grid_idx(out_grid_kind, self.grid_pos);
+                let res_grid = buf_res.get_grid_idx(out_grid_kind, self.grid_pos);
+                {
+                    trace!(
+                        "HSqueeze {:?} -> {:?}, grid {out_grid} grid pos {:?}",
+                        buf_in, buf_out, self.grid_pos
+                    );
+                    let (gx, gy) = self.grid_pos;
+                    let in_avg = Ref::map(buf_avg.buffer_grid[in_grid].data.borrow(), |x| {
+                        x.as_ref().unwrap()
+                    });
+                    let has_next = gx + 1 < buffers[*buf_out].grid_shape.0;
+                    let gx_next = if has_next { gx + 1 } else { gx };
+                    let next_avg_grid = buf_avg.get_grid_idx(out_grid_kind, (gx_next, gy));
+                    let in_next_avg =
+                        Ref::map(buf_avg.buffer_grid[next_avg_grid].data.borrow(), |x| {
+                            x.as_ref().unwrap()
+                        });
+                    let in_next_avg_rect = if has_next {
+                        Some(in_next_avg.data.get_rect(buf_avg.get_grid_rect(
+                            frame_header,
+                            out_grid_kind,
+                            (gx_next, gy),
+                        )))
+                    } else {
+                        None
+                    };
+                    let in_res = Ref::map(buf_res.buffer_grid[res_grid].data.borrow(), |x| {
+                        x.as_ref().unwrap()
+                    });
+                    let out_prev = if gx == 0 {
+                        None
+                    } else {
+                        let prev_out_grid =
+                            buffers[*buf_out].get_grid_idx(out_grid_kind, (gx - 1, gy));
+                        Some(Ref::map(
+                            buffers[*buf_out].buffer_grid[prev_out_grid].data.borrow(),
+                            |x| x.as_ref().unwrap(),
+                        ))
+                    };
+
+                    with_buffers(buffers, &[*buf_out], out_grid, false, |mut bufs| {
+                        super::squeeze::do_hsqueeze_step(
+                            &in_avg.data.get_rect(buf_avg.get_grid_rect(
+                                frame_header,
+                                out_grid_kind,
+                                (gx, gy),
+                            )),
+                            &in_res.data.get_rect(buf_res.get_grid_rect(
+                                frame_header,
+                                out_grid_kind,
+                                (gx, gy),
+                            )),
+                            &in_next_avg_rect,
+                            &out_prev,
+                            &mut bufs,
+                        );
+                        Ok(())
+                    })?;
+                }
+                buffers[buf_in[0]].buffer_grid[in_grid].mark_used();
+                buffers[buf_in[1]].buffer_grid[res_grid].mark_used();
+                Ok(vec![(*buf_out, out_grid)])
+            }
+            TransformStep::VSqueeze { buf_in, buf_out } => {
+                let buf_avg = &buffers[buf_in[0]];
+                let buf_res = &buffers[buf_in[1]];
+                let in_grid = buf_avg.get_grid_idx(out_grid_kind, self.grid_pos);
+                let res_grid = buf_res.get_grid_idx(out_grid_kind, self.grid_pos);
+                {
+                    trace!(
+                        "VSqueeze {:?} -> {:?} grid: {out_grid:?} grid pos: {:?}",
+                        buf_in, buf_out, self.grid_pos
+                    );
+                    let (gx, gy) = self.grid_pos;
+                    let in_avg = Ref::map(buf_avg.buffer_grid[in_grid].data.borrow(), |x| {
+                        x.as_ref().unwrap()
+                    });
+                    let has_next = gy + 1 < buffers[*buf_out].grid_shape.1;
+                    let gy_next = if has_next { gy + 1 } else { gy };
+                    let next_avg_grid = buf_avg.get_grid_idx(out_grid_kind, (gx, gy_next));
+                    let in_next_avg =
+                        Ref::map(buf_avg.buffer_grid[next_avg_grid].data.borrow(), |x| {
+                            x.as_ref().unwrap()
+                        });
+                    let in_next_avg_rect = if has_next {
+                        Some(in_next_avg.data.get_rect(buf_avg.get_grid_rect(
+                            frame_header,
+                            out_grid_kind,
+                            (gx, gy_next),
+                        )))
+                    } else {
+                        None
+                    };
+                    let in_res = Ref::map(buf_res.buffer_grid[res_grid].data.borrow(), |x| {
+                        x.as_ref().unwrap()
+                    });
+                    let out_prev = if gy == 0 {
+                        None
+                    } else {
+                        let prev_out_grid =
+                            buffers[*buf_out].get_grid_idx(out_grid_kind, (gx, gy - 1));
+                        Some(Ref::map(
+                            buffers[*buf_out].buffer_grid[prev_out_grid].data.borrow(),
+                            |x| x.as_ref().unwrap(),
+                        ))
+                    };
+                    let avg_grid_rect =
+                        buf_avg.get_grid_rect(frame_header, out_grid_kind, (gx, gy));
+                    let res_grid_rect =
+                        buf_res.get_grid_rect(frame_header, out_grid_kind, (gx, gy));
+                    with_buffers(buffers, &[*buf_out], out_grid, false, |mut bufs| {
+                        super::squeeze::do_vsqueeze_step(
+                            &in_avg.data.get_rect(avg_grid_rect),
+                            &in_res.data.get_rect(res_grid_rect),
+                            &in_next_avg_rect,
+                            &out_prev,
+                            &mut bufs,
+                        );
+                        Ok(())
+                    })?;
+                }
+                buffers[buf_in[0]].buffer_grid[in_grid].mark_used();
+                buffers[buf_in[1]].buffer_grid[res_grid].mark_used();
+                Ok(vec![(*buf_out, out_grid)])
+            }
+        }
+    }
+}
+
+#[instrument(level = "trace", err)]
+fn check_equal_channels(
+    channels: &[(usize, ChannelInfo)],
+    first_chan: usize,
+    num: usize,
+) -> Result<()> {
+    if first_chan + num > channels.len() {
+        return Err(Error::InvalidChannelRange(
+            first_chan,
+            first_chan + num,
+            channels.len(),
+        ));
+    }
+    for inc in 1..num {
+        if !channels[first_chan]
+            .1
+            .is_equivalent(&channels[first_chan + inc].1)
+        {
+            return Err(Error::MixingDifferentChannels);
+        }
+    }
+    Ok(())
+}
+
+fn meta_apply_single_transform(
+    transform: &headers::modular::Transform,
+    header: &headers::modular::GroupHeader,
+    channels: &mut Vec<(usize, ChannelInfo)>,
+    transform_steps: &mut Vec<TransformStep>,
+    mut add_transform_buffer: impl FnMut(ChannelInfo, String) -> usize,
+) -> Result<()> {
+    match transform.id {
+        TransformId::Rct => {
+            let begin_channel = transform.begin_channel as usize;
+            let op = RctOp::from_u32(transform.rct_type % 7).unwrap();
+            let perm = RctPermutation::from_u32(transform.rct_type / 7)
+                .expect("header decoding should ensure rct_type < 42");
+            check_equal_channels(channels, begin_channel, 3)?;
+            let mut buf_in = [0; 3];
+            let buf_out = [
+                channels[begin_channel].0,
+                channels[begin_channel + 1].0,
+                channels[begin_channel + 2].0,
+            ];
+            for i in 0..3 {
+                let c = &mut channels[begin_channel + i];
+                let mut info = c.1;
+                info.output_channel_idx = -1;
+                c.0 = add_transform_buffer(
+                    info,
+                    format!(
+                        "RCT (op {op:?} perm {perm:?}) starting at channel {begin_channel}, \
+			 input {i}"
+                    ),
+                );
+                buf_in[i] = c.0;
+            }
+            transform_steps.push(TransformStep::Rct {
+                buf_out,
+                buf_in,
+                op,
+                perm,
+            });
+            trace!("applied RCT: {channels:?}");
+        }
+        TransformId::Squeeze => {
+            let steps = if transform.squeezes.is_empty() {
+                super::squeeze::default_squeeze(channels)
+            } else {
+                transform.squeezes.clone()
+            };
+            for step in steps {
+                super::squeeze::check_squeeze_params(channels, &step)?;
+                let in_place = step.in_place;
+                let horizontal = step.horizontal;
+                let begin_channel = step.begin_channel as usize;
+                let num_channels = step.num_channels as usize;
+                let end_channel = begin_channel + num_channels;
+                let new_chan_offset = if in_place {
+                    end_channel
+                } else {
+                    channels.len()
+                };
+                for ic in 0..num_channels {
+                    let chan = &channels[begin_channel + ic].1;
+                    let new_shift = if let Some(shift) = chan.shift {
+                        if shift.0 > 30 || shift.1 > 30 {
+                            return Err(Error::TooManySqueezes);
+                        }
+                        if horizontal {
+                            Some((shift.0 + 1, shift.1))
+                        } else {
+                            Some((shift.0, shift.1 + 1))
+                        }
+                    } else {
+                        None
+                    };
+                    let w = chan.size.0;
+                    let h = chan.size.1;
+                    let (new_size_0, new_size_1) = if horizontal {
+                        ((w.div_ceil(2), h), (w - w.div_ceil(2), h))
+                    } else {
+                        ((w, h.div_ceil(2)), (w, h - h.div_ceil(2)))
+                    };
+                    let new_0 = ChannelInfo {
+                        output_channel_idx: -1,
+                        shift: new_shift,
+                        size: new_size_0,
+                        bit_depth: chan.bit_depth,
+                    };
+                    let buf_0 = add_transform_buffer(
+                        new_0,
+                        format!("Squeezed channel, original channel {}", begin_channel + ic),
+                    );
+                    let new_1 = ChannelInfo {
+                        output_channel_idx: -1,
+                        shift: new_shift,
+                        size: new_size_1,
+                        bit_depth: chan.bit_depth,
+                    };
+                    let buf_1 = add_transform_buffer(
+                        new_1,
+                        format!("Squeeze residual, original channel {}", begin_channel + ic),
+                    );
+                    if horizontal {
+                        transform_steps.push(TransformStep::HSqueeze {
+                            buf_in: [buf_0, buf_1],
+                            buf_out: channels[begin_channel + ic].0,
+                        });
+                    } else {
+                        transform_steps.push(TransformStep::VSqueeze {
+                            buf_in: [buf_0, buf_1],
+                            buf_out: channels[begin_channel + ic].0,
+                        });
+                    }
+                    channels[begin_channel + ic] = (buf_0, new_0);
+                    channels.insert(new_chan_offset + ic, (buf_1, new_1));
+                    trace!("applied squeeze: {channels:?}");
+                }
+            }
+        }
+        TransformId::Palette => {
+            let begin_channel = transform.begin_channel as usize;
+            let num_channels = transform.num_channels as usize;
+            let num_colors = transform.num_colors as usize;
+            let num_deltas = transform.num_deltas as usize;
+            let pred = Predictor::from_u32(transform.predictor_id)
+                .expect("header decoding should ensure a valid predictor");
+            check_equal_channels(channels, begin_channel, num_channels)?;
+            // We already checked the bit_depth for all channels from `begin_channel` is
+            // equal in the line above.
+            let bit_depth = channels[begin_channel].1.bit_depth;
+            let pchan_info = ChannelInfo {
+                output_channel_idx: -1,
+                shift: None,
+                size: (num_colors + num_deltas, num_channels),
+                bit_depth,
+            };
+            let pchan = add_transform_buffer(
+                pchan_info,
+                format!(
+                    "Palette for palette transform starting at channel {begin_channel} with \
+		     {num_channels} channels"
+                ),
+            );
+            let mut inchan_info = channels[begin_channel].1;
+            inchan_info.output_channel_idx = -1;
+            let inchan = add_transform_buffer(
+                inchan_info,
+                format!(
+                    "Pixel data for palette transform starting at channel {begin_channel} with \
+		     {num_channels} channels",
+                ),
+            );
+            transform_steps.push(TransformStep::Palette {
+                buf_in: inchan,
+                buf_pal: pchan,
+                buf_out: channels[begin_channel..(begin_channel + num_channels)]
+                    .iter()
+                    .map(|x| x.0)
+                    .collect(),
+                num_colors,
+                num_deltas,
+                predictor: pred,
+                wp_header: header.wp_header.clone(),
+            });
+            channels.drain(begin_channel + 1..begin_channel + num_channels);
+            channels[begin_channel].0 = inchan;
+            channels.insert(0, (pchan, pchan_info));
+            trace!("applied palette: {channels:?}");
+        }
+        TransformId::Invalid => {
+            unreachable!("header decoding for invalid transforms should fail");
+        }
+    }
+    Ok(())
+}
+
+#[instrument(level = "trace", ret)]
+pub fn meta_apply_transforms(
+    channels: &[ChannelInfo],
+    header: &headers::modular::GroupHeader,
+) -> Result<(Vec<ModularBufferInfo>, Vec<TransformStep>)> {
+    let mut buffer_info = vec![];
+    let mut transform_steps = vec![];
+    // (buffer id, channel info)
+    let mut channels: Vec<_> = channels.iter().cloned().enumerate().collect();
+
+    // First, add all the pre-transform channels to the buffer list.
+    for chan in channels.iter() {
+        buffer_info.push(ModularBufferInfo {
+            info: chan.1,
+            coded_channel_id: -1,
+            description: format!(
+                "Input channel {}, size {}x{}",
+                chan.0, chan.1.size.0, chan.1.size.1
+            ),
+            // To be filled by make_grids.
+            grid_kind: ModularGridKind::None,
+            grid_shape: (0, 0),
+            buffer_grid: vec![],
+        });
+    }
+
+    let mut add_transform_buffer = |info, description| {
+        buffer_info.push(ModularBufferInfo {
+            info,
+            coded_channel_id: -1,
+            description,
+            // To be filled by make_grids.
+            grid_kind: ModularGridKind::None,
+            grid_shape: (0, 0),
+            buffer_grid: vec![],
+        });
+        buffer_info.len() - 1
+    };
+
+    // Apply transforms to the channel list.
+    for transform in &header.transforms {
+        meta_apply_single_transform(
+            transform,
+            header,
+            &mut channels,
+            &mut transform_steps,
+            &mut add_transform_buffer,
+        )?;
+    }
+
+    // All the channels left over at the end of applying transforms are the channels that are
+    // actually coded.
+    for (chid, chan) in channels.iter().enumerate() {
+        buffer_info[chan.0].coded_channel_id = chid as isize;
+    }
+
+    #[cfg(feature = "tracing")]
+    for (i, transform) in transform_steps.iter().enumerate() {
+        trace!("Transform step {i}: {transform:?}");
+    }
+
+    Ok((buffer_info, transform_steps))
+}
+
+#[derive(Debug)]
+pub enum LocalTransformBuffer<'a> {
+    // This channel has been consumed by some transform.
+    Empty,
+    // This channel has not been written to yet.
+    Placeholder(ChannelInfo),
+    // Temporary, locally-allocated channel.
+    Owned(ModularChannel),
+    // Channel belonging to the global image.
+    Borrowed(&'a mut ModularChannel),
+}
+
+impl LocalTransformBuffer<'_> {
+    fn channel_info(&self) -> ChannelInfo {
+        match self {
+            LocalTransformBuffer::Empty => unreachable!("an empty buffer has no channel info"),
+            LocalTransformBuffer::Owned(m) => m.channel_info(),
+            LocalTransformBuffer::Placeholder(c) => *c,
+            LocalTransformBuffer::Borrowed(m) => m.channel_info(),
+        }
+    }
+
+    fn borrow_mut(&mut self) -> &mut ModularChannel {
+        match self {
+            LocalTransformBuffer::Owned(m) => m,
+            LocalTransformBuffer::Borrowed(m) => m,
+            LocalTransformBuffer::Empty => unreachable!("tried to borrow an empty channel"),
+            LocalTransformBuffer::Placeholder(_) => {
+                unreachable!("tried to borrow a placeholder channel")
+            }
+        }
+    }
+
+    fn take(&mut self) -> Self {
+        assert!(!matches!(self, LocalTransformBuffer::Empty));
+        let mut r = LocalTransformBuffer::Empty;
+        std::mem::swap(self, &mut r);
+        r
+    }
+
+    fn allocate_if_needed(&mut self) -> Result<()> {
+        if let LocalTransformBuffer::Placeholder(c) = self {
+            *self = LocalTransformBuffer::Owned(ModularChannel::new_with_shift(
+                c.size,
+                c.shift,
+                c.bit_depth,
+            )?);
+        }
+        Ok(())
+    }
+}
+
+#[instrument(level = "trace", ret)]
+pub fn meta_apply_local_transforms<'a, 'b>(
+    channels_in: Vec<&'a mut ModularChannel>,
+    buffer_storage: &'b mut Vec<LocalTransformBuffer<'a>>,
+    header: &headers::modular::GroupHeader,
+) -> Result<(Vec<&'b mut ModularChannel>, Vec<TransformStep>)> {
+    let mut transform_steps = vec![];
+
+    // (buffer id, channel info)
+    let mut channels: Vec<_> = channels_in
+        .iter()
+        .map(|x| x.channel_info())
+        .enumerate()
+        .collect();
+
+    debug!(?channels, "initial channels");
+
+    // First, add all the pre-transform channels to the buffer list.
+    buffer_storage.extend(channels_in.into_iter().map(LocalTransformBuffer::Borrowed));
+
+    #[allow(unused_variables)]
+    let mut add_transform_buffer = |info, description| {
+        trace!(description, ?info, "adding channel buffer");
+        buffer_storage.push(LocalTransformBuffer::Placeholder(info));
+        buffer_storage.len() - 1
+    };
+
+    // Apply transforms to the channel list.
+    for transform in &header.transforms {
+        meta_apply_single_transform(
+            transform,
+            header,
+            &mut channels,
+            &mut transform_steps,
+            &mut add_transform_buffer,
+        )?;
+    }
+
+    debug!(?channels, ?buffer_storage, "channels after transforms");
+    debug!(?transform_steps);
+
+    // Ensure that the buffer indices in `channels` appear in increasing order, by reordering them
+    // if necessary.
+    if !channels.iter().map(|x| x.0).is_sorted() {
+        let mut buf_new_position: Vec<_> = channels.iter().map(|x| x.0).collect();
+        buf_new_position.sort();
+        let buf_tmp: Vec<_> = channels
+            .iter()
+            .map(|x| {
+                let mut b = LocalTransformBuffer::Empty;
+                std::mem::swap(&mut b, &mut buffer_storage[x.0]);
+                b
+            })
+            .collect();
+
+        let mut buf_remap: Vec<_> = (0..buffer_storage.len()).collect();
+
+        for (new_pos, (ch_info, buf)) in buf_new_position
+            .iter()
+            .cloned()
+            .zip(channels.iter_mut().zip(buf_tmp.into_iter()))
+        {
+            assert!(matches!(
+                buffer_storage[new_pos],
+                LocalTransformBuffer::Empty
+            ));
+            buf_remap[ch_info.0] = new_pos;
+            buffer_storage[new_pos] = buf;
+            ch_info.0 = new_pos;
+        }
+
+        for step in transform_steps.iter_mut() {
+            use std::iter::once;
+            match step {
+                TransformStep::Rct {
+                    buf_in, buf_out, ..
+                } => {
+                    for b in buf_in.iter_mut().chain(buf_out.iter_mut()) {
+                        *b = buf_remap[*b];
+                    }
+                }
+                TransformStep::Palette {
+                    buf_in,
+                    buf_pal,
+                    buf_out,
+                    ..
+                } => {
+                    for b in once(buf_in).chain(once(buf_pal)).chain(buf_out.iter_mut()) {
+                        *b = buf_remap[*b];
+                    }
+                }
+                TransformStep::HSqueeze { buf_in, buf_out }
+                | TransformStep::VSqueeze { buf_in, buf_out } => {
+                    for b in once(buf_out).chain(buf_in.iter_mut()) {
+                        *b = buf_remap[*b];
+                    }
+                }
+            }
+        }
+    }
+
+    debug!(?channels, ?buffer_storage, "sorted channels");
+
+    debug!(?transform_steps);
+
+    // Since RCT steps will try to transfer buffers from the source channels to the destination
+    // channels, make sure we do the reverse transformation here (to have the caller-provided
+    // buffers be used for writing temporary data).
+    for ts in transform_steps.iter() {
+        if let TransformStep::Rct {
+            buf_in, buf_out, ..
+        } = ts
+        {
+            for c in 0..3 {
+                assert_eq!(
+                    buffer_storage[buf_in[c]].channel_info(),
+                    buffer_storage[buf_out[c]].channel_info()
+                );
+                assert!(matches!(
+                    buffer_storage[buf_in[c]],
+                    LocalTransformBuffer::Placeholder(_)
+                ));
+                buffer_storage.swap(buf_in[c], buf_out[c]);
+            }
+        }
+    }
+
+    debug!(?channels, ?buffer_storage, "RCT-adjusted channels");
+
+    // Allocate all the coded channels if they aren't yet.
+    for (buf, _) in channels.iter() {
+        buffer_storage[*buf].allocate_if_needed()?;
+    }
+
+    debug!(?channels, ?buffer_storage, "allocated buffers");
+
+    // Extract references to to-be-decoded buffers.
+    let mut coded_buffers = Vec::with_capacity(channels.len());
+    let mut buffer_tail = &mut buffer_storage[..];
+    let mut last_buffer = None;
+    for (buf, _) in channels {
+        let offset = if let Some(lb) = last_buffer {
+            buf.checked_sub(lb).unwrap()
+        } else {
+            buf + 1
+        };
+        let cur_buf;
+        (cur_buf, buffer_tail) = buffer_tail.split_at_mut(offset);
+        coded_buffers.push(cur_buf.last_mut().unwrap().borrow_mut());
+        last_buffer = Some(buf);
+    }
+
+    Ok((coded_buffers, transform_steps))
+}
+
+impl TransformStep {
+    // Marks that one dependency of this transform is ready, and potentially runs the transform,
+    // returning the new buffers that are now ready.
+    pub fn local_apply(&self, buffers: &mut [LocalTransformBuffer]) -> Result<()> {
+        match self {
+            TransformStep::Rct {
+                buf_in,
+                buf_out,
+                op,
+                perm,
+            } => {
+                for i in 0..3 {
+                    assert_eq!(
+                        buffers[buf_in[i]].channel_info(),
+                        buffers[buf_out[i]].channel_info()
+                    );
+                }
+                let [mut a, mut b, mut c] = [
+                    buffers[buf_in[0]].take(),
+                    buffers[buf_in[1]].take(),
+                    buffers[buf_in[2]].take(),
+                ];
+                {
+                    let mut bufs = [a.borrow_mut(), b.borrow_mut(), c.borrow_mut()];
+                    super::rct::do_rct_step(&mut bufs, *op, *perm);
+                }
+                buffers[buf_out[0]] = a;
+                buffers[buf_out[1]] = b;
+                buffers[buf_out[2]] = c;
+            }
+            TransformStep::Palette {
+                buf_in,
+                buf_pal,
+                buf_out,
+                num_colors,
+                num_deltas,
+                predictor,
+                wp_header,
+            } => {
+                for b in buf_out.iter() {
+                    assert_eq!(
+                        buffers[*b].channel_info().size,
+                        buffers[*buf_in].channel_info().size
+                    );
+                    buffers[*b].allocate_if_needed()?;
+                }
+                let mut img_in = buffers[*buf_in].take();
+                let mut img_pal = buffers[*buf_pal].take();
+                let mut out_bufs: Vec<_> = buf_out.iter().map(|x| buffers[*x].take()).collect();
+                {
+                    let mut bufs: Vec<_> = out_bufs.iter_mut().map(|x| x.borrow_mut()).collect();
+                    super::palette::do_palette_step_general(
+                        img_in.borrow_mut(),
+                        img_pal.borrow_mut(),
+                        &mut bufs,
+                        *num_colors,
+                        *num_deltas,
+                        *predictor,
+                        wp_header,
+                    );
+                }
+                for (pos, buf) in buf_out.iter().zip(out_bufs.into_iter()) {
+                    buffers[*pos] = buf;
+                }
+            }
+            TransformStep::HSqueeze { buf_in, buf_out } => {
+                buffers[*buf_out].allocate_if_needed()?;
+                let mut out_buf = buffers[*buf_out].take();
+                let mut in_avg = buffers[buf_in[0]].take();
+                let mut in_res = buffers[buf_in[1]].take();
+                {
+                    let mut bufs: Vec<_> = vec![out_buf.borrow_mut()];
+                    let in_avg = &in_avg.borrow_mut().data;
+                    let in_res = &in_res.borrow_mut().data;
+                    super::squeeze::do_hsqueeze_step(
+                        &in_avg.get_rect(Rect {
+                            size: in_avg.size(),
+                            origin: (0, 0),
+                        }),
+                        &in_res.get_rect(Rect {
+                            size: in_res.size(),
+                            origin: (0, 0),
+                        }),
+                        &None,
+                        &None,
+                        &mut bufs,
+                    );
+                }
+                buffers[*buf_out] = out_buf;
+            }
+            TransformStep::VSqueeze { buf_in, buf_out } => {
+                buffers[*buf_out].allocate_if_needed()?;
+                let mut out_buf = buffers[*buf_out].take();
+                let mut in_avg = buffers[buf_in[0]].take();
+                let mut in_res = buffers[buf_in[1]].take();
+                {
+                    let mut bufs: Vec<_> = vec![out_buf.borrow_mut()];
+                    let in_avg = &in_avg.borrow_mut().data;
+                    let in_res = &in_res.borrow_mut().data;
+                    super::squeeze::do_vsqueeze_step(
+                        &in_avg.get_rect(Rect {
+                            size: in_avg.size(),
+                            origin: (0, 0),
+                        }),
+                        &in_res.get_rect(Rect {
+                            size: in_res.size(),
+                            origin: (0, 0),
+                        }),
+                        &None,
+                        &None,
+                        &mut bufs,
+                    );
+                }
+                buffers[*buf_out] = out_buf;
+            }
+        };
+
+        Ok(())
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/transforms/mod.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/transforms/mod.rs
new file mode 100644
index 0000000..0c0be9a
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/transforms/mod.rs
@@ -0,0 +1,384 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::cell::RefCell;
+
+use apply::TransformStep;
+pub use apply::TransformStepChunk;
+use num_derive::FromPrimitive;
+
+use crate::frame::modular::ModularBuffer;
+use crate::headers::frame_header::FrameHeader;
+use crate::util::tracing_wrappers::*;
+
+use super::{ModularBufferInfo, ModularGridKind, Predictor};
+
+pub(super) mod apply;
+mod palette;
+mod rct;
+mod squeeze;
+
+#[derive(Debug, FromPrimitive, PartialEq, Clone, Copy)]
+pub enum RctPermutation {
+    Rgb = 0,
+    Gbr = 1,
+    Brg = 2,
+    Rbg = 3,
+    Grb = 4,
+    Bgr = 5,
+}
+
+#[derive(Debug, FromPrimitive, PartialEq, Clone, Copy)]
+pub enum RctOp {
+    Noop = 0,
+    AddFirstToThird = 1,
+    AddFirstToSecond = 2,
+    AddFirstToSecondAndThird = 3,
+    AddAvgToSecond = 4,
+    AddFirstToThirdAndAvgToSecond = 5,
+    YCoCg = 6,
+}
+
+#[instrument(level = "trace", skip_all, ret)]
+pub fn make_grids(
+    frame_header: &FrameHeader,
+    transform_steps: Vec<TransformStep>,
+    section_buffer_indices: &[Vec<usize>],
+    buffer_info: &mut Vec<ModularBufferInfo>,
+) -> Vec<TransformStepChunk> {
+    // Initialize grid sizes, starting from coded channels.
+    for i in section_buffer_indices[1].iter() {
+        buffer_info[*i].grid_kind = ModularGridKind::Lf;
+    }
+    for buffer_indices in section_buffer_indices.iter().skip(2) {
+        for i in buffer_indices.iter() {
+            buffer_info[*i].grid_kind = ModularGridKind::Hf;
+        }
+    }
+
+    trace!(?buffer_info, "post set grid kind for coded channels");
+
+    // Transforms can be un-applied in the opposite order they appear with in the array,
+    // so we can use that information to propagate grid kinds.
+
+    for step in transform_steps.iter().rev() {
+        match step {
+            TransformStep::Rct {
+                buf_in, buf_out, ..
+            } => {
+                let grid_in = buffer_info[buf_in[0]].grid_kind;
+                for i in 0..3 {
+                    assert_eq!(grid_in, buffer_info[buf_in[i]].grid_kind);
+                }
+                for i in 0..3 {
+                    buffer_info[buf_out[i]].grid_kind = grid_in;
+                }
+            }
+            TransformStep::Palette {
+                buf_in, buf_out, ..
+            } => {
+                for buf in buf_out.iter() {
+                    buffer_info[*buf].grid_kind = buffer_info[*buf_in].grid_kind;
+                }
+            }
+            TransformStep::HSqueeze { buf_in, buf_out }
+            | TransformStep::VSqueeze { buf_in, buf_out } => {
+                let mut grid_kind = buffer_info[buf_in[0]]
+                    .grid_kind
+                    .max(buffer_info[buf_in[1]].grid_kind);
+                if grid_kind == ModularGridKind::None
+                    && !buffer_info[*buf_out]
+                        .info
+                        .is_meta_or_small(frame_header.group_dim())
+                {
+                    grid_kind = ModularGridKind::Hf;
+                }
+                buffer_info[*buf_out].grid_kind = grid_kind;
+            }
+        }
+    }
+
+    // Set grid shapes.
+    for buf in buffer_info.iter_mut() {
+        buf.grid_shape = buf.grid_kind.grid_shape(frame_header);
+    }
+
+    trace!(?buffer_info, "post propagate grid kind");
+
+    let get_grid_indices = |shape: (usize, usize)| {
+        (0..shape.1).flat_map(move |y| (0..shape.0).map(move |x| (x as isize, y as isize)))
+    };
+
+    // Create grids.
+    for g in buffer_info.iter_mut() {
+        let is_output = g.info.output_channel_idx >= 0;
+        g.buffer_grid = get_grid_indices(g.grid_shape)
+            .map(|(x, y)| ModularBuffer {
+                data: RefCell::new(None),
+                remaining_uses: if is_output { 1 } else { 0 },
+                used_by_transforms: vec![],
+                size: g
+                    .get_grid_rect(frame_header, g.grid_kind, (x as usize, y as usize))
+                    .size,
+            })
+            .collect();
+    }
+
+    trace!(?buffer_info, "with grids");
+
+    let add_transform_step =
+        |transform: &TransformStep,
+         grid_pos: (isize, isize),
+         grid_transform_steps: &mut Vec<TransformStepChunk>| {
+            let ts = grid_transform_steps.len();
+            grid_transform_steps.push(TransformStepChunk {
+                step: transform.clone(),
+                grid_pos: (grid_pos.0 as usize, grid_pos.1 as usize),
+                incomplete_deps: 0,
+            });
+            ts
+        };
+
+    let add_grid_use = |ts: usize,
+                        input_buffer_idx: usize,
+                        output_grid_kind: ModularGridKind,
+                        output_grid_shape: (usize, usize),
+                        output_grid_pos: (isize, isize),
+                        grid_transform_steps: &mut Vec<TransformStepChunk>,
+                        buffer_info: &mut Vec<ModularBufferInfo>| {
+        let output_grid_size = (output_grid_shape.0 as isize, output_grid_shape.1 as isize);
+        if output_grid_pos.0 < 0
+            || output_grid_pos.0 >= output_grid_size.0
+            || output_grid_pos.1 < 0
+            || output_grid_pos.1 >= output_grid_size.1
+        {
+            // Skip adding uses of non-existent grid positions.
+            return;
+        }
+        let output_grid_pos = (output_grid_pos.0 as usize, output_grid_pos.1 as usize);
+        let input_grid_pos =
+            buffer_info[input_buffer_idx].get_grid_idx(output_grid_kind, output_grid_pos);
+        if !buffer_info[input_buffer_idx].buffer_grid[input_grid_pos]
+            .used_by_transforms
+            .contains(&ts)
+        {
+            buffer_info[input_buffer_idx].buffer_grid[input_grid_pos].remaining_uses += 1;
+            buffer_info[input_buffer_idx].buffer_grid[input_grid_pos]
+                .used_by_transforms
+                .push(ts);
+            grid_transform_steps[ts].incomplete_deps += 1;
+        }
+    };
+
+    // Add grid-ed transforms.
+    let mut grid_transform_steps = vec![];
+
+    for transform in transform_steps {
+        match &transform {
+            TransformStep::Rct {
+                buf_in, buf_out, ..
+            } => {
+                // Easy case: we just depend on the 3 input buffers in the same location.
+                let out_kind = buffer_info[buf_out[0]].grid_kind;
+                let out_shape = buffer_info[buf_out[0]].grid_shape;
+                for (x, y) in get_grid_indices(out_shape) {
+                    let ts = add_transform_step(&transform, (x, y), &mut grid_transform_steps);
+                    for bin in buf_in {
+                        add_grid_use(
+                            ts,
+                            *bin,
+                            out_kind,
+                            out_shape,
+                            (x, y),
+                            &mut grid_transform_steps,
+                            buffer_info,
+                        );
+                    }
+                }
+            }
+            TransformStep::Palette {
+                buf_in,
+                buf_pal,
+                buf_out,
+                predictor,
+                ..
+            } if predictor.requires_full_row() => {
+                // Delta palette with AverageAll or Weighted. Those are special, because we can
+                // only make progress one full image row at a time (since we need decoded values
+                // from the previous row or two rows).
+                let out_kind = buffer_info[buf_out[0]].grid_kind;
+                let out_shape = buffer_info[buf_out[0]].grid_shape;
+                let mut ts = 0;
+                for (x, y) in get_grid_indices(out_shape) {
+                    if x == 0 {
+                        ts = add_transform_step(&transform, (x, y), &mut grid_transform_steps);
+                        add_grid_use(
+                            ts,
+                            *buf_pal,
+                            out_kind,
+                            out_shape,
+                            (x, y),
+                            &mut grid_transform_steps,
+                            buffer_info,
+                        );
+                    }
+                    add_grid_use(
+                        ts,
+                        *buf_in,
+                        out_kind,
+                        out_shape,
+                        (x, y),
+                        &mut grid_transform_steps,
+                        buffer_info,
+                    );
+                    for out in buf_out.iter() {
+                        add_grid_use(
+                            ts,
+                            *out,
+                            out_kind,
+                            out_shape,
+                            (x, y - 1),
+                            &mut grid_transform_steps,
+                            buffer_info,
+                        );
+                    }
+                }
+            }
+            TransformStep::Palette {
+                buf_in,
+                buf_pal,
+                buf_out,
+                predictor,
+                ..
+            } => {
+                // Maybe-delta palette: we depend on the palette and the input buffer in the same
+                // location. We may also depend on other grid positions in the output buffer,
+                // according to the used predictor.
+                let out_kind = buffer_info[buf_out[0]].grid_kind;
+                let out_shape = buffer_info[buf_out[0]].grid_shape;
+                for (x, y) in get_grid_indices(out_shape) {
+                    let ts = add_transform_step(&transform, (x, y), &mut grid_transform_steps);
+                    add_grid_use(
+                        ts,
+                        *buf_pal,
+                        out_kind,
+                        out_shape,
+                        (x, y),
+                        &mut grid_transform_steps,
+                        buffer_info,
+                    );
+                    add_grid_use(
+                        ts,
+                        *buf_in,
+                        out_kind,
+                        out_shape,
+                        (x, y),
+                        &mut grid_transform_steps,
+                        buffer_info,
+                    );
+                    let offsets = match predictor {
+                        Predictor::Zero => [].as_slice(),
+                        _ => &[(0, -1), (-1, 0), (-1, -1)],
+                    };
+                    for (dx, dy) in offsets {
+                        for out in buf_out.iter() {
+                            add_grid_use(
+                                ts,
+                                *out,
+                                out_kind,
+                                out_shape,
+                                (x + dx, y + dy),
+                                &mut grid_transform_steps,
+                                buffer_info,
+                            );
+                        }
+                    }
+                }
+            }
+            TransformStep::HSqueeze { buf_in, buf_out } => {
+                let out_kind = buffer_info[*buf_out].grid_kind;
+                let out_shape = buffer_info[*buf_out].grid_shape;
+                for (x, y) in get_grid_indices(out_shape) {
+                    let ts = add_transform_step(&transform, (x, y), &mut grid_transform_steps);
+                    // Average and residuals from the same position
+                    for bin in buf_in {
+                        add_grid_use(
+                            ts,
+                            *bin,
+                            out_kind,
+                            out_shape,
+                            (x, y),
+                            &mut grid_transform_steps,
+                            buffer_info,
+                        );
+                    }
+                    // Next average
+                    add_grid_use(
+                        ts,
+                        buf_in[0],
+                        out_kind,
+                        out_shape,
+                        (x + 1, y),
+                        &mut grid_transform_steps,
+                        buffer_info,
+                    );
+                    // Previous decoded
+                    add_grid_use(
+                        ts,
+                        *buf_out,
+                        out_kind,
+                        out_shape,
+                        (x - 1, y),
+                        &mut grid_transform_steps,
+                        buffer_info,
+                    );
+                }
+            }
+            TransformStep::VSqueeze { buf_in, buf_out } => {
+                let out_kind = buffer_info[*buf_out].grid_kind;
+                let out_shape = buffer_info[*buf_out].grid_shape;
+                for (x, y) in get_grid_indices(out_shape) {
+                    let ts = add_transform_step(&transform, (x, y), &mut grid_transform_steps);
+                    // Average and residuals from the same position
+                    for bin in buf_in {
+                        add_grid_use(
+                            ts,
+                            *bin,
+                            out_kind,
+                            out_shape,
+                            (x, y),
+                            &mut grid_transform_steps,
+                            buffer_info,
+                        );
+                    }
+                    // Next average
+                    add_grid_use(
+                        ts,
+                        buf_in[0],
+                        out_kind,
+                        out_shape,
+                        (x, y + 1),
+                        &mut grid_transform_steps,
+                        buffer_info,
+                    );
+                    // Previous decoded
+                    add_grid_use(
+                        ts,
+                        *buf_out,
+                        out_kind,
+                        out_shape,
+                        (x, y - 1),
+                        &mut grid_transform_steps,
+                        buffer_info,
+                    );
+                }
+            }
+        }
+    }
+
+    trace!(?grid_transform_steps, ?buffer_info);
+
+    grid_transform_steps
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/transforms/palette.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/transforms/palette.rs
new file mode 100644
index 0000000..ae7c711
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/transforms/palette.rs
@@ -0,0 +1,452 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{
+    error::Result,
+    frame::modular::{
+        ModularChannel, Predictor,
+        predict::{PredictionData, WeightedPredictorState},
+    },
+    headers::modular::WeightedHeader,
+    image::Image,
+};
+
+const RGB_CHANNELS: usize = 3;
+
+// 5x5x5 color cube for the larger cube.
+const LARGE_CUBE: usize = 5;
+
+// Smaller interleaved color cube to fill the holes of the larger cube.
+const SMALL_CUBE: usize = 4;
+const SMALL_CUBE_BITS: usize = 2;
+// SMALL_CUBE ** 3
+const LARGE_CUBE_OFFSET: usize = SMALL_CUBE * SMALL_CUBE * SMALL_CUBE;
+
+fn scale<const DENOM: usize>(value: usize, bit_depth: usize) -> i32 {
+    // return (value * ((1 << bit_depth) - 1)) / DENOM;
+    // We only call this function with SMALL_CUBE or LARGE_CUBE - 1 as DENOM,
+    // allowing us to avoid a division here.
+    const {
+        assert!(DENOM == 4, "denom must be 4");
+    }
+    ((value * ((1 << bit_depth) - 1)) >> 2) as i32
+}
+
+// The purpose of this function is solely to extend the interpretation of
+// palette indices to implicit values. If index < nb_deltas, indicating that the
+// result is a delta palette entry, it is the responsibility of the caller to
+// treat it as such.
+fn get_palette_value(
+    palette: &Image<i32>,
+    index: isize,
+    c: usize,
+    palette_size: usize,
+    bit_depth: usize,
+) -> i32 {
+    if index < 0 {
+        const DELTA_PALETTE: [[i32; 3]; 72] = [
+            [0, 0, 0],
+            [4, 4, 4],
+            [11, 0, 0],
+            [0, 0, -13],
+            [0, -12, 0],
+            [-10, -10, -10],
+            [-18, -18, -18],
+            [-27, -27, -27],
+            [-18, -18, 0],
+            [0, 0, -32],
+            [-32, 0, 0],
+            [-37, -37, -37],
+            [0, -32, -32],
+            [24, 24, 45],
+            [50, 50, 50],
+            [-45, -24, -24],
+            [-24, -45, -45],
+            [0, -24, -24],
+            [-34, -34, 0],
+            [-24, 0, -24],
+            [-45, -45, -24],
+            [64, 64, 64],
+            [-32, 0, -32],
+            [0, -32, 0],
+            [-32, 0, 32],
+            [-24, -45, -24],
+            [45, 24, 45],
+            [24, -24, -45],
+            [-45, -24, 24],
+            [80, 80, 80],
+            [64, 0, 0],
+            [0, 0, -64],
+            [0, -64, -64],
+            [-24, -24, 45],
+            [96, 96, 96],
+            [64, 64, 0],
+            [45, -24, -24],
+            [34, -34, 0],
+            [112, 112, 112],
+            [24, -45, -45],
+            [45, 45, -24],
+            [0, -32, 32],
+            [24, -24, 45],
+            [0, 96, 96],
+            [45, -24, 24],
+            [24, -45, -24],
+            [-24, -45, 24],
+            [0, -64, 0],
+            [96, 0, 0],
+            [128, 128, 128],
+            [64, 0, 64],
+            [144, 144, 144],
+            [96, 96, 0],
+            [-36, -36, 36],
+            [45, -24, -45],
+            [45, -45, -24],
+            [0, 0, -96],
+            [0, 128, 128],
+            [0, 96, 0],
+            [45, 24, -45],
+            [-128, 0, 0],
+            [24, -45, 24],
+            [-45, 24, -45],
+            [64, 0, -64],
+            [64, -64, -64],
+            [96, 0, 96],
+            [45, -45, 24],
+            [24, 45, -45],
+            [64, 64, -64],
+            [128, 128, 0],
+            [0, 0, -128],
+            [-24, 45, -45],
+        ];
+        if c >= RGB_CHANNELS {
+            return 0;
+        }
+        // Do not open the brackets, otherwise INT32_MIN negation could overflow.
+        let mut index = -(index + 1) as usize;
+        index %= 1 + 2 * (DELTA_PALETTE.len() - 1);
+        const MULTIPLIER: [i32; 2] = [-1, 1];
+        let mut result = DELTA_PALETTE[(index + 1) >> 1][c] * MULTIPLIER[index & 1];
+        if bit_depth > 8 {
+            result *= 1 << (bit_depth - 8);
+        }
+        result
+    } else {
+        let mut index = index as usize;
+        if palette_size <= index && index < palette_size + LARGE_CUBE_OFFSET {
+            if c >= RGB_CHANNELS {
+                return 0;
+            }
+            index -= palette_size;
+            index >>= c * SMALL_CUBE_BITS;
+            scale::<SMALL_CUBE>(index % SMALL_CUBE, bit_depth)
+                + (1 << (0.max(bit_depth as isize - 3)))
+        } else if palette_size + LARGE_CUBE_OFFSET <= index {
+            if c >= RGB_CHANNELS {
+                return 0;
+            }
+            index -= palette_size + LARGE_CUBE_OFFSET;
+            // TODO(eustas): should we take care of ambiguity created by
+            //               index >= LARGE_CUBE ** 3 ?
+            match c {
+                0 => (),
+                1 => {
+                    index /= LARGE_CUBE;
+                }
+                2 => {
+                    index /= LARGE_CUBE * LARGE_CUBE;
+                }
+                _ => (),
+            }
+            scale::<{ LARGE_CUBE - 1 }>(index % LARGE_CUBE, bit_depth)
+        } else {
+            palette.row(c)[index]
+        }
+    }
+}
+
+pub fn do_palette_step_general(
+    buf_in: &ModularChannel,
+    buf_pal: &ModularChannel,
+    buf_out: &mut [&mut ModularChannel],
+    num_colors: usize,
+    num_deltas: usize,
+    predictor: Predictor,
+    wp_header: &WeightedHeader,
+) {
+    let (w, h) = buf_in.data.size();
+    let palette = &buf_pal.data;
+    let bit_depth = buf_in.bit_depth.bits_per_sample().min(24) as usize;
+
+    if w == 0 {
+        // Nothing to do.
+        // Avoid touching "empty" channels with non-zero height.
+    } else if num_deltas == 0 && predictor == Predictor::Zero {
+        for (chan_index, out) in buf_out.iter_mut().enumerate() {
+            for y in 0..h {
+                let row_index = buf_in.data.row(y);
+                let row_out = out.data.row_mut(y);
+                for x in 0..w {
+                    let index = row_index[x];
+                    let palette_value = get_palette_value(
+                        palette,
+                        index as isize,
+                        /*c=*/ chan_index,
+                        /*palette_size=*/ num_colors,
+                        /*bit_depth=*/ bit_depth,
+                    );
+                    row_out[x] = palette_value;
+                }
+            }
+        }
+    } else if predictor == Predictor::Weighted {
+        let w = buf_in.data.size().0;
+        for (chan_index, out) in buf_out.iter_mut().enumerate() {
+            let mut wp_state = WeightedPredictorState::new(wp_header, w);
+            for y in 0..h {
+                let idx = buf_in.data.row(y);
+                for (x, &index) in idx.iter().enumerate() {
+                    let palette_entry = get_palette_value(
+                        palette,
+                        index as isize,
+                        /*c=*/ chan_index,
+                        /*palette_size=*/ num_colors + num_deltas,
+                        /*bit_depth=*/ bit_depth,
+                    );
+                    let val = if index < num_deltas as i32 {
+                        let prediction_data = PredictionData::get(&out.data, x, y);
+                        let (wp_pred, _) =
+                            wp_state.predict_and_property((x, y), w, &prediction_data);
+                        let pred = predictor.predict_one(prediction_data, wp_pred);
+                        (pred + palette_entry as i64) as i32
+                    } else {
+                        palette_entry
+                    };
+                    out.data.row_mut(y)[x] = val;
+                    wp_state.update_errors(val, (x, y), w);
+                }
+            }
+        }
+    } else {
+        for (chan_index, out) in buf_out.iter_mut().enumerate() {
+            for y in 0..h {
+                let idx = buf_in.data.row(y);
+                for (x, &index) in idx.iter().enumerate() {
+                    let palette_entry = get_palette_value(
+                        palette,
+                        index as isize,
+                        /*c=*/ chan_index,
+                        /*palette_size=*/ num_colors + num_deltas,
+                        /*bit_depth=*/ bit_depth,
+                    );
+                    let val = if index < num_deltas as i32 {
+                        let pred = predictor
+                            .predict_one(PredictionData::get(&out.data, x, y), /*wp_pred=*/ 0);
+                        (pred + palette_entry as i64) as i32
+                    } else {
+                        palette_entry
+                    };
+                    out.data.row_mut(y)[x] = val;
+                }
+            }
+        }
+    }
+}
+
+#[allow(clippy::too_many_arguments)]
+fn get_prediction_data(
+    buf: &mut [&mut ModularChannel],
+    idx: usize,
+    grid_x: usize,
+    grid_y: usize,
+    grid_xsize: usize,
+    x: usize,
+    y: usize,
+    xsize: usize,
+    ysize: usize,
+) -> PredictionData {
+    PredictionData::get_with_neighbors(
+        &buf[idx].data,
+        if grid_x > 0 {
+            Some(&buf[idx - 1].data)
+        } else {
+            None
+        },
+        if grid_y > 0 {
+            Some(&buf[idx - grid_xsize].data)
+        } else {
+            None
+        },
+        if grid_x > 0 && grid_y > 0 {
+            Some(&buf[idx - grid_xsize - 1].data)
+        } else {
+            None
+        },
+        if grid_x + 1 < grid_xsize {
+            Some(&buf[idx + 1].data)
+        } else {
+            None
+        },
+        if grid_x + 1 < grid_xsize && grid_y > 0 {
+            Some(&buf[idx - grid_xsize + 1].data)
+        } else {
+            None
+        },
+        x,
+        y,
+        xsize,
+        ysize,
+    )
+}
+
+#[allow(clippy::too_many_arguments)]
+pub fn do_palette_step_one_group(
+    buf_in: &ModularChannel,
+    buf_pal: &ModularChannel,
+    buf_out: &mut [&mut ModularChannel],
+    grid_x: usize,
+    grid_y: usize,
+    grid_xsize: usize,
+    grid_ysize: usize,
+    num_colors: usize,
+    num_deltas: usize,
+    predictor: Predictor,
+) {
+    let h = buf_in.data.size().1;
+    let palette = &buf_pal.data;
+    let bit_depth = buf_in.bit_depth.bits_per_sample().min(24) as usize;
+    let num_c = buf_out.len() / (grid_xsize * grid_ysize);
+    let (xsize, ysize) = buf_out[0].data.size();
+
+    for c in 0..num_c {
+        for y in 0..h {
+            let index_img = buf_in.data.row(y);
+            let out_idx = c * grid_ysize * grid_xsize + grid_y * grid_xsize + grid_x;
+            for (x, &index) in index_img.iter().enumerate() {
+                let palette_entry = get_palette_value(
+                    palette,
+                    index as isize,
+                    c,
+                    /*palette_size=*/ num_colors + num_deltas,
+                    /*bit_depth=*/ bit_depth,
+                );
+                let val = if index < num_deltas as i32 {
+                    let pred = predictor.predict_one(
+                        get_prediction_data(
+                            buf_out, out_idx, grid_x, grid_y, grid_xsize, x, y, xsize, ysize,
+                        ),
+                        /*wp_pred=*/ 0,
+                    );
+                    (pred + palette_entry as i64) as i32
+                } else {
+                    palette_entry
+                };
+                buf_out[out_idx].data.row_mut(y)[x] = val;
+            }
+        }
+    }
+}
+
+#[allow(clippy::too_many_arguments)]
+pub fn do_palette_step_group_row(
+    buf_in: &[&ModularChannel],
+    buf_pal: &ModularChannel,
+    buf_out: &mut [&mut ModularChannel],
+    grid_y: usize,
+    grid_xsize: usize,
+    num_colors: usize,
+    num_deltas: usize,
+    predictor: Predictor,
+    wp_header: &WeightedHeader,
+) -> Result<()> {
+    let palette = &buf_pal.data;
+    let h = buf_in[0].data.size().1;
+    let bit_depth = buf_in[0].bit_depth.bits_per_sample().min(24) as usize;
+    let grid_ysize = grid_y + 1;
+    let num_c = buf_out.len() / (grid_xsize * grid_ysize);
+    let total_w = buf_out[0..grid_xsize]
+        .iter()
+        .map(|buf| buf.data.size().0)
+        .sum();
+    let (xsize, ysize) = buf_out[0].data.size();
+
+    if predictor == Predictor::Weighted {
+        for c in 0..num_c {
+            let mut wp_state = WeightedPredictorState::new(wp_header, total_w);
+            let out_row_idx = c * grid_ysize * grid_xsize + grid_y * grid_xsize;
+            if grid_y > 0 {
+                let prev_row_idx = out_row_idx - grid_y * grid_xsize;
+                wp_state.restore_state(
+                    buf_out[prev_row_idx].auxiliary_data.as_ref().unwrap(),
+                    total_w,
+                );
+            }
+            for y in 0..h {
+                for (grid_x, index_buf) in buf_in.iter().enumerate().take(grid_xsize) {
+                    let index_img = index_buf.data.row(y);
+                    let out_idx = out_row_idx + grid_x;
+                    for (x, &index) in index_img.iter().enumerate() {
+                        let palette_entry = get_palette_value(
+                            palette,
+                            index as isize,
+                            c,
+                            /*palette_size=*/ num_colors + num_deltas,
+                            /*bit_depth=*/ bit_depth,
+                        );
+                        let val = if index < num_deltas as i32 {
+                            let prediction_data = get_prediction_data(
+                                buf_out, out_idx, grid_x, grid_y, grid_xsize, x, y, xsize, ysize,
+                            );
+                            let (pred, _) = wp_state.predict_and_property(
+                                (grid_x * xsize + x, y & 1),
+                                total_w,
+                                &prediction_data,
+                            );
+                            (pred + palette_entry as i64) as i32
+                        } else {
+                            palette_entry
+                        };
+                        buf_out[out_idx].data.row_mut(y)[x] = val;
+                        wp_state.update_errors(val, (grid_x * xsize + x, y & 1), total_w);
+                    }
+                }
+            }
+            let mut wp_image = Image::<i32>::new((total_w + 2, 1))?;
+            wp_state.save_state(&mut wp_image, total_w);
+            buf_out[out_row_idx].auxiliary_data = Some(wp_image);
+        }
+    } else {
+        for c in 0..num_c {
+            for y in 0..h {
+                for (grid_x, index_buf) in buf_in.iter().enumerate().take(grid_xsize) {
+                    let index_img = index_buf.data.row(y);
+                    let out_idx = c * grid_ysize * grid_xsize + grid_y * grid_xsize + grid_x;
+                    for (x, &index) in index_img.iter().enumerate() {
+                        let palette_entry = get_palette_value(
+                            palette,
+                            index as isize,
+                            c,
+                            /*palette_size=*/ num_colors + num_deltas,
+                            /*bit_depth=*/ bit_depth,
+                        );
+                        let val = if index < num_deltas as i32 {
+                            let pred = predictor.predict_one(
+                                get_prediction_data(
+                                    buf_out, out_idx, grid_x, grid_y, grid_xsize, x, y, xsize,
+                                    ysize,
+                                ),
+                                /*wp_pred=*/ 0,
+                            );
+                            (pred + palette_entry as i64) as i32
+                        } else {
+                            palette_entry
+                        };
+                        buf_out[out_idx].data.row_mut(y)[x] = val;
+                    }
+                }
+            }
+        }
+    }
+    Ok(())
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/transforms/rct.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/transforms/rct.rs
new file mode 100644
index 0000000..5833125
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/transforms/rct.rs
@@ -0,0 +1,161 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use jxl_simd::{I32SimdVec, ScalarDescriptor, SimdDescriptor, shr, simd_function};
+
+use crate::{
+    frame::modular::{
+        ModularChannel,
+        transforms::{RctOp, RctPermutation},
+    },
+    image::Image,
+    util::tracing_wrappers::*,
+};
+
+#[inline(always)]
+fn rct_impl<D: SimdDescriptor, const OP: u32>(
+    _: D,
+    v0: D::I32Vec,
+    v1: D::I32Vec,
+    v2: D::I32Vec,
+) -> (D::I32Vec, D::I32Vec, D::I32Vec) {
+    const { assert!(OP <= 6) };
+
+    match OP {
+        0 => (v0, v1, v2),
+        1 => (v0, v1, v2 + v0),
+        2 => (v0, v1 + v0, v2),
+        3 => (v0, v1 + v0, v2 + v0),
+        4 => {
+            let avg = shr!(v0 + v2, 1);
+            (v0, v1 + avg, v2)
+        }
+        5 => {
+            let v2 = v0 + v2;
+            let avg = shr!(v0 + v2, 1);
+            (v0, v1 + avg, v2)
+        }
+        6 => {
+            let (y, co, cg) = (v0, v1, v2);
+            let y = y - shr!(cg, 1);
+            let g = cg + y;
+            let y = y - shr!(co, 1);
+            let r = y + co;
+            (r, g, y)
+        }
+        _ => unreachable!(),
+    }
+}
+
+#[inline(always)]
+fn rct_row_impl<D: SimdDescriptor, const OP: u32>(d: D, rgb: [&mut [i32]; 3]) -> [&mut [i32]; 3] {
+    const { assert!(OP <= 6) };
+
+    let [mut it_row_r, mut it_row_g, mut it_row_b] =
+        rgb.map(|x| x.chunks_exact_mut(D::I32Vec::LEN));
+    let it = (&mut it_row_r).zip(&mut it_row_g).zip(&mut it_row_b);
+
+    for ((r, g), b) in it {
+        let v0 = D::I32Vec::load(d, r);
+        let v1 = D::I32Vec::load(d, g);
+        let v2 = D::I32Vec::load(d, b);
+        let (w0, w1, w2) = rct_impl::<D, OP>(d, v0, v1, v2);
+        w0.store(r);
+        w1.store(g);
+        w2.store(b);
+    }
+
+    [
+        it_row_r.into_remainder(),
+        it_row_g.into_remainder(),
+        it_row_b.into_remainder(),
+    ]
+}
+
+#[inline(always)]
+fn rct_loop_impl<D: SimdDescriptor, const OP: u32>(
+    d: D,
+    r: &mut Image<i32>,
+    g: &mut Image<i32>,
+    b: &mut Image<i32>,
+) {
+    const { assert!(OP <= 6) };
+
+    let h = r.size().1;
+
+    for pos_y in 0..h {
+        let mut rgb = [&mut *r, &mut *g, &mut *b].map(|x| x.row_mut(pos_y));
+
+        rgb = rct_row_impl::<D, OP>(d, rgb);
+        if D::I32Vec::LEN > 8 {
+            rgb = rct_row_impl::<_, OP>(d.maybe_downgrade_256bit(), rgb);
+        }
+        if D::I32Vec::LEN > 4 {
+            rgb = rct_row_impl::<_, OP>(d.maybe_downgrade_128bit(), rgb);
+        }
+        if D::I32Vec::LEN > 1 {
+            rct_row_impl::<_, OP>(ScalarDescriptor::new().unwrap(), rgb);
+        }
+    }
+}
+
+simd_function!(
+    rct_loop,
+    d: D,
+    fn rct_loop_fwd(r: &mut Image<i32>, g: &mut Image<i32>, b: &mut Image<i32>, op: RctOp) {
+        match op {
+            RctOp::Noop => {},
+            RctOp::AddFirstToThird => rct_loop_impl::<D, 1>(d, r, g, b),
+            RctOp::AddFirstToSecond => rct_loop_impl::<D, 2>(d, r, g, b),
+            RctOp::AddFirstToSecondAndThird => rct_loop_impl::<D, 3>(d, r, g, b),
+            RctOp::AddAvgToSecond => rct_loop_impl::<D, 4>(d, r, g, b),
+            RctOp::AddFirstToThirdAndAvgToSecond => rct_loop_impl::<D, 5>(d, r, g, b),
+            RctOp::YCoCg => rct_loop_impl::<D, 6>(d, r, g, b),
+        }
+    }
+);
+
+// Applies a RCT in-place to the given buffers.
+#[instrument(level = "debug", skip(buffers), ret)]
+pub fn do_rct_step(buffers: &mut [&mut ModularChannel], op: RctOp, perm: RctPermutation) {
+    let [r, g, b] = buffers else {
+        unreachable!("incorrect buffer count for RCT");
+    };
+
+    if op != RctOp::Noop {
+        rct_loop(&mut r.data, &mut g.data, &mut b.data, op);
+    }
+
+    // Note: Gbr and Brg use the *inverse* permutation compared to libjxl, because we *first* write
+    // to the buffers and then permute them, while in libjxl the buffers to be written to are
+    // permuted first.
+    // The same is true for Rbg/Grb/Bgr, but since those are involutions it doesn't change
+    // anything.
+    match perm {
+        RctPermutation::Rgb => {}
+        RctPermutation::Gbr => {
+            // out[1, 2, 0] = in[0, 1, 2]
+            std::mem::swap(&mut g.data, &mut b.data); // [1, 0, 2]
+            std::mem::swap(&mut r.data, &mut g.data);
+        }
+        RctPermutation::Brg => {
+            // out[2, 0, 1] = in[0, 1, 2]
+            std::mem::swap(&mut r.data, &mut b.data); // [1, 0, 2]
+            std::mem::swap(&mut r.data, &mut g.data);
+        }
+        RctPermutation::Rbg => {
+            // out[0, 2, 1] = in[0, 1, 2]
+            std::mem::swap(&mut b.data, &mut g.data);
+        }
+        RctPermutation::Grb => {
+            // out[1, 0, 2] = in[0, 1, 2]
+            std::mem::swap(&mut r.data, &mut g.data);
+        }
+        RctPermutation::Bgr => {
+            // out[2, 1, 0] = in[0, 1, 2]
+            std::mem::swap(&mut r.data, &mut b.data);
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/transforms/squeeze.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/transforms/squeeze.rs
new file mode 100644
index 0000000..03eb8529
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/transforms/squeeze.rs
@@ -0,0 +1,673 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::cell::Ref;
+
+use jxl_simd::{
+    F32SimdVec, I32SimdVec, SimdDescriptor, SimdMask, U32SimdVec, shl, shr, simd_function,
+};
+
+use crate::{
+    error::{Error, Result},
+    frame::modular::{ChannelInfo, ModularChannel},
+    headers::modular::SqueezeParams,
+    image::{Image, ImageRect},
+};
+
+use crate::util::tracing_wrappers::*;
+
+#[instrument(level = "trace", err)]
+pub fn check_squeeze_params(
+    channels: &[(usize, ChannelInfo)],
+    params: &SqueezeParams,
+) -> Result<()> {
+    let end_channel = (params.begin_channel + params.num_channels) as usize;
+    if end_channel > channels.len() {
+        return Err(Error::InvalidChannelRange(
+            params.begin_channel as usize,
+            params.num_channels as usize,
+            channels.len(),
+        ));
+    }
+    if channels[params.begin_channel as usize].1.is_meta() != channels[end_channel - 1].1.is_meta()
+    {
+        return Err(Error::MixingDifferentChannels);
+    }
+    if channels[params.begin_channel as usize].1.is_meta() && !params.in_place {
+        return Err(Error::MetaSqueezeRequiresInPlace);
+    }
+    Ok(())
+}
+
+pub fn default_squeeze(data_channel_info: &[(usize, ChannelInfo)]) -> Vec<SqueezeParams> {
+    let num_meta_channels = data_channel_info
+        .iter()
+        .take_while(|x| x.1.is_meta())
+        .count();
+
+    let mut w = data_channel_info[num_meta_channels].1.size.0;
+    let mut h = data_channel_info[num_meta_channels].1.size.1;
+    let nc = data_channel_info.len() - num_meta_channels;
+
+    let mut params = vec![];
+
+    if nc > 2 && data_channel_info[num_meta_channels + 1].1.size == (w, h) {
+        // 420 previews
+        let sp = SqueezeParams {
+            horizontal: true,
+            in_place: false,
+            begin_channel: num_meta_channels as u32 + 1,
+            num_channels: 2,
+        };
+        if w > 1 {
+            params.push(sp);
+        }
+        if h > 1 {
+            params.push(SqueezeParams {
+                horizontal: false,
+                ..sp
+            });
+        }
+    }
+
+    const MAX_FIRST_PREVIEW_SIZE: usize = 8;
+
+    let sp = SqueezeParams {
+        begin_channel: num_meta_channels as u32,
+        num_channels: nc as u32,
+        in_place: true,
+        horizontal: false,
+    };
+
+    // vertical first on tall images
+    if w <= h && h > MAX_FIRST_PREVIEW_SIZE {
+        params.push(SqueezeParams {
+            horizontal: false,
+            ..sp
+        });
+        h = h.div_ceil(2);
+    }
+    while w > MAX_FIRST_PREVIEW_SIZE || h > MAX_FIRST_PREVIEW_SIZE {
+        if w > MAX_FIRST_PREVIEW_SIZE {
+            params.push(SqueezeParams {
+                horizontal: true,
+                ..sp
+            });
+            w = w.div_ceil(2);
+        }
+        if h > MAX_FIRST_PREVIEW_SIZE {
+            params.push(SqueezeParams {
+                horizontal: false,
+                ..sp
+            });
+            h = h.div_ceil(2);
+        }
+    }
+
+    params
+}
+
+#[inline(always)]
+fn smooth_tendency_impl<D: SimdDescriptor>(
+    d: D,
+    a: D::I32Vec,
+    b: D::I32Vec,
+    c: D::I32Vec,
+) -> D::I32Vec {
+    let a_b = a - b;
+    let b_c = b - c;
+    let a_c = a - c;
+    let abs_a_b = a_b.abs();
+    let abs_b_c = b_c.abs();
+    let abs_a_c = a_c.abs();
+    let non_monotonic = (a_b ^ b_c).lt_zero();
+    let skip = a_b.eq_zero().andnot(non_monotonic);
+    let skip = b_c.eq_zero().andnot(skip);
+
+    let abs_a_b_3 = abs_a_b.mul_wide_take_high(D::I32Vec::splat(d, 0x55555556));
+
+    let x = shr!(D::I32Vec::splat(d, 2) + abs_a_c + abs_a_b_3, 2);
+
+    let abs_a_b_2_add_x = shl!(abs_a_b, 1) + (x & D::I32Vec::splat(d, 1));
+    let x = x
+        .gt(abs_a_b_2_add_x)
+        .if_then_else_i32(shl!(abs_a_b, 1) + D::I32Vec::splat(d, 1), x);
+
+    let abs_b_c_2 = shl!(abs_b_c, 1);
+    let x = (x + (x & D::I32Vec::splat(d, 1)))
+        .gt(abs_b_c_2)
+        .if_then_else_i32(abs_b_c_2, x);
+
+    let need_neg = a_c.lt_zero();
+    let x = skip.maskz_i32(x);
+    need_neg.if_then_else_i32(-x, x)
+}
+
+#[inline(always)]
+fn smooth_tendency_scalar(b: i64, a: i64, n: i64) -> i64 {
+    let mut diff = 0;
+    if b >= a && a >= n {
+        diff = (4 * b - 3 * n - a + 6) / 12;
+        //      2c = a<<1 + diff - diff&1 <= 2b  so diff - diff&1 <= 2b - 2a
+        //      2d = a<<1 - diff - diff&1 >= 2n  so diff + diff&1 <= 2a - 2n
+        if diff - (diff & 1) > 2 * (b - a) {
+            diff = 2 * (b - a) + 1;
+        }
+        if diff + (diff & 1) > 2 * (a - n) {
+            diff = 2 * (a - n);
+        }
+    } else if b <= a && a <= n {
+        diff = (4 * b - 3 * n - a - 6) / 12;
+        //      2c = a<<1 + diff + diff&1 >= 2b  so diff + diff&1 >= 2b - 2a
+        //      2d = a<<1 - diff + diff&1 <= 2n  so diff - diff&1 >= 2a - 2n
+        if diff + (diff & 1) < 2 * (b - a) {
+            diff = 2 * (b - a) - 1;
+        }
+        if diff - (diff & 1) < 2 * (a - n) {
+            diff = 2 * (a - n);
+        }
+    }
+    diff
+}
+
+#[inline(always)]
+fn unsqueeze_impl<D: SimdDescriptor>(
+    d: D,
+    avg: D::I32Vec,
+    res: D::I32Vec,
+    next_avg: D::I32Vec,
+    prev: D::I32Vec,
+) -> (D::I32Vec, D::I32Vec) {
+    let tendency = smooth_tendency_impl(d, prev, avg, next_avg);
+    let diff = res + tendency;
+    let sign = shr!(diff.bitcast_to_u32(), 31).bitcast_to_i32();
+    let diff_2 = shr!(diff + sign, 1);
+    let a = avg + diff_2;
+    let b = a - diff;
+    (a, b)
+}
+
+#[inline(always)]
+fn unsqueeze_scalar(avg: i32, res: i32, next_avg: i32, prev: i32) -> (i32, i32) {
+    let tendency = smooth_tendency_scalar(prev as i64, avg as i64, next_avg as i64);
+    let diff = (res as i64) + tendency;
+    let a = (avg as i64) + (diff / 2);
+    let b = a - diff;
+    (a as i32, b as i32)
+}
+
+#[inline(always)]
+fn hsqueeze_impl<D: SimdDescriptor>(
+    d: D,
+    y_start: usize,
+    in_avg: &ImageRect<'_, i32>,
+    in_res: &ImageRect<'_, i32>,
+    in_next_avg: &Option<ImageRect<'_, i32>>,
+    out_prev: &Option<Ref<'_, ModularChannel>>,
+    out: &mut Image<i32>,
+) {
+    const {
+        assert!(D::I32Vec::LEN <= 16);
+        assert!(D::I32Vec::LEN.is_power_of_two());
+    }
+
+    let lanes = D::I32Vec::LEN;
+    assert_eq!(y_start % lanes, 0);
+
+    let (w, h) = in_res.size();
+    if lanes == 1 {
+        return hsqueeze_scalar(y_start, in_avg, in_res, in_next_avg, out_prev, out);
+    }
+
+    let has_tail = out.size().0 & 1 == 1;
+    if has_tail {
+        debug_assert!(in_avg.size().0 == w + 1);
+        debug_assert!(out.size().0 == 2 * w + 1);
+    }
+
+    let mask = !(lanes - 1);
+    let y_limit = if w >= lanes { h & mask } else { y_start };
+
+    let mut buf = [0f32; 512];
+    for y in (y_start..y_limit).step_by(lanes) {
+        for dy in 0..lanes {
+            buf[dy] = f32::from_bits(in_avg.row(y + dy)[0] as u32);
+            buf[lanes + dy] = f32::from_bits(in_res.row(y + dy)[0] as u32);
+        }
+        let mut avg_first = D::F32Vec::load(d, &buf).bitcast_to_i32();
+        let mut res_first = D::F32Vec::load(d, &buf[lanes..]).bitcast_to_i32();
+
+        let mut prev_b = match out_prev {
+            None => avg_first,
+            Some(mc) => {
+                let mc_w = mc.data.size().0;
+                let mc = &mc.data;
+                for (dy, out) in buf[..lanes].iter_mut().enumerate() {
+                    *out = f32::from_bits(mc.row(y + dy)[mc_w - 1] as u32);
+                }
+                D::F32Vec::load(d, &buf).bitcast_to_i32()
+            }
+        };
+
+        let remainder_start = ((w - 1) & mask) + 1;
+        let remainder_count = w - remainder_start;
+        for x in (1..remainder_start).step_by(lanes) {
+            let buf_arr = D::F32Vec::make_array_slice_mut(&mut buf);
+
+            for dy in 0..lanes {
+                let avg_row = &in_avg.row(y + dy)[x..][..lanes];
+                let res_row = &in_res.row(y + dy)[x..][..lanes];
+                let avg = D::I32Vec::load(d, avg_row);
+                let res = D::I32Vec::load(d, res_row);
+                avg.bitcast_to_f32().store_array(&mut buf_arr[2 * dy]);
+                res.bitcast_to_f32().store_array(&mut buf_arr[2 * dy + 1]);
+            }
+            D::F32Vec::transpose_square(d, buf_arr, 2);
+            D::F32Vec::transpose_square(d, &mut buf_arr[1..], 2);
+
+            for idx in 0..lanes {
+                let avg_next = D::F32Vec::load_array(d, &buf_arr[2 * idx]).bitcast_to_i32();
+                let res_next = D::F32Vec::load_array(d, &buf_arr[2 * idx + 1]).bitcast_to_i32();
+                let (a, b) = unsqueeze_impl(d, avg_first, res_first, avg_next, prev_b);
+                a.bitcast_to_f32().store_array(&mut buf_arr[2 * idx]);
+                b.bitcast_to_f32().store_array(&mut buf_arr[2 * idx + 1]);
+                avg_first = avg_next;
+                res_first = res_next;
+                prev_b = b;
+            }
+
+            D::F32Vec::transpose_square(d, buf_arr, 1);
+            D::F32Vec::transpose_square(d, &mut buf_arr[lanes..], 1);
+            for dy in 0..lanes {
+                let out_row = &mut out.row_mut(y + dy)[2 * x - 2..][..2 * lanes];
+                for group in 0..2 {
+                    let v = D::F32Vec::load_array(d, &buf_arr[dy + group * lanes]).bitcast_to_i32();
+                    v.store(&mut out_row[group * lanes..]);
+                }
+            }
+        }
+
+        let x = remainder_start;
+        if remainder_count == 0 {
+            let avg_last = if has_tail {
+                for (idx, out) in buf[..lanes].iter_mut().enumerate() {
+                    *out = f32::from_bits(in_avg.row(y + idx)[w] as u32);
+                }
+                D::F32Vec::load(d, &buf).bitcast_to_i32()
+            } else if let Some(mc) = in_next_avg {
+                for (idx, out) in buf[..lanes].iter_mut().enumerate() {
+                    *out = f32::from_bits(mc.row(y + idx)[0] as u32);
+                }
+                D::F32Vec::load(d, &buf).bitcast_to_i32()
+            } else {
+                avg_first
+            };
+
+            let buf_arr = D::F32Vec::make_array_slice_mut(&mut buf);
+            let (a, b) = unsqueeze_impl(d, avg_first, res_first, avg_last, prev_b);
+            a.bitcast_to_f32().store_array(&mut buf_arr[0]);
+            b.bitcast_to_f32().store_array(&mut buf_arr[1]);
+        } else {
+            for dy in 0..lanes {
+                let avg_row = in_avg.row(y + dy);
+                let res_row = in_res.row(y + dy);
+                for dx in 0..remainder_count {
+                    buf[dx + lanes * 2 * dy] = f32::from_bits(avg_row[x + dx] as u32);
+                    buf[dx + lanes * (2 * dy + 1)] = f32::from_bits(res_row[x + dx] as u32);
+                }
+
+                buf[remainder_count + lanes * 2 * dy] = if has_tail {
+                    f32::from_bits(avg_row[w] as u32)
+                } else if let Some(mc) = in_next_avg {
+                    f32::from_bits(mc.row(y + dy)[0] as u32)
+                } else {
+                    buf[remainder_count - 1 + lanes * 2 * dy]
+                };
+            }
+
+            let buf_arr = D::F32Vec::make_array_slice_mut(&mut buf);
+            D::F32Vec::transpose_square(d, buf_arr, 2);
+            D::F32Vec::transpose_square(d, &mut buf_arr[1..], 2);
+
+            for idx in 0..=remainder_count {
+                let avg_next = D::F32Vec::load_array(d, &buf_arr[2 * idx]).bitcast_to_i32();
+                let res_next = D::F32Vec::load_array(d, &buf_arr[2 * idx + 1]).bitcast_to_i32();
+                let (a, b) = unsqueeze_impl(d, avg_first, res_first, avg_next, prev_b);
+                a.bitcast_to_f32().store_array(&mut buf_arr[2 * idx]);
+                b.bitcast_to_f32().store_array(&mut buf_arr[2 * idx + 1]);
+                avg_first = avg_next;
+                res_first = res_next;
+                prev_b = b;
+            }
+        }
+
+        let buf_arr = D::F32Vec::make_array_slice_mut(&mut buf);
+        D::F32Vec::transpose_square(d, buf_arr, 1);
+        D::F32Vec::transpose_square(d, &mut buf_arr[lanes..], 1);
+
+        let x_limit = 2 * (remainder_count + 1);
+        for dy in 0..lanes {
+            let out_row = &mut out.row_mut(y + dy)[2 * x - 2..];
+            for (dx, out) in out_row[..x_limit].iter_mut().enumerate() {
+                let group = dx / lanes;
+                let group_x = dx % lanes;
+                *out = buf[(dy + group * lanes) * lanes + group_x].to_bits() as i32;
+            }
+        }
+
+        if has_tail {
+            for dy in 0..lanes {
+                out.row_mut(y + dy)[2 * w] = in_avg.row(y + dy)[w];
+            }
+        }
+    }
+
+    let remainder_rows = h - y_limit;
+    // We need `lanes > N` to convince the compiler that this function does not recurse
+    if lanes > 8 && remainder_rows >= 8 && w >= 8 {
+        return hsqueeze_impl(
+            d.maybe_downgrade_256bit(),
+            y_limit,
+            in_avg,
+            in_res,
+            in_next_avg,
+            out_prev,
+            out,
+        );
+    }
+    if lanes > 4 && remainder_rows >= 4 && w >= 4 {
+        return hsqueeze_impl(
+            d.maybe_downgrade_128bit(),
+            y_limit,
+            in_avg,
+            in_res,
+            in_next_avg,
+            out_prev,
+            out,
+        );
+    }
+
+    hsqueeze_scalar(y_limit, in_avg, in_res, in_next_avg, out_prev, out)
+}
+
+#[inline(always)]
+fn hsqueeze_scalar(
+    y_start: usize,
+    in_avg: &ImageRect<'_, i32>,
+    in_res: &ImageRect<'_, i32>,
+    in_next_avg: &Option<ImageRect<'_, i32>>,
+    out_prev: &Option<Ref<'_, ModularChannel>>,
+    out: &mut Image<i32>,
+) {
+    let (w, h) = in_res.size();
+
+    debug_assert!(w >= 1);
+    let has_tail = out.size().0 & 1 == 1;
+    if has_tail {
+        debug_assert!(in_avg.size().0 == w + 1);
+        debug_assert!(out.size().0 == 2 * w + 1);
+    }
+
+    for y in y_start..h {
+        let avg_row = in_avg.row(y);
+        let res_row = in_res.row(y);
+        let mut prev_b = match out_prev {
+            None => avg_row[0],
+            Some(mc) => mc.data.row(y)[mc.data.size().0 - 1],
+        };
+        // Guarantee that `avg_row[x + 1]` is available.
+        let x_end = if has_tail { w } else { w - 1 };
+        for x in 0..x_end {
+            let (a, b) = unsqueeze_scalar(avg_row[x], res_row[x], avg_row[x + 1], prev_b);
+            out.row_mut(y)[2 * x] = a;
+            out.row_mut(y)[2 * x + 1] = b;
+            prev_b = b;
+        }
+        if !has_tail {
+            let last_avg = match in_next_avg {
+                None => avg_row[w - 1],
+                Some(mc) => mc.row(y)[0],
+            };
+            let (a, b) = unsqueeze_scalar(avg_row[w - 1], res_row[w - 1], last_avg, prev_b);
+            out.row_mut(y)[2 * w - 2] = a;
+            out.row_mut(y)[2 * w - 1] = b;
+        } else {
+            // 1 last pixel
+            out.row_mut(y)[2 * w] = in_avg.row(y)[w];
+        }
+    }
+}
+
+simd_function!(
+    hsqueeze,
+    d: D,
+    pub fn hsqueeze_fwd(
+        in_avg: &ImageRect<'_, i32>,
+        in_res: &ImageRect<'_, i32>,
+        in_next_avg: &Option<ImageRect<'_, i32>>,
+        out_prev: &Option<Ref<'_, ModularChannel>>,
+        out: &mut Image<i32>,
+    ) {
+        hsqueeze_impl(d, 0, in_avg, in_res, in_next_avg, out_prev, out)
+    }
+);
+
+pub fn do_hsqueeze_step(
+    in_avg: &ImageRect<'_, i32>,
+    in_res: &ImageRect<'_, i32>,
+    in_next_avg: &Option<ImageRect<'_, i32>>,
+    out_prev: &Option<Ref<'_, ModularChannel>>,
+    buffers: &mut [&mut ModularChannel],
+) {
+    trace!("hsqueeze step in_avg: {in_avg:?} in_res: {in_res:?} in_next_avg: {in_next_avg:?}");
+    let out = buffers.first_mut().unwrap();
+    // Shortcut: guarantees that row is at least 1px in the main loop
+    if out.data.size().0 == 0 {
+        return;
+    }
+
+    let (w, h) = in_res.size();
+    // Another shortcut: when output row has just 1px
+    if w == 0 {
+        for y in 0..h {
+            out.data.row_mut(y)[0] = in_avg.row(y)[0];
+        }
+        return;
+    }
+    // Otherwise: 2 or more in in row
+    hsqueeze(in_avg, in_res, in_next_avg, out_prev, &mut out.data);
+}
+
+#[inline(always)]
+fn vsqueeze_impl<D: SimdDescriptor>(
+    d: D,
+    x_start: usize,
+    in_avg: &ImageRect<'_, i32>,
+    in_res: &ImageRect<'_, i32>,
+    in_next_avg: &Option<ImageRect<'_, i32>>,
+    out_prev: &Option<Ref<'_, ModularChannel>>,
+    out: &mut Image<i32>,
+) {
+    const { assert!(D::I32Vec::LEN.is_power_of_two()) };
+
+    let lanes = D::I32Vec::LEN;
+    assert_eq!(x_start % lanes, 0);
+
+    let (w, h) = in_res.size();
+    if lanes == 1 {
+        return vsqueeze_scalar(x_start, in_avg, in_res, in_next_avg, out_prev, out);
+    }
+
+    let has_tail = out.size().1 & 1 == 1;
+    if has_tail {
+        debug_assert!(in_avg.size().1 == h + 1);
+        debug_assert!(out.size().1 == 2 * h + 1);
+    }
+
+    let mask = !(lanes - 1);
+    let x_limit = if w >= lanes { w & mask } else { x_start };
+
+    let prev_b_row = match out_prev {
+        None => in_avg.row(0),
+        Some(mc) => mc.data.row(mc.data.size().1 - 1),
+    };
+
+    for x in (x_start..x_limit).step_by(lanes) {
+        let mut prev_b = D::I32Vec::load(d, &prev_b_row[x..]);
+        let mut avg_first = D::I32Vec::load(d, &in_avg.row(0)[x..]);
+        let mut res_first = D::I32Vec::load(d, &in_res.row(0)[x..]);
+        for y in 0..h - 1 {
+            let avg_next = D::I32Vec::load(d, &in_avg.row(y + 1)[x..]);
+            let (a, b) = unsqueeze_impl(d, avg_first, res_first, avg_next, prev_b);
+            a.store(&mut out.row_mut(2 * y)[x..]);
+            b.store(&mut out.row_mut(2 * y + 1)[x..]);
+            prev_b = b;
+            avg_first = avg_next;
+            res_first = D::I32Vec::load(d, &in_res.row(y + 1)[x..]);
+        }
+
+        let avg_last = if has_tail {
+            D::I32Vec::load(d, &in_avg.row(h)[x..])
+        } else if let Some(mc) = in_next_avg {
+            D::I32Vec::load(d, &mc.row(0)[x..])
+        } else {
+            avg_first
+        };
+        let (a, b) = unsqueeze_impl(d, avg_first, res_first, avg_last, prev_b);
+        a.store(&mut out.row_mut(2 * h - 2)[x..]);
+        b.store(&mut out.row_mut(2 * h - 1)[x..]);
+
+        if has_tail {
+            avg_last.store(&mut out.row_mut(2 * h)[x..]);
+        }
+    }
+
+    let remainder_cols = w - x_limit;
+    // We need `lanes > N` to convince the compiler that this function does not recurse
+    if lanes > 8 && remainder_cols >= 8 {
+        return vsqueeze_impl(
+            d.maybe_downgrade_256bit(),
+            x_limit,
+            in_avg,
+            in_res,
+            in_next_avg,
+            out_prev,
+            out,
+        );
+    }
+    if lanes > 4 && remainder_cols >= 4 {
+        return vsqueeze_impl(
+            d.maybe_downgrade_128bit(),
+            x_limit,
+            in_avg,
+            in_res,
+            in_next_avg,
+            out_prev,
+            out,
+        );
+    }
+
+    vsqueeze_scalar(x_limit, in_avg, in_res, in_next_avg, out_prev, out)
+}
+
+#[inline(always)]
+fn vsqueeze_scalar(
+    x_start: usize,
+    in_avg: &ImageRect<'_, i32>,
+    in_res: &ImageRect<'_, i32>,
+    in_next_avg: &Option<ImageRect<'_, i32>>,
+    out_prev: &Option<Ref<'_, ModularChannel>>,
+    out: &mut Image<i32>,
+) {
+    let (w, h) = in_res.size();
+
+    let has_tail = out.size().1 & 1 == 1;
+    if has_tail {
+        debug_assert!(in_avg.size().1 == h + 1);
+        debug_assert!(out.size().1 == 2 * h + 1);
+    }
+
+    {
+        let prev_b_row = match out_prev {
+            None => in_avg.row(0),
+            Some(mc) => mc.data.row(mc.data.size().1 - 1),
+        };
+        let avg_row = in_avg.row(0);
+        let res_row = in_res.row(0);
+        let avg_row_next = if !has_tail && (h == 1) {
+            debug_assert!(in_next_avg.is_none());
+            in_avg.row(0)
+        } else {
+            in_avg.row(1)
+        };
+        for x in x_start..w {
+            let (a, b) = unsqueeze_scalar(avg_row[x], res_row[x], avg_row_next[x], prev_b_row[x]);
+            out.row_mut(0)[x] = a;
+            out.row_mut(1)[x] = b;
+        }
+    }
+    for y in 1..h {
+        let avg_row = in_avg.row(y);
+        let res_row = in_res.row(y);
+        let avg_row_next = if has_tail || y < h - 1 {
+            in_avg.row(y + 1)
+        } else {
+            match in_next_avg {
+                None => avg_row,
+                Some(mc) => mc.row(0),
+            }
+        };
+        for x in x_start..w {
+            let (a, b) = unsqueeze_scalar(
+                avg_row[x],
+                res_row[x],
+                avg_row_next[x],
+                out.row(2 * y - 1)[x],
+            );
+            out.row_mut(2 * y)[x] = a;
+            out.row_mut(2 * y + 1)[x] = b;
+        }
+    }
+    if has_tail {
+        out.row_mut(2 * h)[x_start..].copy_from_slice(&in_avg.row(h)[x_start..]);
+    }
+}
+
+simd_function!(
+    vsqueeze,
+    d: D,
+    pub fn vsqueeze_fwd(
+        in_avg: &ImageRect<'_, i32>,
+        in_res: &ImageRect<'_, i32>,
+        in_next_avg: &Option<ImageRect<'_, i32>>,
+        out_prev: &Option<Ref<'_, ModularChannel>>,
+        out: &mut Image<i32>,
+    ) {
+        vsqueeze_impl(d, 0, in_avg, in_res, in_next_avg, out_prev, out)
+    }
+);
+
+pub fn do_vsqueeze_step(
+    in_avg: &ImageRect<'_, i32>,
+    in_res: &ImageRect<'_, i32>,
+    in_next_avg: &Option<ImageRect<'_, i32>>,
+    out_prev: &Option<Ref<'_, ModularChannel>>,
+    buffers: &mut [&mut ModularChannel],
+) {
+    trace!("vsqueeze step in_avg: {in_avg:?} in_res: {in_res:?} in_next_avg: {in_next_avg:?}");
+    let out = &mut buffers.first_mut().unwrap().data;
+    // Shortcut: guarantees that there at least 1 output row
+    if out.size().1 == 0 {
+        return;
+    }
+    // Another shortcut: when there is one output row
+    if in_res.size().1 == 0 {
+        out.row_mut(0).copy_from_slice(in_avg.row(0));
+        return;
+    }
+    // Otherwise: 2 or more rows
+
+    vsqueeze(in_avg, in_res, in_next_avg, out_prev, out);
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/tree.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/tree.rs
new file mode 100644
index 0000000..dbf42768
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/tree.rs
@@ -0,0 +1,319 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::fmt::Debug;
+
+use super::{Predictor, predict::WeightedPredictorState};
+use crate::{
+    bit_reader::BitReader,
+    entropy_coding::decode::Histograms,
+    entropy_coding::decode::SymbolReader,
+    error::{Error, Result},
+    frame::modular::predict::PredictionData,
+    image::Image,
+    util::{NewWithCapacity, tracing_wrappers::*},
+};
+
+#[derive(Debug, Clone, Copy)]
+pub enum TreeNode {
+    Split {
+        property: u8,
+        val: i32,
+        left: u32,
+        right: u32,
+    },
+    Leaf {
+        predictor: Predictor,
+        offset: i32,
+        multiplier: u32,
+        id: u32,
+    },
+}
+
+pub struct Tree {
+    pub nodes: Vec<TreeNode>,
+    pub histograms: Histograms,
+}
+
+impl Debug for Tree {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "Tree[{:?}]", self.nodes)
+    }
+}
+
+#[derive(Debug)]
+pub struct PredictionResult {
+    pub guess: i64,
+    pub multiplier: u32,
+    pub context: u32,
+}
+
+pub const NUM_NONREF_PROPERTIES: usize = 16;
+pub const PROPERTIES_PER_PREVCHAN: usize = 4;
+
+const SPLIT_VAL_CONTEXT: usize = 0;
+const PROPERTY_CONTEXT: usize = 1;
+const PREDICTOR_CONTEXT: usize = 2;
+const OFFSET_CONTEXT: usize = 3;
+const MULTIPLIER_LOG_CONTEXT: usize = 4;
+const MULTIPLIER_BITS_CONTEXT: usize = 5;
+const NUM_TREE_CONTEXTS: usize = 6;
+
+// Note: `property_buffer` is passed as input because this implementation relies on having the
+// previous values available for computing the local gradient property.
+// Also, the first two properties (the static properties) should be already set by the caller.
+// All other properties should be 0 on the first call in a row.
+#[inline]
+#[instrument(level = "trace", ret)]
+#[allow(clippy::too_many_arguments)]
+pub(super) fn predict(
+    tree: &[TreeNode],
+    prediction_data: PredictionData,
+    xsize: usize,
+    wp_state: Option<&mut WeightedPredictorState>,
+    x: usize,
+    y: usize,
+    references: &Image<i32>,
+    property_buffer: &mut [i32],
+) -> PredictionResult {
+    let PredictionData {
+        left,
+        top,
+        toptop,
+        topleft,
+        topright,
+        leftleft,
+        toprightright: _toprightright,
+    } = prediction_data;
+
+    trace!(
+        left,
+        top, topleft, topright, leftleft, toptop, _toprightright
+    );
+
+    // Position
+    property_buffer[2] = y as i32;
+    property_buffer[3] = x as i32;
+
+    // Neighbours
+    property_buffer[4] = top.abs();
+    property_buffer[5] = left.abs();
+    property_buffer[6] = top;
+    property_buffer[7] = left;
+
+    // Local gradient
+    property_buffer[8] = left.wrapping_sub(property_buffer[9]);
+    property_buffer[9] = left.wrapping_add(top).wrapping_sub(topleft);
+
+    // FFV1 context properties
+    property_buffer[10] = left.wrapping_sub(topleft);
+    property_buffer[11] = topleft.wrapping_sub(top);
+    property_buffer[12] = top.wrapping_sub(topright);
+    property_buffer[13] = top.wrapping_sub(toptop);
+    property_buffer[14] = left.wrapping_sub(leftleft);
+
+    // Weighted predictor property.
+    let wp_pred;
+    (wp_pred, property_buffer[15]) = wp_state
+        .map(|wp_state| wp_state.predict_and_property((x, y), xsize, &prediction_data))
+        .unwrap_or((0, 0));
+
+    // Reference properties.
+    let num_refs = references.size().0;
+    if num_refs != 0 {
+        let ref_properties = &mut property_buffer[NUM_NONREF_PROPERTIES..];
+        ref_properties[..num_refs].copy_from_slice(&references.row(x)[..num_refs]);
+    }
+
+    trace!(?property_buffer, "new properties");
+
+    let mut tree_node = 0;
+    while let TreeNode::Split {
+        property,
+        val,
+        left,
+        right,
+    } = tree[tree_node]
+    {
+        if property_buffer[property as usize] > val {
+            trace!(
+                "left at node {tree_node} [{} > {val}]",
+                property_buffer[property as usize]
+            );
+            tree_node = left as usize;
+        } else {
+            trace!(
+                "right at node {tree_node} [{} <= {val}]",
+                property_buffer[property as usize]
+            );
+            tree_node = right as usize;
+        }
+    }
+
+    trace!(leaf = ?tree[tree_node]);
+
+    let TreeNode::Leaf {
+        predictor,
+        offset,
+        multiplier,
+        id,
+    } = tree[tree_node]
+    else {
+        unreachable!();
+    };
+
+    let pred = predictor.predict_one(prediction_data, wp_pred);
+
+    PredictionResult {
+        guess: pred + offset as i64,
+        multiplier,
+        context: id,
+    }
+}
+
+impl Tree {
+    #[instrument(level = "debug", skip(br), err)]
+    pub fn read(br: &mut BitReader, size_limit: usize) -> Result<Tree> {
+        assert!(size_limit <= u32::MAX as usize);
+        trace!(pos = br.total_bits_read());
+        let tree_histograms = Histograms::decode(NUM_TREE_CONTEXTS, br, true)?;
+        let mut tree_reader = SymbolReader::new(&tree_histograms, br, None)?;
+        // TODO(veluca): consider early-exiting for trees known to be infinite.
+        let mut tree: Vec<TreeNode> = vec![];
+        let mut to_decode = 1;
+        let mut leaf_id = 0;
+        let mut max_property = 0;
+        while to_decode > 0 {
+            if tree.len() > size_limit {
+                return Err(Error::TreeTooLarge(tree.len(), size_limit));
+            }
+            if tree.len() >= tree.capacity() {
+                tree.try_reserve(tree.len() * 2 + 1)?;
+            }
+            to_decode -= 1;
+            let property = tree_reader.read_unsigned(&tree_histograms, br, PROPERTY_CONTEXT);
+            trace!(property);
+            if let Some(property) = property.checked_sub(1) {
+                // inner node.
+                if property > 255 {
+                    return Err(Error::InvalidProperty(property));
+                }
+                max_property = max_property.max(property);
+                let splitval = tree_reader.read_signed(&tree_histograms, br, SPLIT_VAL_CONTEXT);
+                let left_child = (tree.len() + to_decode + 1) as u32;
+                let node = TreeNode::Split {
+                    property: property as u8,
+                    val: splitval,
+                    left: left_child,
+                    right: left_child + 1,
+                };
+                trace!("split node {:?}", node);
+                to_decode += 2;
+                tree.push(node);
+            } else {
+                let predictor = Predictor::try_from(tree_reader.read_unsigned(
+                    &tree_histograms,
+                    br,
+                    PREDICTOR_CONTEXT,
+                ))?;
+                let offset = tree_reader.read_signed(&tree_histograms, br, OFFSET_CONTEXT);
+                let mul_log =
+                    tree_reader.read_unsigned(&tree_histograms, br, MULTIPLIER_LOG_CONTEXT);
+                if mul_log >= 31 {
+                    return Err(Error::TreeMultiplierTooLarge(mul_log, 31));
+                }
+                let mul_bits =
+                    tree_reader.read_unsigned(&tree_histograms, br, MULTIPLIER_BITS_CONTEXT);
+                let multiplier = (mul_bits as u64 + 1) << mul_log;
+                if multiplier > (u32::MAX as u64) {
+                    return Err(Error::TreeMultiplierBitsTooLarge(mul_bits, mul_log));
+                }
+                let node = TreeNode::Leaf {
+                    predictor,
+                    offset,
+                    id: leaf_id,
+                    multiplier: multiplier as u32,
+                };
+                leaf_id += 1;
+                trace!("leaf node {:?}", node);
+                tree.push(node);
+            }
+        }
+        tree_reader.check_final_state(&tree_histograms, br)?;
+
+        let num_properties = max_property as usize + 1;
+        let mut property_ranges = Vec::new_with_capacity(num_properties * tree.len())?;
+        property_ranges.resize(num_properties * tree.len(), (i32::MIN, i32::MAX));
+        let mut height = Vec::new_with_capacity(tree.len())?;
+        height.resize(tree.len(), 0);
+        for i in 0..tree.len() {
+            const HEIGHT_LIMIT: usize = 2048;
+            if height[i] > HEIGHT_LIMIT {
+                return Err(Error::TreeTooLarge(height[i], HEIGHT_LIMIT));
+            }
+            if let TreeNode::Split {
+                property,
+                val,
+                left,
+                right,
+            } = tree[i]
+            {
+                height[left as usize] = height[i] + 1;
+                height[right as usize] = height[i] + 1;
+                for p in 0..num_properties {
+                    if p == property as usize {
+                        let (l, u) = property_ranges[i * num_properties + p];
+                        if l > val || u <= val {
+                            return Err(Error::TreeSplitOnEmptyRange(p as u8, val, l, u));
+                        }
+                        trace!(
+                            "splitting at node {i} on property {p}, range [{l}, {u}] at position {val}"
+                        );
+                        property_ranges[left as usize * num_properties + p] = (val + 1, u);
+                        property_ranges[right as usize * num_properties + p] = (l, val);
+                    } else {
+                        property_ranges[left as usize * num_properties + p] =
+                            property_ranges[i * num_properties + p];
+                        property_ranges[right as usize * num_properties + p] =
+                            property_ranges[i * num_properties + p];
+                    }
+                }
+            } else {
+                #[cfg(feature = "tracing")]
+                {
+                    for p in 0..num_properties {
+                        let (l, u) = property_ranges[i * num_properties + p];
+                        trace!("final range at node {i} property {p}: [{l}, {u}]");
+                    }
+                }
+            }
+        }
+
+        let histograms = Histograms::decode(tree.len().div_ceil(2), br, true)?;
+
+        Ok(Tree {
+            nodes: tree,
+            histograms,
+        })
+    }
+
+    pub fn max_property_count(&self) -> usize {
+        self.nodes
+            .iter()
+            .map(|x| match x {
+                TreeNode::Leaf { .. } => 0,
+                TreeNode::Split { property, .. } => *property,
+            })
+            .max()
+            .unwrap_or_default() as usize
+            + 1
+    }
+
+    pub fn num_prev_channels(&self) -> usize {
+        self.max_property_count()
+            .saturating_sub(NUM_NONREF_PROPERTIES)
+            .div_ceil(PROPERTIES_PER_PREVCHAN)
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/quant_weights.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/quant_weights.rs
new file mode 100644
index 0000000..0d03824
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/quant_weights.rs
@@ -0,0 +1,3153 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::{f32::consts::SQRT_2, sync::OnceLock};
+
+use crate::util::f16;
+
+use crate::{
+    BLOCK_DIM, BLOCK_SIZE,
+    bit_reader::BitReader,
+    error::{
+        Error::{
+            HfQuantFactorTooSmall, InvalidDistanceBand, InvalidQuantEncoding,
+            InvalidQuantEncodingMode, InvalidQuantizationTableWeight, InvalidRawQuantTable,
+        },
+        Result,
+    },
+    frame::{
+        LfGlobalState,
+        modular::{ModularChannel, ModularStreamId, decode::decode_modular_subbitstream},
+    },
+    headers::{bit_depth::BitDepth, frame_header::FrameHeader},
+    image::Rect,
+};
+use jxl_transforms::transform_map::*;
+
+pub const INV_LF_QUANT: [f32; 3] = [4096.0, 512.0, 256.0];
+
+pub const LF_QUANT: [f32; 3] = [
+    1.0 / INV_LF_QUANT[0],
+    1.0 / INV_LF_QUANT[1],
+    1.0 / INV_LF_QUANT[2],
+];
+
+const ALMOST_ZERO: f32 = 1e-8;
+
+const LOG2_NUM_QUANT_MODES: usize = 3;
+
+#[derive(Debug)]
+pub struct DctQuantWeightParams {
+    params: [[f32; Self::MAX_DISTANCE_BANDS]; 3],
+    num_bands: usize,
+}
+impl DctQuantWeightParams {
+    const LOG2_MAX_DISTANCE_BANDS: usize = 4;
+    const MAX_DISTANCE_BANDS: usize = 1 + (1 << Self::LOG2_MAX_DISTANCE_BANDS);
+
+    #[inline(never)]
+    pub fn from_array<const N: usize>(values: &[[f32; N]; 3]) -> Self {
+        let mut result = Self {
+            params: [[0.0; Self::MAX_DISTANCE_BANDS]; 3],
+            num_bands: N,
+        };
+        for (params, values) in result.params.iter_mut().zip(values) {
+            params[..values.len()].copy_from_slice(values);
+        }
+        result
+    }
+
+    #[inline(never)]
+    pub fn decode(br: &mut BitReader) -> Result<Self> {
+        let num_bands = br.read(Self::LOG2_MAX_DISTANCE_BANDS)? as usize + 1;
+        let mut params = [[0.0; Self::MAX_DISTANCE_BANDS]; 3];
+        for row in params.iter_mut() {
+            for item in row[..num_bands].iter_mut() {
+                *item = f32::from(f16::from_bits(br.read(16)? as u16));
+            }
+            if row[0] < ALMOST_ZERO {
+                return Err(HfQuantFactorTooSmall(row[0]));
+            }
+            row[0] *= 64.0;
+        }
+        Ok(DctQuantWeightParams { params, num_bands })
+    }
+}
+
+#[allow(clippy::large_enum_variant)]
+#[derive(Debug)]
+pub enum QuantEncoding {
+    Library,
+    // a.k.a. "Hornuss"
+    Identity {
+        xyb_weights: [[f32; 3]; 3],
+    },
+    Dct2 {
+        xyb_weights: [[f32; 6]; 3],
+    },
+    Dct4 {
+        params: DctQuantWeightParams,
+        xyb_mul: [[f32; 2]; 3],
+    },
+    Dct4x8 {
+        params: DctQuantWeightParams,
+        xyb_mul: [f32; 3],
+    },
+    Afv {
+        params4x8: DctQuantWeightParams,
+        params4x4: DctQuantWeightParams,
+        weights: [[f32; 9]; 3],
+    },
+    Dct {
+        params: DctQuantWeightParams,
+    },
+    Raw {
+        qtable: Vec<i32>,
+        qtable_den: f32,
+    },
+}
+
+impl QuantEncoding {
+    // TODO(veluca): figure out if this should actually be unused.
+    #[allow(dead_code)]
+    pub fn raw_from_qtable(qtable: Vec<i32>, shift: i32) -> Self {
+        Self::Raw {
+            qtable,
+            qtable_den: (1 << shift) as f32 * (1.0 / (8.0 * 255.0)),
+        }
+    }
+
+    pub fn decode(
+        mut required_size_x: usize,
+        mut required_size_y: usize,
+        index: usize,
+        header: &FrameHeader,
+        lf_global: &LfGlobalState,
+        br: &mut BitReader,
+    ) -> Result<Self> {
+        let required_size = required_size_x * required_size_y;
+        required_size_x *= BLOCK_DIM;
+        required_size_y *= BLOCK_DIM;
+        let mode = br.read(LOG2_NUM_QUANT_MODES)? as u8;
+        match mode {
+            0 => Ok(Self::Library),
+            1 => {
+                if required_size != 1 {
+                    return Err(InvalidQuantEncoding {
+                        mode,
+                        required_size,
+                    });
+                }
+                let mut xyb_weights = [[0.0; 3]; 3];
+                for row in xyb_weights.iter_mut() {
+                    for item in row.iter_mut() {
+                        *item = f32::from(f16::from_bits(br.read(16)? as u16));
+                        if item.abs() < ALMOST_ZERO {
+                            return Err(HfQuantFactorTooSmall(*item));
+                        }
+                        *item *= 64.0;
+                    }
+                }
+                Ok(Self::Identity { xyb_weights })
+            }
+            2 => {
+                if required_size != 1 {
+                    return Err(InvalidQuantEncoding {
+                        mode,
+                        required_size,
+                    });
+                }
+                let mut xyb_weights = [[0.0; 6]; 3];
+                for row in xyb_weights.iter_mut() {
+                    for item in row.iter_mut() {
+                        *item = f32::from(f16::from_bits(br.read(16)? as u16));
+                        if item.abs() < ALMOST_ZERO {
+                            return Err(HfQuantFactorTooSmall(*item));
+                        }
+                        *item *= 64.0;
+                    }
+                }
+                Ok(Self::Dct2 { xyb_weights })
+            }
+            3 => {
+                if required_size != 1 {
+                    return Err(InvalidQuantEncoding {
+                        mode,
+                        required_size,
+                    });
+                }
+                let mut xyb_mul = [[0.0; 2]; 3];
+                for row in xyb_mul.iter_mut() {
+                    for item in row.iter_mut() {
+                        *item = f32::from(f16::from_bits(br.read(16)? as u16));
+                        if item.abs() < ALMOST_ZERO {
+                            return Err(HfQuantFactorTooSmall(*item));
+                        }
+                    }
+                }
+                let params = DctQuantWeightParams::decode(br)?;
+                Ok(Self::Dct4 { params, xyb_mul })
+            }
+            4 => {
+                if required_size != 1 {
+                    return Err(InvalidQuantEncoding {
+                        mode,
+                        required_size,
+                    });
+                }
+                let mut xyb_mul = [0.0; 3];
+                for item in xyb_mul.iter_mut() {
+                    *item = f32::from(f16::from_bits(br.read(16)? as u16));
+                    if item.abs() < ALMOST_ZERO {
+                        return Err(HfQuantFactorTooSmall(*item));
+                    }
+                }
+                let params = DctQuantWeightParams::decode(br)?;
+                Ok(Self::Dct4x8 { params, xyb_mul })
+            }
+            5 => {
+                if required_size != 1 {
+                    return Err(InvalidQuantEncoding {
+                        mode,
+                        required_size,
+                    });
+                }
+                let mut weights = [[0.0; 9]; 3];
+                for row in weights.iter_mut() {
+                    for item in row.iter_mut() {
+                        *item = f32::from(f16::from_bits(br.read(16)? as u16));
+                    }
+                    for item in row[0..6].iter_mut() {
+                        *item *= 64.0;
+                    }
+                }
+                let params4x8 = DctQuantWeightParams::decode(br)?;
+                let params4x4 = DctQuantWeightParams::decode(br)?;
+                Ok(Self::Afv {
+                    params4x8,
+                    params4x4,
+                    weights,
+                })
+            }
+            6 => {
+                let params = DctQuantWeightParams::decode(br)?;
+                Ok(Self::Dct { params })
+            }
+            7 => {
+                let qtable_den = f32::from(f16::from_bits(br.read(16)? as u16));
+                if qtable_den < ALMOST_ZERO {
+                    // qtable[] values are already checked for <= 0 so the denominator may not be negative.
+                    return Err(InvalidRawQuantTable);
+                }
+                let bit_depth = BitDepth::integer_samples(8);
+                let mut image = [
+                    ModularChannel::new((required_size_x, required_size_y), bit_depth)?,
+                    ModularChannel::new((required_size_x, required_size_y), bit_depth)?,
+                    ModularChannel::new((required_size_x, required_size_y), bit_depth)?,
+                ];
+                let stream_id = ModularStreamId::QuantTable(index).get_id(header);
+                decode_modular_subbitstream(
+                    image.iter_mut().collect(),
+                    stream_id,
+                    None,
+                    &lf_global.tree,
+                    br,
+                )?;
+                let mut qtable = Vec::with_capacity(required_size_x * required_size_y * 3);
+                for channel in image.iter_mut() {
+                    for entry in channel
+                        .data
+                        .get_rect(Rect {
+                            size: (required_size_x, required_size_y),
+                            origin: (0, 0),
+                        })
+                        .iter()
+                    {
+                        qtable.push(entry);
+                        if entry <= 0 {
+                            return Err(InvalidRawQuantTable);
+                        }
+                    }
+                }
+                Ok(Self::Raw { qtable, qtable_den })
+            }
+            _ => Err(InvalidQuantEncoding {
+                mode,
+                required_size,
+            }),
+        }
+    }
+}
+
+#[derive(Clone, Copy, Debug)]
+enum QuantTable {
+    // Update QuantTable::VALUES when changing this!
+    Dct,
+    Identity,
+    Dct2x2,
+    Dct4x4,
+    Dct16x16,
+    Dct32x32,
+    // Dct16x8
+    Dct8x16,
+    // Dct32x8
+    Dct8x32,
+    // Dct32x16
+    Dct16x32,
+    Dct4x8,
+    // Dct8x4
+    Afv0,
+    // Afv1
+    // Afv2
+    // Afv3
+    Dct64x64,
+    // Dct64x32,
+    Dct32x64,
+    Dct128x128,
+    // Dct128x64,
+    Dct64x128,
+    Dct256x256,
+    // Dct256x128,
+    Dct128x256,
+}
+
+impl QuantTable {
+    pub const CARDINALITY: usize = Self::VALUES.len();
+    pub const VALUES: [QuantTable; 17] = [
+        QuantTable::Dct,
+        QuantTable::Identity,
+        QuantTable::Dct2x2,
+        QuantTable::Dct4x4,
+        QuantTable::Dct16x16,
+        QuantTable::Dct32x32,
+        // QuantTable::Dct16x8
+        QuantTable::Dct8x16,
+        // QuantTable::Dct32x8
+        QuantTable::Dct8x32,
+        // QuantTable::Dct32x16
+        QuantTable::Dct16x32,
+        QuantTable::Dct4x8,
+        // QuantTable::Dct8x4
+        QuantTable::Afv0,
+        // QuantTable::Afv1
+        // QuantTable::Afv2
+        // QuantTable::Afv3
+        QuantTable::Dct64x64,
+        // QuantTable::Dct64x32,
+        QuantTable::Dct32x64,
+        QuantTable::Dct128x128,
+        // QuantTable::Dct128x64,
+        QuantTable::Dct64x128,
+        QuantTable::Dct256x256,
+        // QuantTable::Dct256x128,
+        QuantTable::Dct128x256,
+    ];
+    pub fn from_usize(idx: usize) -> Result<QuantTable> {
+        match QuantTable::VALUES.get(idx) {
+            Some(table) => Ok(*table),
+            None => Err(InvalidQuantEncodingMode),
+        }
+    }
+    fn for_strategy(strategy: HfTransformType) -> QuantTable {
+        match strategy {
+            HfTransformType::DCT => QuantTable::Dct,
+            HfTransformType::IDENTITY => QuantTable::Identity,
+            HfTransformType::DCT2X2 => QuantTable::Dct2x2,
+            HfTransformType::DCT4X4 => QuantTable::Dct4x4,
+            HfTransformType::DCT16X16 => QuantTable::Dct16x16,
+            HfTransformType::DCT32X32 => QuantTable::Dct32x32,
+            HfTransformType::DCT16X8 | HfTransformType::DCT8X16 => QuantTable::Dct8x16,
+            HfTransformType::DCT32X8 | HfTransformType::DCT8X32 => QuantTable::Dct8x32,
+            HfTransformType::DCT32X16 | HfTransformType::DCT16X32 => QuantTable::Dct16x32,
+            HfTransformType::DCT4X8 | HfTransformType::DCT8X4 => QuantTable::Dct4x8,
+            HfTransformType::AFV0
+            | HfTransformType::AFV1
+            | HfTransformType::AFV2
+            | HfTransformType::AFV3 => QuantTable::Afv0,
+            HfTransformType::DCT64X64 => QuantTable::Dct64x64,
+            HfTransformType::DCT64X32 | HfTransformType::DCT32X64 => QuantTable::Dct32x64,
+            HfTransformType::DCT128X128 => QuantTable::Dct128x128,
+            HfTransformType::DCT128X64 | HfTransformType::DCT64X128 => QuantTable::Dct64x128,
+            HfTransformType::DCT256X256 => QuantTable::Dct256x256,
+            HfTransformType::DCT256X128 | HfTransformType::DCT128X256 => QuantTable::Dct128x256,
+        }
+    }
+}
+
+pub struct DequantMatrices {
+    computed_mask: u32,
+    table: Vec<f32>,
+    inv_table: Vec<f32>,
+    table_offsets: [usize; HfTransformType::CARDINALITY * 3],
+    encodings: Vec<QuantEncoding>,
+}
+
+#[allow(clippy::excessive_precision)]
+impl DequantMatrices {
+    fn dct() -> QuantEncoding {
+        QuantEncoding::Dct {
+            params: DctQuantWeightParams::from_array(&[
+                [3150.0, 0.0, -0.4, -0.4, -0.4, -2.0],
+                [560.0, 0.0, -0.3, -0.3, -0.3, -0.3],
+                [512.0, -2.0, -1.0, 0.0, -1.0, -2.0],
+            ]),
+        }
+    }
+    fn id() -> QuantEncoding {
+        QuantEncoding::Identity {
+            xyb_weights: [
+                [280.0, 3160.0, 3160.0],
+                [60.0, 864.0, 864.0],
+                [18.0, 200.0, 200.0],
+            ],
+        }
+    }
+    fn dct2x2() -> QuantEncoding {
+        QuantEncoding::Dct2 {
+            xyb_weights: [
+                [3840.0, 2560.0, 1280.0, 640.0, 480.0, 300.0],
+                [960.0, 640.0, 320.0, 180.0, 140.0, 120.0],
+                [640.0, 320.0, 128.0, 64.0, 32.0, 16.0],
+            ],
+        }
+    }
+    fn dct4x4() -> QuantEncoding {
+        QuantEncoding::Dct4 {
+            params: DctQuantWeightParams::from_array(&[
+                [2200.0, 0.0, 0.0, 0.0],
+                [392.0, 0.0, 0.0, 0.0],
+                [112.0, -0.25, -0.25, -0.5],
+            ]),
+            xyb_mul: [[1.0, 1.0], [1.0, 1.0], [1.0, 1.0]],
+        }
+    }
+    fn dct16x16() -> QuantEncoding {
+        QuantEncoding::Dct {
+            params: DctQuantWeightParams::from_array(&[
+                [
+                    8996.8725711814115328,
+                    -1.3000777393353804,
+                    -0.49424529824571225,
+                    -0.439093774457103443,
+                    -0.6350101832695744,
+                    -0.90177264050827612,
+                    -1.6162099239887414,
+                ],
+                [
+                    3191.48366296844234752,
+                    -0.67424582104194355,
+                    -0.80745813428471001,
+                    -0.44925837484843441,
+                    -0.35865440981033403,
+                    -0.31322389111877305,
+                    -0.37615025315725483,
+                ],
+                [
+                    1157.50408145487200256,
+                    -2.0531423165804414,
+                    -1.4,
+                    -0.50687130033378396,
+                    -0.42708730624733904,
+                    -1.4856834539296244,
+                    -4.9209142884401604,
+                ],
+            ]),
+        }
+    }
+    fn dct32x32() -> QuantEncoding {
+        QuantEncoding::Dct {
+            params: DctQuantWeightParams::from_array(&[
+                [
+                    15718.40830982518931456,
+                    -1.025,
+                    -0.98,
+                    -0.9012,
+                    -0.4,
+                    -0.48819395464,
+                    -0.421064,
+                    -0.27,
+                ],
+                [
+                    7305.7636810695983104,
+                    -0.8041958212306401,
+                    -0.7633036457487539,
+                    -0.55660379990111464,
+                    -0.49785304658857626,
+                    -0.43699592683512467,
+                    -0.40180866526242109,
+                    -0.27321683125358037,
+                ],
+                [
+                    3803.53173721215041536,
+                    -3.060733579805728,
+                    -2.0413270132490346,
+                    -2.0235650159727417,
+                    -0.5495389509954993,
+                    -0.4,
+                    -0.4,
+                    -0.3,
+                ],
+            ]),
+        }
+    }
+
+    // dct16x8
+    fn dct8x16() -> QuantEncoding {
+        QuantEncoding::Dct {
+            params: DctQuantWeightParams::from_array(&[
+                [7240.7734393502, -0.7, -0.7, -0.2, -0.2, -0.2, -0.5],
+                [1448.15468787004, -0.5, -0.5, -0.5, -0.2, -0.2, -0.2],
+                [506.854140754517, -1.4, -0.2, -0.5, -0.5, -1.5, -3.6],
+            ]),
+        }
+    }
+
+    // dct32x8
+    fn dct8x32() -> QuantEncoding {
+        QuantEncoding::Dct {
+            params: DctQuantWeightParams::from_array(&[
+                [
+                    16283.2494710648897,
+                    -1.7812845336559429,
+                    -1.6309059012653515,
+                    -1.0382179034313539,
+                    -0.85,
+                    -0.7,
+                    -0.9,
+                    -1.2360638576849587,
+                ],
+                [
+                    5089.15750884921511936,
+                    -0.320049391452786891,
+                    -0.35362849922161446,
+                    -0.30340000000000003,
+                    -0.61,
+                    -0.5,
+                    -0.5,
+                    -0.6,
+                ],
+                [
+                    3397.77603275308720128,
+                    -0.321327362693153371,
+                    -0.34507619223117997,
+                    -0.70340000000000003,
+                    -0.9,
+                    -1.0,
+                    -1.0,
+                    -1.1754605576265209,
+                ],
+            ]),
+        }
+    }
+
+    // dct32x16
+    fn dct16x32() -> QuantEncoding {
+        QuantEncoding::Dct {
+            params: DctQuantWeightParams::from_array(&[
+                [
+                    13844.97076442300573,
+                    -0.97113799999999995,
+                    -0.658,
+                    -0.42026,
+                    -0.22712,
+                    -0.2206,
+                    -0.226,
+                    -0.6,
+                ],
+                [
+                    4798.964084220744293,
+                    -0.61125308982767057,
+                    -0.83770786552491361,
+                    -0.79014862079498627,
+                    -0.2692727459704829,
+                    -0.38272769465388551,
+                    -0.22924222653091453,
+                    -0.20719098826199578,
+                ],
+                [
+                    1807.236946760964614,
+                    -1.2,
+                    -1.2,
+                    -0.7,
+                    -0.7,
+                    -0.7,
+                    -0.4,
+                    -0.5,
+                ],
+            ]),
+        }
+    }
+
+    // dct8x4
+    fn dct4x8() -> QuantEncoding {
+        QuantEncoding::Dct4x8 {
+            params: DctQuantWeightParams::from_array(&[
+                [
+                    2198.050556016380522,
+                    -0.96269623020744692,
+                    -0.76194253026666783,
+                    -0.6551140670773547,
+                ],
+                [
+                    764.3655248643528689,
+                    -0.92630200888366945,
+                    -0.9675229603596517,
+                    -0.27845290869168118,
+                ],
+                [
+                    527.107573587542228,
+                    -1.4594385811273854,
+                    -1.450082094097871593,
+                    -1.5843722511996204,
+                ],
+            ]),
+            xyb_mul: [1.0, 1.0, 1.0],
+        }
+    }
+    // AFV
+    fn afv0() -> QuantEncoding {
+        let QuantEncoding::Dct4x8 {
+            params: params4x8, ..
+        } = Self::dct4x8()
+        else {
+            unreachable!();
+        };
+        let QuantEncoding::Dct4 {
+            params: params4x4, ..
+        } = Self::dct4x4()
+        else {
+            unreachable!()
+        };
+        QuantEncoding::Afv {
+            params4x8,
+            params4x4,
+            weights: [
+                [
+                    3072.0, 3072.0, // 4x4/4x8 DC tendency.
+                    256.0, 256.0, 256.0, // AFV corner.
+                    414.0, 0.0, 0.0, 0.0, // AFV high freqs.
+                ],
+                [
+                    1024.0, 1024.0, // 4x4/4x8 DC tendency.
+                    50.0, 50.0, 50.0, // AFV corner.
+                    58.0, 0.0, 0.0, 0.0, // AFV high freqs.
+                ],
+                [
+                    384.0, 384.0, // 4x4/4x8 DC tendency.
+                    12.0, 12.0, 12.0, // AFV corner.
+                    22.0, -0.25, -0.25, -0.25, // AFV high freqs.
+                ],
+            ],
+        }
+    }
+
+    fn dct64x64() -> QuantEncoding {
+        QuantEncoding::Dct {
+            params: DctQuantWeightParams::from_array(&[
+                [
+                    0.9 * 26629.073922049845,
+                    -1.025,
+                    -0.78,
+                    -0.65012,
+                    -0.19041574084286472,
+                    -0.20819395464,
+                    -0.421064,
+                    -0.32733845535848671,
+                ],
+                [
+                    0.9 * 9311.3238710010046,
+                    -0.3041958212306401,
+                    -0.3633036457487539,
+                    -0.35660379990111464,
+                    -0.3443074455424403,
+                    -0.33699592683512467,
+                    -0.30180866526242109,
+                    -0.27321683125358037,
+                ],
+                [
+                    0.9 * 4992.2486445538634,
+                    -1.2,
+                    -1.2,
+                    -0.8,
+                    -0.7,
+                    -0.7,
+                    -0.4,
+                    -0.5,
+                ],
+            ]),
+        }
+    }
+
+    // dct64x32
+    fn dct32x64() -> QuantEncoding {
+        QuantEncoding::Dct {
+            params: DctQuantWeightParams::from_array(&[
+                [
+                    0.65 * 23629.073922049845,
+                    -1.025,
+                    -0.78,
+                    -0.65012,
+                    -0.19041574084286472,
+                    -0.20819395464,
+                    -0.421064,
+                    -0.32733845535848671,
+                ],
+                [
+                    0.65 * 8611.3238710010046,
+                    -0.3041958212306401,
+                    -0.3633036457487539,
+                    -0.35660379990111464,
+                    -0.3443074455424403,
+                    -0.33699592683512467,
+                    -0.30180866526242109,
+                    -0.27321683125358037,
+                ],
+                [
+                    0.65 * 4492.2486445538634,
+                    -1.2,
+                    -1.2,
+                    -0.8,
+                    -0.7,
+                    -0.7,
+                    -0.4,
+                    -0.5,
+                ],
+            ]),
+        }
+    }
+    fn dct128x128() -> QuantEncoding {
+        QuantEncoding::Dct {
+            params: DctQuantWeightParams::from_array(&[
+                [
+                    1.8 * 26629.073922049845,
+                    -1.025,
+                    -0.78,
+                    -0.65012,
+                    -0.19041574084286472,
+                    -0.20819395464,
+                    -0.421064,
+                    -0.32733845535848671,
+                ],
+                [
+                    1.8 * 9311.3238710010046,
+                    -0.3041958212306401,
+                    -0.3633036457487539,
+                    -0.35660379990111464,
+                    -0.3443074455424403,
+                    -0.33699592683512467,
+                    -0.30180866526242109,
+                    -0.27321683125358037,
+                ],
+                [
+                    1.8 * 4992.2486445538634,
+                    -1.2,
+                    -1.2,
+                    -0.8,
+                    -0.7,
+                    -0.7,
+                    -0.4,
+                    -0.5,
+                ],
+            ]),
+        }
+    }
+
+    // dct128x64
+    fn dct64x128() -> QuantEncoding {
+        QuantEncoding::Dct {
+            params: DctQuantWeightParams::from_array(&[
+                [
+                    1.3 * 23629.073922049845,
+                    -1.025,
+                    -0.78,
+                    -0.65012,
+                    -0.19041574084286472,
+                    -0.20819395464,
+                    -0.421064,
+                    -0.32733845535848671,
+                ],
+                [
+                    1.3 * 8611.3238710010046,
+                    -0.3041958212306401,
+                    -0.3633036457487539,
+                    -0.35660379990111464,
+                    -0.3443074455424403,
+                    -0.33699592683512467,
+                    -0.30180866526242109,
+                    -0.27321683125358037,
+                ],
+                [
+                    1.3 * 4492.2486445538634,
+                    -1.2,
+                    -1.2,
+                    -0.8,
+                    -0.7,
+                    -0.7,
+                    -0.4,
+                    -0.5,
+                ],
+            ]),
+        }
+    }
+    fn dct256x256() -> QuantEncoding {
+        QuantEncoding::Dct {
+            params: DctQuantWeightParams::from_array(&[
+                [
+                    3.6 * 26629.073922049845,
+                    -1.025,
+                    -0.78,
+                    -0.65012,
+                    -0.19041574084286472,
+                    -0.20819395464,
+                    -0.421064,
+                    -0.32733845535848671,
+                ],
+                [
+                    3.6 * 9311.3238710010046,
+                    -0.3041958212306401,
+                    -0.3633036457487539,
+                    -0.35660379990111464,
+                    -0.3443074455424403,
+                    -0.33699592683512467,
+                    -0.30180866526242109,
+                    -0.27321683125358037,
+                ],
+                [
+                    3.6 * 4992.2486445538634,
+                    -1.2,
+                    -1.2,
+                    -0.8,
+                    -0.7,
+                    -0.7,
+                    -0.4,
+                    -0.5,
+                ],
+            ]),
+        }
+    }
+
+    // dct256x128
+    fn dct128x256() -> QuantEncoding {
+        QuantEncoding::Dct {
+            params: DctQuantWeightParams::from_array(&[
+                [
+                    2.6 * 23629.073922049845,
+                    -1.025,
+                    -0.78,
+                    -0.65012,
+                    -0.19041574084286472,
+                    -0.20819395464,
+                    -0.421064,
+                    -0.32733845535848671,
+                ],
+                [
+                    2.6 * 8611.3238710010046,
+                    -0.3041958212306401,
+                    -0.3633036457487539,
+                    -0.35660379990111464,
+                    -0.3443074455424403,
+                    -0.33699592683512467,
+                    -0.30180866526242109,
+                    -0.27321683125358037,
+                ],
+                [
+                    2.6 * 4492.2486445538634,
+                    -1.2,
+                    -1.2,
+                    -0.8,
+                    -0.7,
+                    -0.7,
+                    -0.4,
+                    -0.5,
+                ],
+            ]),
+        }
+    }
+
+    pub fn library() -> &'static [QuantEncoding; QuantTable::CARDINALITY] {
+        static QUANTS: OnceLock<[QuantEncoding; QuantTable::CARDINALITY]> = OnceLock::new();
+        QUANTS.get_or_init(|| {
+            [
+                DequantMatrices::dct(),
+                DequantMatrices::id(),
+                DequantMatrices::dct2x2(),
+                DequantMatrices::dct4x4(),
+                DequantMatrices::dct16x16(),
+                DequantMatrices::dct32x32(),
+                DequantMatrices::dct8x16(),
+                DequantMatrices::dct8x32(),
+                DequantMatrices::dct16x32(),
+                DequantMatrices::dct4x8(),
+                DequantMatrices::afv0(),
+                DequantMatrices::dct64x64(),
+                DequantMatrices::dct32x64(),
+                // Same default for large transforms (128+) as for 64x* transforms.
+                DequantMatrices::dct128x128(),
+                DequantMatrices::dct64x128(),
+                DequantMatrices::dct256x256(),
+                DequantMatrices::dct128x256(),
+            ]
+        })
+    }
+
+    pub fn matrix(&self, quant_kind: HfTransformType, c: usize) -> &[f32] {
+        assert_ne!((1 << quant_kind as u32) & self.computed_mask, 0);
+        &self.table[self.table_offsets[quant_kind as usize * 3 + c]..]
+    }
+
+    // TODO(veluca): figure out if this should actually be unused.
+    #[allow(dead_code)]
+    pub fn inv_matrix(&self, quant_kind: HfTransformType, c: usize) -> &[f32] {
+        assert_ne!((1 << quant_kind as u32) & self.computed_mask, 0);
+        &self.inv_table[self.table_offsets[quant_kind as usize * 3 + c]..]
+    }
+
+    pub fn decode(
+        header: &FrameHeader,
+        lf_global: &LfGlobalState,
+        br: &mut BitReader,
+    ) -> Result<Self> {
+        let all_default = br.read(1)? == 1;
+        let mut encodings = Vec::with_capacity(QuantTable::CARDINALITY);
+        if all_default {
+            for _ in 0..QuantTable::CARDINALITY {
+                encodings.push(QuantEncoding::Library)
+            }
+        } else {
+            for (i, (&required_size_x, required_size_y)) in Self::REQUIRED_SIZE_X
+                .iter()
+                .zip(Self::REQUIRED_SIZE_Y)
+                .enumerate()
+            {
+                encodings.push(QuantEncoding::decode(
+                    required_size_x,
+                    required_size_y,
+                    i,
+                    header,
+                    lf_global,
+                    br,
+                )?);
+            }
+        }
+        Ok(Self {
+            computed_mask: 0,
+            table: vec![0.0; Self::TOTAL_TABLE_SIZE],
+            inv_table: vec![0.0; Self::TOTAL_TABLE_SIZE],
+            table_offsets: [0; HfTransformType::CARDINALITY * 3],
+            encodings,
+        })
+    }
+
+    pub const REQUIRED_SIZE_X: [usize; QuantTable::CARDINALITY] =
+        [1, 1, 1, 1, 2, 4, 1, 1, 2, 1, 1, 8, 4, 16, 8, 32, 16];
+
+    pub const REQUIRED_SIZE_Y: [usize; QuantTable::CARDINALITY] =
+        [1, 1, 1, 1, 2, 4, 2, 4, 4, 1, 1, 8, 8, 16, 16, 32, 32];
+
+    pub const SUM_REQUIRED_X_Y: usize = 2056;
+
+    pub const TOTAL_TABLE_SIZE: usize = Self::SUM_REQUIRED_X_Y * BLOCK_SIZE * 3;
+
+    pub fn ensure_computed(&mut self, acs_mask: u32) -> Result<()> {
+        let mut offsets = [0usize; QuantTable::CARDINALITY * 3];
+        let mut pos = 0usize;
+        for i in 0..QuantTable::CARDINALITY {
+            let num = DequantMatrices::REQUIRED_SIZE_X[i]
+                * DequantMatrices::REQUIRED_SIZE_Y[i]
+                * BLOCK_SIZE;
+            for c in 0..3 {
+                offsets[3 * i + c] = pos + c * num;
+            }
+            pos += 3 * num;
+        }
+        for i in 0..HfTransformType::CARDINALITY {
+            for c in 0..3 {
+                self.table_offsets[i * 3 + c] =
+                    offsets[QuantTable::for_strategy(HfTransformType::from_usize(i).unwrap())
+                        as usize
+                        * 3
+                        + c];
+            }
+        }
+        let mut kind_mask = 0u32;
+        for i in 0..HfTransformType::CARDINALITY {
+            if acs_mask & (1u32 << i) != 0 {
+                kind_mask |= 1u32 << QuantTable::for_strategy(HfTransformType::VALUES[i]) as u32;
+            }
+        }
+        let mut computed_kind_mask = 0u32;
+        for i in 0..HfTransformType::CARDINALITY {
+            if self.computed_mask & (1u32 << i) != 0 {
+                computed_kind_mask |=
+                    1u32 << QuantTable::for_strategy(HfTransformType::VALUES[i]) as u32;
+            }
+        }
+        for table in 0..QuantTable::CARDINALITY {
+            if (1u32 << table) & computed_kind_mask != 0 {
+                continue;
+            }
+            if (1u32 << table) & !kind_mask != 0 {
+                continue;
+            }
+            match self.encodings[table] {
+                QuantEncoding::Library => {
+                    self.compute_quant_table(true, table, offsets[table * 3])?
+                }
+                _ => self.compute_quant_table(false, table, offsets[table * 3])?,
+            };
+        }
+        self.computed_mask |= acs_mask;
+        Ok(())
+    }
+    fn compute_quant_table(
+        &mut self,
+        library: bool,
+        table_num: usize,
+        offset: usize,
+    ) -> Result<usize> {
+        let encoding = if library {
+            &DequantMatrices::library()[table_num]
+        } else {
+            &self.encodings[table_num]
+        };
+        let quant_table_idx = QuantTable::from_usize(table_num)? as usize;
+        let wrows = 8 * DequantMatrices::REQUIRED_SIZE_X[quant_table_idx];
+        let wcols = 8 * DequantMatrices::REQUIRED_SIZE_Y[quant_table_idx];
+        let num = wrows * wcols;
+        let mut weights = vec![0f32; 3 * num];
+        match encoding {
+            QuantEncoding::Library => {
+                // Library and copy quant encoding should get replaced by the actual
+                // parameters by the caller.
+                return Err(InvalidQuantEncodingMode);
+            }
+            QuantEncoding::Identity { xyb_weights } => {
+                for c in 0..3 {
+                    for i in 0..64 {
+                        weights[64 * c + i] = xyb_weights[c][0];
+                    }
+                    weights[64 * c + 1] = xyb_weights[c][1];
+                    weights[64 * c + 8] = xyb_weights[c][1];
+                    weights[64 * c + 9] = xyb_weights[c][2];
+                }
+            }
+            QuantEncoding::Dct2 { xyb_weights } => {
+                for (c, xyb_weight) in xyb_weights.iter().enumerate() {
+                    let start = c * 64;
+                    weights[start] = 0xBAD as f32;
+                    weights[start + 1] = xyb_weight[0];
+                    weights[start + 8] = xyb_weight[0];
+                    weights[start + 9] = xyb_weight[1];
+                    for y in 0..2 {
+                        for x in 0..2 {
+                            weights[start + y * 8 + x + 2] = xyb_weight[2];
+                            weights[start + (y + 2) * 8 + x] = xyb_weight[2];
+                        }
+                    }
+                    for y in 0..2 {
+                        for x in 0..2 {
+                            weights[start + (y + 2) * 8 + x + 2] = xyb_weight[3];
+                        }
+                    }
+                    for y in 0..4 {
+                        for x in 0..4 {
+                            weights[start + y * 8 + x + 4] = xyb_weight[4];
+                            weights[start + (y + 4) * 8 + x] = xyb_weight[4];
+                        }
+                    }
+                    for y in 0..4 {
+                        for x in 0..4 {
+                            weights[start + (y + 4) * 8 + x + 4] = xyb_weight[5];
+                        }
+                    }
+                }
+            }
+            QuantEncoding::Dct4 { params, xyb_mul } => {
+                let mut weights4x4 = [0f32; 3 * 4 * 4];
+                get_quant_weights(4, 4, params, &mut weights4x4)?;
+                for c in 0..3 {
+                    for y in 0..BLOCK_DIM {
+                        for x in 0..BLOCK_DIM {
+                            weights[c * num + y * BLOCK_DIM + x] =
+                                weights4x4[c * 16 + (y / 2) * 4 + (x / 2)];
+                        }
+                    }
+                    weights[c * num + 1] /= xyb_mul[c][0];
+                    weights[c * num + BLOCK_DIM] /= xyb_mul[c][0];
+                    weights[c * num + BLOCK_DIM + 1] /= xyb_mul[c][1];
+                }
+            }
+            QuantEncoding::Dct4x8 { params, xyb_mul } => {
+                let mut weights4x8 = [0f32; 3 * 4 * 8];
+                get_quant_weights(4, 8, params, &mut weights4x8)?;
+                for c in 0..3 {
+                    for y in 0..BLOCK_DIM {
+                        for x in 0..BLOCK_DIM {
+                            weights[c * num + y * BLOCK_DIM + x] =
+                                weights4x8[c * 32 + (y / 2) * 8 + x];
+                        }
+                    }
+                    weights[c * num + BLOCK_DIM] /= xyb_mul[c];
+                }
+            }
+            QuantEncoding::Dct { params } => {
+                get_quant_weights(wrows, wcols, params, &mut weights)?;
+            }
+            QuantEncoding::Raw { qtable, qtable_den } => {
+                if qtable.len() != 3 * num {
+                    return Err(InvalidRawQuantTable);
+                }
+                for i in 0..3 * num {
+                    weights[i] = 1f32 / (qtable_den * qtable[i] as f32);
+                }
+            }
+            QuantEncoding::Afv {
+                params4x8,
+                params4x4,
+                weights: afv_weights,
+            } => {
+                const FREQS: [f32; 16] = [
+                    0xBAD as f32,
+                    0xBAD as f32,
+                    0.8517778890324296,
+                    5.37778436506804,
+                    0xBAD as f32,
+                    0xBAD as f32,
+                    4.734747904497923,
+                    5.449245381693219,
+                    1.6598270267479331,
+                    4f32,
+                    7.275749096817861,
+                    10.423227632456525,
+                    2.662932286148962,
+                    7.630657783650829,
+                    8.962388608184032,
+                    12.97166202570235,
+                ];
+                let mut weights4x8 = [0f32; 3 * 4 * 8];
+                get_quant_weights(4, 8, params4x8, &mut weights4x8)?;
+                let mut weights4x4 = [0f32; 3 * 4 * 4];
+                get_quant_weights(4, 4, params4x4, &mut weights4x4)?;
+                const LO: f32 = 0.8517778890324296;
+                const HI: f32 = 12.97166202570235f32 - LO + 1e-6f32;
+                for c in 0..3 {
+                    let mut bands = [0f32; 4];
+                    bands[0] = afv_weights[c][5];
+                    if bands[0] < ALMOST_ZERO {
+                        return Err(InvalidDistanceBand(0, bands[0]));
+                    }
+                    for i in 1..4 {
+                        bands[i] = bands[i - 1] * mult(afv_weights[c][i + 5]);
+                        if bands[i] < ALMOST_ZERO {
+                            return Err(InvalidDistanceBand(i, bands[i]));
+                        }
+                    }
+
+                    {
+                        let start = c * 64;
+                        weights[start] = 1f32;
+                        let mut set = |x, y, val| {
+                            weights[start + y * 8 + x] = val;
+                        };
+                        set(0, 1, afv_weights[c][0]);
+                        set(1, 0, afv_weights[c][1]);
+                        set(0, 2, afv_weights[c][2]);
+                        set(2, 0, afv_weights[c][3]);
+                        set(2, 2, afv_weights[c][4]);
+
+                        for y in 0..4 {
+                            for x in 0..4 {
+                                if x < 2 && y < 2 {
+                                    continue;
+                                }
+                                let val = interpolate(FREQS[y * 4 + x] - LO, HI, &bands);
+                                set(2 * x, 2 * y, val);
+                            }
+                        }
+                    }
+
+                    for y in 0..BLOCK_DIM / 2 {
+                        for x in 0..BLOCK_DIM {
+                            if x == 0 && y == 0 {
+                                continue;
+                            }
+                            weights[c * num + (2 * y + 1) * BLOCK_DIM + x] =
+                                weights4x8[c * 32 + y * 8 + x];
+                        }
+                    }
+
+                    for y in 0..BLOCK_DIM / 2 {
+                        for x in 0..BLOCK_DIM / 2 {
+                            if x == 0 && y == 0 {
+                                continue;
+                            }
+                            weights[c * num + (2 * y) * BLOCK_DIM + 2 * x + 1] =
+                                weights4x4[c * 16 + y * 4 + x];
+                        }
+                    }
+                }
+            }
+        }
+        for (i, weight) in weights.iter().enumerate() {
+            if !(ALMOST_ZERO..=1.0 / ALMOST_ZERO).contains(weight) {
+                return Err(InvalidQuantizationTableWeight(*weight));
+            }
+            self.table[offset + i] = 1f32 / weight;
+            self.inv_table[offset + i] = *weight;
+        }
+        let (xs, ys) = coefficient_layout(
+            DequantMatrices::REQUIRED_SIZE_X[quant_table_idx],
+            DequantMatrices::REQUIRED_SIZE_Y[quant_table_idx],
+        );
+        for c in 0..3 {
+            for y in 0..ys {
+                for x in 0..xs {
+                    self.inv_table[offset + c * ys * xs * BLOCK_SIZE + y * BLOCK_DIM * xs + x] =
+                        0f32;
+                }
+            }
+        }
+        Ok(0)
+    }
+}
+
+fn coefficient_layout(rows: usize, cols: usize) -> (usize, usize) {
+    (
+        if rows < cols { rows } else { cols },
+        if rows < cols { cols } else { rows },
+    )
+}
+
+fn get_quant_weights(
+    rows: usize,
+    cols: usize,
+    distance_bands: &DctQuantWeightParams,
+    out: &mut [f32],
+) -> Result<()> {
+    for c in 0..3 {
+        let mut bands = [0f32; DctQuantWeightParams::MAX_DISTANCE_BANDS];
+        bands[0] = distance_bands.params[c][0];
+        if bands[0] < ALMOST_ZERO {
+            return Err(InvalidDistanceBand(0, bands[0]));
+        }
+        for i in 1..distance_bands.num_bands {
+            bands[i] = bands[i - 1] * mult(distance_bands.params[c][i]);
+            if bands[i] < ALMOST_ZERO {
+                return Err(InvalidDistanceBand(i, bands[i]));
+            }
+        }
+        let scale = (distance_bands.num_bands - 1) as f32 / (SQRT_2 + 1e-6);
+        let rcpcol = scale / (cols - 1) as f32;
+        let rcprow = scale / (rows - 1) as f32;
+        for y in 0..rows {
+            let dy = y as f32 * rcprow;
+            let dy2 = dy * dy;
+            for x in 0..cols {
+                let dx = x as f32 * rcpcol;
+                let scaled_distance = (dx * dx + dy2).sqrt();
+                let weight = if distance_bands.num_bands == 1 {
+                    bands[0]
+                } else {
+                    interpolate_vec(scaled_distance, &bands)
+                };
+                out[c * cols * rows + y * cols + x] = weight;
+            }
+        }
+    }
+    Ok(())
+}
+
+fn interpolate_vec(scaled_pos: f32, array: &[f32]) -> f32 {
+    let idxf32 = scaled_pos.floor();
+    let frac = scaled_pos - idxf32;
+    let idx = idxf32 as usize;
+    let a = array[idx];
+    let b = array[1..][idx];
+    (b / a).powf(frac) * a
+}
+
+fn interpolate(pos: f32, max: f32, array: &[f32]) -> f32 {
+    let scaled_pos = pos * (array.len() - 1) as f32 / max;
+    let idx = scaled_pos as usize;
+    let a = array[idx];
+    let b = array[idx + 1];
+    a * (b / a).powf(scaled_pos - idx as f32)
+}
+
+fn mult(v: f32) -> f32 {
+    if v > 0f32 {
+        1f32 + v
+    } else {
+        1f32 / (1f32 - v)
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use crate::error::Result;
+    use crate::frame::quant_weights::DequantMatrices;
+    use crate::util::test::{assert_all_almost_abs_eq, assert_almost_abs_eq, assert_almost_eq};
+
+    #[test]
+    fn check_required_x_y() {
+        assert_eq!(
+            DequantMatrices::SUM_REQUIRED_X_Y,
+            DequantMatrices::REQUIRED_SIZE_X
+                .iter()
+                .zip(DequantMatrices::REQUIRED_SIZE_Y)
+                .map(|(&x, y)| x * y)
+                .sum()
+        );
+    }
+
+    #[test]
+    fn check_dequant_matrix_correctness() -> Result<()> {
+        let mut matrices = DequantMatrices {
+            computed_mask: 0,
+            table: vec![0.0; DequantMatrices::TOTAL_TABLE_SIZE],
+            inv_table: vec![0.0; DequantMatrices::TOTAL_TABLE_SIZE],
+            table_offsets: [0; HfTransformType::CARDINALITY * 3],
+            encodings: (0..QuantTable::CARDINALITY)
+                .map(|_| QuantEncoding::Library)
+                .collect(),
+        };
+        matrices.ensure_computed(!0)?;
+
+        // Golden data produced by libjxl.
+        let target_offsets: [usize; 81] = [
+            0, 64, 128, 192, 256, 320, 384, 448, 512, 576, 640, 704, 768, 1024, 1280, 1536, 2560,
+            3584, 4608, 4736, 4864, 4608, 4736, 4864, 4992, 5248, 5504, 4992, 5248, 5504, 5760,
+            6272, 6784, 5760, 6272, 6784, 7296, 7360, 7424, 7296, 7360, 7424, 7488, 7552, 7616,
+            7488, 7552, 7616, 7488, 7552, 7616, 7488, 7552, 7616, 7680, 11776, 15872, 19968, 22016,
+            24064, 19968, 22016, 24064, 26112, 42496, 58880, 75264, 83456, 91648, 75264, 83456,
+            91648, 99840, 165376, 230912, 296448, 329216, 361984, 296448, 329216, 361984,
+        ];
+        assert_all_almost_abs_eq(matrices.table_offsets, target_offsets, 0);
+
+        // Golden data produced by libjxl.
+        let target_table = [
+            0.000317f32,
+            0.000629f32,
+            0.000457f32,
+            0.000367f32,
+            0.000378f32,
+            0.000709f32,
+            0.000593f32,
+            0.000566f32,
+            0.000629f32,
+            0.001192f32,
+            0.000943f32,
+            0.001786f32,
+            0.003042f32,
+            0.002372f32,
+            0.001998f32,
+            0.002044f32,
+            0.003341f32,
+            0.002907f32,
+            0.002804f32,
+            0.003042f32,
+            0.004229f32,
+            0.003998f32,
+            0.001953f32,
+            0.011969f32,
+            0.011719f32,
+            0.007886f32,
+            0.008374f32,
+            0.015337f32,
+            0.011719f32,
+            0.011719f32,
+            0.011969f32,
+            0.032080f32,
+            0.025368f32,
+            0.003571f32,
+            0.003571f32,
+            0.003571f32,
+            0.003571f32,
+            0.003571f32,
+            0.003571f32,
+            0.003571f32,
+            0.003571f32,
+            0.003571f32,
+            0.003571f32,
+            0.003571f32,
+            0.016667f32,
+            0.016667f32,
+            0.016667f32,
+            0.016667f32,
+            0.016667f32,
+            0.016667f32,
+            0.016667f32,
+            0.016667f32,
+            0.016667f32,
+            0.016667f32,
+            0.016667f32,
+            0.055556f32,
+            0.055556f32,
+            0.055556f32,
+            0.055556f32,
+            0.055556f32,
+            0.055556f32,
+            0.055556f32,
+            0.055556f32,
+            0.055556f32,
+            0.055556f32,
+            0.055556f32,
+            0.000335f32,
+            0.002083f32,
+            0.002083f32,
+            0.001563f32,
+            0.000781f32,
+            0.002083f32,
+            0.003333f32,
+            0.002083f32,
+            0.002083f32,
+            0.003333f32,
+            0.003333f32,
+            0.000335f32,
+            0.007143f32,
+            0.007143f32,
+            0.005556f32,
+            0.003125f32,
+            0.007143f32,
+            0.008333f32,
+            0.007143f32,
+            0.007143f32,
+            0.008333f32,
+            0.008333f32,
+            0.000335f32,
+            0.031250f32,
+            0.031250f32,
+            0.015625f32,
+            0.007812f32,
+            0.031250f32,
+            0.062500f32,
+            0.031250f32,
+            0.031250f32,
+            0.062500f32,
+            0.062500f32,
+            0.000455f32,
+            0.000455f32,
+            0.000455f32,
+            0.000455f32,
+            0.000455f32,
+            0.000455f32,
+            0.000455f32,
+            0.000455f32,
+            0.000455f32,
+            0.000455f32,
+            0.000455f32,
+            0.002551f32,
+            0.002551f32,
+            0.002551f32,
+            0.002551f32,
+            0.002551f32,
+            0.002551f32,
+            0.002551f32,
+            0.002551f32,
+            0.002551f32,
+            0.002551f32,
+            0.002551f32,
+            0.008929f32,
+            0.014654f32,
+            0.012241f32,
+            0.011161f32,
+            0.010455f32,
+            0.015352f32,
+            0.013951f32,
+            0.012706f32,
+            0.014654f32,
+            0.020926f32,
+            0.017433f32,
+            0.000111f32,
+            0.000469f32,
+            0.000258f32,
+            0.000640f32,
+            0.000388f32,
+            0.001007f32,
+            0.000566f32,
+            0.001880f32,
+            0.000946f32,
+            0.000886f32,
+            0.001880f32,
+            0.000313f32,
+            0.001168f32,
+            0.000531f32,
+            0.001511f32,
+            0.000962f32,
+            0.001959f32,
+            0.001399f32,
+            0.002531f32,
+            0.001908f32,
+            0.001850f32,
+            0.002531f32,
+            0.000864f32,
+            0.007969f32,
+            0.002684f32,
+            0.010653f32,
+            0.006434f32,
+            0.015981f32,
+            0.009743f32,
+            0.040354f32,
+            0.014631f32,
+            0.013468f32,
+            0.040354f32,
+            0.000064f32,
+            0.000135f32,
+            0.000279f32,
+            0.000521f32,
+            0.000760f32,
+            0.001145f32,
+            0.000502f32,
+            0.000647f32,
+            0.000911f32,
+            0.001286f32,
+            0.001685f32,
+            0.000137f32,
+            0.000257f32,
+            0.000464f32,
+            0.000739f32,
+            0.001126f32,
+            0.001645f32,
+            0.000706f32,
+            0.000959f32,
+            0.001327f32,
+            0.001839f32,
+            0.002404f32,
+            0.000263f32,
+            0.001155f32,
+            0.003800f32,
+            0.010779f32,
+            0.016740f32,
+            0.024003f32,
+            0.010258f32,
+            0.014299f32,
+            0.019509f32,
+            0.026824f32,
+            0.035546f32,
+            0.000138f32,
+            0.000515f32,
+            0.000425f32,
+            0.000333f32,
+            0.000362f32,
+            0.000559f32,
+            0.000507f32,
+            0.000500f32,
+            0.000538f32,
+            0.000686f32,
+            0.000666f32,
+            0.000691f32,
+            0.002504f32,
+            0.001785f32,
+            0.001353f32,
+            0.001443f32,
+            0.002721f32,
+            0.002469f32,
+            0.002432f32,
+            0.002617f32,
+            0.003340f32,
+            0.003241f32,
+            0.001973f32,
+            0.010000f32,
+            0.006529f32,
+            0.005339f32,
+            0.005497f32,
+            0.012033f32,
+            0.009689f32,
+            0.009374f32,
+            0.011033f32,
+            0.031220f32,
+            0.026814f32,
+            0.000138f32,
+            0.000515f32,
+            0.000425f32,
+            0.000333f32,
+            0.000362f32,
+            0.000559f32,
+            0.000507f32,
+            0.000500f32,
+            0.000538f32,
+            0.000686f32,
+            0.000666f32,
+            0.000691f32,
+            0.002504f32,
+            0.001785f32,
+            0.001353f32,
+            0.001443f32,
+            0.002721f32,
+            0.002469f32,
+            0.002432f32,
+            0.002617f32,
+            0.003340f32,
+            0.003241f32,
+            0.001973f32,
+            0.010000f32,
+            0.006529f32,
+            0.005339f32,
+            0.005497f32,
+            0.012033f32,
+            0.009689f32,
+            0.009374f32,
+            0.011033f32,
+            0.031220f32,
+            0.026814f32,
+            0.000061f32,
+            0.001686f32,
+            0.000890f32,
+            0.000539f32,
+            0.000524f32,
+            0.003058f32,
+            0.002221f32,
+            0.001956f32,
+            0.002130f32,
+            0.002809f32,
+            0.007926f32,
+            0.000196f32,
+            0.000734f32,
+            0.000453f32,
+            0.000376f32,
+            0.000372f32,
+            0.001148f32,
+            0.000906f32,
+            0.000822f32,
+            0.000877f32,
+            0.001084f32,
+            0.002058f32,
+            0.000294f32,
+            0.001684f32,
+            0.000872f32,
+            0.000599f32,
+            0.000587f32,
+            0.003612f32,
+            0.002411f32,
+            0.002042f32,
+            0.002282f32,
+            0.003276f32,
+            0.009683f32,
+            0.000061f32,
+            0.001686f32,
+            0.000890f32,
+            0.000539f32,
+            0.000524f32,
+            0.003058f32,
+            0.002221f32,
+            0.001956f32,
+            0.002130f32,
+            0.002809f32,
+            0.007926f32,
+            0.000196f32,
+            0.000734f32,
+            0.000453f32,
+            0.000376f32,
+            0.000372f32,
+            0.001148f32,
+            0.000906f32,
+            0.000822f32,
+            0.000877f32,
+            0.001084f32,
+            0.002058f32,
+            0.000294f32,
+            0.001684f32,
+            0.000872f32,
+            0.000599f32,
+            0.000587f32,
+            0.003612f32,
+            0.002411f32,
+            0.002042f32,
+            0.002282f32,
+            0.003276f32,
+            0.009683f32,
+            0.000072f32,
+            0.000339f32,
+            0.000172f32,
+            0.000429f32,
+            0.000308f32,
+            0.000552f32,
+            0.000422f32,
+            0.000388f32,
+            0.000557f32,
+            0.000496f32,
+            0.000935f32,
+            0.000208f32,
+            0.001118f32,
+            0.000422f32,
+            0.001498f32,
+            0.000958f32,
+            0.002133f32,
+            0.001464f32,
+            0.001310f32,
+            0.002154f32,
+            0.001903f32,
+            0.002817f32,
+            0.000553f32,
+            0.004679f32,
+            0.001639f32,
+            0.008626f32,
+            0.003998f32,
+            0.015372f32,
+            0.008305f32,
+            0.006659f32,
+            0.015623f32,
+            0.012761f32,
+            0.026404f32,
+            0.000072f32,
+            0.000339f32,
+            0.000172f32,
+            0.000429f32,
+            0.000308f32,
+            0.000552f32,
+            0.000422f32,
+            0.000388f32,
+            0.000557f32,
+            0.000496f32,
+            0.000935f32,
+            0.000208f32,
+            0.001118f32,
+            0.000422f32,
+            0.001498f32,
+            0.000958f32,
+            0.002133f32,
+            0.001464f32,
+            0.001310f32,
+            0.002154f32,
+            0.001903f32,
+            0.002817f32,
+            0.000553f32,
+            0.004679f32,
+            0.001639f32,
+            0.008626f32,
+            0.003998f32,
+            0.015372f32,
+            0.008305f32,
+            0.006659f32,
+            0.015623f32,
+            0.012761f32,
+            0.026404f32,
+            0.000455f32,
+            0.001419f32,
+            0.001007f32,
+            0.000853f32,
+            0.000733f32,
+            0.001530f32,
+            0.001456f32,
+            0.001211f32,
+            0.001672f32,
+            0.002347f32,
+            0.001967f32,
+            0.001308f32,
+            0.004385f32,
+            0.002909f32,
+            0.002409f32,
+            0.002080f32,
+            0.004796f32,
+            0.004518f32,
+            0.003629f32,
+            0.005108f32,
+            0.006026f32,
+            0.005529f32,
+            0.001897f32,
+            0.009714f32,
+            0.005643f32,
+            0.004386f32,
+            0.003585f32,
+            0.010940f32,
+            0.010108f32,
+            0.007561f32,
+            0.012828f32,
+            0.024294f32,
+            0.017414f32,
+            0.000455f32,
+            0.001419f32,
+            0.001007f32,
+            0.000853f32,
+            0.000733f32,
+            0.001530f32,
+            0.001456f32,
+            0.001211f32,
+            0.001672f32,
+            0.002347f32,
+            0.001967f32,
+            0.001308f32,
+            0.004385f32,
+            0.002909f32,
+            0.002409f32,
+            0.002080f32,
+            0.004796f32,
+            0.004518f32,
+            0.003629f32,
+            0.005108f32,
+            0.006026f32,
+            0.005529f32,
+            0.001897f32,
+            0.009714f32,
+            0.005643f32,
+            0.004386f32,
+            0.003585f32,
+            0.010940f32,
+            0.010108f32,
+            0.007561f32,
+            0.012828f32,
+            0.024294f32,
+            0.017414f32,
+            1.000000f32,
+            0.002415f32,
+            0.001007f32,
+            0.003906f32,
+            0.000733f32,
+            0.001530f32,
+            0.002415f32,
+            0.001211f32,
+            0.002415f32,
+            0.002415f32,
+            0.001967f32,
+            1.000000f32,
+            0.017241f32,
+            0.002909f32,
+            0.020000f32,
+            0.002080f32,
+            0.004796f32,
+            0.017241f32,
+            0.003629f32,
+            0.017241f32,
+            0.017241f32,
+            0.005529f32,
+            1.000000f32,
+            0.058364f32,
+            0.005643f32,
+            0.083333f32,
+            0.003585f32,
+            0.010940f32,
+            0.064815f32,
+            0.007561f32,
+            0.050237f32,
+            0.088778f32,
+            0.017414f32,
+            1.000000f32,
+            0.002415f32,
+            0.001007f32,
+            0.003906f32,
+            0.000733f32,
+            0.001530f32,
+            0.002415f32,
+            0.001211f32,
+            0.002415f32,
+            0.002415f32,
+            0.001967f32,
+            1.000000f32,
+            0.017241f32,
+            0.002909f32,
+            0.020000f32,
+            0.002080f32,
+            0.004796f32,
+            0.017241f32,
+            0.003629f32,
+            0.017241f32,
+            0.017241f32,
+            0.005529f32,
+            1.000000f32,
+            0.058364f32,
+            0.005643f32,
+            0.083333f32,
+            0.003585f32,
+            0.010940f32,
+            0.064815f32,
+            0.007561f32,
+            0.050237f32,
+            0.088778f32,
+            0.017414f32,
+            1.000000f32,
+            0.002415f32,
+            0.001007f32,
+            0.003906f32,
+            0.000733f32,
+            0.001530f32,
+            0.002415f32,
+            0.001211f32,
+            0.002415f32,
+            0.002415f32,
+            0.001967f32,
+            1.000000f32,
+            0.017241f32,
+            0.002909f32,
+            0.020000f32,
+            0.002080f32,
+            0.004796f32,
+            0.017241f32,
+            0.003629f32,
+            0.017241f32,
+            0.017241f32,
+            0.005529f32,
+            1.000000f32,
+            0.058364f32,
+            0.005643f32,
+            0.083333f32,
+            0.003585f32,
+            0.010940f32,
+            0.064815f32,
+            0.007561f32,
+            0.050237f32,
+            0.088778f32,
+            0.017414f32,
+            1.000000f32,
+            0.002415f32,
+            0.001007f32,
+            0.003906f32,
+            0.000733f32,
+            0.001530f32,
+            0.002415f32,
+            0.001211f32,
+            0.002415f32,
+            0.002415f32,
+            0.001967f32,
+            1.000000f32,
+            0.017241f32,
+            0.002909f32,
+            0.020000f32,
+            0.002080f32,
+            0.004796f32,
+            0.017241f32,
+            0.003629f32,
+            0.017241f32,
+            0.017241f32,
+            0.005529f32,
+            1.000000f32,
+            0.058364f32,
+            0.005643f32,
+            0.083333f32,
+            0.003585f32,
+            0.010940f32,
+            0.064815f32,
+            0.007561f32,
+            0.050237f32,
+            0.088778f32,
+            0.017414f32,
+            0.000042f32,
+            0.000152f32,
+            0.000298f32,
+            0.000128f32,
+            0.000268f32,
+            0.000407f32,
+            0.000268f32,
+            0.000364f32,
+            0.000299f32,
+            0.000380f32,
+            0.000623f32,
+            0.000119f32,
+            0.000213f32,
+            0.000391f32,
+            0.000195f32,
+            0.000328f32,
+            0.000571f32,
+            0.000329f32,
+            0.000525f32,
+            0.000393f32,
+            0.000542f32,
+            0.000803f32,
+            0.000223f32,
+            0.001090f32,
+            0.003367f32,
+            0.000867f32,
+            0.002454f32,
+            0.006359f32,
+            0.002462f32,
+            0.005715f32,
+            0.003396f32,
+            0.005943f32,
+            0.010539f32,
+            0.000065f32,
+            0.000136f32,
+            0.000249f32,
+            0.000399f32,
+            0.000481f32,
+            0.000616f32,
+            0.000394f32,
+            0.000449f32,
+            0.000528f32,
+            0.000700f32,
+            0.000944f32,
+            0.000179f32,
+            0.000237f32,
+            0.000329f32,
+            0.000453f32,
+            0.000619f32,
+            0.000836f32,
+            0.000444f32,
+            0.000554f32,
+            0.000714f32,
+            0.000920f32,
+            0.001172f32,
+            0.000342f32,
+            0.000788f32,
+            0.001774f32,
+            0.003270f32,
+            0.005731f32,
+            0.009499f32,
+            0.003143f32,
+            0.004679f32,
+            0.007422f32,
+            0.010736f32,
+            0.015538f32,
+            0.000065f32,
+            0.000136f32,
+            0.000249f32,
+            0.000399f32,
+            0.000481f32,
+            0.000616f32,
+            0.000394f32,
+            0.000449f32,
+            0.000528f32,
+            0.000700f32,
+            0.000944f32,
+            0.000179f32,
+            0.000237f32,
+            0.000329f32,
+            0.000453f32,
+            0.000619f32,
+            0.000836f32,
+            0.000444f32,
+            0.000554f32,
+            0.000714f32,
+            0.000920f32,
+            0.001172f32,
+            0.000342f32,
+            0.000788f32,
+            0.001774f32,
+            0.003270f32,
+            0.005731f32,
+            0.009499f32,
+            0.003143f32,
+            0.004679f32,
+            0.007422f32,
+            0.010736f32,
+            0.015538f32,
+            0.000021f32,
+            0.000148f32,
+            0.000127f32,
+            0.000094f32,
+            0.000083f32,
+            0.000212f32,
+            0.000175f32,
+            0.000163f32,
+            0.000159f32,
+            0.000164f32,
+            0.000329f32,
+            0.000060f32,
+            0.000194f32,
+            0.000149f32,
+            0.000122f32,
+            0.000113f32,
+            0.000294f32,
+            0.000251f32,
+            0.000224f32,
+            0.000217f32,
+            0.000228f32,
+            0.000420f32,
+            0.000111f32,
+            0.001651f32,
+            0.001032f32,
+            0.000701f32,
+            0.000605f32,
+            0.003305f32,
+            0.002650f32,
+            0.002162f32,
+            0.002031f32,
+            0.002222f32,
+            0.005691f32,
+            0.000033f32,
+            0.000120f32,
+            0.000234f32,
+            0.000104f32,
+            0.000213f32,
+            0.000334f32,
+            0.000214f32,
+            0.000303f32,
+            0.000236f32,
+            0.000315f32,
+            0.000521f32,
+            0.000089f32,
+            0.000161f32,
+            0.000297f32,
+            0.000148f32,
+            0.000254f32,
+            0.000444f32,
+            0.000255f32,
+            0.000412f32,
+            0.000299f32,
+            0.000424f32,
+            0.000638f32,
+            0.000171f32,
+            0.000850f32,
+            0.002654f32,
+            0.000698f32,
+            0.002002f32,
+            0.005130f32,
+            0.002014f32,
+            0.004672f32,
+            0.002695f32,
+            0.004847f32,
+            0.008953f32,
+            0.000033f32,
+            0.000120f32,
+            0.000234f32,
+            0.000104f32,
+            0.000213f32,
+            0.000334f32,
+            0.000214f32,
+            0.000303f32,
+            0.000236f32,
+            0.000315f32,
+            0.000521f32,
+            0.000089f32,
+            0.000161f32,
+            0.000297f32,
+            0.000148f32,
+            0.000254f32,
+            0.000444f32,
+            0.000255f32,
+            0.000412f32,
+            0.000299f32,
+            0.000424f32,
+            0.000638f32,
+            0.000171f32,
+            0.000850f32,
+            0.002654f32,
+            0.000698f32,
+            0.002002f32,
+            0.005130f32,
+            0.002014f32,
+            0.004672f32,
+            0.002695f32,
+            0.004847f32,
+            0.008953f32,
+            0.000010f32,
+            0.000062f32,
+            0.000026f32,
+            0.000077f32,
+            0.000055f32,
+            0.000106f32,
+            0.000076f32,
+            0.000069f32,
+            0.000108f32,
+            0.000087f32,
+            0.000165f32,
+            0.000030f32,
+            0.000072f32,
+            0.000044f32,
+            0.000103f32,
+            0.000067f32,
+            0.000147f32,
+            0.000101f32,
+            0.000086f32,
+            0.000149f32,
+            0.000124f32,
+            0.000211f32,
+            0.000056f32,
+            0.000487f32,
+            0.000166f32,
+            0.000920f32,
+            0.000424f32,
+            0.001655f32,
+            0.000897f32,
+            0.000664f32,
+            0.001683f32,
+            0.001291f32,
+            0.002862f32,
+            0.000016f32,
+            0.000115f32,
+            0.000099f32,
+            0.000073f32,
+            0.000065f32,
+            0.000164f32,
+            0.000136f32,
+            0.000127f32,
+            0.000124f32,
+            0.000128f32,
+            0.000256f32,
+            0.000045f32,
+            0.000144f32,
+            0.000111f32,
+            0.000091f32,
+            0.000084f32,
+            0.000219f32,
+            0.000187f32,
+            0.000168f32,
+            0.000162f32,
+            0.000171f32,
+            0.000314f32,
+            0.000086f32,
+            0.001260f32,
+            0.000790f32,
+            0.000537f32,
+            0.000465f32,
+            0.002528f32,
+            0.002026f32,
+            0.001657f32,
+            0.001560f32,
+            0.001709f32,
+            0.004355f32,
+            0.000016f32,
+            0.000115f32,
+            0.000099f32,
+            0.000073f32,
+            0.000065f32,
+            0.000164f32,
+            0.000136f32,
+            0.000127f32,
+            0.000124f32,
+            0.000128f32,
+            0.000256f32,
+            0.000045f32,
+            0.000144f32,
+            0.000111f32,
+            0.000091f32,
+            0.000084f32,
+            0.000219f32,
+            0.000187f32,
+            0.000168f32,
+            0.000162f32,
+            0.000171f32,
+            0.000314f32,
+            0.000086f32,
+            0.001260f32,
+            0.000790f32,
+            0.000537f32,
+            0.000465f32,
+            0.002528f32,
+            0.002026f32,
+            0.001657f32,
+            0.001560f32,
+            0.001709f32,
+            0.004355f32,
+        ];
+        let mut target_table_index = 0;
+        for i in 0..HfTransformType::CARDINALITY {
+            let qt_idx = QuantTable::for_strategy(HfTransformType::from_usize(i).unwrap()) as usize;
+            let size = DequantMatrices::REQUIRED_SIZE_X[qt_idx]
+                * DequantMatrices::REQUIRED_SIZE_Y[qt_idx]
+                * BLOCK_SIZE;
+            for c in 0..3 {
+                let start = matrices.table_offsets[3 * i + c];
+                for j in (start..start + size).step_by(size / 10) {
+                    assert_almost_abs_eq(matrices.table[j], target_table[target_table_index], 1e-5);
+                    target_table_index += 1;
+                }
+            }
+        }
+        // Golden data produced by libjxl.
+        let target_inv_table = [
+            0.000000f32,
+            1_590.757_8_f32,
+            2_188.414_6_f32,
+            2_726.993_f32,
+            2_648.627_7_f32,
+            1_410.374_f32,
+            1_686.279_4_f32,
+            1_765.964_1_f32,
+            1_590.757_8_f32,
+            838.702_15_f32,
+            1_060.592_9_f32,
+            0.000000f32,
+            328.723_8_f32,
+            421.547_42_f32,
+            500.443_73_f32,
+            489.194_1_f32,
+            299.277_44_f32,
+            344.016_4_f32,
+            356.627_56_f32,
+            328.723_8_f32,
+            236.484_7_f32,
+            250.119_8_f32,
+            0.000000f32,
+            83.550804f32,
+            85.333_32_f32,
+            126.804_84_f32,
+            119.412384f32,
+            65.203_81_f32,
+            85.333_23_f32,
+            85.333244f32,
+            83.550804f32,
+            31.172384f32,
+            39.419487f32,
+            0.000000f32,
+            280.000000f32,
+            280.000000f32,
+            280.000000f32,
+            280.000000f32,
+            280.000000f32,
+            280.000000f32,
+            280.000000f32,
+            280.000000f32,
+            280.000000f32,
+            280.000000f32,
+            0.000000f32,
+            60.000000f32,
+            60.000000f32,
+            60.000000f32,
+            60.000000f32,
+            60.000000f32,
+            60.000000f32,
+            60.000000f32,
+            60.000000f32,
+            60.000000f32,
+            60.000000f32,
+            0.000000f32,
+            18.000000f32,
+            18.000000f32,
+            18.000000f32,
+            18.000000f32,
+            18.000000f32,
+            18.000000f32,
+            18.000000f32,
+            18.000000f32,
+            18.000000f32,
+            18.000000f32,
+            0.000000f32,
+            480.000000f32,
+            480.000000f32,
+            640.000000f32,
+            1280.000000f32,
+            480.000000f32,
+            300.000000f32,
+            480.000000f32,
+            480.000000f32,
+            300.000000f32,
+            300.000000f32,
+            0.000000f32,
+            140.000000f32,
+            140.000000f32,
+            180.000000f32,
+            320.000000f32,
+            140.000000f32,
+            120.000000f32,
+            140.000000f32,
+            140.000000f32,
+            120.000000f32,
+            120.000000f32,
+            0.000000f32,
+            32.000000f32,
+            32.000000f32,
+            64.000000f32,
+            128.000000f32,
+            32.000000f32,
+            16.000000f32,
+            32.000000f32,
+            32.000000f32,
+            16.000000f32,
+            16.000000f32,
+            0.000000f32,
+            2_199.999_5_f32,
+            2_199.998_8_f32,
+            2_199.997_f32,
+            2_199.997_8_f32,
+            2_199.999_3_f32,
+            2_199.997_f32,
+            2_199.998_3_f32,
+            2_199.999_5_f32,
+            2_199.997_f32,
+            2_199.998_3_f32,
+            0.000000f32,
+            391.999_94_f32,
+            391.999_76_f32,
+            391.999_45_f32,
+            391.999_63_f32,
+            391.999_85_f32,
+            391.999_45_f32,
+            391.999_7_f32,
+            391.999_94_f32,
+            391.999_45_f32,
+            391.999_7_f32,
+            0.000000f32,
+            68.239_35_f32,
+            81.689606f32,
+            89.600_1_f32,
+            95.651_69_f32,
+            65.137_18_f32,
+            71.680_09_f32,
+            78.702_8_f32,
+            68.239_35_f32,
+            47.786777f32,
+            57.363_38_f32,
+            0.000000f32,
+            2_134.025_f32,
+            3_880.564_5_f32,
+            1_561.426_1_f32,
+            2_580.273_2_f32,
+            993.463_3_f32,
+            1_766.659_2_f32,
+            531.866_15_f32,
+            1_057.315_1_f32,
+            1_129.141_7_f32,
+            531.866_15_f32,
+            0.000000f32,
+            856.371_03_f32,
+            1_884.007_1_f32,
+            661.633_f32,
+            1_039.256_2_f32,
+            510.514_92_f32,
+            714.580_6_f32,
+            395.167_5_f32,
+            524.174_9_f32,
+            540.578_f32,
+            395.167_5_f32,
+            0.000000f32,
+            125.492_86_f32,
+            372.602_72_f32,
+            93.867_99_f32,
+            155.421_52_f32,
+            62.573_67_f32,
+            102.638_92_f32,
+            24.780632f32,
+            68.345_99_f32,
+            74.248_6_f32,
+            24.780632f32,
+            0.000000f32,
+            7_394.222_7_f32,
+            3_578.031_f32,
+            1_919.217_f32,
+            1_315.414_7_f32,
+            873.481_14_f32,
+            1_993.637_6_f32,
+            1_544.639_8_f32,
+            1_097.804_9_f32,
+            777.788_7_f32,
+            593.406_25_f32,
+            0.000000f32,
+            3_889.284_f32,
+            2_156.401_9_f32,
+            1_353.482_9_f32,
+            888.446_17_f32,
+            607.867_1_f32,
+            1_416.747_f32,
+            1_042.852_7_f32,
+            753.371_15_f32,
+            543.717_3_f32,
+            415.901_12_f32,
+            0.000000f32,
+            865.445_74_f32,
+            263.145_42_f32,
+            92.775_6_f32,
+            59.736_86_f32,
+            41.660606f32,
+            97.485_29_f32,
+            69.935_29_f32,
+            51.259308f32,
+            37.279_94_f32,
+            28.132723f32,
+            0.000000f32,
+            1_943.121_3_f32,
+            2_353.786_9_f32,
+            3_003.803_7_f32,
+            2_759.090_6_f32,
+            1_787.990_7_f32,
+            1_970.900_4_f32,
+            2_000.403_2_f32,
+            1_859.104_f32,
+            1_456.708_3_f32,
+            1_501.485_4_f32,
+            0.000000f32,
+            399.333_1_f32,
+            560.170_4_f32,
+            739.322_3_f32,
+            692.840_9_f32,
+            367.452_f32,
+            405.042_f32,
+            411.105_13_f32,
+            382.066_6_f32,
+            299.369_78_f32,
+            308.571_96_f32,
+            0.000000f32,
+            100.000015f32,
+            153.171_57_f32,
+            187.309_95_f32,
+            181.919_97_f32,
+            83.107_42_f32,
+            103.207_18_f32,
+            106.674_48_f32,
+            90.637794f32,
+            32.030476f32,
+            37.294_44_f32,
+            0.000000f32,
+            1_943.121_3_f32,
+            2_353.786_9_f32,
+            3_003.803_7_f32,
+            2_759.090_6_f32,
+            1_787.990_7_f32,
+            1_970.900_4_f32,
+            2_000.403_2_f32,
+            1_859.104_f32,
+            1_456.708_3_f32,
+            1_501.485_4_f32,
+            0.000000f32,
+            399.333_1_f32,
+            560.170_4_f32,
+            739.322_3_f32,
+            692.840_9_f32,
+            367.452_f32,
+            405.042_f32,
+            411.105_13_f32,
+            382.066_6_f32,
+            299.369_78_f32,
+            308.571_96_f32,
+            0.000000f32,
+            100.000015f32,
+            153.171_57_f32,
+            187.309_95_f32,
+            181.919_97_f32,
+            83.107_42_f32,
+            103.207_18_f32,
+            106.674_48_f32,
+            90.637794f32,
+            32.030476f32,
+            37.294_44_f32,
+            0.000000f32,
+            593.167_f32,
+            1_123.533_1_f32,
+            1_855.866_1_f32,
+            1_908.905_2_f32,
+            326.994_14_f32,
+            450.258_58_f32,
+            511.279_08_f32,
+            469.570_34_f32,
+            356.047_f32,
+            126.164_13_f32,
+            0.000000f32,
+            1_362.585_8_f32,
+            2_208.564_f32,
+            2_662.055_2_f32,
+            2_690.115_7_f32,
+            871.264_95_f32,
+            1_103.732_8_f32,
+            1_216.298_7_f32,
+            1_139.726_f32,
+            922.482_9_f32,
+            485.887_88_f32,
+            0.000000f32,
+            593.843_3_f32,
+            1_146.650_3_f32,
+            1_669.026_5_f32,
+            1_704.578_1_f32,
+            276.873_93_f32,
+            414.831_3_f32,
+            489.748_35_f32,
+            438.224_15_f32,
+            305.274_23_f32,
+            103.268776f32,
+            0.000000f32,
+            593.167_f32,
+            1_123.533_1_f32,
+            1_855.866_1_f32,
+            1_908.905_2_f32,
+            326.994_14_f32,
+            450.258_58_f32,
+            511.279_08_f32,
+            469.570_34_f32,
+            356.047_f32,
+            126.164_13_f32,
+            0.000000f32,
+            1_362.585_8_f32,
+            2_208.564_f32,
+            2_662.055_2_f32,
+            2_690.115_7_f32,
+            871.264_95_f32,
+            1_103.732_8_f32,
+            1_216.298_7_f32,
+            1_139.726_f32,
+            922.482_9_f32,
+            485.887_88_f32,
+            0.000000f32,
+            593.843_3_f32,
+            1_146.650_3_f32,
+            1_669.026_5_f32,
+            1_704.578_1_f32,
+            276.873_93_f32,
+            414.831_3_f32,
+            489.748_35_f32,
+            438.224_15_f32,
+            305.274_23_f32,
+            103.268776f32,
+            0.000000f32,
+            2_951.45_f32,
+            5_803.090_3_f32,
+            2_333.720_7_f32,
+            3_250.279_3_f32,
+            1_812.437_7_f32,
+            2_367.215_3_f32,
+            2_575.901_6_f32,
+            1_794.716_f32,
+            2_014.430_4_f32,
+            1_070.065_2_f32,
+            0.000000f32,
+            894.280_7_f32,
+            2_366.964_4_f32,
+            667.591_43_f32,
+            1_044.054_9_f32,
+            468.918_46_f32,
+            683.237_6_f32,
+            763.157_1_f32,
+            464.274_26_f32,
+            525.577_7_f32,
+            355.034_94_f32,
+            0.000000f32,
+            213.711_44_f32,
+            609.947_6_f32,
+            115.928_83_f32,
+            250.111_22_f32,
+            65.055_44_f32,
+            120.410_9_f32,
+            150.171_69_f32,
+            64.008_35_f32,
+            78.361_82_f32,
+            37.872444f32,
+            0.000000f32,
+            2_951.45_f32,
+            5_803.090_3_f32,
+            2_333.720_7_f32,
+            3_250.279_3_f32,
+            1_812.437_7_f32,
+            2_367.215_3_f32,
+            2_575.901_6_f32,
+            1_794.716_f32,
+            2_014.430_4_f32,
+            1_070.065_2_f32,
+            0.000000f32,
+            894.280_7_f32,
+            2_366.964_4_f32,
+            667.591_43_f32,
+            1_044.054_9_f32,
+            468.918_46_f32,
+            683.237_6_f32,
+            763.157_1_f32,
+            464.274_26_f32,
+            525.577_7_f32,
+            355.034_94_f32,
+            0.000000f32,
+            213.711_44_f32,
+            609.947_6_f32,
+            115.928_83_f32,
+            250.111_22_f32,
+            65.055_44_f32,
+            120.410_9_f32,
+            150.171_69_f32,
+            64.008_35_f32,
+            78.361_82_f32,
+            37.872444f32,
+            0.000000f32,
+            704.524_2_f32,
+            993.091_86_f32,
+            1_173.002_2_f32,
+            1_364.454_1_f32,
+            653.527_9_f32,
+            687.044_7_f32,
+            825.446_53_f32,
+            597.922_5_f32,
+            426.046_05_f32,
+            508.395_4_f32,
+            0.000000f32,
+            228.070_65_f32,
+            343.725_7_f32,
+            415.080_72_f32,
+            480.806_3_f32,
+            208.487_34_f32,
+            221.326_13_f32,
+            275.591_58_f32,
+            195.755_52_f32,
+            165.941_71_f32,
+            180.871_83_f32,
+            0.000000f32,
+            102.945_56_f32,
+            177.209_15_f32,
+            227.986_3_f32,
+            278.956_88_f32,
+            91.407_4_f32,
+            98.934_02_f32,
+            132.264_72_f32,
+            77.957184f32,
+            41.162014f32,
+            57.426_7_f32,
+            0.000000f32,
+            704.524_2_f32,
+            993.091_86_f32,
+            1_173.002_2_f32,
+            1_364.454_1_f32,
+            653.527_9_f32,
+            687.044_7_f32,
+            825.446_53_f32,
+            597.922_5_f32,
+            426.046_05_f32,
+            508.395_4_f32,
+            0.000000f32,
+            228.070_65_f32,
+            343.725_7_f32,
+            415.080_72_f32,
+            480.806_3_f32,
+            208.487_34_f32,
+            221.326_13_f32,
+            275.591_58_f32,
+            195.755_52_f32,
+            165.941_71_f32,
+            180.871_83_f32,
+            0.000000f32,
+            102.945_56_f32,
+            177.209_15_f32,
+            227.986_3_f32,
+            278.956_88_f32,
+            91.407_4_f32,
+            98.934_02_f32,
+            132.264_72_f32,
+            77.957184f32,
+            41.162014f32,
+            57.426_7_f32,
+            0.000000f32,
+            413.999_94_f32,
+            993.091_86_f32,
+            256.000000f32,
+            1_364.454_1_f32,
+            653.527_9_f32,
+            413.999_66_f32,
+            825.446_53_f32,
+            413.999_73_f32,
+            413.999_42_f32,
+            508.395_4_f32,
+            0.000000f32,
+            57.999_99_f32,
+            343.725_7_f32,
+            50.000000f32,
+            480.806_3_f32,
+            208.487_34_f32,
+            57.999954f32,
+            275.591_58_f32,
+            57.999_96_f32,
+            57.999_92_f32,
+            180.871_83_f32,
+            0.000000f32,
+            17.133793f32,
+            177.209_15_f32,
+            12.000000f32,
+            278.956_88_f32,
+            91.407_4_f32,
+            15.428568f32,
+            132.264_72_f32,
+            19.905685f32,
+            11.264012f32,
+            57.426_7_f32,
+            0.000000f32,
+            413.999_94_f32,
+            993.091_86_f32,
+            256.000000f32,
+            1_364.454_1_f32,
+            653.527_9_f32,
+            413.999_66_f32,
+            825.446_53_f32,
+            413.999_73_f32,
+            413.999_42_f32,
+            508.395_4_f32,
+            0.000000f32,
+            57.999_99_f32,
+            343.725_7_f32,
+            50.000000f32,
+            480.806_3_f32,
+            208.487_34_f32,
+            57.999954f32,
+            275.591_58_f32,
+            57.999_96_f32,
+            57.999_92_f32,
+            180.871_83_f32,
+            0.000000f32,
+            17.133793f32,
+            177.209_15_f32,
+            12.000000f32,
+            278.956_88_f32,
+            91.407_4_f32,
+            15.428568f32,
+            132.264_72_f32,
+            19.905685f32,
+            11.264012f32,
+            57.426_7_f32,
+            0.000000f32,
+            413.999_94_f32,
+            993.091_86_f32,
+            256.000000f32,
+            1_364.454_1_f32,
+            653.527_9_f32,
+            413.999_66_f32,
+            825.446_53_f32,
+            413.999_73_f32,
+            413.999_42_f32,
+            508.395_4_f32,
+            0.000000f32,
+            57.999_99_f32,
+            343.725_7_f32,
+            50.000000f32,
+            480.806_3_f32,
+            208.487_34_f32,
+            57.999954f32,
+            275.591_58_f32,
+            57.999_96_f32,
+            57.999_92_f32,
+            180.871_83_f32,
+            0.000000f32,
+            17.133793f32,
+            177.209_15_f32,
+            12.000000f32,
+            278.956_88_f32,
+            91.407_4_f32,
+            15.428568f32,
+            132.264_72_f32,
+            19.905685f32,
+            11.264012f32,
+            57.426_7_f32,
+            0.000000f32,
+            413.999_94_f32,
+            993.091_86_f32,
+            256.000000f32,
+            1_364.454_1_f32,
+            653.527_9_f32,
+            413.999_66_f32,
+            825.446_53_f32,
+            413.999_73_f32,
+            413.999_42_f32,
+            508.395_4_f32,
+            0.000000f32,
+            57.999_99_f32,
+            343.725_7_f32,
+            50.000000f32,
+            480.806_3_f32,
+            208.487_34_f32,
+            57.999954f32,
+            275.591_58_f32,
+            57.999_96_f32,
+            57.999_92_f32,
+            180.871_83_f32,
+            0.000000f32,
+            17.133793f32,
+            177.209_15_f32,
+            12.000000f32,
+            278.956_88_f32,
+            91.407_4_f32,
+            15.428568f32,
+            132.264_72_f32,
+            19.905685f32,
+            11.264012f32,
+            57.426_7_f32,
+            0.000000f32,
+            6_582.816_4_f32,
+            3_359.388_7_f32,
+            7_791.875_5_f32,
+            3_729.601_3_f32,
+            2_454.834_f32,
+            3_725.529_f32,
+            2_744.766_4_f32,
+            3_349.231_4_f32,
+            2_634.738_8_f32,
+            1_604.219_2_f32,
+            0.000000f32,
+            4_684.622_6_f32,
+            2_554.650_4_f32,
+            5_132.672_f32,
+            3_046.984_1_f32,
+            1_750.527_1_f32,
+            3_041.338_1_f32,
+            1_903.525_6_f32,
+            2_542.798_3_f32,
+            1_845.962_4_f32,
+            1_245.448_2_f32,
+            0.000000f32,
+            917.482_67_f32,
+            297.010_62_f32,
+            1_153.165_4_f32,
+            407.573_73_f32,
+            157.246_46_f32,
+            406.220_34_f32,
+            174.986_19_f32,
+            294.497_8_f32,
+            168.263_95_f32,
+            94.887_52_f32,
+            0.000000f32,
+            7_337.233_f32,
+            4_022.487_3_f32,
+            2_505.753_7_f32,
+            2_076.849_f32,
+            1_622.844_2_f32,
+            2_538.46_f32,
+            2_227.385_5_f32,
+            1_893.945_9_f32,
+            1_428.085_7_f32,
+            1_059.229_1_f32,
+            0.000000f32,
+            4_215.989_f32,
+            3_039.568_4_f32,
+            2_205.074_5_f32,
+            1_614.652_6_f32,
+            1_196.811_4_f32,
+            2_254.153_8_f32,
+            1_805.539_f32,
+            1_401.511_f32,
+            1_087.307_5_f32,
+            853.323_6_f32,
+            0.000000f32,
+            1_268.412_f32,
+            563.855_9_f32,
+            305.841_95_f32,
+            174.499_47_f32,
+            105.278_36_f32,
+            318.157_75_f32,
+            213.698_53_f32,
+            134.729_1_f32,
+            93.148544f32,
+            64.359_23_f32,
+            0.000000f32,
+            7_337.233_f32,
+            4_022.487_3_f32,
+            2_505.753_7_f32,
+            2_076.849_f32,
+            1_622.844_2_f32,
+            2_538.46_f32,
+            2_227.385_5_f32,
+            1_893.945_9_f32,
+            1_428.085_7_f32,
+            1_059.229_1_f32,
+            0.000000f32,
+            4_215.989_f32,
+            3_039.568_4_f32,
+            2_205.074_5_f32,
+            1_614.652_6_f32,
+            1_196.811_4_f32,
+            2_254.153_8_f32,
+            1_805.539_f32,
+            1_401.511_f32,
+            1_087.307_5_f32,
+            853.323_6_f32,
+            0.000000f32,
+            1_268.412_f32,
+            563.855_9_f32,
+            305.841_95_f32,
+            174.499_47_f32,
+            105.278_36_f32,
+            318.157_75_f32,
+            213.698_53_f32,
+            134.729_1_f32,
+            93.148544f32,
+            64.359_23_f32,
+            0.000000f32,
+            6_766.112_f32,
+            7_894.433_6_f32,
+            10_627.11_f32,
+            12_049.799_f32,
+            4_716.169_f32,
+            5_715.242_f32,
+            6_145.953_6_f32,
+            6_284.098_6_f32,
+            6_085.547_f32,
+            3_040.497_3_f32,
+            0.000000f32,
+            5_164.680_7_f32,
+            6_709.773_f32,
+            8_223.506_f32,
+            8_877.354_5_f32,
+            3_396.971_2_f32,
+            3_985.426_5_f32,
+            4_455.855_5_f32,
+            4_610.580_6_f32,
+            4_388.779_f32,
+            2_379.244_9_f32,
+            0.000000f32,
+            605.837_65_f32,
+            968.753_9_f32,
+            1_427.095_5_f32,
+            1_653.824_2_f32,
+            302.614_8_f32,
+            377.299_22_f32,
+            462.613_9_f32,
+            492.384_12_f32,
+            449.969_45_f32,
+            175.714_2_f32,
+            0.000000f32,
+            8_341.217_f32,
+            4_268.698_f32,
+            9_660.034_f32,
+            4_689.038_f32,
+            2_994.779_5_f32,
+            4_679.943_f32,
+            3_301.692_6_f32,
+            4_245.340_3_f32,
+            3_177.615_5_f32,
+            1_918.587_6_f32,
+            0.000000f32,
+            6_214.485_4_f32,
+            3_367.615_5_f32,
+            6_734.941_4_f32,
+            3_939.316_2_f32,
+            2_253.354_2_f32,
+            3_926.354_7_f32,
+            2_424.556_6_f32,
+            3_339.36_f32,
+            2_355.843_5_f32,
+            1_568.312_6_f32,
+            0.000000f32,
+            1_176.600_6_f32,
+            376.791_66_f32,
+            1_432.170_2_f32,
+            499.566_1_f32,
+            194.944_96_f32,
+            496.622_07_f32,
+            214.034_21_f32,
+            371.035_58_f32,
+            206.326_42_f32,
+            111.690674f32,
+            0.000000f32,
+            8_341.217_f32,
+            4_268.698_f32,
+            9_660.034_f32,
+            4_689.038_f32,
+            2_994.779_5_f32,
+            4_679.943_f32,
+            3_301.692_6_f32,
+            4_245.340_3_f32,
+            3_177.615_5_f32,
+            1_918.587_6_f32,
+            0.000000f32,
+            6_214.485_4_f32,
+            3_367.615_5_f32,
+            6_734.941_4_f32,
+            3_939.316_2_f32,
+            2_253.354_2_f32,
+            3_926.354_7_f32,
+            2_424.556_6_f32,
+            3_339.36_f32,
+            2_355.843_5_f32,
+            1_568.312_6_f32,
+            0.000000f32,
+            1_176.600_6_f32,
+            376.791_66_f32,
+            1_432.170_2_f32,
+            499.566_1_f32,
+            194.944_96_f32,
+            496.622_07_f32,
+            214.034_21_f32,
+            371.035_58_f32,
+            206.326_42_f32,
+            111.690674f32,
+            0.000000f32,
+            16_091.596_f32,
+            37_886.605_f32,
+            13_018.401_f32,
+            18_061.066_f32,
+            9_417.376_f32,
+            13_138.253_f32,
+            14_536.568_f32,
+            9_251.921_f32,
+            11_539.108_f32,
+            6_057.114_3_f32,
+            0.000000f32,
+            13_859.232_f32,
+            22_801.957_f32,
+            9_733.233_f32,
+            14_894.771_f32,
+            6_785.853_f32,
+            9_871.179_f32,
+            11_663.131_f32,
+            6_696.171_4_f32,
+            8_087.468_3_f32,
+            4_742.546_f32,
+            0.000000f32,
+            2_052.832_f32,
+            6_023.987_f32,
+            1_086.971_4_f32,
+            2_357.806_6_f32,
+            604.310_36_f32,
+            1_115.282_2_f32,
+            1_506.556_9_f32,
+            594.140_56_f32,
+            774.890_87_f32,
+            349.454_04_f32,
+            0.000000f32,
+            8_696.038_f32,
+            10_137.892_f32,
+            13_662.467_f32,
+            15_456.473_f32,
+            6_081.469_f32,
+            7_342.178_f32,
+            7_888.129_4_f32,
+            8_059.175_3_f32,
+            7_800.867_f32,
+            3_911.675_f32,
+            0.000000f32,
+            6_930.828_6_f32,
+            8_992.589_f32,
+            11_005.801_f32,
+            11_864.501_f32,
+            4_558.516_6_f32,
+            5_342.787_6_f32,
+            5_964.875_5_f32,
+            6_164.648_f32,
+            5_863.846_7_f32,
+            3_188.496_8_f32,
+            0.000000f32,
+            793.949_34_f32,
+            1_266.555_7_f32,
+            1_861.544_6_f32,
+            2_151.571_5_f32,
+            395.616_76_f32,
+            493.578_8_f32,
+            603.603_2_f32,
+            641.048_8_f32,
+            585.055_24_f32,
+            229.617_22_f32,
+            0.000000f32,
+            8_696.038_f32,
+            10_137.892_f32,
+            13_662.467_f32,
+            15_456.473_f32,
+            6_081.469_f32,
+            7_342.178_f32,
+            7_888.129_4_f32,
+            8_059.175_3_f32,
+            7_800.867_f32,
+            3_911.675_f32,
+            0.000000f32,
+            6_930.828_6_f32,
+            8_992.589_f32,
+            11_005.801_f32,
+            11_864.501_f32,
+            4_558.516_6_f32,
+            5_342.787_6_f32,
+            5_964.875_5_f32,
+            6_164.648_f32,
+            5_863.846_7_f32,
+            3_188.496_8_f32,
+            0.000000f32,
+            793.949_34_f32,
+            1_266.555_7_f32,
+            1_861.544_6_f32,
+            2_151.571_5_f32,
+            395.616_76_f32,
+            493.578_8_f32,
+            603.603_2_f32,
+            641.048_8_f32,
+            585.055_24_f32,
+            229.617_22_f32,
+        ];
+        let mut target_inv_table_index = 0;
+        for i in 0..HfTransformType::CARDINALITY {
+            let qt_idx = QuantTable::for_strategy(HfTransformType::from_usize(i).unwrap()) as usize;
+            let size = DequantMatrices::REQUIRED_SIZE_X[qt_idx]
+                * DequantMatrices::REQUIRED_SIZE_Y[qt_idx]
+                * BLOCK_SIZE;
+            for c in 0..3 {
+                let start = matrices.table_offsets[3 * i + c];
+                for j in (start..start + size).step_by(size / 10) {
+                    assert_almost_eq(
+                        matrices.inv_table[j],
+                        target_inv_table[target_inv_table_index],
+                        1f32,
+                        1e-3,
+                    );
+                    target_inv_table_index += 1;
+                }
+            }
+        }
+        Ok(())
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/quantizer.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/quantizer.rs
new file mode 100644
index 0000000..57413e8
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/quantizer.rs
@@ -0,0 +1,76 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{
+    bit_reader::BitReader,
+    error::{Error, Result},
+    frame::quant_weights,
+    headers::encodings::{Empty, UnconditionalCoder},
+};
+
+pub const NUM_QUANT_TABLES: usize = 17;
+pub const GLOBAL_SCALE_DENOM: usize = 1 << 16;
+
+#[derive(Debug)]
+pub struct LfQuantFactors {
+    pub quant_factors: [f32; 3],
+    pub inv_quant_factors: [f32; 3],
+}
+
+impl LfQuantFactors {
+    pub fn new(br: &mut BitReader) -> Result<LfQuantFactors> {
+        let mut quant_factors = [0.0f32; 3];
+        if br.read(1)? == 1 {
+            quant_factors = quant_weights::LF_QUANT;
+        } else {
+            for qf in quant_factors.iter_mut() {
+                *qf = f32::read_unconditional(&(), br, &Empty {})? / 128.0;
+                if *qf < 1e-8 {
+                    return Err(Error::LfQuantFactorTooSmall(*qf));
+                }
+            }
+        }
+
+        let inv_quant_factors = quant_factors.map(f32::recip);
+
+        Ok(LfQuantFactors {
+            quant_factors,
+            inv_quant_factors,
+        })
+    }
+}
+
+#[derive(Debug)]
+pub struct QuantizerParams {
+    pub global_scale: u32,
+    pub quant_lf: u32,
+}
+
+impl QuantizerParams {
+    pub fn read(br: &mut BitReader) -> Result<QuantizerParams> {
+        let global_scale = match br.read(2)? {
+            0 => br.read(11)? + 1,
+            1 => br.read(11)? + 2049,
+            2 => br.read(12)? + 4097,
+            _ => br.read(16)? + 8193,
+        };
+        let quant_lf = match br.read(2)? {
+            0 => 16,
+            1 => br.read(5)? + 1,
+            2 => br.read(8)? + 1,
+            _ => br.read(16)? + 1,
+        };
+        Ok(QuantizerParams {
+            global_scale: global_scale as u32,
+            quant_lf: quant_lf as u32,
+        })
+    }
+    pub fn inv_global_scale(&self) -> f32 {
+        GLOBAL_SCALE_DENOM as f32 / self.global_scale as f32
+    }
+    pub fn inv_quant_lf(&self) -> f32 {
+        self.inv_global_scale() / self.quant_lf as f32
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/render.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/render.rs
new file mode 100644
index 0000000..6642ad8
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/render.rs
@@ -0,0 +1,573 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::sync::Arc;
+
+use crate::api::JxlCms;
+use crate::api::JxlColorType;
+use crate::api::JxlDataFormat;
+use crate::api::JxlOutputBuffer;
+use crate::bit_reader::BitReader;
+use crate::error::{Error, Result};
+use crate::features::epf::create_sigma_image;
+use crate::headers::frame_header::Encoding;
+use crate::headers::{Orientation, color_encoding::ColorSpace, extra_channels::ExtraChannel};
+use crate::image::Rect;
+#[cfg(test)]
+use crate::render::SimpleRenderPipeline;
+use crate::render::buffer_splitter::BufferSplitter;
+use crate::render::{LowMemoryRenderPipeline, RenderPipeline, RenderPipelineBuilder, stages::*};
+use crate::{
+    api::JxlPixelFormat,
+    frame::{DecoderState, Frame, LfGlobalState},
+    headers::frame_header::FrameHeader,
+    image::Image,
+};
+
+#[cfg(test)]
+macro_rules! pipeline {
+    ($frame: expr, $pipeline: ident, $op: expr) => {
+        if $frame.use_simple_pipeline {
+            let $pipeline = $frame
+                .render_pipeline
+                .as_mut()
+                .unwrap()
+                .downcast_mut::<SimpleRenderPipeline>()
+                .unwrap();
+            $op
+        } else {
+            use crate::render::LowMemoryRenderPipeline;
+            let $pipeline = $frame
+                .render_pipeline
+                .as_mut()
+                .unwrap()
+                .downcast_mut::<LowMemoryRenderPipeline>()
+                .unwrap();
+            $op
+        }
+    };
+}
+
+#[cfg(not(test))]
+macro_rules! pipeline {
+    ($frame: expr, $pipeline: ident, $op: expr) => {{
+        let $pipeline = $frame.render_pipeline.as_mut().unwrap();
+        $op
+    }};
+}
+
+pub(crate) use pipeline;
+
+impl Frame {
+    /// Add conversion stages for non-float output formats.
+    /// This is needed before saving to U8/U16/F16 formats to convert from the pipeline's f32.
+    fn add_conversion_stages<P: RenderPipeline>(
+        mut pipeline: RenderPipelineBuilder<P>,
+        channels: &[usize],
+        data_format: JxlDataFormat,
+    ) -> Result<RenderPipelineBuilder<P>> {
+        use crate::render::stages::{
+            ConvertF32ToF16Stage, ConvertF32ToU8Stage, ConvertF32ToU16Stage,
+        };
+
+        match data_format {
+            JxlDataFormat::U8 { bit_depth } => {
+                for &channel in channels {
+                    pipeline =
+                        pipeline.add_inout_stage(ConvertF32ToU8Stage::new(channel, bit_depth))?;
+                }
+            }
+            JxlDataFormat::U16 { bit_depth, .. } => {
+                for &channel in channels {
+                    pipeline =
+                        pipeline.add_inout_stage(ConvertF32ToU16Stage::new(channel, bit_depth))?;
+                }
+            }
+            JxlDataFormat::F16 { .. } => {
+                for &channel in channels {
+                    pipeline = pipeline.add_inout_stage(ConvertF32ToF16Stage::new(channel))?;
+                }
+            }
+            // F32 doesn't need conversion - the pipeline already uses f32
+            JxlDataFormat::F32 { .. } => {}
+        }
+        Ok(pipeline)
+    }
+
+    pub fn decode_and_render_hf_groups(
+        &mut self,
+        api_buffers: &mut Option<&mut [JxlOutputBuffer<'_>]>,
+        pixel_format: &JxlPixelFormat,
+        groups: Vec<(usize, Vec<(usize, BitReader)>)>,
+    ) -> Result<()> {
+        if self.render_pipeline.is_none() {
+            assert_eq!(groups.iter().map(|x| x.1.len()).sum::<usize>(), 0);
+            // We don't yet have any output ready (as the pipeline would be initialized otherwise),
+            // so exit without doing anything.
+            return Ok(());
+        }
+
+        let mut buffers: Vec<Option<JxlOutputBuffer>> = Vec::new();
+
+        macro_rules! buffers_from_api {
+            ($get_next: expr) => {
+                if pixel_format.color_data_format.is_some() {
+                    buffers.push($get_next);
+                }
+
+                for fmt in &pixel_format.extra_channel_format {
+                    if fmt.is_some() {
+                        buffers.push($get_next);
+                    }
+                }
+            };
+        }
+
+        if let Some(api_buffers) = api_buffers {
+            let mut api_buffers_iter = api_buffers.iter_mut();
+            buffers_from_api!(Some(JxlOutputBuffer::reborrow(
+                api_buffers_iter.next().unwrap(),
+            )));
+        } else {
+            buffers_from_api!(None);
+        }
+
+        // Temporarily remove the reference/lf frames to be saved; we will move them back once
+        // rendering is done.
+        let mut reference_frame_data = std::mem::take(&mut self.reference_frame_data);
+        let mut lf_frame_data = std::mem::take(&mut self.lf_frame_data);
+
+        if let Some(ref_images) = &mut reference_frame_data {
+            buffers.extend(ref_images.iter_mut().map(|img| {
+                let rect = Rect {
+                    size: img.size(),
+                    origin: (0, 0),
+                };
+                Some(JxlOutputBuffer::from_image_rect_mut(
+                    img.get_rect_mut(rect).into_raw(),
+                ))
+            }));
+        };
+
+        if let Some(lf_images) = &mut lf_frame_data {
+            buffers.extend(lf_images.iter_mut().map(|img| {
+                let rect = Rect {
+                    size: img.size(),
+                    origin: (0, 0),
+                };
+                Some(JxlOutputBuffer::from_image_rect_mut(
+                    img.get_rect_mut(rect).into_raw(),
+                ))
+            }));
+        };
+
+        pipeline!(self, p, p.check_buffer_sizes(&mut buffers[..])?);
+
+        let mut buffer_splitter = BufferSplitter::new(&mut buffers[..]);
+
+        pipeline!(self, p, p.render_outside_frame(&mut buffer_splitter)?);
+
+        // Render data from the lf global section, if we didn't do so already, before rendering HF.
+        if !self.lf_global_was_rendered {
+            self.lf_global_was_rendered = true;
+            let lf_global = self.lf_global.as_mut().unwrap();
+            let mut pass_to_pipeline = |chan, group, num_passes, image| {
+                pipeline!(
+                    self,
+                    p,
+                    p.set_buffer_for_group(chan, group, num_passes, image, &mut buffer_splitter)?
+                );
+                Ok(())
+            };
+            lf_global
+                .modular_global
+                .process_output(0, 0, &self.header, &mut pass_to_pipeline)?;
+            for group in 0..self.header.num_lf_groups() {
+                lf_global.modular_global.process_output(
+                    1,
+                    group,
+                    &self.header,
+                    &mut pass_to_pipeline,
+                )?;
+            }
+        }
+
+        for (group, passes) in groups {
+            // TODO(veluca): render all the available passes at once.
+            for (pass, br) in passes {
+                self.decode_hf_group(group, pass, br, &mut buffer_splitter)?;
+            }
+        }
+
+        self.reference_frame_data = reference_frame_data;
+        self.lf_frame_data = lf_frame_data;
+
+        Ok(())
+    }
+
+    pub(crate) fn build_render_pipeline<T: RenderPipeline>(
+        decoder_state: &DecoderState,
+        frame_header: &FrameHeader,
+        lf_global: &LfGlobalState,
+        epf_sigma: &Option<Arc<Image<f32>>>,
+        pixel_format: &JxlPixelFormat,
+    ) -> Result<Box<T>> {
+        let num_channels = frame_header.num_extra_channels as usize + 3;
+        let num_temp_channels = if frame_header.has_noise() { 3 } else { 0 };
+        let metadata = &decoder_state.file_header.image_metadata;
+        let mut pipeline = RenderPipelineBuilder::<T>::new(
+            num_channels + num_temp_channels,
+            frame_header.size_upsampled(),
+            frame_header.upsampling.ilog2() as usize,
+            frame_header.log_group_dim(),
+            frame_header.passes.num_passes as usize,
+        );
+
+        if frame_header.encoding == Encoding::Modular {
+            if decoder_state.file_header.image_metadata.xyb_encoded {
+                pipeline = pipeline
+                    .add_inout_stage(ConvertModularXYBToF32Stage::new(0, &lf_global.lf_quant))?
+            } else {
+                for i in 0..3 {
+                    pipeline = pipeline
+                        .add_inout_stage(ConvertModularToF32Stage::new(i, metadata.bit_depth))?;
+                }
+            }
+        }
+        for i in 3..num_channels {
+            pipeline =
+                pipeline.add_inout_stage(ConvertModularToF32Stage::new(i, metadata.bit_depth))?;
+        }
+
+        for c in 0..3 {
+            if frame_header.hshift(c) != 0 {
+                pipeline = pipeline.add_inout_stage(HorizontalChromaUpsample::new(c))?;
+            }
+            if frame_header.vshift(c) != 0 {
+                pipeline = pipeline.add_inout_stage(VerticalChromaUpsample::new(c))?;
+            }
+        }
+
+        let filters = &frame_header.restoration_filter;
+        if filters.gab {
+            pipeline = pipeline
+                .add_inout_stage(GaborishStage::new(
+                    0,
+                    filters.gab_x_weight1,
+                    filters.gab_x_weight2,
+                ))?
+                .add_inout_stage(GaborishStage::new(
+                    1,
+                    filters.gab_y_weight1,
+                    filters.gab_y_weight2,
+                ))?
+                .add_inout_stage(GaborishStage::new(
+                    2,
+                    filters.gab_b_weight1,
+                    filters.gab_b_weight2,
+                ))?;
+        }
+
+        let rf = &frame_header.restoration_filter;
+        if rf.epf_iters >= 3 {
+            pipeline = pipeline.add_inout_stage(Epf0Stage::new(
+                rf.epf_pass0_sigma_scale,
+                rf.epf_border_sad_mul,
+                rf.epf_channel_scale,
+                epf_sigma.as_ref().unwrap().clone(),
+            ))?
+        }
+        if rf.epf_iters >= 1 {
+            pipeline = pipeline.add_inout_stage(Epf1Stage::new(
+                1.0,
+                rf.epf_border_sad_mul,
+                rf.epf_channel_scale,
+                epf_sigma.as_ref().unwrap().clone(),
+            ))?
+        }
+        if rf.epf_iters >= 2 {
+            pipeline = pipeline.add_inout_stage(Epf2Stage::new(
+                rf.epf_pass2_sigma_scale,
+                rf.epf_border_sad_mul,
+                rf.epf_channel_scale,
+                epf_sigma.as_ref().unwrap().clone(),
+            ))?
+        }
+
+        let late_ec_upsample = frame_header.upsampling > 1
+            && frame_header
+                .ec_upsampling
+                .iter()
+                .all(|x| *x == frame_header.upsampling);
+
+        if !late_ec_upsample {
+            let transform_data = &decoder_state.file_header.transform_data;
+            for (ec, ec_up) in frame_header.ec_upsampling.iter().enumerate() {
+                if *ec_up > 1 {
+                    pipeline = match *ec_up {
+                        2 => pipeline.add_inout_stage(Upsample2x::new(transform_data, 3 + ec)),
+                        4 => pipeline.add_inout_stage(Upsample4x::new(transform_data, 3 + ec)),
+                        8 => pipeline.add_inout_stage(Upsample8x::new(transform_data, 3 + ec)),
+                        _ => unreachable!(),
+                    }?;
+                }
+            }
+        }
+
+        if frame_header.has_patches() {
+            pipeline = pipeline.add_inplace_stage(PatchesStage {
+                patches: lf_global.patches.clone().unwrap(),
+                extra_channels: metadata.extra_channel_info.clone(),
+                decoder_state: decoder_state.reference_frames.clone(),
+            })?
+        }
+
+        if frame_header.has_splines() {
+            pipeline = pipeline.add_inplace_stage(SplinesStage::new(
+                lf_global.splines.clone().unwrap(),
+                frame_header.size(),
+                &lf_global.color_correlation_params.unwrap_or_default(),
+                decoder_state.high_precision,
+            ))?
+        }
+
+        if frame_header.upsampling > 1 {
+            let transform_data = &decoder_state.file_header.transform_data;
+            let nb_channels = if late_ec_upsample {
+                3 + frame_header.ec_upsampling.len()
+            } else {
+                3
+            };
+            for c in 0..nb_channels {
+                pipeline = match frame_header.upsampling {
+                    2 => pipeline.add_inout_stage(Upsample2x::new(transform_data, c)),
+                    4 => pipeline.add_inout_stage(Upsample4x::new(transform_data, c)),
+                    8 => pipeline.add_inout_stage(Upsample8x::new(transform_data, c)),
+                    _ => unreachable!(),
+                }?;
+            }
+        }
+
+        if frame_header.has_noise() {
+            pipeline = pipeline
+                .add_inout_stage(ConvolveNoiseStage::new(num_channels))?
+                .add_inout_stage(ConvolveNoiseStage::new(num_channels + 1))?
+                .add_inout_stage(ConvolveNoiseStage::new(num_channels + 2))?
+                .add_inplace_stage(AddNoiseStage::new(
+                    *lf_global.noise.as_ref().unwrap(),
+                    lf_global.color_correlation_params.unwrap_or_default(),
+                    num_channels,
+                ))?;
+        }
+
+        let num_regular_output_buffers = frame_header.num_extra_channels as usize + 1;
+        assert_eq!(
+            pixel_format.extra_channel_format.len(),
+            frame_header.num_extra_channels as usize
+        );
+
+        assert!(frame_header.lf_level == 0 || !frame_header.can_be_referenced);
+
+        if frame_header.lf_level != 0 {
+            for i in 0..3 {
+                pipeline = pipeline.add_save_stage(
+                    &[i],
+                    Orientation::Identity,
+                    num_regular_output_buffers + i,
+                    JxlColorType::Grayscale,
+                    JxlDataFormat::f32(),
+                )?;
+            }
+        }
+        if frame_header.can_be_referenced && frame_header.save_before_ct {
+            for i in 0..num_channels {
+                pipeline = pipeline.add_save_stage(
+                    &[i],
+                    Orientation::Identity,
+                    num_regular_output_buffers + i,
+                    JxlColorType::Grayscale,
+                    JxlDataFormat::f32(),
+                )?;
+            }
+        }
+
+        let mut linear = false;
+        let output_color_info = OutputColorInfo::from_header(&decoder_state.file_header)?;
+        if frame_header.do_ycbcr {
+            pipeline = pipeline.add_inplace_stage(YcbcrToRgbStage::new(0))?;
+        } else if decoder_state.file_header.image_metadata.xyb_encoded {
+            pipeline = pipeline.add_inplace_stage(XybStage::new(0, output_color_info.clone()))?;
+            if decoder_state.xyb_output_linear {
+                linear = true;
+            } else {
+                pipeline = pipeline
+                    .add_inplace_stage(FromLinearStage::new(0, output_color_info.tf.clone()))?;
+            }
+        }
+
+        if frame_header.needs_blending() {
+            if linear {
+                pipeline = pipeline
+                    .add_inplace_stage(FromLinearStage::new(0, output_color_info.tf.clone()))?;
+                linear = false;
+            }
+            pipeline = pipeline.add_inplace_stage(BlendingStage::new(
+                frame_header,
+                &decoder_state.file_header,
+                decoder_state.reference_frames.clone(),
+            )?)?;
+            // TODO(veluca): we might not need to add an extend stage if the image size is
+            // compatible with the frame size.
+            pipeline = pipeline.add_extend_stage(ExtendToImageDimensionsStage::new(
+                frame_header,
+                &decoder_state.file_header,
+                decoder_state.reference_frames.clone(),
+            )?)?;
+        }
+
+        if frame_header.can_be_referenced && !frame_header.save_before_ct {
+            if linear {
+                pipeline = pipeline
+                    .add_inplace_stage(FromLinearStage::new(0, output_color_info.tf.clone()))?;
+                linear = false;
+            }
+            for i in 0..num_channels {
+                pipeline = pipeline.add_save_stage(
+                    &[i],
+                    Orientation::Identity,
+                    num_regular_output_buffers + i,
+                    JxlColorType::Grayscale,
+                    JxlDataFormat::f32(),
+                )?;
+            }
+        }
+
+        if decoder_state.render_spotcolors {
+            for (i, info) in decoder_state
+                .file_header
+                .image_metadata
+                .extra_channel_info
+                .iter()
+                .enumerate()
+            {
+                if info.ec_type == ExtraChannel::SpotColor {
+                    pipeline = pipeline
+                        .add_inplace_stage(SpotColorStage::new(i, info.spot_color.unwrap()))?;
+                }
+            }
+        }
+
+        if frame_header.is_visible() {
+            let color_space = decoder_state
+                .file_header
+                .image_metadata
+                .color_encoding
+                .color_space;
+            let num_color_channels = if color_space == ColorSpace::Gray {
+                1
+            } else {
+                3
+            };
+            let alpha_in_color = if pixel_format.color_type.has_alpha() {
+                decoder_state
+                    .file_header
+                    .image_metadata
+                    .extra_channel_info
+                    .iter()
+                    .enumerate()
+                    .find(|x| x.1.ec_type == ExtraChannel::Alpha)
+                    .map(|x| x.0 + 3)
+            } else {
+                None
+            };
+            if pixel_format.color_type.is_grayscale() && num_color_channels == 3 {
+                return Err(Error::NotGrayscale);
+            }
+            if decoder_state.file_header.image_metadata.xyb_encoded
+                && decoder_state.xyb_output_linear
+                && !linear
+            {
+                pipeline = pipeline
+                    .add_inplace_stage(ToLinearStage::new(0, output_color_info.tf.clone()))?;
+            }
+            let color_source_channels: &[usize] =
+                match (pixel_format.color_type.is_grayscale(), alpha_in_color) {
+                    (true, None) => &[0],
+                    (true, Some(c)) => &[0, c],
+                    (false, None) => &[0, 1, 2],
+                    (false, Some(c)) => &[0, 1, 2, c],
+                };
+            if let Some(df) = &pixel_format.color_data_format {
+                // Add conversion stages for non-float output formats
+                pipeline = Self::add_conversion_stages(pipeline, color_source_channels, *df)?;
+                pipeline = pipeline.add_save_stage(
+                    color_source_channels,
+                    metadata.orientation,
+                    0,
+                    pixel_format.color_type,
+                    *df,
+                )?;
+            }
+            for i in 0..frame_header.num_extra_channels as usize {
+                if let Some(df) = &pixel_format.extra_channel_format[i] {
+                    // Add conversion stages for non-float output formats
+                    pipeline = Self::add_conversion_stages(pipeline, &[3 + i], *df)?;
+                    pipeline = pipeline.add_save_stage(
+                        &[3 + i],
+                        metadata.orientation,
+                        1 + i,
+                        JxlColorType::Grayscale,
+                        *df,
+                    )?;
+                }
+            }
+        }
+        pipeline.build()
+    }
+
+    pub fn prepare_render_pipeline(
+        &mut self,
+        pixel_format: &JxlPixelFormat,
+        _cms: Option<&dyn JxlCms>,
+    ) -> Result<()> {
+        let lf_global = self.lf_global.as_mut().unwrap();
+        let epf_sigma = if self.header.restoration_filter.epf_iters > 0 {
+            let sigma_image = create_sigma_image(&self.header, lf_global, &self.hf_meta)?;
+            Some(Arc::new(sigma_image))
+        } else {
+            None
+        };
+
+        #[cfg(test)]
+        let render_pipeline = if self.use_simple_pipeline {
+            Self::build_render_pipeline::<SimpleRenderPipeline>(
+                &self.decoder_state,
+                &self.header,
+                lf_global,
+                &epf_sigma,
+                pixel_format,
+            )? as Box<dyn std::any::Any>
+        } else {
+            Self::build_render_pipeline::<LowMemoryRenderPipeline>(
+                &self.decoder_state,
+                &self.header,
+                lf_global,
+                &epf_sigma,
+                pixel_format,
+            )? as Box<dyn std::any::Any>
+        };
+        #[cfg(not(test))]
+        let render_pipeline = Self::build_render_pipeline::<LowMemoryRenderPipeline>(
+            &self.decoder_state,
+            &self.header,
+            lf_global,
+            &epf_sigma,
+            pixel_format,
+        )?;
+        self.render_pipeline = Some(render_pipeline);
+        self.lf_global_was_rendered = false;
+        Ok(())
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/bit_depth.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/bit_depth.rs
new file mode 100644
index 0000000..898e721e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/bit_depth.rs
@@ -0,0 +1,96 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{bit_reader::BitReader, error::Error, headers::encodings::*};
+use jxl_macros::UnconditionalCoder;
+
+use std::fmt::Debug;
+
+#[derive(UnconditionalCoder, Clone, Copy, PartialEq, Eq)]
+#[validate]
+pub struct BitDepth {
+    #[default(false)]
+    floating_point_sample: bool,
+    #[select_coder(floating_point_sample)]
+    #[coder_true(u2S(32, 16, 24, Bits(6)+1))]
+    #[coder_false(u2S(8, 10, 12, Bits(6)+1))]
+    #[default(8)]
+    bits_per_sample: u32,
+    #[condition(floating_point_sample)]
+    #[default(0)]
+    #[coder(Bits(4)+1)]
+    exponent_bits_per_sample: u32,
+}
+
+impl Debug for BitDepth {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        if self.floating_point_sample {
+            match (self.bits_per_sample, self.exponent_bits_per_sample) {
+                (32, 8) => {
+                    write!(f, "F32")
+                }
+                (16, 5) => {
+                    write!(f, "F16")
+                }
+                _ => {
+                    write!(
+                        f,
+                        "FloatE{}M{}",
+                        self.exponent_bits_per_sample,
+                        self.bits_per_sample - self.exponent_bits_per_sample - 1
+                    )
+                }
+            }
+        } else {
+            write!(f, "U{}", self.bits_per_sample)
+        }
+    }
+}
+
+impl BitDepth {
+    pub fn integer_samples(bits_per_sample: u32) -> BitDepth {
+        BitDepth {
+            floating_point_sample: false,
+            bits_per_sample,
+            exponent_bits_per_sample: 0,
+        }
+    }
+    #[cfg(test)]
+    pub fn f32() -> BitDepth {
+        BitDepth {
+            floating_point_sample: true,
+            bits_per_sample: 32,
+            exponent_bits_per_sample: 8,
+        }
+    }
+    pub fn bits_per_sample(&self) -> u32 {
+        self.bits_per_sample
+    }
+    pub fn exponent_bits_per_sample(&self) -> u32 {
+        self.exponent_bits_per_sample
+    }
+    pub fn floating_point_sample(&self) -> bool {
+        self.floating_point_sample
+    }
+    fn check(&self, _: &Empty) -> Result<(), Error> {
+        if self.floating_point_sample {
+            if self.exponent_bits_per_sample < 2 || self.exponent_bits_per_sample > 8 {
+                Err(Error::InvalidExponent(self.exponent_bits_per_sample))
+            } else {
+                let mantissa_bits =
+                    self.bits_per_sample as i32 - self.exponent_bits_per_sample as i32 - 1;
+                if !(2..=23).contains(&mantissa_bits) {
+                    Err(Error::InvalidMantissa(mantissa_bits))
+                } else {
+                    Ok(())
+                }
+            }
+        } else if self.bits_per_sample > 31 {
+            Err(Error::InvalidBitsPerSample(self.bits_per_sample))
+        } else {
+            Ok(())
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/color_encoding.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/color_encoding.rs
new file mode 100644
index 0000000..d4299928
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/color_encoding.rs
@@ -0,0 +1,204 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{bit_reader::BitReader, error::Error, headers::encodings::*};
+use jxl_macros::UnconditionalCoder;
+use num_derive::FromPrimitive;
+use std::fmt;
+
+#[allow(clippy::upper_case_acronyms)]
+#[derive(UnconditionalCoder, Copy, Clone, PartialEq, Debug, FromPrimitive)]
+pub enum ColorSpace {
+    RGB,
+    Gray,
+    XYB,
+    Unknown,
+}
+
+impl fmt::Display for ColorSpace {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "{}",
+            match self {
+                ColorSpace::RGB => "RGB",
+                ColorSpace::Gray => "Gra",
+                ColorSpace::XYB => "XYB",
+                ColorSpace::Unknown => "CS?",
+            }
+        )
+    }
+}
+
+#[allow(clippy::upper_case_acronyms)]
+#[derive(UnconditionalCoder, Copy, Clone, PartialEq, Debug, FromPrimitive)]
+pub enum WhitePoint {
+    D65 = 1,
+    Custom = 2,
+    E = 10,
+    DCI = 11,
+}
+
+#[allow(clippy::upper_case_acronyms)]
+#[derive(UnconditionalCoder, Copy, Clone, PartialEq, Debug, FromPrimitive)]
+pub enum Primaries {
+    SRGB = 1,
+    Custom = 2,
+    BT2100 = 9,
+    P3 = 11,
+}
+
+#[allow(clippy::upper_case_acronyms)]
+#[derive(UnconditionalCoder, Copy, Clone, PartialEq, Debug, FromPrimitive)]
+pub enum TransferFunction {
+    BT709 = 1,
+    Unknown = 2,
+    Linear = 8,
+    SRGB = 13,
+    PQ = 16,
+    DCI = 17,
+    HLG = 18,
+}
+
+#[derive(UnconditionalCoder, Copy, Clone, PartialEq, Debug, FromPrimitive)]
+pub enum RenderingIntent {
+    Perceptual = 0,
+    Relative,
+    Saturation,
+    Absolute,
+}
+
+impl fmt::Display for RenderingIntent {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "{}",
+            match self {
+                RenderingIntent::Perceptual => "Per",
+                RenderingIntent::Relative => "Rel",
+                RenderingIntent::Saturation => "Sat",
+                RenderingIntent::Absolute => "Abs",
+            }
+        )
+    }
+}
+
+#[derive(UnconditionalCoder, Debug, Clone)]
+pub struct CustomXY {
+    #[default(0)]
+    #[coder(u2S(Bits(19), Bits(19) + 524288, Bits(20) + 1048576, Bits(21) + 2097152))]
+    pub x: i32,
+    #[default(0)]
+    #[coder(u2S(Bits(19), Bits(19) + 524288, Bits(20) + 1048576, Bits(21) + 2097152))]
+    pub y: i32,
+}
+
+impl CustomXY {
+    /// Converts the stored scaled integer coordinates to f32 (x, y) values.
+    pub fn as_f32_coords(&self) -> (f32, f32) {
+        (self.x as f32 / 1_000_000.0, self.y as f32 / 1_000_000.0)
+    }
+
+    pub fn from_f32_coords(x: f32, y: f32) -> Self {
+        Self {
+            x: (x * 1_000_000.0).round() as i32,
+            y: (y * 1_000_000.0).round() as i32,
+        }
+    }
+}
+
+pub struct CustomTransferFunctionNonserialized {
+    color_space: ColorSpace,
+}
+
+#[derive(UnconditionalCoder, Debug, Clone)]
+#[nonserialized(CustomTransferFunctionNonserialized)]
+#[validate]
+pub struct CustomTransferFunction {
+    #[condition(nonserialized.color_space != ColorSpace::XYB)]
+    #[default(false)]
+    pub have_gamma: bool,
+    #[condition(have_gamma)]
+    #[default(3333333)] // XYB gamma
+    #[coder(Bits(24))]
+    pub gamma: u32,
+    #[condition(!have_gamma && nonserialized.color_space != ColorSpace::XYB)]
+    #[default(TransferFunction::SRGB)]
+    pub transfer_function: TransferFunction,
+}
+
+impl CustomTransferFunction {
+    #[cfg(test)]
+    pub fn empty() -> CustomTransferFunction {
+        CustomTransferFunction {
+            have_gamma: false,
+            gamma: 0,
+            transfer_function: TransferFunction::Unknown,
+        }
+    }
+    pub fn gamma(&self) -> f32 {
+        assert!(self.have_gamma);
+        self.gamma as f32 * 0.0000001
+    }
+
+    pub fn check(&self, _: &CustomTransferFunctionNonserialized) -> Result<(), Error> {
+        if self.have_gamma {
+            let gamma = self.gamma();
+            if gamma > 1.0 || gamma * 8192.0 < 1.0 {
+                Err(Error::InvalidGamma(gamma))
+            } else {
+                Ok(())
+            }
+        } else {
+            Ok(())
+        }
+    }
+}
+
+#[derive(UnconditionalCoder, Debug, Clone)]
+#[validate]
+pub struct ColorEncoding {
+    // all_default is never read.
+    #[allow(dead_code)]
+    #[all_default]
+    all_default: bool,
+    #[default(false)]
+    pub want_icc: bool,
+    #[default(ColorSpace::RGB)]
+    pub color_space: ColorSpace,
+    #[condition(!want_icc && color_space != ColorSpace::XYB)]
+    #[default(WhitePoint::D65)]
+    pub white_point: WhitePoint,
+    // TODO(veluca): can this be merged in the enum?!
+    #[condition(white_point == WhitePoint::Custom)]
+    #[default(CustomXY::default(&field_nonserialized))]
+    pub white: CustomXY,
+    #[condition(!want_icc && color_space != ColorSpace::XYB && color_space != ColorSpace::Gray)]
+    #[default(Primaries::SRGB)]
+    pub primaries: Primaries,
+    #[condition(primaries == Primaries::Custom)]
+    #[default([CustomXY::default(&field_nonserialized), CustomXY::default(&field_nonserialized), CustomXY::default(&field_nonserialized)])]
+    pub custom_primaries: [CustomXY; 3],
+    #[condition(!want_icc)]
+    #[default(CustomTransferFunction::default(&field_nonserialized))]
+    #[nonserialized(color_space: color_space)]
+    pub tf: CustomTransferFunction,
+    #[condition(!want_icc)]
+    #[default(RenderingIntent::Relative)]
+    pub rendering_intent: RenderingIntent,
+}
+
+impl ColorEncoding {
+    pub fn check(&self, _: &Empty) -> Result<(), Error> {
+        if !self.want_icc
+            && (self.color_space == ColorSpace::Unknown
+                || self.tf.transfer_function == TransferFunction::Unknown)
+        {
+            Err(Error::InvalidColorEncoding)
+        } else {
+            Ok(())
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/encodings.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/encodings.rs
new file mode 100644
index 0000000..7c0b964
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/encodings.rs
@@ -0,0 +1,423 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use super::{frame_header::PermutationNonserialized, permutation::Permutation};
+use crate::{
+    bit_reader::BitReader,
+    entropy_coding::decode::{Histograms, SymbolReader, unpack_signed},
+    error::Error,
+};
+
+pub enum U32 {
+    Bits(usize),
+    BitsOffset { n: usize, off: u32 },
+    Val(u32),
+}
+
+impl U32 {
+    pub fn read(&self, br: &mut BitReader) -> Result<u32, Error> {
+        match *self {
+            U32::Bits(n) => Ok(br.read(n)? as u32),
+            U32::BitsOffset { n, off } => Ok(br.read(n)? as u32 + off),
+            U32::Val(val) => Ok(val),
+        }
+    }
+}
+
+pub enum U32Coder {
+    Direct(U32),
+    Select(U32, U32, U32, U32),
+}
+
+#[derive(Default)]
+pub struct Empty {}
+
+pub trait UnconditionalCoder<Config>
+where
+    Self: Sized,
+{
+    type Nonserialized;
+    fn read_unconditional(
+        config: &Config,
+        br: &mut BitReader,
+        nonserialized: &Self::Nonserialized,
+    ) -> Result<Self, Error>;
+}
+
+impl UnconditionalCoder<()> for bool {
+    type Nonserialized = Empty;
+    fn read_unconditional(
+        _: &(),
+        br: &mut BitReader,
+        _: &Self::Nonserialized,
+    ) -> Result<bool, Error> {
+        Ok(br.read(1)? != 0)
+    }
+}
+
+impl UnconditionalCoder<()> for f32 {
+    type Nonserialized = Empty;
+    fn read_unconditional(
+        _: &(),
+        br: &mut BitReader,
+        _: &Self::Nonserialized,
+    ) -> Result<f32, Error> {
+        use crate::util::f16;
+        let ret = f16::from_bits(br.read(16)? as u16);
+        if !ret.is_finite() {
+            Err(Error::FloatNaNOrInf)
+        } else {
+            Ok(ret.to_f32())
+        }
+    }
+}
+
+impl UnconditionalCoder<U32Coder> for u32 {
+    type Nonserialized = Empty;
+    fn read_unconditional(
+        config: &U32Coder,
+        br: &mut BitReader,
+        _: &Self::Nonserialized,
+    ) -> Result<u32, Error> {
+        match config {
+            U32Coder::Direct(u) => u.read(br),
+            U32Coder::Select(u0, u1, u2, u3) => {
+                let selector = br.read(2)?;
+                match selector {
+                    0 => u0.read(br),
+                    1 => u1.read(br),
+                    2 => u2.read(br),
+                    _ => u3.read(br),
+                }
+            }
+        }
+    }
+}
+
+impl UnconditionalCoder<U32Coder> for i32 {
+    type Nonserialized = Empty;
+    fn read_unconditional(
+        config: &U32Coder,
+        br: &mut BitReader,
+        nonserialized: &Self::Nonserialized,
+    ) -> Result<i32, Error> {
+        let u = u32::read_unconditional(config, br, nonserialized)?;
+        Ok(unpack_signed(u))
+    }
+}
+
+impl UnconditionalCoder<()> for u64 {
+    type Nonserialized = Empty;
+    fn read_unconditional(
+        _: &(),
+        br: &mut BitReader,
+        _: &Self::Nonserialized,
+    ) -> Result<u64, Error> {
+        match br.read(2)? {
+            0 => Ok(0),
+            1 => Ok(1 + br.read(4)?),
+            2 => Ok(17 + br.read(8)?),
+            _ => {
+                let mut result: u64 = br.read(12)?;
+                let mut shift = 12;
+                while br.read(1)? == 1 {
+                    if shift >= 60 {
+                        assert_eq!(shift, 60);
+                        return Ok(result | (br.read(4)? << shift));
+                    }
+                    result |= br.read(8)? << shift;
+                    shift += 8;
+                }
+                Ok(result)
+            }
+        }
+    }
+}
+
+impl UnconditionalCoder<()> for String {
+    type Nonserialized = Empty;
+    fn read_unconditional(
+        _: &(),
+        br: &mut BitReader,
+        nonserialized: &Self::Nonserialized,
+    ) -> Result<String, Error> {
+        let len = u32::read_unconditional(
+            &U32Coder::Select(
+                U32::Val(0),
+                U32::Bits(4),
+                U32::BitsOffset { n: 5, off: 16 },
+                U32::BitsOffset { n: 10, off: 48 },
+            ),
+            br,
+            nonserialized,
+        )?;
+        let mut ret = String::new();
+        ret.reserve(len as usize);
+        for _ in 0..len {
+            ret.push(br.read(8)? as u8 as char);
+        }
+        Ok(ret)
+    }
+}
+
+impl UnconditionalCoder<()> for Permutation {
+    type Nonserialized = PermutationNonserialized;
+    fn read_unconditional(
+        _: &(),
+        br: &mut BitReader,
+        nonserialized: &Self::Nonserialized,
+    ) -> Result<Permutation, Error> {
+        // TODO: This is quadratic when incrementally parsing byte by byte,
+        // we might want to find a better way of reading the permutation.
+        let ret = if nonserialized.permuted {
+            let size = nonserialized.num_entries;
+            let num_contexts = 8;
+            let histograms = Histograms::decode(num_contexts, br, /*allow_lz77=*/ true)?;
+            let mut reader = SymbolReader::new(&histograms, br, None)?;
+            Permutation::decode(size, 0, &histograms, br, &mut reader)
+        } else {
+            Ok(Permutation::default())
+        };
+        br.jump_to_byte_boundary()?;
+        ret
+    }
+}
+
+impl<T: UnconditionalCoder<Config>, Config, const N: usize> UnconditionalCoder<Config> for [T; N] {
+    type Nonserialized = T::Nonserialized;
+    fn read_unconditional(
+        config: &Config,
+        br: &mut BitReader,
+        nonserialized: &Self::Nonserialized,
+    ) -> Result<[T; N], Error> {
+        use array_init::try_array_init;
+        try_array_init(|_| T::read_unconditional(config, br, nonserialized))
+    }
+}
+
+pub struct VectorCoder<T: Sized> {
+    pub size_coder: U32Coder,
+    pub value_coder: T,
+}
+
+impl<Config, T: UnconditionalCoder<Config>> UnconditionalCoder<VectorCoder<Config>> for Vec<T> {
+    type Nonserialized = T::Nonserialized;
+    fn read_unconditional(
+        config: &VectorCoder<Config>,
+        br: &mut BitReader,
+        nonserialized: &Self::Nonserialized,
+    ) -> Result<Vec<T>, Error> {
+        let len = u32::read_unconditional(&config.size_coder, br, &Empty {})?;
+        let mut ret: Vec<T> = Vec::new();
+        ret.reserve_exact(len as usize);
+        for _ in 0..len {
+            ret.push(T::read_unconditional(
+                &config.value_coder,
+                br,
+                nonserialized,
+            )?);
+        }
+        Ok(ret)
+    }
+}
+
+pub struct SelectCoder<T: Sized> {
+    pub use_true: bool,
+    pub coder_true: T,
+    pub coder_false: T,
+}
+
+// Marker trait to avoid conflicting declarations for [T; N].
+pub trait Selectable {}
+impl Selectable for u32 {}
+
+impl<Config, T: UnconditionalCoder<Config> + Selectable> UnconditionalCoder<SelectCoder<Config>>
+    for T
+{
+    type Nonserialized = <T as UnconditionalCoder<Config>>::Nonserialized;
+    fn read_unconditional(
+        config: &SelectCoder<Config>,
+        br: &mut BitReader,
+        nonserialized: &Self::Nonserialized,
+    ) -> Result<T, Error> {
+        if config.use_true {
+            T::read_unconditional(&config.coder_true, br, nonserialized)
+        } else {
+            T::read_unconditional(&config.coder_false, br, nonserialized)
+        }
+    }
+}
+
+pub trait ConditionalCoder<Config>
+where
+    Self: Sized,
+{
+    type Nonserialized;
+    fn read_conditional(
+        config: &Config,
+        condition: bool,
+        br: &mut BitReader,
+        nonserialized: &Self::Nonserialized,
+    ) -> Result<Self, Error>;
+}
+
+impl<Config, T: UnconditionalCoder<Config>> ConditionalCoder<Config> for Option<T> {
+    type Nonserialized = T::Nonserialized;
+    fn read_conditional(
+        config: &Config,
+        condition: bool,
+        br: &mut BitReader,
+        nonserialized: &Self::Nonserialized,
+    ) -> Result<Option<T>, Error> {
+        if condition {
+            Ok(Some(T::read_unconditional(config, br, nonserialized)?))
+        } else {
+            Ok(None)
+        }
+    }
+}
+
+impl ConditionalCoder<()> for String {
+    type Nonserialized = Empty;
+    fn read_conditional(
+        _: &(),
+        condition: bool,
+        br: &mut BitReader,
+        nonserialized: &Empty,
+    ) -> Result<String, Error> {
+        if condition {
+            String::read_unconditional(&(), br, nonserialized)
+        } else {
+            Ok(String::new())
+        }
+    }
+}
+
+impl<Config, T: UnconditionalCoder<Config>> ConditionalCoder<VectorCoder<Config>> for Vec<T> {
+    type Nonserialized = T::Nonserialized;
+    fn read_conditional(
+        config: &VectorCoder<Config>,
+        condition: bool,
+        br: &mut BitReader,
+        nonserialized: &Self::Nonserialized,
+    ) -> Result<Vec<T>, Error> {
+        if condition {
+            Vec::read_unconditional(config, br, nonserialized)
+        } else {
+            Ok(Vec::new())
+        }
+    }
+}
+
+pub trait DefaultedElementCoder<Config, T>
+where
+    Self: Sized,
+{
+    type Nonserialized;
+    fn read_defaulted_element(
+        config: &Config,
+        condition: bool,
+        default: T,
+        br: &mut BitReader,
+        nonserialized: &Self::Nonserialized,
+    ) -> Result<Self, Error>;
+}
+
+impl<Config, T> DefaultedElementCoder<VectorCoder<Config>, T> for Vec<T>
+where
+    T: UnconditionalCoder<Config> + Clone,
+{
+    type Nonserialized = T::Nonserialized;
+
+    fn read_defaulted_element(
+        config: &VectorCoder<Config>,
+        condition: bool,
+        default: T,
+        br: &mut BitReader,
+        nonserialized: &Self::Nonserialized,
+    ) -> Result<Self, Error> {
+        let len = u32::read_unconditional(&config.size_coder, br, &Empty {})?;
+        if condition {
+            let mut ret: Vec<T> = Vec::new();
+            ret.reserve_exact(len as usize);
+            for _ in 0..len {
+                ret.push(T::read_unconditional(
+                    &config.value_coder,
+                    br,
+                    nonserialized,
+                )?);
+            }
+            Ok(ret)
+        } else {
+            Ok(vec![default; len as usize])
+        }
+    }
+}
+
+pub trait DefaultedCoder<Config>
+where
+    Self: Sized,
+{
+    type Nonserialized;
+    fn read_defaulted(
+        config: &Config,
+        condition: bool,
+        default: Self,
+        br: &mut BitReader,
+        nonserialized: &Self::Nonserialized,
+    ) -> Result<Self, Error>;
+}
+
+impl<Config, T: UnconditionalCoder<Config>> DefaultedCoder<Config> for T {
+    type Nonserialized = T::Nonserialized;
+    fn read_defaulted(
+        config: &Config,
+        condition: bool,
+        default: Self,
+        br: &mut BitReader,
+        nonserialized: &Self::Nonserialized,
+    ) -> Result<T, Error> {
+        if condition {
+            Ok(T::read_unconditional(config, br, nonserialized)?)
+        } else {
+            Ok(default)
+        }
+    }
+}
+
+// TODO(veluca93): this will likely need to be implemented differently if
+// there are extensions.
+#[derive(Debug, PartialEq, Default, Clone)]
+pub struct Extensions {}
+
+impl UnconditionalCoder<()> for Extensions {
+    type Nonserialized = Empty;
+    fn read_unconditional(
+        _: &(),
+        br: &mut BitReader,
+        _: &Self::Nonserialized,
+    ) -> Result<Extensions, Error> {
+        let selector = u64::read_unconditional(&(), br, &Empty {})?;
+        let mut total_size: u64 = 0;
+        for i in 0..64 {
+            if (selector & (1u64 << i)) != 0 {
+                let size = u64::read_unconditional(&(), br, &Empty {})?;
+                let sum = total_size.checked_add(size);
+                if let Some(s) = sum {
+                    total_size = s;
+                } else {
+                    return Err(Error::SizeOverflow);
+                }
+            }
+        }
+        let total_size = usize::try_from(total_size);
+        if let Ok(ts) = total_size {
+            br.skip_bits(ts)?;
+        } else {
+            return Err(Error::SizeOverflow);
+        }
+        Ok(Extensions {})
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/extra_channels.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/extra_channels.rs
new file mode 100644
index 0000000..78aa235
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/extra_channels.rs
@@ -0,0 +1,99 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{
+    bit_reader::BitReader,
+    error::Error,
+    headers::{bit_depth::BitDepth, encodings::*},
+};
+use jxl_macros::UnconditionalCoder;
+use num_derive::FromPrimitive;
+
+#[allow(clippy::upper_case_acronyms)]
+#[derive(UnconditionalCoder, Copy, Clone, PartialEq, Debug, FromPrimitive, Eq)]
+pub enum ExtraChannel {
+    Alpha,
+    Depth,
+    SpotColor,
+    SelectionMask,
+    Black,
+    CFA,
+    Thermal,
+    Reserved0,
+    Reserved1,
+    Reserved2,
+    Reserved3,
+    Reserved4,
+    Reserved5,
+    Reserved6,
+    Reserved7,
+    Unknown,
+    Optional,
+}
+
+// TODO(veluca): figure out if these fields should be unused.
+#[allow(dead_code)]
+#[derive(UnconditionalCoder, Debug, Clone)]
+#[validate]
+pub struct ExtraChannelInfo {
+    #[all_default]
+    all_default: bool,
+    #[default(ExtraChannel::Alpha)]
+    pub ec_type: ExtraChannel,
+    #[default(BitDepth::default(&field_nonserialized))]
+    bit_depth: BitDepth,
+    #[coder(u2S(0, 3, 4, Bits(3) + 1))]
+    #[default(0)]
+    dim_shift: u32,
+    name: String,
+    // TODO(veluca93): if using Option<bool>, this is None when all_default.
+    #[condition(ec_type == ExtraChannel::Alpha)]
+    #[default(false)]
+    alpha_associated: bool,
+    #[condition(ec_type == ExtraChannel::SpotColor)]
+    pub spot_color: Option<[f32; 4]>,
+    #[condition(ec_type == ExtraChannel::CFA)]
+    #[coder(u2S(1, Bits(2), Bits(4) + 3, Bits(8) + 19))]
+    cfa_channel: Option<u32>,
+}
+
+impl ExtraChannelInfo {
+    #[cfg(test)]
+    #[allow(clippy::too_many_arguments)]
+    pub fn new(
+        all_default: bool,
+        ec_type: ExtraChannel,
+        bit_depth: BitDepth,
+        dim_shift: u32,
+        name: String,
+        alpha_associated: bool,
+        spot_color: Option<[f32; 4]>,
+        cfa_channel: Option<u32>,
+    ) -> ExtraChannelInfo {
+        ExtraChannelInfo {
+            all_default,
+            ec_type,
+            bit_depth,
+            dim_shift,
+            name,
+            alpha_associated,
+            spot_color,
+            cfa_channel,
+        }
+    }
+    pub fn dim_shift(&self) -> u32 {
+        self.dim_shift
+    }
+    pub fn alpha_associated(&self) -> bool {
+        self.alpha_associated
+    }
+    fn check(&self, _: &Empty) -> Result<(), Error> {
+        if self.dim_shift > 3 {
+            Err(Error::DimShiftTooLarge(self.dim_shift))
+        } else {
+            Ok(())
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/frame_header.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/frame_header.rs
new file mode 100644
index 0000000..68c59e6
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/frame_header.rs
@@ -0,0 +1,789 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(clippy::excessive_precision)]
+
+use crate::{
+    BLOCK_DIM, GROUP_DIM,
+    bit_reader::BitReader,
+    error::Error,
+    headers::{encodings::*, extra_channels::ExtraChannelInfo},
+    image::Rect,
+    util::FloorLog2,
+};
+
+use jxl_macros::UnconditionalCoder;
+use num_derive::FromPrimitive;
+use std::cmp::min;
+
+use super::Animation;
+
+#[derive(UnconditionalCoder, Copy, Clone, PartialEq, Debug, FromPrimitive)]
+pub enum FrameType {
+    RegularFrame = 0,
+    LFFrame = 1,
+    ReferenceOnly = 2,
+    SkipProgressive = 3,
+}
+
+#[derive(UnconditionalCoder, Copy, Clone, PartialEq, Debug, FromPrimitive)]
+pub enum Encoding {
+    VarDCT = 0,
+    Modular = 1,
+}
+
+struct Flags;
+
+impl Flags {
+    pub const ENABLE_NOISE: u64 = 1;
+    pub const ENABLE_PATCHES: u64 = 2;
+    pub const ENABLE_SPLINES: u64 = 0x10;
+    pub const USE_LF_FRAME: u64 = 0x20;
+    pub const SKIP_ADAPTIVE_LF_SMOOTHING: u64 = 0x80;
+}
+
+#[derive(UnconditionalCoder, Debug, PartialEq)]
+pub struct Passes {
+    #[coder(u2S(1, 2, 3, Bits(3) + 4))]
+    #[default(1)]
+    pub num_passes: u32,
+
+    #[coder(u2S(0, 1, 2, Bits(1) + 3))]
+    #[default(0)]
+    #[condition(num_passes != 1)]
+    num_ds: u32,
+
+    #[size_coder(explicit(num_passes - 1))]
+    #[coder(Bits(2))]
+    #[default_element(0)]
+    #[condition(num_passes != 1)]
+    pub shift: Vec<u32>,
+
+    #[size_coder(explicit(num_ds))]
+    #[coder(u2S(1, 2, 4, 8))]
+    #[default_element(1)]
+    #[condition(num_passes != 1)]
+    downsample: Vec<u32>,
+
+    #[size_coder(explicit(num_ds))]
+    #[coder(u2S(0, 1, 2, Bits(3)))]
+    #[default_element(0)]
+    #[condition(num_passes != 1)]
+    last_pass: Vec<u32>,
+}
+
+impl Passes {
+    pub fn downsampling_bracket(&self, pass: usize) -> (usize, usize) {
+        let mut max_shift = 2;
+        let mut min_shift = 3;
+        for i in 0..pass + 1 {
+            for j in 0..self.num_ds as usize {
+                if i == self.last_pass[j] as usize {
+                    min_shift = self.downsample[j].floor_log2();
+                }
+            }
+            if i + 1 == self.num_passes as usize {
+                min_shift = 0;
+            }
+            if i != pass {
+                max_shift = min_shift - 1;
+            }
+        }
+        (min_shift as usize, max_shift as usize)
+    }
+}
+
+#[derive(UnconditionalCoder, Copy, Clone, PartialEq, Debug, FromPrimitive)]
+pub enum BlendingMode {
+    Replace = 0,
+    Add = 1,
+    Blend = 2,
+    AlphaWeightedAdd = 3,
+    Mul = 4,
+}
+
+#[derive(Default)]
+pub struct BlendingInfoNonserialized {
+    num_extra_channels: u32,
+    full_frame: bool,
+}
+
+#[derive(UnconditionalCoder, Debug, PartialEq, Clone)]
+#[nonserialized(BlendingInfoNonserialized)]
+pub struct BlendingInfo {
+    #[coder(u2S(0, 1, 2, Bits(2) + 3))]
+    #[default(BlendingMode::Replace)]
+    pub mode: BlendingMode,
+
+    /* Spec: "Let multi_extra be true if and only if and the number of extra channels is at least two."
+    libjxl condition is num_extra_channels > 0 */
+    #[coder(u2S(0, 1, 2, Bits(3) + 3))]
+    #[default(0)]
+    #[condition(nonserialized.num_extra_channels > 0 &&
+        (mode == BlendingMode::Blend || mode == BlendingMode::AlphaWeightedAdd))]
+    pub alpha_channel: u32,
+
+    #[default(false)]
+    #[condition(nonserialized.num_extra_channels > 0 &&
+        (mode == BlendingMode::Blend || mode == BlendingMode::AlphaWeightedAdd || mode == BlendingMode::Mul))]
+    pub clamp: bool,
+
+    #[coder(u2S(0, 1, 2, 3))]
+    #[default(0)]
+    // This condition is called `resets_canvas` in the spec
+    #[condition(!(nonserialized.full_frame && mode == BlendingMode::Replace))]
+    pub source: u32,
+}
+
+pub struct RestorationFilterNonserialized {
+    encoding: Encoding,
+}
+
+#[derive(UnconditionalCoder, Debug, PartialEq)]
+#[nonserialized(RestorationFilterNonserialized)]
+pub struct RestorationFilter {
+    #[all_default]
+    all_default: bool,
+
+    #[default(true)]
+    pub gab: bool,
+
+    #[default(false)]
+    #[condition(gab)]
+    gab_custom: bool,
+
+    #[default(0.115169525)]
+    #[condition(gab_custom)]
+    pub gab_x_weight1: f32,
+
+    #[default(0.061248592)]
+    #[condition(gab_custom)]
+    pub gab_x_weight2: f32,
+
+    #[default(0.115169525)]
+    #[condition(gab_custom)]
+    pub gab_y_weight1: f32,
+
+    #[default(0.061248592)]
+    #[condition(gab_custom)]
+    pub gab_y_weight2: f32,
+
+    #[default(0.115169525)]
+    #[condition(gab_custom)]
+    pub gab_b_weight1: f32,
+
+    #[default(0.061248592)]
+    #[condition(gab_custom)]
+    pub gab_b_weight2: f32,
+
+    #[coder(Bits(2))]
+    #[default(2)]
+    pub epf_iters: u32,
+
+    #[default(false)]
+    #[condition(epf_iters > 0 && nonserialized.encoding == Encoding::VarDCT)]
+    epf_sharp_custom: bool,
+
+    #[default([0.0, 1.0 / 7.0, 2.0 / 7.0, 3.0 / 7.0, 4.0 / 7.0, 5.0 / 7.0, 6.0 / 7.0, 1.0])]
+    #[condition(epf_sharp_custom)]
+    pub epf_sharp_lut: [f32; 8],
+
+    #[default(false)]
+    #[condition(epf_iters > 0)]
+    epf_weight_custom: bool,
+
+    #[default([40.0, 5.0, 3.5])]
+    #[condition(epf_weight_custom)]
+    pub epf_channel_scale: [f32; 3],
+
+    #[default(0.45)]
+    #[condition(epf_weight_custom)]
+    epf_pass1_zeroflush: f32,
+
+    #[default(0.6)]
+    #[condition(epf_weight_custom)]
+    epf_pass2_zeroflush: f32,
+
+    #[default(false)]
+    #[condition(epf_iters > 0)]
+    epf_sigma_custom: bool,
+
+    #[default(0.46)]
+    #[condition(epf_sigma_custom && nonserialized.encoding == Encoding::VarDCT)]
+    pub epf_quant_mul: f32,
+
+    #[default(0.9)]
+    #[condition(epf_sigma_custom)]
+    pub epf_pass0_sigma_scale: f32,
+
+    #[default(6.5)]
+    #[condition(epf_sigma_custom)]
+    pub epf_pass2_sigma_scale: f32,
+
+    #[default(2.0 / 3.0)]
+    #[condition(epf_sigma_custom)]
+    pub epf_border_sad_mul: f32,
+
+    #[default(1.0)]
+    #[condition(epf_iters > 0 && nonserialized.encoding == Encoding::Modular)]
+    pub epf_sigma_for_modular: f32,
+
+    #[default(Extensions::default())]
+    extensions: Extensions,
+}
+
+pub struct PermutationNonserialized {
+    pub num_entries: u32,
+    pub permuted: bool,
+}
+
+pub struct FrameHeaderNonserialized {
+    pub xyb_encoded: bool,
+    pub num_extra_channels: u32,
+    pub extra_channel_info: Vec<ExtraChannelInfo>,
+    pub have_animation: bool,
+    pub have_timecode: bool,
+    pub img_width: u32,
+    pub img_height: u32,
+}
+
+const H_SHIFT: [usize; 4] = [0, 1, 1, 0];
+const V_SHIFT: [usize; 4] = [0, 1, 0, 1];
+
+fn compute_jpeg_shift(jpeg_upsampling: &[u32], shift_table: &[usize]) -> u32 {
+    jpeg_upsampling
+        .iter()
+        .map(|&ch| shift_table[ch as usize])
+        .max()
+        .unwrap_or(0) as u32
+}
+
+#[derive(UnconditionalCoder, Debug, PartialEq)]
+#[nonserialized(FrameHeaderNonserialized)]
+#[aligned]
+#[validate]
+pub struct FrameHeader {
+    #[all_default]
+    all_default: bool,
+
+    #[coder(Bits(2))]
+    #[default(FrameType::RegularFrame)]
+    pub frame_type: FrameType,
+
+    #[coder(Bits(1))]
+    #[default(Encoding::VarDCT)]
+    pub encoding: Encoding,
+
+    #[default(0)]
+    flags: u64,
+
+    #[default(false)]
+    #[condition(!nonserialized.xyb_encoded)]
+    pub do_ycbcr: bool,
+
+    #[coder(Bits(2))]
+    #[default([0, 0, 0])]
+    #[condition(do_ycbcr && flags & Flags::USE_LF_FRAME == 0)]
+    jpeg_upsampling: [u32; 3],
+
+    #[coder(u2S(1, 2, 4, 8))]
+    #[default(1)]
+    #[condition(flags & Flags::USE_LF_FRAME == 0)]
+    pub upsampling: u32,
+
+    #[size_coder(explicit(nonserialized.num_extra_channels))]
+    #[coder(u2S(1, 2, 4, 8))]
+    #[default_element(1)]
+    #[condition(flags & Flags::USE_LF_FRAME == 0)]
+    pub ec_upsampling: Vec<u32>,
+
+    #[coder(Bits(2))]
+    #[default(1)]
+    #[condition(encoding == Encoding::Modular)]
+    group_size_shift: u32,
+
+    #[coder(Bits(3))]
+    #[default(3)]
+    #[condition(encoding == Encoding::VarDCT && nonserialized.xyb_encoded)]
+    pub x_qm_scale: u32,
+
+    #[coder(Bits(3))]
+    #[default(2)]
+    #[condition(encoding == Encoding::VarDCT && nonserialized.xyb_encoded)]
+    pub b_qm_scale: u32,
+
+    #[condition(frame_type != FrameType::ReferenceOnly)]
+    #[default(Passes::default(&field_nonserialized))]
+    pub passes: Passes,
+
+    #[coder(u2S(1, 2, 3, 4))]
+    #[default(0)]
+    #[condition(frame_type == FrameType::LFFrame)]
+    pub lf_level: u32,
+
+    #[default(false)]
+    #[condition(frame_type != FrameType::LFFrame)]
+    have_crop: bool,
+
+    #[coder(u2S(Bits(8), Bits(11) + 256, Bits(14) + 2304, Bits(30) + 18688))]
+    #[default(0)]
+    #[condition(have_crop && frame_type != FrameType::ReferenceOnly)]
+    pub x0: i32,
+
+    #[coder(u2S(Bits(8), Bits(11) + 256, Bits(14) + 2304, Bits(30) + 18688))]
+    #[default(0)]
+    #[condition(have_crop && frame_type != FrameType::ReferenceOnly)]
+    pub y0: i32,
+
+    #[coder(u2S(Bits(8), Bits(11) + 256, Bits(14) + 2304, Bits(30) + 18688))]
+    #[default(0)]
+    #[condition(have_crop)]
+    frame_width: u32,
+
+    #[coder(u2S(Bits(8), Bits(11) + 256, Bits(14) + 2304, Bits(30) + 18688))]
+    #[default(0)]
+    #[condition(have_crop)]
+    frame_height: u32,
+
+    // The following 2 fields are not actually serialized, but just used as variables to help with
+    // defining later conditions.
+    #[default(x0 <= 0 && y0 <= 0 && (frame_width as i64 + x0 as i64) >= nonserialized.img_width as i64 &&
+        (frame_height as i64 + y0 as i64) >= nonserialized.img_height as i64)]
+    #[condition(false)]
+    completely_covers: bool,
+
+    #[default(!have_crop || completely_covers)]
+    #[condition(false)]
+    full_frame: bool,
+
+    /* "normal_frame" denotes the condition !all_default
+    && (frame_type == kRegularFrame || frame_type == kSkipProgressive) */
+    #[default(BlendingInfo::default(&field_nonserialized))]
+    #[condition(frame_type == FrameType::RegularFrame || frame_type == FrameType::SkipProgressive)]
+    #[nonserialized(num_extra_channels : nonserialized.num_extra_channels, full_frame : full_frame)]
+    pub blending_info: BlendingInfo,
+
+    #[size_coder(explicit(nonserialized.num_extra_channels))]
+    #[condition(frame_type == FrameType::RegularFrame || frame_type == FrameType::SkipProgressive)]
+    #[default_element(BlendingInfo::default(&field_nonserialized))]
+    #[nonserialized(num_extra_channels : nonserialized.num_extra_channels, full_frame: full_frame)]
+    pub ec_blending_info: Vec<BlendingInfo>,
+
+    #[coder(u2S(0, 1, Bits(8), Bits(32)))]
+    #[default(0)]
+    #[condition((frame_type == FrameType::RegularFrame ||
+        frame_type == FrameType::SkipProgressive) && nonserialized.have_animation)]
+    pub duration: u32,
+
+    #[coder(Bits(32))]
+    #[default(0)]
+    #[condition((frame_type == FrameType::RegularFrame ||
+        frame_type == FrameType::SkipProgressive) && nonserialized.have_timecode)]
+    timecode: u32,
+
+    #[default(frame_type == FrameType::RegularFrame)]
+    #[condition(frame_type == FrameType::RegularFrame || frame_type == FrameType::SkipProgressive)]
+    pub is_last: bool,
+
+    #[coder(Bits(2))]
+    #[default(0)]
+    #[condition(frame_type != FrameType::LFFrame && !is_last)]
+    pub save_as_reference: u32,
+
+    // The following 2 fields are not actually serialized, but just used as variables to help with
+    // defining later conditions.
+    #[default(!is_last && frame_type != FrameType::LFFrame && (duration == 0 || save_as_reference != 0))]
+    #[condition(false)]
+    pub can_be_referenced: bool,
+
+    #[default(can_be_referenced && blending_info.mode == BlendingMode::Replace && full_frame &&
+              (frame_type == FrameType::RegularFrame || frame_type == FrameType::SkipProgressive))]
+    #[condition(false)]
+    save_before_ct_def_false: bool,
+
+    #[default(frame_type == FrameType::LFFrame)]
+    #[condition(frame_type == FrameType::ReferenceOnly || save_before_ct_def_false)]
+    pub save_before_ct: bool,
+
+    pub name: String,
+
+    #[default(RestorationFilter::default(&field_nonserialized))]
+    #[nonserialized(encoding : encoding)]
+    pub restoration_filter: RestorationFilter,
+
+    #[default(Extensions::default())]
+    extensions: Extensions,
+
+    // The following fields are not actually serialized, but just used as variables for
+    // implementing the methods below.
+    #[coder(Bits(0))]
+    #[default(if frame_width == 0 { nonserialized.img_width } else { frame_width })]
+    #[condition(false)]
+    pub width: u32,
+
+    #[coder(Bits(0))]
+    #[default(if frame_height == 0 { nonserialized.img_height } else { frame_height })]
+    #[condition(false)]
+    pub height: u32,
+
+    #[coder(Bits(0))]
+    #[default(compute_jpeg_shift(&jpeg_upsampling, &H_SHIFT))]
+    #[condition(false)]
+    pub maxhs: u32,
+
+    #[coder(Bits(0))]
+    #[default(compute_jpeg_shift(&jpeg_upsampling, &V_SHIFT))]
+    #[condition(false)]
+    pub maxvs: u32,
+
+    #[coder(Bits(0))]
+    #[default(nonserialized.num_extra_channels)]
+    #[condition(false)]
+    pub num_extra_channels: u32,
+}
+
+impl FrameHeader {
+    pub fn log_group_dim(&self) -> usize {
+        (GROUP_DIM.ilog2() - 1 + self.group_size_shift) as usize
+    }
+    pub fn group_dim(&self) -> usize {
+        1 << self.log_group_dim()
+    }
+    pub fn lf_group_dim(&self) -> usize {
+        self.group_dim() * BLOCK_DIM
+    }
+
+    pub fn num_groups(&self) -> usize {
+        self.size_groups().0 * self.size_groups().1
+    }
+
+    pub fn num_lf_groups(&self) -> usize {
+        self.size_lf_groups().0 * self.size_lf_groups().1
+    }
+
+    pub fn num_toc_entries(&self) -> usize {
+        let num_groups = self.num_groups();
+        let num_dc_groups = self.num_lf_groups();
+
+        if num_groups == 1 && self.passes.num_passes == 1 {
+            1
+        } else {
+            2 + num_dc_groups + num_groups * self.passes.num_passes as usize
+        }
+    }
+
+    pub fn duration(&self, animation: &Animation) -> f64 {
+        (self.duration as f64) * 1000.0 * (animation.tps_denominator as f64)
+            / (animation.tps_numerator as f64)
+    }
+
+    pub fn has_patches(&self) -> bool {
+        self.flags & Flags::ENABLE_PATCHES != 0
+    }
+
+    pub fn has_noise(&self) -> bool {
+        self.flags & Flags::ENABLE_NOISE != 0
+    }
+
+    pub fn has_splines(&self) -> bool {
+        self.flags & Flags::ENABLE_SPLINES != 0
+    }
+    pub fn has_lf_frame(&self) -> bool {
+        self.flags & Flags::USE_LF_FRAME != 0
+    }
+    pub fn should_do_adaptive_lf_smoothing(&self) -> bool {
+        self.flags & Flags::SKIP_ADAPTIVE_LF_SMOOTHING == 0
+            && !self.has_lf_frame()
+            && self.encoding == Encoding::VarDCT
+    }
+    pub fn raw_hshift(&self, c: usize) -> usize {
+        H_SHIFT[self.jpeg_upsampling[c] as usize]
+    }
+    pub fn hshift(&self, c: usize) -> usize {
+        (self.maxhs as usize) - self.raw_hshift(c)
+    }
+    pub fn raw_vshift(&self, c: usize) -> usize {
+        V_SHIFT[self.jpeg_upsampling[c] as usize]
+    }
+    pub fn vshift(&self, c: usize) -> usize {
+        (self.maxvs as usize) - self.raw_vshift(c)
+    }
+    pub fn is444(&self) -> bool {
+        self.hshift(0) == 0 && self.vshift(0) == 0 &&  // Cb
+        self.hshift(2) == 0 && self.vshift(2) == 0 &&  // Cr
+        self.hshift(1) == 0 && self.vshift(1) == 0 // Y
+    }
+    pub fn is420(&self) -> bool {
+        self.hshift(0) == 1 && self.vshift(0) == 1 &&  // Cb
+        self.hshift(2) == 1 && self.vshift(2) == 1 &&  // Cr
+        self.hshift(1) == 0 && self.vshift(1) == 0 // Y
+    }
+    pub fn is422(&self) -> bool {
+        self.hshift(0) == 1 && self.vshift(0) == 0 &&  // Cb
+        self.hshift(2) == 1 && self.vshift(2) == 0 &&  // Cr
+        self.hshift(1) == 0 && self.vshift(1) == 0 // Y
+    }
+    pub fn is440(&self) -> bool {
+        self.hshift(0) == 0 && self.vshift(0) == 1 &&  // Cb
+        self.hshift(2) == 0 && self.vshift(2) == 1 &&  // Cr
+        self.hshift(1) == 0 && self.vshift(1) == 0 // Y
+    }
+
+    pub fn is_visible(&self) -> bool {
+        (self.is_last || self.duration > 0)
+            && (self.frame_type == FrameType::RegularFrame
+                || self.frame_type == FrameType::SkipProgressive)
+    }
+
+    pub fn needs_blending(&self) -> bool {
+        if !(self.frame_type == FrameType::RegularFrame
+            || self.frame_type == FrameType::SkipProgressive)
+        {
+            return false;
+        }
+        let replace_all = self.blending_info.mode == BlendingMode::Replace
+            && self
+                .ec_blending_info
+                .iter()
+                .all(|x| x.mode == BlendingMode::Replace);
+        self.have_crop || !replace_all
+    }
+
+    /// The dimensions of this frame, as coded in the codestream, excluding padding pixels.
+    pub fn size(&self) -> (usize, usize) {
+        let (width, height) = self.size_upsampled();
+        (
+            width.div_ceil(self.upsampling as usize),
+            height.div_ceil(self.upsampling as usize),
+        )
+    }
+
+    /// The dimensions of this frame, as coded in the codestream, in 8x8 blocks.
+    pub fn size_blocks(&self) -> (usize, usize) {
+        (
+            self.size().0.div_ceil(BLOCK_DIM << self.maxhs) << self.maxhs,
+            self.size().1.div_ceil(BLOCK_DIM << self.maxvs) << self.maxvs,
+        )
+    }
+
+    /// The dimensions of this frame, as coded in the codestream but including padding pixels.
+    pub fn size_padded(&self) -> (usize, usize) {
+        if self.encoding == Encoding::Modular {
+            self.size()
+        } else {
+            (
+                self.size_blocks().0 * BLOCK_DIM,
+                self.size_blocks().1 * BLOCK_DIM,
+            )
+        }
+    }
+
+    /// The dimensions of this frame, after upsampling.
+    pub fn size_upsampled(&self) -> (usize, usize) {
+        (
+            self.width.div_ceil(1 << (3 * self.lf_level)) as usize,
+            self.height.div_ceil(1 << (3 * self.lf_level)) as usize,
+        )
+    }
+
+    pub fn size_padded_upsampled(&self) -> (usize, usize) {
+        let (xsize, ysize) = self.size_padded();
+        (
+            xsize * self.upsampling as usize,
+            ysize * self.upsampling as usize,
+        )
+    }
+
+    /// The dimensions of this frame, in groups.
+    pub fn size_groups(&self) -> (usize, usize) {
+        (
+            self.size().0.div_ceil(self.group_dim()),
+            self.size().1.div_ceil(self.group_dim()),
+        )
+    }
+
+    /// The dimensions of this frame, in LF groups.
+    pub fn size_lf_groups(&self) -> (usize, usize) {
+        (
+            self.size_blocks().0.div_ceil(self.group_dim()),
+            self.size_blocks().1.div_ceil(self.group_dim()),
+        )
+    }
+
+    pub fn block_group_rect(&self, group: usize) -> Rect {
+        let group_dims = self.size_groups();
+        let block_dims = self.size_blocks();
+        let group_dim_in_blocks = self.group_dim() >> 3;
+        let gx = group % group_dims.0;
+        let gy = group / group_dims.0;
+        let origin = (gx * group_dim_in_blocks, gy * group_dim_in_blocks);
+        let size = (
+            min(
+                block_dims.0.checked_sub(origin.0).unwrap(),
+                group_dim_in_blocks,
+            ),
+            min(
+                block_dims.1.checked_sub(origin.1).unwrap(),
+                group_dim_in_blocks,
+            ),
+        );
+        Rect { origin, size }
+    }
+
+    pub fn lf_group_rect(&self, group: usize) -> Rect {
+        let lf_dims = self.size_lf_groups();
+        let block_dims = self.size_blocks();
+        let gx = group % lf_dims.0;
+        let gy = group / lf_dims.0;
+        let origin = (gx * self.group_dim(), gy * self.group_dim());
+        let size = (
+            min(
+                block_dims.0.checked_sub(origin.0).unwrap(),
+                self.group_dim(),
+            ),
+            min(
+                block_dims.1.checked_sub(origin.1).unwrap(),
+                self.group_dim(),
+            ),
+        );
+        Rect { origin, size }
+    }
+
+    pub fn postprocess(&mut self, nonserialized: &FrameHeaderNonserialized) {
+        if self.upsampling > 1 {
+            for i in 0..nonserialized.extra_channel_info.len() {
+                let dim_shift = nonserialized.extra_channel_info[i].dim_shift();
+                self.ec_upsampling[i] <<= dim_shift;
+            }
+        }
+        if self.encoding != Encoding::VarDCT || !nonserialized.xyb_encoded {
+            self.x_qm_scale = 2;
+        }
+    }
+
+    fn check(&self, nonserialized: &FrameHeaderNonserialized) -> Result<(), Error> {
+        if self.upsampling > 1
+            && let Some((info, upsampling)) = nonserialized
+                .extra_channel_info
+                .iter()
+                .zip(&self.ec_upsampling)
+                .find(|(info, ec_upsampling)| {
+                    ((*ec_upsampling << info.dim_shift()) < self.upsampling)
+                        || (**ec_upsampling > 8)
+                })
+        {
+            return Err(Error::InvalidEcUpsampling(
+                self.upsampling,
+                info.dim_shift(),
+                *upsampling,
+            ));
+        }
+
+        if self.passes.num_ds >= self.passes.num_passes {
+            return Err(Error::NumPassesTooLarge(
+                self.passes.num_ds,
+                self.passes.num_passes,
+            ));
+        }
+
+        if !self.save_before_ct && !self.full_frame && self.frame_type == FrameType::ReferenceOnly {
+            return Err(Error::NonPatchReferenceWithCrop);
+        }
+        if !self.is444()
+            && ((self.flags & Flags::SKIP_ADAPTIVE_LF_SMOOTHING) == 0)
+            && self.encoding == Encoding::VarDCT
+        {
+            return Err(Error::Non444ChromaSubsampling);
+        }
+        Ok(())
+    }
+}
+
+#[cfg(test)]
+mod test_frame_header {
+    use super::super::permutation::Permutation;
+    use super::super::toc::Toc;
+    use super::*;
+    use crate::util::test::read_headers_and_toc;
+    use test_log::test;
+
+    #[test]
+    fn test_basic() {
+        let (_, frame_header, toc) =
+            read_headers_and_toc(include_bytes!("../../resources/test/basic.jxl")).unwrap();
+        assert_eq!(frame_header.frame_type, FrameType::RegularFrame);
+        assert_eq!(frame_header.encoding, Encoding::VarDCT);
+        assert_eq!(frame_header.flags, 0);
+        assert_eq!(frame_header.upsampling, 1);
+        assert_eq!(frame_header.x_qm_scale, 2);
+        assert_eq!(frame_header.b_qm_scale, 2);
+        assert!(!frame_header.have_crop);
+        assert!(!frame_header.save_before_ct);
+        assert_eq!(frame_header.name, String::from(""));
+        assert_eq!(frame_header.restoration_filter.epf_iters, 1);
+        assert_eq!(
+            toc,
+            Toc {
+                permuted: false,
+                permutation: Permutation::default(),
+                entries: [53].to_vec(),
+            }
+        )
+    }
+
+    #[test]
+    fn test_extra_channel() {
+        let frame_header =
+            read_headers_and_toc(include_bytes!("../../resources/test/extra_channels.jxl"))
+                .unwrap()
+                .1;
+        assert_eq!(frame_header.frame_type, FrameType::RegularFrame);
+        assert_eq!(frame_header.encoding, Encoding::Modular);
+        assert_eq!(frame_header.flags, 0);
+        assert_eq!(frame_header.upsampling, 1);
+        assert_eq!(frame_header.ec_upsampling, vec![1]);
+        // libjxl x_qm_scale = 2, but condition is false (should be 3 according to the draft)
+        // Doesn't actually matter since this is modular mode and the value doesn't get used.
+        assert_eq!(frame_header.x_qm_scale, 3);
+        assert_eq!(frame_header.b_qm_scale, 2);
+        assert!(!frame_header.have_crop);
+        assert!(!frame_header.save_before_ct);
+        assert_eq!(frame_header.name, String::from(""));
+        assert_eq!(frame_header.restoration_filter.epf_iters, 0);
+        assert!(!frame_header.restoration_filter.gab);
+    }
+
+    #[test]
+    fn test_has_permutation() {
+        let (_, frame_header, toc) =
+            read_headers_and_toc(include_bytes!("../../resources/test/has_permutation.jxl"))
+                .unwrap();
+        assert_eq!(frame_header.frame_type, FrameType::RegularFrame);
+        assert_eq!(frame_header.encoding, Encoding::VarDCT);
+        assert_eq!(frame_header.flags, 0);
+        assert_eq!(frame_header.upsampling, 1);
+        assert_eq!(frame_header.x_qm_scale, 3);
+        assert_eq!(frame_header.b_qm_scale, 2);
+        assert!(!frame_header.have_crop);
+        assert!(!frame_header.save_before_ct);
+        assert_eq!(frame_header.name, String::from(""));
+        assert_eq!(frame_header.restoration_filter.epf_iters, 1);
+        assert_eq!(
+            toc,
+            Toc {
+                permuted: true,
+                permutation: Permutation(vec![
+                    0u32, 1, 42, 48, 2, 3, 4, 5, 6, 7, 8, 9, 43, 10, 11, 12, 13, 14, 15, 16, 17,
+                    44, 18, 19, 20, 21, 22, 23, 24, 25, 45, 26, 27, 28, 29, 30, 31, 32, 33, 46, 34,
+                    35, 36, 37, 38, 39, 40, 41, 47,
+                ]),
+                entries: vec![
+                    155, 992, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 9, 9, 9, 9, 9, 9, 9,
+                    9, 9, 9, 9, 9, 9, 9, 9, 9, 5, 5, 5, 5, 5, 5, 5, 5, 697, 5, 5, 5, 5, 5, 60,
+                ],
+            },
+        )
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/image_metadata.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/image_metadata.rs
new file mode 100644
index 0000000..12843d9
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/image_metadata.rs
@@ -0,0 +1,222 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{
+    bit_reader::BitReader,
+    error::Error,
+    headers::{bit_depth::*, color_encoding::*, encodings::*, extra_channels::*, size::*},
+    image::Rect,
+};
+use jxl_macros::UnconditionalCoder;
+use num_derive::FromPrimitive;
+
+#[derive(Debug, Default, Clone)]
+pub struct Signature;
+
+impl Signature {
+    pub fn new() -> Signature {
+        Signature {}
+    }
+}
+
+impl crate::headers::encodings::UnconditionalCoder<()> for Signature {
+    type Nonserialized = Empty;
+    fn read_unconditional(_: &(), br: &mut BitReader, _: &Empty) -> Result<Signature, Error> {
+        let sig1 = br.read(8)? as u8;
+        let sig2 = br.read(8)? as u8;
+        if (sig1, sig2) != (0xff, 0x0a) {
+            Err(Error::InvalidSignature)
+        } else {
+            Ok(Signature {})
+        }
+    }
+}
+
+#[derive(UnconditionalCoder, Copy, Clone, PartialEq, Debug, FromPrimitive)]
+pub enum Orientation {
+    Identity = 1,
+    FlipHorizontal = 2,
+    Rotate180 = 3,
+    FlipVertical = 4,
+    Transpose = 5,
+    Rotate90Cw = 6,
+    AntiTranspose = 7,
+    Rotate90Ccw = 8,
+}
+
+impl Orientation {
+    pub fn is_transposing(&self) -> bool {
+        matches!(
+            self,
+            Orientation::Transpose
+                | Orientation::AntiTranspose
+                | Orientation::Rotate90Cw
+                | Orientation::Rotate90Ccw
+        )
+    }
+
+    pub fn map_size(&self, size: (usize, usize)) -> (usize, usize) {
+        if self.is_transposing() {
+            (size.1, size.0)
+        } else {
+            size
+        }
+    }
+
+    pub fn display_pixel(&self, (x, y): (usize, usize), size: (usize, usize)) -> (usize, usize) {
+        match self {
+            Orientation::Identity => (x, y),
+            Orientation::FlipHorizontal => (size.0 - 1 - x, y),
+            Orientation::Rotate180 => (size.0 - 1 - x, size.1 - 1 - y),
+            Orientation::FlipVertical => (x, size.1 - 1 - y),
+            Orientation::Transpose => (y, x),
+            Orientation::Rotate90Cw => (size.1 - 1 - y, x),
+            Orientation::AntiTranspose => (size.1 - 1 - y, size.0 - 1 - x),
+            Orientation::Rotate90Ccw => (y, size.0 - 1 - x),
+        }
+    }
+
+    pub fn display_rect(
+        &self,
+        Rect {
+            size: (sx, sy),
+            origin: (ox, oy),
+        }: Rect,
+        size: (usize, usize),
+    ) -> Rect {
+        match self {
+            Orientation::Identity => Rect {
+                origin: (ox, oy),
+                size: (sx, sy),
+            },
+            Orientation::FlipHorizontal => Rect {
+                origin: (size.0 - sx - ox, oy),
+                size: (sx, sy),
+            },
+            Orientation::Rotate180 => Rect {
+                origin: (size.0 - sx - ox, size.1 - sy - oy),
+                size: (sx, sy),
+            },
+            Orientation::FlipVertical => Rect {
+                origin: (ox, size.1 - sy - oy),
+                size: (sx, sy),
+            },
+            Orientation::Transpose => Rect {
+                origin: (oy, ox),
+                size: (sy, sx),
+            },
+            Orientation::Rotate90Cw => Rect {
+                origin: (size.1 - sy - oy, ox),
+                size: (sy, sx),
+            },
+            Orientation::AntiTranspose => Rect {
+                origin: (size.1 - sy - oy, size.0 - sx - ox),
+                size: (sy, sx),
+            },
+            Orientation::Rotate90Ccw => Rect {
+                origin: (oy, size.0 - sx - ox),
+                size: (sy, sx),
+            },
+        }
+    }
+}
+
+#[derive(UnconditionalCoder, Debug, Clone)]
+pub struct Animation {
+    #[coder(u2S(100, 1000, Bits(10) + 1, Bits(30) + 1))]
+    pub tps_numerator: u32,
+    #[coder(u2S(1, 1001, Bits(8) + 1, Bits(10) + 1))]
+    pub tps_denominator: u32,
+    #[coder(u2S(0, Bits(3), Bits(16), Bits(32)))]
+    pub num_loops: u32,
+    pub have_timecodes: bool,
+}
+
+#[derive(UnconditionalCoder, Debug, Clone)]
+#[validate]
+pub struct ToneMapping {
+    #[all_default]
+    pub all_default: bool,
+    #[default(255.0)]
+    pub intensity_target: f32,
+    #[default(0.0)]
+    pub min_nits: f32,
+    #[default(false)]
+    pub relative_to_max_display: bool,
+    #[default(0.0)]
+    pub linear_below: f32,
+}
+
+impl ToneMapping {
+    #[cfg(test)]
+    pub fn empty() -> ToneMapping {
+        ToneMapping {
+            all_default: false,
+            intensity_target: 0f32,
+            min_nits: 0f32,
+            relative_to_max_display: false,
+            linear_below: 0f32,
+        }
+    }
+    pub fn check(&self, _: &Empty) -> Result<(), Error> {
+        if self.intensity_target <= 0.0 {
+            Err(Error::InvalidIntensityTarget(self.intensity_target))
+        } else if self.min_nits < 0.0 || self.min_nits > self.intensity_target {
+            Err(Error::InvalidMinNits(self.min_nits))
+        } else if self.linear_below < 0.0
+            || (self.relative_to_max_display && self.linear_below > 1.0)
+        {
+            Err(Error::InvalidLinearBelow(
+                self.relative_to_max_display,
+                self.linear_below,
+            ))
+        } else {
+            Ok(())
+        }
+    }
+}
+
+// TODO(veluca): figure out if these fields should be unused.
+#[allow(dead_code)]
+#[derive(UnconditionalCoder, Debug, Clone)]
+pub struct ImageMetadata {
+    #[all_default]
+    all_default: bool,
+    #[default(false)]
+    extra_fields: bool,
+    #[condition(extra_fields)]
+    #[default(Orientation::Identity)]
+    #[coder(Bits(3) + 1)]
+    pub orientation: Orientation,
+    #[condition(extra_fields)]
+    #[default(false)]
+    have_intrinsic_size: bool, // TODO(veluca93): fold have_ fields in Option.
+    #[condition(have_intrinsic_size)]
+    pub intrinsic_size: Option<Size>,
+    #[condition(extra_fields)]
+    #[default(false)]
+    have_preview: bool,
+    #[condition(have_preview)]
+    pub preview: Option<Preview>,
+    #[condition(extra_fields)]
+    #[default(false)]
+    have_animation: bool,
+    #[condition(have_animation)]
+    pub animation: Option<Animation>,
+    #[default(BitDepth::default(&field_nonserialized))]
+    pub bit_depth: BitDepth,
+    #[default(true)]
+    pub modular_16bit_sufficient: bool,
+    #[size_coder(implicit(u2S(0, 1, Bits(4) + 2, Bits(12) + 1)))]
+    pub extra_channel_info: Vec<ExtraChannelInfo>,
+    #[default(true)]
+    pub xyb_encoded: bool,
+    #[default(ColorEncoding::default(&field_nonserialized))]
+    pub color_encoding: ColorEncoding,
+    #[condition(extra_fields)]
+    #[default(ToneMapping::default(&field_nonserialized))]
+    pub tone_mapping: ToneMapping,
+    extensions: Option<Extensions>,
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/mod.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/mod.rs
new file mode 100644
index 0000000..f980cd7
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/mod.rs
@@ -0,0 +1,82 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+pub mod bit_depth;
+pub mod color_encoding;
+pub mod encodings;
+pub mod extra_channels;
+pub mod frame_header;
+pub mod image_metadata;
+pub mod modular;
+pub mod permutation;
+pub mod size;
+pub mod toc;
+pub mod transform_data;
+
+use crate::{bit_reader::BitReader, error::Error, headers::encodings::*};
+use frame_header::FrameHeaderNonserialized;
+use jxl_macros::UnconditionalCoder;
+
+pub use image_metadata::*;
+pub use size::Size;
+pub use transform_data::*;
+
+#[derive(UnconditionalCoder, Debug, Clone)]
+pub struct FileHeader {
+    #[allow(dead_code)]
+    signature: Signature,
+    pub size: Size,
+    pub image_metadata: ImageMetadata,
+    #[nonserialized(xyb_encoded : image_metadata.xyb_encoded)]
+    pub transform_data: CustomTransformData,
+}
+
+pub trait JxlHeader
+where
+    Self: Sized,
+{
+    fn read(br: &mut BitReader) -> Result<Self, Error>;
+}
+
+impl<T> JxlHeader for T
+where
+    T: UnconditionalCoder<()>,
+    T::Nonserialized: Default,
+{
+    fn read(br: &mut BitReader) -> Result<Self, Error> {
+        Self::read_unconditional(&(), br, &T::Nonserialized::default())
+    }
+}
+
+impl FileHeader {
+    pub fn frame_header_nonserialized(&self) -> FrameHeaderNonserialized {
+        self.frame_header_nonserialized_with_size(self.size.xsize(), self.size.ysize())
+    }
+
+    pub fn preview_frame_header_nonserialized(&self) -> Option<FrameHeaderNonserialized> {
+        let preview = self.image_metadata.preview.as_ref()?;
+        Some(self.frame_header_nonserialized_with_size(preview.xsize(), preview.ysize()))
+    }
+
+    fn frame_header_nonserialized_with_size(
+        &self,
+        img_width: u32,
+        img_height: u32,
+    ) -> FrameHeaderNonserialized {
+        let have_timecode = match self.image_metadata.animation {
+            Some(ref animation) => animation.have_timecodes,
+            None => false,
+        };
+        FrameHeaderNonserialized {
+            xyb_encoded: self.image_metadata.xyb_encoded,
+            num_extra_channels: self.image_metadata.extra_channel_info.len() as u32,
+            extra_channel_info: self.image_metadata.extra_channel_info.clone(),
+            have_animation: self.image_metadata.animation.is_some(),
+            have_timecode,
+            img_width,
+            img_height,
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/modular.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/modular.rs
new file mode 100644
index 0000000..5ac2709
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/modular.rs
@@ -0,0 +1,166 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{
+    bit_reader::BitReader,
+    error::{Error, Result},
+    frame::modular::Predictor,
+    headers::encodings::*,
+};
+use jxl_macros::UnconditionalCoder;
+use num_derive::FromPrimitive;
+
+use super::encodings;
+
+#[derive(UnconditionalCoder, Debug, PartialEq, Clone)]
+pub struct WeightedHeader {
+    #[all_default]
+    pub all_default: bool,
+
+    #[coder(Bits(5))]
+    #[default(16)]
+    pub p1c: u32,
+
+    #[coder(Bits(5))]
+    #[default(10)]
+    pub p2c: u32,
+
+    #[coder(Bits(5))]
+    #[default(7)]
+    pub p3ca: u32,
+
+    #[coder(Bits(5))]
+    #[default(7)]
+    pub p3cb: u32,
+
+    #[coder(Bits(5))]
+    #[default(7)]
+    pub p3cc: u32,
+
+    #[coder(Bits(5))]
+    #[default(0)]
+    pub p3cd: u32,
+
+    #[coder(Bits(5))]
+    #[default(0)]
+    pub p3ce: u32,
+
+    #[coder(Bits(4))]
+    #[default(0xd)]
+    pub w0: u32,
+
+    #[coder(Bits(4))]
+    #[default(0xc)]
+    pub w1: u32,
+
+    #[coder(Bits(4))]
+    #[default(0xc)]
+    pub w2: u32,
+
+    #[coder(Bits(4))]
+    #[default(0xc)]
+    pub w3: u32,
+}
+
+impl WeightedHeader {
+    pub fn w(&self, i: usize) -> Result<u32> {
+        match i {
+            0 => Ok(self.w0),
+            1 => Ok(self.w1),
+            2 => Ok(self.w2),
+            3 => Ok(self.w3),
+            _ => unreachable!(
+            "WeightedHeader::w called with an out-of-bounds index: {}.
+            This indicates a logical error in the calling code, which should ensure 'i' is within 0..=3.",
+            i),
+        }
+    }
+}
+
+#[derive(UnconditionalCoder, Debug, PartialEq, Clone, Copy)]
+pub struct SqueezeParams {
+    pub horizontal: bool,
+    pub in_place: bool,
+    #[coder(u2S(Bits(3), Bits(6) + 8, Bits(10) + 72, Bits(13) + 1096))]
+    pub begin_channel: u32,
+    #[coder(u2S(1, 2, 3, Bits(4) + 4))]
+    pub num_channels: u32,
+}
+
+#[derive(UnconditionalCoder, Copy, Clone, PartialEq, Debug, FromPrimitive)]
+pub enum TransformId {
+    Rct = 0,
+    Palette = 1,
+    Squeeze = 2,
+    Invalid = 3,
+}
+
+#[derive(UnconditionalCoder, Debug, PartialEq)]
+#[validate]
+pub struct Transform {
+    #[coder(Bits(2))]
+    pub id: TransformId,
+
+    #[condition(id == TransformId::Rct || id == TransformId::Palette)]
+    #[coder(u2S(Bits(3), Bits(6) + 8, Bits(10) + 72, Bits(13) + 1096))]
+    #[default(0)]
+    pub begin_channel: u32,
+
+    #[condition(id == TransformId::Rct)]
+    #[coder(u2S(6, Bits(2), Bits(4) + 2, Bits(6) + 10))]
+    #[default(6)]
+    pub rct_type: u32,
+
+    #[condition(id == TransformId::Palette)]
+    #[coder(u2S(1, 3, 4, Bits(13) + 1))]
+    #[default(3)]
+    pub num_channels: u32,
+
+    #[condition(id == TransformId::Palette)]
+    #[coder(u2S(Bits(8), Bits(10) + 256, Bits(12) + 1280, Bits(16)+5376))]
+    #[default(256)]
+    pub num_colors: u32,
+
+    #[condition(id == TransformId::Palette)]
+    #[coder(u2S(0, Bits(8)+1, Bits(10) + 257, Bits(16)+1281))]
+    #[default(0)]
+    pub num_deltas: u32,
+
+    #[condition(id == TransformId::Palette)]
+    #[coder(Bits(4))]
+    #[default(0)]
+    pub predictor_id: u32,
+
+    #[condition(id == TransformId::Squeeze)]
+    #[size_coder(implicit(u2S(0, Bits(4) + 1, Bits(6) + 9, Bits(8) + 41)))]
+    #[default(Vec::new())]
+    pub squeezes: Vec<SqueezeParams>,
+}
+
+impl Transform {
+    fn check(&self, _: &encodings::Empty) -> Result<()> {
+        if self.id == TransformId::Invalid {
+            return Err(Error::InvalidTransformId);
+        }
+
+        if self.rct_type >= 42 {
+            return Err(Error::InvalidRCT(self.rct_type));
+        }
+
+        if self.predictor_id >= Predictor::NUM_PREDICTORS {
+            return Err(Error::InvalidPredictor(self.predictor_id));
+        }
+
+        Ok(())
+    }
+}
+
+#[derive(UnconditionalCoder, Debug, PartialEq)]
+pub struct GroupHeader {
+    pub use_global_tree: bool,
+    pub wp_header: WeightedHeader,
+    #[size_coder(implicit(u2S(0, 1, Bits(4) + 2, Bits(8) + 18)))]
+    pub transforms: Vec<Transform>,
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/permutation.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/permutation.rs
new file mode 100644
index 0000000..7858e5c
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/permutation.rs
@@ -0,0 +1,340 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::bit_reader::BitReader;
+use crate::entropy_coding::decode::Histograms;
+use crate::entropy_coding::decode::SymbolReader;
+use crate::error::{Error, Result};
+use crate::util::{CeilLog2, NewWithCapacity, tracing_wrappers::instrument, value_of_lowest_1_bit};
+
+#[derive(Debug, PartialEq, Default)]
+pub struct Permutation(pub Vec<u32>);
+
+impl std::ops::Deref for Permutation {
+    type Target = [u32];
+
+    fn deref(&self) -> &[u32] {
+        &self.0
+    }
+}
+
+impl Permutation {
+    /// Decode a permutation from entropy-coded stream.
+    pub fn decode(
+        size: u32,
+        skip: u32,
+        histograms: &Histograms,
+        br: &mut BitReader,
+        entropy_reader: &mut SymbolReader,
+    ) -> Result<Self> {
+        let end = entropy_reader.read_unsigned(histograms, br, get_context(size));
+        Self::decode_inner(size, skip, end, |ctx| {
+            entropy_reader.read_unsigned(histograms, br, ctx)
+        })
+    }
+
+    fn decode_inner(
+        size: u32,
+        skip: u32,
+        end: u32,
+        mut read: impl FnMut(usize) -> u32,
+    ) -> Result<Self> {
+        if end > size - skip {
+            return Err(Error::InvalidPermutationSize { size, skip, end });
+        }
+
+        let mut lehmer = Vec::new_with_capacity(end as usize)?;
+
+        let mut prev_val = 0u32;
+        for idx in skip..(skip + end) {
+            let val = read(get_context(prev_val));
+            if val >= size - idx {
+                return Err(Error::InvalidPermutationLehmerCode {
+                    size,
+                    idx,
+                    lehmer: val,
+                });
+            }
+            lehmer.push(val);
+            prev_val = val;
+        }
+
+        // Initialize the full permutation vector with skipped elements intact
+        let mut permutation = Vec::new_with_capacity((size - skip) as usize)?;
+        permutation.extend(0..size);
+
+        // Decode the Lehmer code into the slice starting at `skip`
+        let permuted_slice = decode_lehmer_code(&lehmer, &permutation[skip as usize..])?;
+
+        // Replace the target slice in `permutation`
+        permutation[skip as usize..].copy_from_slice(&permuted_slice);
+
+        // Ensure the permutation has the correct size
+        assert_eq!(permutation.len(), size as usize);
+
+        Ok(Self(permutation))
+    }
+
+    pub fn compose(&mut self, other: &Permutation) {
+        assert_eq!(self.0.len(), other.0.len());
+        let mut tmp: Vec<u32> = vec![0; self.0.len()];
+        for (i, val) in tmp.iter_mut().enumerate().take(self.0.len()) {
+            *val = self.0[other.0[i] as usize]
+        }
+        self.0.copy_from_slice(&tmp[..]);
+    }
+}
+
+// Decodes the Lehmer code in `code` and returns the permuted slice.
+#[instrument(level = "debug", ret, err)]
+fn decode_lehmer_code(code: &[u32], permutation_slice: &[u32]) -> Result<Vec<u32>> {
+    let n = permutation_slice.len();
+    if n == 0 {
+        return Err(Error::InvalidPermutationLehmerCode {
+            size: 0,
+            idx: 0,
+            lehmer: 0,
+        });
+    }
+
+    let mut permuted = Vec::new_with_capacity(n)?;
+    permuted.extend_from_slice(permutation_slice);
+
+    let padded_n = (n as u32).next_power_of_two() as usize;
+
+    // Allocate temp array inside the function
+    let mut temp = Vec::new_with_capacity(padded_n)?;
+    temp.extend((0..padded_n as u32).map(|x| value_of_lowest_1_bit(x + 1)));
+
+    for (i, permuted_item) in permuted.iter_mut().enumerate() {
+        let code_i = *code.get(i).unwrap_or(&0);
+
+        // Adjust the maximum allowed value for code_i
+        if code_i as usize > n - i - 1 {
+            return Err(Error::InvalidPermutationLehmerCode {
+                size: n as u32,
+                idx: i as u32,
+                lehmer: code_i,
+            });
+        }
+
+        let mut rank = code_i + 1;
+
+        // Extract i-th unused element via implicit order-statistics tree.
+        let mut bit = padded_n;
+        let mut next = 0usize;
+        while bit != 0 {
+            let cand = next + bit;
+            if cand == 0 || cand > padded_n {
+                return Err(Error::InvalidPermutationLehmerCode {
+                    size: n as u32,
+                    idx: i as u32,
+                    lehmer: code_i,
+                });
+            }
+            bit >>= 1;
+            if temp[cand - 1] < rank {
+                next = cand;
+                rank -= temp[cand - 1];
+            }
+        }
+
+        *permuted_item = permutation_slice[next];
+
+        next += 1;
+        while next <= padded_n {
+            temp[next - 1] -= 1;
+            next += value_of_lowest_1_bit(next as u32) as usize;
+        }
+    }
+
+    Ok(permuted)
+}
+
+// Decodes the Lehmer code in `code` and returns the permuted vector.
+#[cfg(test)]
+fn decode_lehmer_code_naive(code: &[u32], permutation_slice: &[u32]) -> Result<Vec<u32>> {
+    let n = code.len();
+    if n == 0 {
+        return Err(Error::InvalidPermutationLehmerCode {
+            size: 0,
+            idx: 0,
+            lehmer: 0,
+        });
+    }
+
+    // Ensure permutation_slice has sufficient length
+    if permutation_slice.len() < n {
+        return Err(Error::InvalidPermutationLehmerCode {
+            size: n as u32,
+            idx: 0,
+            lehmer: 0,
+        });
+    }
+
+    // Create temp array with values from permutation_slice
+    let mut temp = permutation_slice.to_vec();
+    let mut permuted = Vec::new_with_capacity(n)?;
+
+    // Iterate over the Lehmer code
+    for (i, &idx) in code.iter().enumerate() {
+        if idx as usize >= temp.len() {
+            return Err(Error::InvalidPermutationLehmerCode {
+                size: n as u32,
+                idx: i as u32,
+                lehmer: idx,
+            });
+        }
+
+        // Assign temp[idx] to permuted vector
+        permuted.push(temp.remove(idx as usize));
+    }
+
+    // Append any remaining elements from temp to permuted
+    permuted.extend(temp);
+
+    Ok(permuted)
+}
+
+fn get_context(x: u32) -> usize {
+    (x + 1).ceil_log2().min(7) as usize
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use arbtest::arbitrary::{self, Arbitrary, Unstructured};
+    use core::assert_eq;
+    use test_log::test;
+
+    #[test]
+    fn generate_permutation_arbtest() {
+        arbtest::arbtest(|u| {
+            let input = PermutationInput::arbitrary(u)?;
+
+            let permutation_slice = input.permutation.as_slice();
+
+            let perm1 = decode_lehmer_code(&input.code, permutation_slice);
+            let perm2 = decode_lehmer_code_naive(&input.code, permutation_slice);
+
+            assert_eq!(
+                perm1.map_err(|x| x.to_string()),
+                perm2.map_err(|x| x.to_string())
+            );
+            Ok(())
+        });
+    }
+
+    #[derive(Debug)]
+    struct PermutationInput {
+        code: Vec<u32>,
+        permutation: Vec<u32>,
+    }
+
+    impl<'a> Arbitrary<'a> for PermutationInput {
+        fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self, arbitrary::Error> {
+            // Generate a reasonable size to prevent tests from taking too long
+            let size_lehmer = u.int_in_range(1..=1000)?;
+
+            let mut lehmer: Vec<u32> = Vec::with_capacity(size_lehmer as usize);
+            for i in 0..size_lehmer {
+                let max_val = size_lehmer - i - 1;
+                let val = if max_val > 0 {
+                    u.int_in_range(0..=max_val)?
+                } else {
+                    0
+                };
+                lehmer.push(val);
+            }
+
+            let mut permutation = Vec::new();
+            let size_permutation = u.int_in_range(size_lehmer..=1000)?;
+            permutation.extend(0..size_permutation);
+
+            let num_of_swaps = u.int_in_range(0..=100)?;
+            for _ in 0..num_of_swaps {
+                // Randomly swap two positions
+                let pos1 = u.int_in_range(0..=size_permutation - 1)?;
+                let pos2 = u.int_in_range(0..=size_permutation - 1)?;
+                permutation.swap(pos1 as usize, pos2 as usize);
+            }
+
+            Ok(PermutationInput {
+                code: lehmer,
+                permutation,
+            })
+        }
+    }
+
+    #[test]
+    fn simple() {
+        // Lehmer code: [1, 1, 2, 3, 3, 6, 0, 1]
+        let code = vec![1u32, 1, 2, 3, 3, 6, 0, 1];
+        let skip = 4;
+        let size = 16;
+
+        let permutation_slice: Vec<u32> = (skip..size).collect();
+
+        let permuted = decode_lehmer_code(&code, &permutation_slice).unwrap();
+        let permuted_naive = decode_lehmer_code_naive(&code, &permutation_slice).unwrap();
+
+        let mut permutation = Vec::with_capacity(size as usize);
+        permutation.extend(0..skip); // Add skipped elements
+        permutation.extend(permuted.iter());
+        let expected_permutation = vec![0, 1, 2, 3, 5, 6, 8, 10, 11, 15, 4, 9, 7, 12, 13, 14];
+
+        assert_eq!(permutation, expected_permutation);
+        assert_eq!(permuted, permuted_naive);
+    }
+
+    #[test]
+    fn decode_lehmer_compare_different_length() -> Result<(), Box<dyn std::error::Error>> {
+        // Lehmer code: [1, 1, 2, 3, 3, 6, 0, 1]
+        let code = vec![1u32, 1, 2, 3, 3, 6, 0, 1];
+        let skip = 4;
+        let size = 16;
+
+        let permutation_slice: Vec<u32> = (skip..size).collect();
+
+        let permuted_optimized = decode_lehmer_code(&code, &permutation_slice)?;
+        let permuted_naive = decode_lehmer_code_naive(&code, &permutation_slice)?;
+
+        let expected_permuted = vec![5u32, 6, 8, 10, 11, 15, 4, 9, 7, 12, 13, 14];
+
+        assert_eq!(permuted_optimized, expected_permuted);
+        assert_eq!(permuted_naive, expected_permuted);
+        assert_eq!(permuted_optimized, permuted_naive);
+
+        Ok(())
+    }
+
+    #[test]
+    fn decode_lehmer_compare_same_length() -> Result<(), Box<dyn std::error::Error>> {
+        // Lehmer code: [2, 3, 0, 0, 0]
+        let code = vec![2u32, 3, 0, 0, 0];
+        let n = code.len();
+        let permutation_slice: Vec<u32> = (0..n as u32).collect();
+
+        let permuted_optimized = decode_lehmer_code(&code, &permutation_slice)?;
+        let permuted_naive = decode_lehmer_code_naive(&code, &permutation_slice)?;
+
+        let expected_permutation = vec![2u32, 4, 0, 1, 3];
+
+        assert_eq!(permuted_optimized, expected_permutation);
+        assert_eq!(permuted_naive, expected_permutation);
+        assert_eq!(permuted_optimized, permuted_naive);
+
+        Ok(())
+    }
+
+    #[test]
+    fn lehmer_out_of_bounds() {
+        let code = vec![4];
+        let permutation_slice: Vec<u32> = (4..8).collect();
+
+        let result = decode_lehmer_code(&code, &permutation_slice);
+        assert!(result.is_err());
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/size.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/size.rs
new file mode 100644
index 0000000..108c4e7
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/size.rs
@@ -0,0 +1,112 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{bit_reader::BitReader, error::Error, headers::encodings::*};
+use jxl_macros::UnconditionalCoder;
+use num_derive::FromPrimitive;
+
+#[derive(UnconditionalCoder, Copy, Clone, PartialEq, Debug, FromPrimitive, Default)]
+enum AspectRatio {
+    #[default]
+    Unknown = 0,
+    Ratio1Over1 = 1,
+    Ratio12Over10 = 2,
+    Ratio4Over3 = 3,
+    Ratio3Over2 = 4,
+    Ratio16Over9 = 5,
+    Ratio5Over4 = 6,
+    Ratio2Over1 = 7,
+}
+
+#[derive(UnconditionalCoder, Debug, Clone, Default)]
+pub struct Size {
+    small: bool,
+    #[condition(small)]
+    #[coder(Bits(5) + 1)]
+    ysize_div8: Option<u32>,
+    #[condition(!small)]
+    #[coder(1 + u2S(Bits(9), Bits(13), Bits(18), Bits(30)))]
+    ysize: Option<u32>,
+    #[coder(Bits(3))]
+    ratio: AspectRatio,
+    #[condition(small && ratio == AspectRatio::Unknown)]
+    #[coder(Bits(5) + 1)]
+    xsize_div8: Option<u32>,
+    #[condition(!small && ratio == AspectRatio::Unknown)]
+    #[coder(1 + u2S(Bits(9), Bits(13), Bits(18), Bits(30)))]
+    xsize: Option<u32>,
+}
+
+#[derive(UnconditionalCoder, Debug, Clone)]
+pub struct Preview {
+    div8: bool,
+    #[condition(div8)]
+    #[coder(u2S(16, 32, Bits(5) + 1, Bits(9) + 33))]
+    ysize_div8: Option<u32>,
+    #[condition(!div8)]
+    #[coder(1 + u2S(Bits(6), Bits(8) + 64, Bits(10) + 320, Bits(12) + 1344))]
+    ysize: Option<u32>,
+    #[coder(Bits(3))]
+    ratio: AspectRatio,
+    #[condition(div8 && ratio == AspectRatio::Unknown)]
+    #[coder(u2S(16, 32, Bits(5) + 1, Bits(9) + 33))]
+    xsize_div8: Option<u32>,
+    #[condition(!div8 && ratio == AspectRatio::Unknown)]
+    #[coder(1 + u2S(Bits(6), Bits(8) + 64, Bits(10) + 320, Bits(12) + 1344))]
+    xsize: Option<u32>,
+}
+
+fn map_aspect_ratio<T: Fn() -> u32>(ysize: u32, ratio: AspectRatio, fallback: T) -> u32 {
+    match ratio {
+        AspectRatio::Unknown => fallback(),
+        AspectRatio::Ratio1Over1 => ysize,
+        AspectRatio::Ratio12Over10 => (ysize as u64 * 12 / 10) as u32,
+        AspectRatio::Ratio4Over3 => (ysize as u64 * 4 / 3) as u32,
+        AspectRatio::Ratio3Over2 => (ysize as u64 * 3 / 2) as u32,
+        AspectRatio::Ratio16Over9 => (ysize as u64 * 16 / 9) as u32,
+        AspectRatio::Ratio5Over4 => (ysize as u64 * 5 / 4) as u32,
+        AspectRatio::Ratio2Over1 => ysize * 2,
+    }
+}
+
+impl Size {
+    pub fn ysize(&self) -> u32 {
+        if self.small {
+            self.ysize_div8.unwrap() * 8
+        } else {
+            self.ysize.unwrap()
+        }
+    }
+
+    pub fn xsize(&self) -> u32 {
+        map_aspect_ratio(self.ysize(), self.ratio, /* fallback */ || {
+            if self.small {
+                self.xsize_div8.unwrap() * 8
+            } else {
+                self.xsize.unwrap()
+            }
+        })
+    }
+}
+
+impl Preview {
+    pub fn ysize(&self) -> u32 {
+        if self.div8 {
+            self.ysize_div8.unwrap() * 8
+        } else {
+            self.ysize.unwrap()
+        }
+    }
+
+    pub fn xsize(&self) -> u32 {
+        map_aspect_ratio(self.ysize(), self.ratio, /* fallback */ || {
+            if self.div8 {
+                self.xsize_div8.unwrap() * 8
+            } else {
+                self.xsize.unwrap()
+            }
+        })
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/toc.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/toc.rs
new file mode 100644
index 0000000..eecbe8e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/toc.rs
@@ -0,0 +1,172 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use jxl_macros::UnconditionalCoder;
+
+use crate::{
+    bit_reader::BitReader,
+    error::{Error, Result},
+    headers::{encodings::*, frame_header::PermutationNonserialized},
+};
+
+use super::permutation::Permutation;
+
+pub struct TocNonserialized {
+    pub num_entries: u32,
+}
+
+#[derive(UnconditionalCoder, Debug, PartialEq)]
+#[nonserialized(TocNonserialized)]
+pub struct Toc {
+    #[default(false)]
+    pub permuted: bool,
+
+    // Here we don't use `condition(permuted)`, because `jump_to_byte_boundary` needs to be executed in both cases
+    #[default(Permutation::default())]
+    #[nonserialized(num_entries: nonserialized.num_entries, permuted: permuted)]
+    pub permutation: Permutation,
+
+    #[coder(u2S(Bits(10), Bits(14) + 1024, Bits(22) + 17408, Bits(30) + 4211712))]
+    #[size_coder(explicit(nonserialized.num_entries))]
+    pub entries: Vec<u32>,
+}
+
+#[derive(Debug)]
+pub struct IncrementalTocReader {
+    num_entries: u32,
+    permuted: bool,
+    permutation: Option<Permutation>,
+    entries: Vec<u32>,
+}
+
+impl IncrementalTocReader {
+    pub fn new(num_entries: u32, br: &mut BitReader) -> Result<Self> {
+        let permuted = bool::read_unconditional(&(), br, &Empty {})?;
+        let mut entries = Vec::new();
+        entries.try_reserve(num_entries as usize)?;
+        Ok(Self {
+            num_entries,
+            permuted,
+            permutation: None,
+            entries,
+        })
+    }
+
+    pub fn num_read_entries(&self) -> u32 {
+        self.entries.len() as u32
+    }
+
+    pub fn remaining_entries(&self) -> u32 {
+        self.num_entries - self.entries.len() as u32
+    }
+
+    pub fn is_complete(&self) -> bool {
+        self.permutation.is_some() && self.remaining_entries() == 0
+    }
+
+    pub fn read_step(&mut self, br: &mut BitReader) -> Result<()> {
+        if self.permutation.is_none() {
+            return self.read_permutation(br);
+        }
+
+        let entry_coder = U32Coder::Select(
+            U32::Bits(10),
+            U32::BitsOffset { n: 14, off: 1024 },
+            U32::BitsOffset { n: 22, off: 17408 },
+            U32::BitsOffset {
+                n: 30,
+                off: 4211712,
+            },
+        );
+        let entry = u32::read_unconditional(&entry_coder, br, &Empty {})?;
+        self.entries.push(entry);
+        Ok(())
+    }
+
+    fn read_permutation(&mut self, br: &mut BitReader) -> Result<()> {
+        let permutation = Permutation::read_unconditional(
+            &(),
+            br,
+            &PermutationNonserialized {
+                num_entries: self.num_entries,
+                permuted: self.permuted,
+            },
+        )?;
+        self.permutation = Some(permutation);
+        Ok(())
+    }
+
+    pub fn finalize(self) -> Toc {
+        assert!(self.is_complete());
+        let permutation = self.permutation.unwrap();
+        Toc {
+            permuted: self.permuted,
+            permutation,
+            entries: self.entries,
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use std::ops::ControlFlow;
+
+    use test_log::test;
+
+    use super::*;
+
+    #[test]
+    fn parse_arb() {
+        arbtest::arbtest(|u| {
+            // Not permuted
+            let mut bytes = vec![0u8];
+            let mut buf = 0u64;
+            let mut buf_bits = 0u32;
+            let mut num_entries = 0u32;
+
+            u.arbitrary_loop(Some(1), Some(256), |u| {
+                let selector = u.int_in_range(0..=3)?;
+                let bits = match selector {
+                    0 => 10,
+                    1 => 14,
+                    2 => 22,
+                    _ => 30,
+                };
+                let val = u.int_in_range(0u64..=((1 << bits) - 1))?;
+                let val = (val << 2) | selector as u64;
+
+                buf |= val << buf_bits;
+                buf_bits += bits + 2;
+                if buf_bits >= 32 {
+                    let bytes_to_add = (buf as u32).to_le_bytes();
+                    bytes.extend_from_slice(&bytes_to_add);
+                    buf >>= 32;
+                    buf_bits -= 32;
+                }
+
+                num_entries += 1;
+                Ok(ControlFlow::Continue(()))
+            })?;
+            if buf_bits > 0 {
+                let bytes_to_add = (buf as u32).to_le_bytes();
+                bytes.extend_from_slice(&bytes_to_add);
+            }
+
+            let mut br = BitReader::new(&bytes);
+            let expected =
+                Toc::read_unconditional(&(), &mut br, &TocNonserialized { num_entries }).unwrap();
+
+            let mut br = BitReader::new(&bytes);
+            let mut parser = IncrementalTocReader::new(num_entries, &mut br).unwrap();
+            while !parser.is_complete() {
+                parser.read_step(&mut br).unwrap();
+            }
+            let actual = parser.finalize();
+
+            assert_eq!(actual, expected);
+            Ok(())
+        });
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/transform_data.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/transform_data.rs
new file mode 100644
index 0000000..f22e649
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/transform_data.rs
@@ -0,0 +1,342 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(clippy::excessive_precision)]
+
+use crate::{bit_reader::BitReader, error::Error, headers::encodings::*};
+use jxl_macros::UnconditionalCoder;
+#[derive(Default)]
+pub struct CustomTransformDataNonserialized {
+    pub xyb_encoded: bool,
+}
+
+#[derive(UnconditionalCoder, Debug, Clone)]
+pub struct OpsinInverseMatrix {
+    // We never read the all_default field.
+    #[allow(dead_code)]
+    #[all_default]
+    all_default: bool,
+    #[default([11.031566901960783, -9.866943921568629, -0.16462299647058826,
+               -3.254147380392157,  4.418770392156863,  -0.16462299647058826,
+               -3.6588512862745097, 2.7129230470588235, 1.9459282392156863])]
+    pub inverse_matrix: [f32; 9],
+    #[default([-0.0037930732552754493; 3])]
+    pub opsin_biases: [f32; 3],
+    #[default([1.0 - 0.05465007330715401, 1.0 - 0.07005449891748593, 1.0 - 0.049935103337343655, 0.145])]
+    pub quant_biases: [f32; 4],
+}
+
+const DEFAULT_KERN_2: [f32; 15] = [
+    -0.01716200,
+    -0.03452303,
+    -0.04022174,
+    -0.02921014,
+    -0.00624645,
+    0.14111091,
+    0.28896755,
+    0.00278718,
+    -0.01610267,
+    0.56661550,
+    0.03777607,
+    -0.01986694,
+    -0.03144731,
+    -0.01185068,
+    -0.00213539,
+];
+
+const DEFAULT_KERN_4: [f32; 55] = [
+    -0.02419067,
+    -0.03491987,
+    -0.03693351,
+    -0.03094285,
+    -0.00529785,
+    -0.01663432,
+    -0.03556863,
+    -0.03888905,
+    -0.03516850,
+    -0.00989469,
+    0.23651958,
+    0.33392945,
+    -0.01073543,
+    -0.01313181,
+    -0.03556694,
+    0.13048175,
+    0.40103025,
+    0.03951150,
+    -0.02077584,
+    0.46914198,
+    -0.00209270,
+    -0.01484589,
+    -0.04064806,
+    0.18942530,
+    0.56279892,
+    0.06674400,
+    -0.02335494,
+    -0.03551682,
+    -0.00754830,
+    -0.02267919,
+    -0.02363578,
+    0.00315804,
+    -0.03399098,
+    -0.01359519,
+    -0.00091653,
+    -0.00335467,
+    -0.01163294,
+    -0.01610294,
+    -0.00974088,
+    -0.00191622,
+    -0.01095446,
+    -0.03198464,
+    -0.04455121,
+    -0.02799790,
+    -0.00645912,
+    0.06390599,
+    0.22963888,
+    0.00630981,
+    -0.01897349,
+    0.67537268,
+    0.08483369,
+    -0.02534994,
+    -0.02205197,
+    -0.01667999,
+    -0.00384443,
+];
+
+const DEFAULT_KERN_8: [f32; 210] = [
+    -0.02928613,
+    -0.03706353,
+    -0.03783812,
+    -0.03324558,
+    -0.00447632,
+    -0.02519406,
+    -0.03752601,
+    -0.03901508,
+    -0.03663285,
+    -0.00646649,
+    -0.02066407,
+    -0.03838633,
+    -0.04002101,
+    -0.03900035,
+    -0.00901973,
+    -0.01626393,
+    -0.03954148,
+    -0.04046620,
+    -0.03979621,
+    -0.01224485,
+    0.29895328,
+    0.35757708,
+    -0.02447552,
+    -0.01081748,
+    -0.04314594,
+    0.23903219,
+    0.41119301,
+    -0.00573046,
+    -0.01450239,
+    -0.04246845,
+    0.17567618,
+    0.45220643,
+    0.02287757,
+    -0.01936783,
+    -0.03583255,
+    0.11572472,
+    0.47416733,
+    0.06284440,
+    -0.02685066,
+    0.42720050,
+    -0.02248939,
+    -0.01155273,
+    -0.04562755,
+    0.28689496,
+    0.49093869,
+    -0.00007891,
+    -0.01545926,
+    -0.04562659,
+    0.21238920,
+    0.53980934,
+    0.03369474,
+    -0.02070211,
+    -0.03866988,
+    0.14229550,
+    0.56593398,
+    0.08045181,
+    -0.02888298,
+    -0.03680918,
+    -0.00542229,
+    -0.02920477,
+    -0.02788574,
+    -0.02118180,
+    -0.03942402,
+    -0.00775547,
+    -0.02433614,
+    -0.03193943,
+    -0.02030828,
+    -0.04044014,
+    -0.01074016,
+    -0.01930822,
+    -0.03620399,
+    -0.01974125,
+    -0.03919545,
+    -0.01456093,
+    -0.00045072,
+    -0.00360110,
+    -0.01020207,
+    -0.01231907,
+    -0.00638988,
+    -0.00071592,
+    -0.00279122,
+    -0.00957115,
+    -0.01288327,
+    -0.00730937,
+    -0.00107783,
+    -0.00210156,
+    -0.00890705,
+    -0.01317668,
+    -0.00813895,
+    -0.00153491,
+    -0.02128481,
+    -0.04173044,
+    -0.04831487,
+    -0.03293190,
+    -0.00525260,
+    -0.01720322,
+    -0.04052736,
+    -0.05045706,
+    -0.03607317,
+    -0.00738030,
+    -0.01341764,
+    -0.03965629,
+    -0.05151616,
+    -0.03814886,
+    -0.01005819,
+    0.18968273,
+    0.33063684,
+    -0.01300105,
+    -0.01372950,
+    -0.04017465,
+    0.13727832,
+    0.36402234,
+    0.01027890,
+    -0.01832107,
+    -0.03365072,
+    0.08734506,
+    0.38194295,
+    0.04338228,
+    -0.02525993,
+    0.56408126,
+    0.00458352,
+    -0.01648227,
+    -0.04887868,
+    0.24585519,
+    0.62026135,
+    0.04314807,
+    -0.02213737,
+    -0.04158014,
+    0.16637289,
+    0.65027023,
+    0.09621636,
+    -0.03101388,
+    -0.04082742,
+    -0.00904519,
+    -0.02790922,
+    -0.02117818,
+    0.00798662,
+    -0.03995711,
+    -0.01243427,
+    -0.02231705,
+    -0.02946266,
+    0.00992055,
+    -0.03600283,
+    -0.01684920,
+    -0.00111684,
+    -0.00411204,
+    -0.01297130,
+    -0.01723725,
+    -0.01022545,
+    -0.00165306,
+    -0.00313110,
+    -0.01218016,
+    -0.01763266,
+    -0.01125620,
+    -0.00231663,
+    -0.01374149,
+    -0.03797620,
+    -0.05142937,
+    -0.03117307,
+    -0.00581914,
+    -0.01064003,
+    -0.03608089,
+    -0.05272168,
+    -0.03375670,
+    -0.00795586,
+    0.09628104,
+    0.27129991,
+    -0.00353779,
+    -0.01734151,
+    -0.03153981,
+    0.05686230,
+    0.28500998,
+    0.02230594,
+    -0.02374955,
+    0.68214326,
+    0.05018048,
+    -0.02320852,
+    -0.04383616,
+    0.18459474,
+    0.71517975,
+    0.10805613,
+    -0.03263677,
+    -0.03637639,
+    -0.01394373,
+    -0.02511203,
+    -0.01728636,
+    0.05407331,
+    -0.02867568,
+    -0.01893131,
+    -0.00240854,
+    -0.00446511,
+    -0.01636187,
+    -0.02377053,
+    -0.01522848,
+    -0.00333334,
+    -0.00819975,
+    -0.02964169,
+    -0.04499287,
+    -0.02745350,
+    -0.00612408,
+    0.02727416,
+    0.19446600,
+    0.00159832,
+    -0.02232473,
+    0.74982506,
+    0.11452620,
+    -0.03348048,
+    -0.01605681,
+    -0.02070339,
+    -0.00458223,
+];
+
+// TODO(firsching): remove once we use this!
+#[allow(dead_code)]
+#[derive(UnconditionalCoder, Debug, Clone)]
+#[nonserialized(CustomTransformDataNonserialized)]
+pub struct CustomTransformData {
+    #[all_default]
+    all_default: bool,
+    #[condition(nonserialized.xyb_encoded)]
+    #[default(OpsinInverseMatrix::default(&field_nonserialized))]
+    pub opsin_inverse_matrix: OpsinInverseMatrix,
+    #[default(0)]
+    #[coder(Bits(3))]
+    custom_weight_mask: u32,
+    #[condition((custom_weight_mask & 1) != 0)]
+    #[default(DEFAULT_KERN_2)]
+    pub weights2: [f32; 15],
+    #[condition((custom_weight_mask & 2) != 0)]
+    #[default(DEFAULT_KERN_4)]
+    pub weights4: [f32; 55],
+    #[condition((custom_weight_mask & 4) != 0)]
+    #[default(DEFAULT_KERN_8)]
+    pub weights8: [f32; 210],
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/icc/header.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/icc/header.rs
new file mode 100644
index 0000000..996dc954c
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/icc/header.rs
@@ -0,0 +1,51 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{error::Result, util::NewWithCapacity};
+
+use super::{ICC_HEADER_SIZE, IccStream};
+
+fn predict_header(idx: usize, output_size: u32, header: &[u8]) -> u8 {
+    match idx {
+        0..=3 => output_size.to_be_bytes()[idx],
+        8 => 4,
+        12..=23 => b"mntrRGB XYZ "[idx - 12],
+        36..=39 => b"acsp"[idx - 36],
+        // APPL
+        41 | 42 if header[40] == b'A' => b'P',
+        43 if header[40] == b'A' => b'L',
+        // MSFT
+        41 if header[40] == b'M' => b'S',
+        42 if header[40] == b'M' => b'F',
+        43 if header[40] == b'M' => b'T',
+        // SGI_
+        42 if header[40] == b'S' && header[41] == b'G' => b'I',
+        43 if header[40] == b'S' && header[41] == b'G' => b' ',
+        // SUNW
+        42 if header[40] == b'S' && header[41] == b'U' => b'N',
+        43 if header[40] == b'S' && header[41] == b'U' => b'W',
+        70 => 246,
+        71 => 214,
+        73 => 1,
+        78 => 211,
+        79 => 45,
+        80..=83 => header[4 + idx - 80],
+        _ => 0,
+    }
+}
+
+pub(super) fn read_header(data_stream: &mut IccStream, output_size: u64) -> Result<Vec<u8>> {
+    let header_size = output_size.min(ICC_HEADER_SIZE);
+    let header_data = data_stream.read_to_vec_exact(header_size as usize)?;
+
+    let mut profile = Vec::new_with_capacity(output_size as usize)?;
+
+    for (idx, &e) in header_data.iter().enumerate() {
+        let p = predict_header(idx, output_size as u32, &header_data);
+        profile.push(p.wrapping_add(e));
+    }
+
+    Ok(profile)
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/icc/mod.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/icc/mod.rs
new file mode 100644
index 0000000..8144607
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/icc/mod.rs
@@ -0,0 +1,208 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::io::Cursor;
+
+use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
+
+use crate::bit_reader::*;
+use crate::entropy_coding::decode::Histograms;
+use crate::entropy_coding::decode::SymbolReader;
+use crate::error::{Error, Result};
+use crate::headers::encodings::*;
+use crate::util::NewWithCapacity;
+use crate::util::tracing_wrappers::warn;
+
+mod header;
+mod stream;
+mod tag;
+
+use header::read_header;
+use stream::{IccStream, read_varint_from_reader};
+use tag::{read_single_command, read_tag_list};
+
+const ICC_CONTEXTS: usize = 41;
+const ICC_HEADER_SIZE: u64 = 128;
+
+fn read_icc_inner(stream: &mut IccStream) -> Result<Vec<u8>, Error> {
+    let output_size = stream.read_varint()?;
+    let commands_size = stream.read_varint()?;
+    if stream.bytes_read().saturating_add(commands_size) > stream.len() {
+        return Err(Error::InvalidIccStream);
+    }
+
+    // Simple check to avoid allocating too large buffer.
+    if output_size > (1 << 28) {
+        return Err(Error::IccTooLarge);
+    }
+
+    if output_size + 65536 < stream.len() {
+        return Err(Error::IccTooLarge);
+    }
+
+    // Extract command stream first.
+    let commands = stream.read_to_vec_exact(commands_size as usize)?;
+    let mut commands_stream = Cursor::new(commands);
+    // `stream` contains data stream from here.
+    let data_stream = stream;
+
+    // Decode ICC profile header.
+    let mut decoded_profile = read_header(data_stream, output_size)?;
+    if output_size <= ICC_HEADER_SIZE {
+        return Ok(decoded_profile);
+    }
+
+    // Convert to slice writer to prevent buffer from growing.
+    // `read_header` above returns buffer with capacity of `output_size`, so this doesn't realloc.
+    debug_assert_eq!(decoded_profile.capacity(), output_size as usize);
+    decoded_profile.resize(output_size as usize, 0);
+    let mut decoded_profile_writer = Cursor::new(&mut *decoded_profile);
+    decoded_profile_writer.set_position(ICC_HEADER_SIZE);
+
+    // Decode tag list.
+    let v = read_varint_from_reader(&mut commands_stream)?;
+    if let Some(num_tags) = v.checked_sub(1) {
+        if (output_size - ICC_HEADER_SIZE) / 12 < num_tags {
+            warn!(output_size, num_tags, "num_tags too large");
+            return Err(Error::InvalidIccStream);
+        }
+
+        let num_tags = num_tags as u32;
+        decoded_profile_writer
+            .write_u32::<BigEndian>(num_tags)
+            .map_err(|_| Error::InvalidIccStream)?;
+
+        read_tag_list(
+            data_stream,
+            &mut commands_stream,
+            &mut decoded_profile_writer,
+            num_tags,
+            output_size,
+        )?;
+    }
+
+    // Decode tag data.
+    // Will not enter the loop if end of stream was reached while decoding tag list.
+    while let Ok(command) = commands_stream.read_u8() {
+        read_single_command(
+            data_stream,
+            &mut commands_stream,
+            &mut decoded_profile_writer,
+            command,
+        )?;
+    }
+
+    // Validate output size.
+    let actual_len = decoded_profile_writer.position();
+    if actual_len != output_size {
+        warn!(output_size, actual_len, "ICC profile size mismatch");
+        return Err(Error::InvalidIccStream);
+    }
+
+    Ok(decoded_profile)
+}
+
+/// Struct to incrementally decode an ICC profile.
+pub struct IncrementalIccReader {
+    histograms: Histograms,
+    reader: SymbolReader,
+    out_buf: Vec<u8>,
+    len: usize,
+    // [prev, prev_prev]
+    prev_bytes: [u8; 2],
+}
+
+impl IncrementalIccReader {
+    pub fn new(br: &mut BitReader) -> Result<Self> {
+        let len = u64::read_unconditional(&(), br, &Empty {})?;
+        if len > 1u64 << 20 {
+            return Err(Error::IccTooLarge);
+        }
+
+        let len = len as usize;
+
+        let histograms = Histograms::decode(ICC_CONTEXTS, br, true)?;
+        let reader = SymbolReader::new(&histograms, br, None)?;
+        Ok(Self {
+            histograms,
+            reader,
+            len,
+            out_buf: Vec::new_with_capacity(len)?,
+            prev_bytes: [0, 0],
+        })
+    }
+
+    fn get_icc_ctx(&self) -> u32 {
+        if self.out_buf.len() <= ICC_HEADER_SIZE as usize {
+            return 0;
+        }
+
+        let [b1, b2] = self.prev_bytes;
+
+        let p1 = match b1 {
+            b'a'..=b'z' | b'A'..=b'Z' => 0,
+            b'0'..=b'9' | b'.' | b',' => 1,
+            0..=1 => 2 + b1 as u32,
+            2..=15 => 4,
+            241..=254 => 5,
+            255 => 6,
+            _ => 7,
+        };
+        let p2 = match b2 {
+            b'a'..=b'z' | b'A'..=b'Z' => 0,
+            b'0'..=b'9' | b'.' | b',' => 1,
+            0..=15 => 2,
+            241..=255 => 3,
+            _ => 4,
+        };
+
+        1 + p1 + 8 * p2
+    }
+
+    pub fn num_coded_bytes(&self) -> usize {
+        self.len
+    }
+
+    pub fn remaining(&self) -> usize {
+        assert!(self.num_coded_bytes() >= self.out_buf.len());
+        self.num_coded_bytes() - self.out_buf.len()
+    }
+
+    pub fn read_one(&mut self, br: &mut BitReader) -> Result<()> {
+        let ctx = self.get_icc_ctx() as usize;
+        let checkpoint = self.reader.checkpoint::<1>();
+        let sym = self.reader.read_unsigned(&self.histograms, br, ctx);
+
+        if let Err(err) = br.check_for_error() {
+            self.reader.restore(checkpoint);
+            return Err(err);
+        }
+        if sym >= 256 {
+            warn!(sym, "Invalid symbol in ICC stream");
+            return Err(Error::InvalidIccStream);
+        }
+
+        let b = sym as u8;
+        self.out_buf.push(b);
+        self.prev_bytes = [b, self.prev_bytes[0]];
+        Ok(())
+    }
+
+    pub fn read_all(&mut self, br: &mut BitReader) -> Result<()> {
+        for _ in self.out_buf.len()..self.num_coded_bytes() {
+            self.read_one(br)?;
+        }
+        Ok(())
+    }
+
+    pub fn finalize(self, br: &mut BitReader) -> Result<Vec<u8>> {
+        assert_eq!(self.num_coded_bytes(), self.out_buf.len());
+        self.reader.check_final_state(&self.histograms, br)?;
+        let mut stream = IccStream::new(self.out_buf);
+        let profile = read_icc_inner(&mut stream)?;
+        stream.finalize()?;
+        Ok(profile)
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/icc/stream.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/icc/stream.rs
new file mode 100644
index 0000000..4ca9109
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/icc/stream.rs
@@ -0,0 +1,118 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::io::{Read, Write};
+
+use byteorder::{ReadBytesExt, WriteBytesExt};
+
+use crate::error::{Error, Result};
+use crate::util::NewWithCapacity;
+use crate::util::tracing_wrappers::{instrument, warn};
+
+fn read_varint(mut read_one: impl FnMut() -> Result<u8>) -> Result<u64> {
+    let mut value = 0u64;
+    let mut shift = 0;
+    while shift < 63 {
+        let b = read_one()?;
+        value |= ((b & 0x7f) as u64) << shift;
+        if b & 0x80 == 0 {
+            break;
+        }
+        shift += 7;
+    }
+    Ok(value)
+}
+
+pub(super) fn read_varint_from_reader(stream: &mut impl Read) -> Result<u64> {
+    read_varint(|| stream.read_u8().map_err(|_| Error::IccEndOfStream))
+}
+
+pub(super) struct IccStream {
+    command_stream: Vec<u8>,
+    bytes_read: u64,
+}
+
+impl IccStream {
+    pub(super) fn new(command_stream: Vec<u8>) -> Self {
+        Self {
+            command_stream,
+            bytes_read: 0,
+        }
+    }
+
+    pub fn len(&self) -> u64 {
+        self.command_stream.len() as u64
+    }
+
+    pub fn bytes_read(&self) -> u64 {
+        self.bytes_read
+    }
+
+    pub fn remaining_bytes(&self) -> u64 {
+        self.len() - self.bytes_read
+    }
+
+    fn read_one(&mut self) -> Result<u8> {
+        if self.remaining_bytes() == 0 {
+            return Err(Error::IccEndOfStream);
+        }
+        self.bytes_read += 1;
+        Ok(self.command_stream[self.bytes_read as usize - 1])
+    }
+
+    pub fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
+        if buf.len() > self.remaining_bytes() as usize {
+            return Err(Error::IccEndOfStream);
+        }
+
+        for b in buf {
+            *b = self.read_one()?;
+        }
+
+        Ok(())
+    }
+
+    pub fn read_to_vec_exact(&mut self, len: usize) -> Result<Vec<u8>> {
+        if len > self.remaining_bytes() as usize {
+            return Err(Error::IccEndOfStream);
+        }
+
+        let mut out = Vec::new_with_capacity(len)?;
+
+        for _ in 0..len {
+            out.push(self.read_one()?);
+        }
+
+        Ok(out)
+    }
+
+    pub fn read_varint(&mut self) -> Result<u64> {
+        read_varint(|| self.read_one())
+    }
+
+    pub fn copy_bytes(&mut self, writer: &mut impl Write, len: usize) -> Result<()> {
+        if len > self.remaining_bytes() as usize {
+            return Err(Error::IccEndOfStream);
+        }
+
+        for _ in 0..len {
+            let b = self.read_one()?;
+            writer.write_u8(b).map_err(|_| Error::InvalidIccStream)?;
+        }
+
+        Ok(())
+    }
+
+    #[instrument(skip_all, err)]
+    pub fn finalize(self) -> Result<()> {
+        // Check if all bytes are read
+        if self.bytes_read == self.command_stream.len() as u64 {
+            Ok(())
+        } else {
+            warn!("ICC stream is not fully consumed");
+            Err(Error::InvalidIccStream)
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/icc/tag.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/icc/tag.rs
new file mode 100644
index 0000000..a8fa39ca
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/icc/tag.rs
@@ -0,0 +1,242 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::io::{Cursor, Write};
+
+use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
+
+use crate::error::{Error, Result};
+use crate::util::NewWithCapacity;
+use crate::util::tracing_wrappers::warn;
+
+use super::{ICC_HEADER_SIZE, IccStream, read_varint_from_reader};
+
+const COMMON_TAGS: [&[u8; 4]; 19] = [
+    b"rTRC", b"rXYZ", b"cprt", b"wtpt", b"bkpt", b"rXYZ", b"gXYZ", b"bXYZ", b"kXYZ", b"rTRC",
+    b"gTRC", b"bTRC", b"kTRC", b"chad", b"desc", b"chrm", b"dmnd", b"dmdd", b"lumi",
+];
+
+const COMMON_DATA: [&[u8; 4]; 8] = [
+    b"XYZ ", b"desc", b"text", b"mluc", b"para", b"curv", b"sf32", b"gbd ",
+];
+
+pub(super) fn read_tag_list(
+    data_stream: &mut IccStream,
+    commands_stream: &mut Cursor<Vec<u8>>,
+    decoded_profile: &mut Cursor<&mut [u8]>,
+    num_tags: u32,
+    output_size: u64,
+) -> Result<()> {
+    let mut prev_tagstart = num_tags * 12 + ICC_HEADER_SIZE as u32;
+    let mut prev_tagsize = 0u32;
+
+    loop {
+        let Ok(command) = commands_stream.read_u8() else {
+            // End of commands stream
+            return Ok(());
+        };
+
+        let tagcode = command & 63;
+        let tag = match tagcode {
+            0 => break,
+            1 => {
+                let mut tag = [0u8; 4];
+                data_stream.read_exact(&mut tag)?;
+                tag
+            }
+            2..=20 => *COMMON_TAGS[(tagcode - 2) as usize],
+            _ => return Err(Error::InvalidIccStream),
+        };
+
+        let tagstart = if command & 64 == 0 {
+            prev_tagstart + prev_tagsize
+        } else {
+            read_varint_from_reader(commands_stream)? as u32
+        };
+        let tagsize = match &tag {
+            _ if command & 128 != 0 => read_varint_from_reader(commands_stream)? as u32,
+            b"rXYZ" | b"gXYZ" | b"bXYZ" | b"kXYZ" | b"wtpt" | b"bkpt" | b"lumi" => 20,
+            _ => prev_tagsize,
+        };
+        if (tagstart as u64 + tagsize as u64) > output_size {
+            warn!(output_size, tagstart, tagsize, "tag size overflow");
+            return Err(Error::InvalidIccStream);
+        }
+
+        prev_tagstart = tagstart;
+        prev_tagsize = tagsize;
+
+        let write_result = (|| -> std::io::Result<()> {
+            decoded_profile.write_all(&tag)?;
+            decoded_profile.write_u32::<BigEndian>(tagstart)?;
+            decoded_profile.write_u32::<BigEndian>(tagsize)?;
+            if tagcode == 2 {
+                decoded_profile.write_all(b"gTRC")?;
+                decoded_profile.write_u32::<BigEndian>(tagstart)?;
+                decoded_profile.write_u32::<BigEndian>(tagsize)?;
+                decoded_profile.write_all(b"bTRC")?;
+                decoded_profile.write_u32::<BigEndian>(tagstart)?;
+                decoded_profile.write_u32::<BigEndian>(tagsize)?;
+            } else if tagcode == 3 {
+                decoded_profile.write_all(b"gXYZ")?;
+                decoded_profile.write_u32::<BigEndian>(tagstart + tagsize)?;
+                decoded_profile.write_u32::<BigEndian>(tagsize)?;
+                decoded_profile.write_all(b"bXYZ")?;
+                decoded_profile.write_u32::<BigEndian>(tagstart + tagsize * 2)?;
+                decoded_profile.write_u32::<BigEndian>(tagsize)?;
+            }
+            Ok(())
+        })();
+        write_result.map_err(|_| Error::InvalidIccStream)?;
+    }
+
+    Ok(())
+}
+
+fn shuffle_w2(bytes: &[u8]) -> Result<Vec<u8>> {
+    let len = bytes.len();
+    let mut out = Vec::new_with_capacity(len)?;
+
+    let height = len / 2;
+    let odd = len % 2;
+    for idx in 0..height {
+        out.push(bytes[idx]);
+        out.push(bytes[idx + height + odd]);
+    }
+    if odd != 0 {
+        out.push(bytes[height]);
+    }
+    Ok(out)
+}
+
+fn shuffle_w4(bytes: &[u8]) -> Result<Vec<u8>> {
+    let len = bytes.len();
+    let mut out = Vec::new_with_capacity(len)?;
+
+    let step = len / 4;
+    let wide_count = len % 4;
+    for idx in 0..step {
+        let mut base = idx;
+        for _ in 0..wide_count {
+            out.push(bytes[base]);
+            base += step + 1;
+        }
+        for _ in wide_count..4 {
+            out.push(bytes[base]);
+            base += step;
+        }
+    }
+    for idx in 1..=wide_count {
+        out.push(bytes[(step + 1) * idx - 1]);
+    }
+    Ok(out)
+}
+
+pub(super) fn read_single_command(
+    data_stream: &mut IccStream,
+    commands_stream: &mut Cursor<Vec<u8>>,
+    decoded_profile: &mut Cursor<&mut [u8]>,
+    command: u8,
+) -> Result<()> {
+    use std::num::Wrapping;
+
+    match command {
+        1 => {
+            let num = read_varint_from_reader(commands_stream)? as usize;
+            data_stream.copy_bytes(decoded_profile, num)?;
+        }
+        2 | 3 => {
+            let num = read_varint_from_reader(commands_stream)? as usize;
+            let bytes = data_stream.read_to_vec_exact(num)?;
+            let bytes = if command == 2 {
+                shuffle_w2(&bytes)?
+            } else {
+                shuffle_w4(&bytes)?
+            };
+            decoded_profile
+                .write_all(&bytes)
+                .map_err(|_| Error::InvalidIccStream)?;
+        }
+        4 => {
+            let flags = commands_stream
+                .read_u8()
+                .map_err(|_| Error::InvalidIccStream)?;
+            let width = ((flags & 3) + 1) as usize;
+            let order = (flags >> 2) & 3;
+            if width == 3 || order == 3 {
+                return Err(Error::InvalidIccStream);
+            }
+
+            let stride = if (flags & 16) == 0 {
+                width
+            } else {
+                let stride = read_varint_from_reader(commands_stream)? as usize;
+                if stride < width {
+                    return Err(Error::InvalidIccStream);
+                }
+                stride
+            };
+            if stride.saturating_mul(4) >= decoded_profile.position() as usize {
+                return Err(Error::InvalidIccStream);
+            }
+
+            let num = read_varint_from_reader(commands_stream)? as usize;
+            let bytes = data_stream.read_to_vec_exact(num)?;
+            let bytes = match width {
+                1 => bytes,
+                2 => shuffle_w2(&bytes)?,
+                4 => shuffle_w4(&bytes)?,
+                _ => unreachable!(),
+            };
+
+            for i in (0..num).step_by(width) {
+                let base_position = decoded_profile.position() as usize;
+                let buffer_slice = decoded_profile.get_ref();
+
+                let mut prev = [Wrapping(0u32); 3];
+                for (j, p) in prev[..=order as usize].iter_mut().enumerate() {
+                    let offset = base_position - (stride * (j + 1));
+                    let mut p_bytes = [0u8; 4];
+                    p_bytes[(4 - width)..].copy_from_slice(&buffer_slice[offset..offset + width]);
+                    p.0 = u32::from_be_bytes(p_bytes);
+                }
+
+                let p = match order {
+                    0 => prev[0],
+                    1 => Wrapping(2) * prev[0] - prev[1],
+                    2 => Wrapping(3) * (prev[0] - prev[1]) + prev[2],
+                    _ => unreachable!(),
+                };
+
+                decoded_profile.set_position(base_position as u64);
+                for j in 0..width.min(num - i) {
+                    let val = Wrapping(bytes[i + j] as u32) + (p >> (8 * (width - 1 - j)));
+                    decoded_profile
+                        .write_u8(val.0 as u8)
+                        .map_err(|_| Error::InvalidIccStream)?;
+                }
+            }
+        }
+        10 => {
+            let mut bytes = [0u8; 20];
+            bytes[..4].copy_from_slice(b"XYZ ");
+            data_stream.read_exact(&mut bytes[8..])?;
+            decoded_profile
+                .write_all(&bytes)
+                .map_err(|_| Error::InvalidIccStream)?;
+        }
+        16..=23 => {
+            decoded_profile
+                .write_all(COMMON_DATA[command as usize - 16])
+                .and_then(|_| decoded_profile.write_all(&[0u8; 4]))
+                .map_err(|_| Error::InvalidIccStream)?;
+        }
+        _ => {
+            return Err(Error::InvalidIccStream);
+        }
+    }
+
+    Ok(())
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/data_type.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/data_type.rs
new file mode 100644
index 0000000..1705c28
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/data_type.rs
@@ -0,0 +1,142 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::fmt::Debug;
+
+mod private {
+    pub trait Sealed {}
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum DataTypeTag {
+    U8,
+    U16,
+    U32,
+    F32,
+    I8,
+    I16,
+    I32,
+    F16,
+    F64,
+}
+
+impl DataTypeTag {
+    // Note that the const block below asserts that the implementation of this method is correct
+    // (as in, matches the size of the types that the tag corresponds to).
+    pub const fn size(&self) -> usize {
+        match self {
+            DataTypeTag::U8 | DataTypeTag::I8 => 1,
+            DataTypeTag::U16 | DataTypeTag::F16 | DataTypeTag::I16 => 2,
+            DataTypeTag::U32 | DataTypeTag::F32 | DataTypeTag::I32 => 4,
+            DataTypeTag::F64 => 8,
+        }
+    }
+}
+
+const _: () = {
+    assert!(std::mem::size_of::<i8>() == DataTypeTag::I8.size());
+    assert!(std::mem::size_of::<u8>() == DataTypeTag::U8.size());
+    assert!(std::mem::size_of::<i16>() == DataTypeTag::I16.size());
+    assert!(std::mem::size_of::<u16>() == DataTypeTag::U16.size());
+    assert!(std::mem::size_of::<crate::util::f16>() == DataTypeTag::F16.size());
+    assert!(std::mem::size_of::<i32>() == DataTypeTag::I32.size());
+    assert!(std::mem::size_of::<u32>() == DataTypeTag::U32.size());
+    assert!(std::mem::size_of::<f32>() == DataTypeTag::F32.size());
+    assert!(std::mem::size_of::<f64>() == DataTypeTag::F64.size());
+};
+
+/// # Safety
+/// Any type implementing this trait must be a "bag-of-bits" type with no padding.
+/// Moreover, Self::DATA_TYPE_ID.size() must match the size of `Self`.
+pub unsafe trait ImageDataType:
+    private::Sealed + Copy + Default + 'static + Debug + PartialEq + Send + Sync
+{
+    /// ID of this data type. Different types *must* have different values (this is not a safety
+    /// requirement).
+    const DATA_TYPE_ID: DataTypeTag;
+
+    fn from_f64(f: f64) -> Self;
+    fn to_f64(self) -> f64;
+    #[cfg(test)]
+    fn random<R: rand::Rng>(rng: &mut R) -> Self;
+}
+
+#[cfg(test)]
+macro_rules! type_min {
+    (f32) => {
+        0.0f32
+    };
+    (f64) => {
+        0.0f64
+    };
+    ($ty: ty) => {
+        <$ty>::MIN
+    };
+}
+
+#[cfg(test)]
+macro_rules! type_max {
+    (f32) => {
+        1.0f32
+    };
+    (f64) => {
+        1.0f64
+    };
+    ($ty: ty) => {
+        <$ty>::MAX
+    };
+}
+
+macro_rules! impl_image_data_type {
+    ($ty: ident, $id: ident) => {
+        impl private::Sealed for $ty {}
+        // SAFETY: primitive integer/float types are bag-of-bits types.
+        unsafe impl ImageDataType for $ty {
+            const DATA_TYPE_ID: DataTypeTag = DataTypeTag::$id;
+            fn from_f64(f: f64) -> $ty {
+                f as $ty
+            }
+            fn to_f64(self) -> f64 {
+                self as f64
+            }
+            #[cfg(test)]
+            fn random<R: rand::Rng>(rng: &mut R) -> Self {
+                use rand::distr::{Distribution, Uniform};
+                let min = type_min!($ty);
+                let max = type_max!($ty);
+                Uniform::new_inclusive(min, max).unwrap().sample(rng)
+            }
+        }
+    };
+}
+
+impl_image_data_type!(u8, U8);
+impl_image_data_type!(u16, U16);
+impl_image_data_type!(u32, U32);
+impl_image_data_type!(f32, F32);
+impl_image_data_type!(i8, I8);
+impl_image_data_type!(i16, I16);
+impl_image_data_type!(i32, I32);
+
+// Meant to be used by the simple render pipeline and in general for
+// testing purposes.
+impl_image_data_type!(f64, F64);
+
+impl private::Sealed for crate::util::f16 {}
+// SAFETY: f16 is a bag-of-bits type (transparent wrapper around u16).
+unsafe impl ImageDataType for crate::util::f16 {
+    const DATA_TYPE_ID: DataTypeTag = DataTypeTag::F16;
+    fn from_f64(f: f64) -> crate::util::f16 {
+        crate::util::f16::from_f64(f)
+    }
+    fn to_f64(self) -> f64 {
+        crate::util::f16::to_f64(self)
+    }
+    #[cfg(test)]
+    fn random<R: rand::Rng>(rng: &mut R) -> Self {
+        use rand::distr::{Distribution, Uniform};
+        Self::from_f64(Uniform::new(0.0f32, 1.0f32).unwrap().sample(rng) as f64)
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/internal.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/internal.rs
new file mode 100644
index 0000000..b1fceb0
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/internal.rs
@@ -0,0 +1,364 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::{
+    alloc::{Layout, alloc, alloc_zeroed, dealloc},
+    fmt::Debug,
+    mem::MaybeUninit,
+    ptr::null_mut,
+};
+
+use crate::{
+    error::{Error, Result},
+    util::{CACHE_LINE_BYTE_SIZE, tracing_wrappers::*},
+};
+
+use super::Rect;
+
+#[derive(Debug, Clone, Copy)]
+pub(super) struct RawImageBuffer {
+    // Safety invariant:
+    //  - uninit data is never written to `buf`.
+    //  - `buf` is valid for reads for all bytes in the ranges
+    //    `buf[i*bytes_between_rows..i*bytes_between_rows+bytes_per_row]` for all values of `i`
+    //    from `0` to `num_rows-1`.
+    //  - all the bytes in those ranges (and in between) are part of the same allocated object.
+    //  - if `num_rows > 0`, then `bytes_per_row > 0`, `bytes_per_row <= bytes_between_rows`.
+    //  - The computation `E = bytes_between_rows * (num_rows-1) + bytes_per_row` does not
+    //    overflow and has a result that is at most `isize::MAX`, or num_rows is 0.
+    // We will call the bytes in the range above the "accessible bytes" of a RawImageBuffer.
+    // Note that wrapper structs around RawImageBuffer might have a safety invariant that declares
+    // that the struct has write access to the accessible bytes of a RawImageBuffer; in that case,
+    // that is equivalent to saying that `buf` is *also* valid for *writes*.
+    buf: *mut MaybeUninit<u8>,
+    bytes_per_row: usize,
+    num_rows: usize,
+    bytes_between_rows: usize,
+}
+
+// SAFETY: The safety invariant on RawImageBuffer enforces ownership rules on the contained data,
+// there is no reason for it not to be Send.
+unsafe impl Send for RawImageBuffer {}
+
+// SAFETY: RawImageBuffer does not use any kind of interior mutability, so it is safe to share
+// between threads.
+unsafe impl Sync for RawImageBuffer {}
+
+impl RawImageBuffer {
+    pub(super) fn check_vals(num_rows: usize, bytes_per_row: usize, bytes_between_rows: usize) {
+        if num_rows > 0 {
+            assert!(bytes_per_row > 0);
+            assert!(bytes_between_rows >= bytes_per_row);
+            assert!(
+                bytes_between_rows
+                    .checked_mul(num_rows - 1)
+                    .unwrap()
+                    .checked_add(bytes_per_row)
+                    .unwrap()
+                    <= isize::MAX as usize
+            );
+        }
+    }
+
+    /// Checks that self.buf, self.bytes_per_row, self.bytes_between_rows are all multiple of align.
+    /// This guarantees that `self.get_row()` and `self.get_row_mut()` return slices aligned to
+    /// `align`.
+    #[inline(always)]
+    pub(super) fn is_aligned(&self, align: usize) -> bool {
+        self.bytes_per_row.is_multiple_of(align)
+            && self.bytes_between_rows.is_multiple_of(align)
+            && (self.buf as usize).is_multiple_of(align)
+    }
+
+    /// Creates a new RawImageBuffer from raw pointers.
+    /// It is guaranteed that `buf` will never be used to write uninitialized data.
+    ///
+    /// # Safety
+    /// - `buf` must be valid for reads for all bytes in the range
+    ///   `buf[i*bytes_between_rows..i*bytes_between_rows+bytes_per_row]` for all values of `i`
+    ///   from `0` to `num_rows-1`.
+    /// - The bytes in these ranges must not be accessed as long as the returned `Self` is in scope.
+    /// - All the bytes in those ranges (and in between) must be part of the same allocated object.
+    ///
+    /// Note: these safety requirements match those of JxlOutputBuffer::new_from_ptr, except we
+    /// only request validity for reads.
+    pub(super) unsafe fn new_from_ptr(
+        buf: *mut MaybeUninit<u8>,
+        num_rows: usize,
+        bytes_per_row: usize,
+        bytes_between_rows: usize,
+    ) -> Self {
+        RawImageBuffer::check_vals(num_rows, bytes_per_row, bytes_between_rows);
+        // SAFETY: caller guarantees the buf-related requirements, and other safety invariants are
+        // checked in check_vals.
+        Self {
+            buf,
+            bytes_per_row,
+            bytes_between_rows,
+            num_rows,
+        }
+    }
+
+    fn empty() -> Self {
+        // Safety note: the safety invariant is trivially verified.
+        RawImageBuffer {
+            buf: null_mut(),
+            bytes_per_row: 0,
+            num_rows: 0,
+            bytes_between_rows: 0,
+        }
+    }
+
+    /// Returns the minimum size that the allocation containing the image data must have, or 0 if
+    /// this is an empty image.
+    pub(super) fn minimum_allocation_size(&self) -> usize {
+        if self.num_rows == 0 {
+            0
+        } else {
+            // Note: the safety invariant guarantees no overflow.
+            (self.num_rows - 1) * self.bytes_between_rows + self.bytes_per_row
+        }
+    }
+
+    #[inline]
+    pub(super) fn byte_size(&self) -> (usize, usize) {
+        (self.bytes_per_row, self.num_rows)
+    }
+
+    /// # Safety
+    /// - No uninit data must be written to the returned slice.
+    /// - The caller must ensure that ownership rules are respected (for example, because they
+    ///   have exclusive access to the data).
+    #[inline(always)]
+    pub(super) unsafe fn row_mut(&mut self, row: usize) -> &mut [MaybeUninit<u8>] {
+        // SAFETY: The safety requirements for distinct_rows_mut match the ones for row_mut.
+        unsafe { self.distinct_rows_mut([row])[0] }
+    }
+
+    /// Note: this is quadratic in the number of rows.
+    /// # Safety
+    /// - No uninit data must be written to the returned slice.
+    /// - The caller must ensure that ownership rules are respected (for example, because they
+    ///   have exclusive access to the data).
+    #[inline(always)]
+    pub(super) unsafe fn distinct_rows_mut<I: DistinctRowsIndexes>(
+        &mut self,
+        rows: I,
+    ) -> I::Output<'_, MaybeUninit<u8>> {
+        // SAFETY: the safety requirements of `get_rows_mut` are the same as the ones for
+        // `distinct_rows_mut`.
+        unsafe { rows.get_rows_mut(self) }
+    }
+
+    /// # Safety
+    /// The caller must ensure that ownership and lifetime rules are respected (for example,
+    /// because they have shared access to the data).
+    #[inline(always)]
+    pub(super) unsafe fn row(&self, row: usize) -> &[MaybeUninit<u8>] {
+        assert!(row < self.num_rows);
+        let start = row * self.bytes_between_rows;
+        // SAFETY: `start` is guaranteed to be <= isize::MAX, and `self.buf + start` is guaranteed
+        // to fit within the same allocated object, as per safety invariants of this struct.
+        // We checked above that `row` and `cols` satisfy the requirements to apply the safety
+        // invariant.
+        let start = unsafe { self.buf.add(start) };
+        // SAFETY: due to the struct safety invariant, we know the entire slice is in a range of
+        // memory valid for writes. Moreover, the caller promises not to write uninitialized data
+        // in the returned slice. Finally, the caller guarantees aliasing rules will not be violated.
+        unsafe { std::slice::from_raw_parts(start, self.bytes_per_row) }
+    }
+
+    /// Extracts a sub-rectangle from this buffer. Rectangle coordinates are in bytes.
+    /// Safety note: the returned RawImageBuffer retains the same kind of access (read or write) as `self`.
+    pub(super) fn rect(&self, rect: Rect) -> Self {
+        if rect.size.0 == 0 || rect.size.1 == 0 {
+            return Self::empty();
+        }
+        // More helpful message in debug builds (not needed for safety).
+        if cfg!(debug_assertions) {
+            rect.check_within(self.byte_size());
+        }
+        assert!(rect.origin.1 < self.num_rows);
+        assert!(rect.origin.1.checked_add(rect.size.1).unwrap() <= self.num_rows);
+        assert!(rect.origin.0 < self.bytes_per_row);
+        assert!(rect.origin.0.checked_add(rect.size.0).unwrap() <= self.bytes_per_row);
+        // SAFETY: the safety invariant of `self`, together with the above check, guarantees that
+        // the calculation does not overflow and that the new pointer stays within the bounds of
+        // the allocation.
+        let start_ptr = unsafe {
+            self.buf
+                .add(rect.origin.1 * self.bytes_between_rows + rect.origin.0)
+        };
+        // SAFETY: Thanks to the check above, all the bytes accessible from `buf` at the
+        // appropriate ranges are a subset of the ones accessible from `self.buf` at the
+        // correct ranges for `self`. Thus, the safety invariant of `self` ensures that
+        // the safety preconditions of this call are satisfied.
+        unsafe { Self::new_from_ptr(start_ptr, rect.size.1, rect.size.0, self.bytes_between_rows) }
+    }
+
+    /// Returns zeroed memory if `uninit` is `false`, otherwise it returns uninitialized
+    /// memory. The returned buffer is aligned to CACHE_LINE_BYTE_SIZE bytes.
+    /// The returned RawImageBuffer owns the memory it references, which belongs to a single
+    /// allocation of size minimum_allocation_size().
+    pub(super) fn try_allocate(byte_size: (usize, usize), uninit: bool) -> Result<RawImageBuffer> {
+        let (bytes_per_row, num_rows) = byte_size;
+        // To simplify modular transform logic, we allow empty images, because some modular
+        // meta-images can have 0 bytes_per_row or num_rows (e.g. delta-palette, reference property image).
+        if bytes_per_row == 0 || num_rows == 0 {
+            return Ok(RawImageBuffer::empty());
+        }
+        // These limits let us not worry about overflows.
+        if bytes_per_row as u64 >= i64::MAX as u64 / 4 || num_rows as u64 >= i64::MAX as u64 / 4 {
+            return Err(Error::ImageSizeTooLarge(bytes_per_row, num_rows));
+        }
+        debug!("trying to allocate image");
+        let bytes_between_rows =
+            bytes_per_row.div_ceil(CACHE_LINE_BYTE_SIZE) * CACHE_LINE_BYTE_SIZE;
+        // Note: matches RawImageBuffer::minimum_allocation_size.
+        let allocation_len = (num_rows - 1)
+            .checked_mul(bytes_between_rows)
+            .unwrap()
+            .checked_add(bytes_per_row)
+            .unwrap();
+        assert_ne!(allocation_len, 0);
+        let layout = Layout::from_size_align(allocation_len, CACHE_LINE_BYTE_SIZE).unwrap();
+        // SAFETY: we just checked that allocation_len is not 0.
+        let memory = unsafe {
+            if uninit {
+                alloc(layout)
+            } else {
+                alloc_zeroed(layout)
+            }
+        };
+        if memory.is_null() {
+            return Err(Error::ImageOutOfMemory(bytes_per_row, num_rows));
+        }
+        // SAFETY: `memory` points to a contiguous array of size minimum_allocation_size(), and we
+        // transfer ownership so the validity requirements are satisfied.
+        Ok(unsafe {
+            RawImageBuffer::new_from_ptr(
+                memory as *mut MaybeUninit<u8>,
+                num_rows,
+                bytes_per_row,
+                bytes_between_rows,
+            )
+        })
+    }
+
+    /// Returns a copy of the current buffer contents in a new buffer that owns the returned data.
+    /// The data is allocated with `try_allocate` so that it matches the size of the current image.
+    ///
+    /// This function is meant to be used when `self` is an owned buffer, and will panic if the
+    /// bytes between rows of a newly allocated image with the same size does not match the value
+    /// for `self`.
+    ///
+    /// # Safety
+    /// The caller must ensure that the data referenced by self -- *all*
+    /// self.minimum_allocation_size() bytes starting from self.buf, not just the accessible bytes
+    /// -- can be read.
+    pub(super) unsafe fn try_clone(&self) -> Result<Self> {
+        let out = RawImageBuffer::try_allocate(self.byte_size(), true)?;
+        assert_eq!(self.bytes_per_row, out.bytes_per_row);
+        assert_eq!(self.bytes_between_rows, out.bytes_between_rows);
+        assert_eq!(self.num_rows, out.num_rows);
+        let data_len = self.minimum_allocation_size();
+        assert_eq!(
+            self.minimum_allocation_size(),
+            out.minimum_allocation_size()
+        );
+        if data_len != 0 {
+            // SAFETY: since both `self` and `out` own the allocation, which has size `data_len`, this copy
+            // is safe.
+            unsafe {
+                std::ptr::copy_nonoverlapping(self.buf, out.buf, data_len);
+            }
+        }
+        Ok(out)
+    }
+
+    /// Deallocates an owning buffer that was allocated by try_allocate.
+    ///
+    /// # Safety
+    /// The data referenced by `self` must have been allocated with Self::try_allocate.
+    pub(super) unsafe fn deallocate(&mut self) {
+        if !self.buf.is_null() {
+            let allocation_len = self.minimum_allocation_size();
+            let layout = Layout::from_size_align(allocation_len, CACHE_LINE_BYTE_SIZE).unwrap();
+            // SAFETY: the buffer was allocated in `try_allocate` with the same layout.
+            unsafe {
+                dealloc(self.buf as *mut u8, layout);
+            }
+        }
+    }
+}
+
+#[allow(private_interfaces)]
+pub trait DistinctRowsIndexes {
+    type Output<'a, T: 'static>;
+
+    /// # Safety
+    /// - No uninit data must be written to the returned slice.
+    /// - The caller must ensure that ownership rules are respected (for example, because they
+    ///   have exclusive access to the data).
+    unsafe fn get_rows_mut<'a>(
+        &self,
+        image: &'a mut RawImageBuffer,
+    ) -> Self::Output<'a, MaybeUninit<u8>>;
+
+    /// # Safety
+    /// - The rows are properly aligned
+    /// - The rows contain data that is valid for type T (and thus initialized).
+    unsafe fn transmute_rows<'a, T: 'static>(
+        rows: Self::Output<'a, MaybeUninit<u8>>,
+    ) -> Self::Output<'a, T>;
+}
+
+#[allow(private_interfaces)]
+impl<const S: usize> DistinctRowsIndexes for [usize; S] {
+    type Output<'a, T: 'static> = [&'a mut [T]; S];
+
+    #[inline(always)]
+    unsafe fn get_rows_mut<'a>(
+        &self,
+        image: &'a mut RawImageBuffer,
+    ) -> Self::Output<'a, MaybeUninit<u8>> {
+        for i in 0..S {
+            assert!(self[i] < image.num_rows);
+            for j in i + 1..S {
+                assert_ne!(self[i], self[j]);
+            }
+        }
+        let start = self.map(|row| row * image.bytes_between_rows);
+        let start = start.map(|start| {
+            // SAFETY: `start` is guaranteed to be <= isize::MAX, and `self.buf + start` is guaranteed
+            // to fit within the same allocated object, as per safety invariants of the image struct.
+            // We checked above that `row` satisfies the requirements to apply the safety invariant.
+            unsafe { image.buf.add(start) }
+        });
+        start.map(|start| {
+            // SAFETY: due to the struct safety invariant, we know the entire slice is in a range of
+            // memory valid for writes. Moreover, the caller promises not to write uninitialized
+            // data in the returned slice. Finally, the caller guarantees aliasing rules will not
+            // be violated outside of this struct, and since we checked that all the values of
+            // `self` are distinct they are also not violated across the various slices returned by
+            unsafe { std::slice::from_raw_parts_mut(start, image.bytes_per_row) }
+        })
+    }
+
+    #[inline(always)]
+    unsafe fn transmute_rows<'a, T: 'static>(
+        rows: Self::Output<'a, MaybeUninit<u8>>,
+    ) -> Self::Output<'a, T> {
+        rows.map(|row| {
+            // SAFETY: The caller guarantees the transmute is safe and proper alignment.
+            unsafe {
+                std::slice::from_raw_parts_mut(
+                    row.as_mut_ptr() as *mut T,
+                    row.len() / std::mem::size_of::<T>(),
+                )
+            }
+        })
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/mod.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/mod.rs
new file mode 100644
index 0000000..24d37b2
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/mod.rs
@@ -0,0 +1,22 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(unsafe_code)]
+
+mod data_type;
+mod internal;
+mod output_buffer;
+mod raw;
+mod rect;
+#[cfg(test)]
+mod test;
+mod typed;
+
+pub use data_type::DataTypeTag;
+pub use data_type::ImageDataType;
+pub use output_buffer::JxlOutputBuffer;
+pub use raw::{OwnedRawImage, RawImageRect, RawImageRectMut};
+pub use rect::Rect;
+pub use typed::{Image, ImageRect, ImageRectMut};
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/output_buffer.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/output_buffer.rs
new file mode 100644
index 0000000..c177f1b2
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/output_buffer.rs
@@ -0,0 +1,115 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::{fmt::Debug, marker::PhantomData, mem::MaybeUninit};
+
+use super::{RawImageRectMut, Rect, internal::RawImageBuffer};
+
+#[derive(Debug)]
+#[repr(transparent)]
+pub struct JxlOutputBuffer<'a> {
+    // Safety invariant: `self` has exclusive (write) access to the accessible bytes of `inner`.
+    inner: RawImageBuffer,
+    _ph: PhantomData<&'a mut u8>,
+}
+
+impl<'a> JxlOutputBuffer<'a> {
+    /// Creates a new JxlOutputBuffer from raw pointers.
+    /// It is guaranteed that `buf` will never be used to write uninitialized data.
+    ///
+    /// # Safety
+    /// - `buf` must be valid for writes for all bytes in the range
+    ///   `buf[i*bytes_between_rows..i*bytes_between_rows+bytes_per_row]` for all values of `i`
+    ///   from `0` to `num_rows-1`.
+    /// - The bytes in these ranges must not be accessed as long as the returned `Self` is in scope.
+    /// - All the bytes in those ranges (and in between) must be part of the same allocated object.
+    pub unsafe fn new_from_ptr(
+        buf: *mut MaybeUninit<u8>,
+        num_rows: usize,
+        bytes_per_row: usize,
+        bytes_between_rows: usize,
+    ) -> Self {
+        JxlOutputBuffer {
+            // SAFETY: the safety conditions on RawImageBuffer::new_from_ptr are strictly weaker.
+            // We are promised write access to the underlying data, so our own safety invariant is
+            // respected.
+            inner: unsafe {
+                RawImageBuffer::new_from_ptr(buf, num_rows, bytes_per_row, bytes_between_rows)
+            },
+            _ph: PhantomData,
+        }
+    }
+
+    pub fn from_image_rect_mut(raw: RawImageRectMut<'a>) -> Self {
+        Self {
+            // Safety note: since `raw` has exclusive access to the data, we are just transferring
+            // this access.
+            inner: raw.data,
+            _ph: PhantomData,
+        }
+    }
+
+    /// Creates a new JxlOutputBuffer from a slice of uninit data.
+    /// It is guaranteed that `buf` will never be used to write uninitalized data.
+    pub fn new_uninit(
+        buf: &'a mut [MaybeUninit<u8>],
+        num_rows: usize,
+        bytes_per_row: usize,
+    ) -> Self {
+        assert!(buf.len() >= bytes_per_row * num_rows);
+        // SAFETY: The assert above guarantees that `buf` has enough space to satisfy the first
+        // safety requirement, and the rest follow from borrowing from a &mut [].
+        unsafe { Self::new_from_ptr(buf.as_mut_ptr(), num_rows, bytes_per_row, bytes_per_row) }
+    }
+
+    pub fn new(buf: &'a mut [u8], num_rows: usize, bytes_per_row: usize) -> Self {
+        Self::new_uninit(
+            // SAFETY: `new_uninit` guarantees that no uninit data is ever written to the passed-in
+            // slice. Moreover, `T` and `MaybeUninit<T>` have the same memory layout.
+            unsafe { std::slice::from_raw_parts_mut(buf.as_mut_ptr().cast(), buf.len()) },
+            num_rows,
+            bytes_per_row,
+        )
+    }
+
+    pub(crate) fn reborrow(lender: &'a mut JxlOutputBuffer<'_>) -> JxlOutputBuffer<'a> {
+        // Safety note: this is effectively equivalent to a reborrow.
+        Self {
+            _ph: PhantomData,
+            ..*lender
+        }
+    }
+
+    /// # Safety
+    /// The caller must guarantee that the returned slice is not used for writing uninit data.
+    pub(crate) unsafe fn row_mut(&mut self, row: usize) -> &mut [MaybeUninit<u8>] {
+        // SAFETY: caller guarantees no uninit data is written, and we have write access to the
+        // data due to safety invariant.
+        unsafe { self.inner.row_mut(row) }
+    }
+
+    #[inline]
+    pub fn write_bytes(&mut self, row: usize, col: usize, bytes: &[u8]) {
+        // SAFETY: We never use the returned slice to write uninit data, and we have write access
+        // to the data.
+        let slice = unsafe { self.inner.row_mut(row) };
+        for (w, s) in slice.iter_mut().skip(col).zip(bytes.iter().copied()) {
+            w.write(s);
+        }
+    }
+
+    pub fn byte_size(&self) -> (usize, usize) {
+        self.inner.byte_size()
+    }
+
+    pub fn rect(&mut self, rect: Rect) -> JxlOutputBuffer<'_> {
+        // Safety note: the return value borrows from `self`, so we are lending our memory to the
+        // returned JxlOutputBuffer.
+        Self {
+            inner: self.inner.rect(rect),
+            _ph: PhantomData,
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/raw.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/raw.rs
new file mode 100644
index 0000000..bbc661a
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/raw.rs
@@ -0,0 +1,230 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::{fmt::Debug, marker::PhantomData};
+
+use crate::{error::Result, util::CACHE_LINE_BYTE_SIZE};
+
+use super::{Rect, internal::RawImageBuffer};
+
+pub struct OwnedRawImage {
+    // Safety invariant: all the accessible bytes of `self.data` are initialized, and
+    // belongs to a single allocation that lives until `self` is dropped.
+    // The data referenced by self.data was allocated by RawImageBuffer::try_allocate.
+    // `data.is_aligned(CACHE_LINE_BYTE_SIZE)` is true.
+    pub(super) data: RawImageBuffer,
+    offset: (usize, usize),
+    padding: (usize, usize),
+}
+
+impl OwnedRawImage {
+    pub fn new_zeroed_with_padding(
+        byte_size: (usize, usize),
+        offset: (usize, usize),
+        mut padding: (usize, usize),
+    ) -> Result<Self> {
+        // Since RawImageBuffer::try_allocate will round up the length of a row to a cache line,
+        // might as well declare that as available padding space.
+        if !(padding.0 + byte_size.0).is_multiple_of(CACHE_LINE_BYTE_SIZE) {
+            padding.0 += CACHE_LINE_BYTE_SIZE - (padding.0 + byte_size.0) % CACHE_LINE_BYTE_SIZE;
+        }
+        Ok(Self {
+            // Safety note: the returned memory is initialized and part of a single allocation of
+            // the correct length.
+            data: RawImageBuffer::try_allocate(
+                (byte_size.0 + padding.0, byte_size.1 + padding.1),
+                false,
+            )?,
+            offset,
+            padding,
+        })
+    }
+
+    pub fn get_rect_including_padding_mut(&mut self, rect: Rect) -> RawImageRectMut<'_> {
+        RawImageRectMut {
+            // Safety note: we are lending exclusive ownership to RawImageRectMut.
+            data: self.data.rect(rect),
+            _ph: PhantomData,
+        }
+    }
+
+    pub fn get_rect_including_padding(&'_ self, rect: Rect) -> RawImageRect<'_> {
+        RawImageRect {
+            // Safety note: correctness ensured by the return value borrowing from `self`.
+            data: self.data.rect(rect),
+            _ph: PhantomData,
+        }
+    }
+
+    fn shift_rect(&self, rect: Rect) -> Rect {
+        if cfg!(debug_assertions) {
+            // Check the original rect is within the content size (without padding)
+            rect.check_within(self.byte_size());
+        }
+        Rect {
+            origin: (rect.origin.0 + self.offset.0, rect.origin.1 + self.offset.1),
+            size: rect.size,
+        }
+    }
+
+    pub fn get_rect_mut(&mut self, rect: Rect) -> RawImageRectMut<'_> {
+        self.get_rect_including_padding_mut(self.shift_rect(rect))
+    }
+
+    pub fn get_rect(&'_ self, rect: Rect) -> RawImageRect<'_> {
+        self.get_rect_including_padding(self.shift_rect(rect))
+    }
+
+    #[inline(always)]
+    pub fn row_mut(&mut self, row: usize) -> &mut [u8] {
+        let offset = self.offset;
+        let end = offset.0 + self.byte_size().0;
+        // SAFETY: we don't write uninit data to `row`, and we have ownership of the accessible
+        // bytes of `self.data`.
+        let row = &mut unsafe { self.data.row_mut(row + offset.1) }[offset.0..end];
+        // SAFETY: MaybeUninit<u8> and u8 have the same size and layout, and our safety invariant
+        // guarantees the data is initialized.
+        unsafe { std::slice::from_raw_parts_mut(row.as_mut_ptr() as *mut u8, row.len()) }
+    }
+
+    #[inline(always)]
+    pub fn row(&self, row: usize) -> &[u8] {
+        let offset = self.offset;
+        let end = offset.0 + self.byte_size().0;
+        // SAFETY: we have shared access to the accessible bytes of `self.data`.
+        let row = &unsafe { self.data.row(row + offset.1) }[offset.0..end];
+        // SAFETY: MaybeUninit<u8> and u8 have the same size and layout, and our safety invariant
+        // guarantees the data is initialized.
+        unsafe { std::slice::from_raw_parts(row.as_ptr() as *const u8, row.len()) }
+    }
+
+    pub fn byte_size(&self) -> (usize, usize) {
+        let size = self.data.byte_size();
+        (size.0 - self.padding.0, size.1 - self.padding.1)
+    }
+
+    pub fn byte_offset(&self) -> (usize, usize) {
+        self.offset
+    }
+
+    pub fn byte_padding(&self) -> (usize, usize) {
+        self.padding
+    }
+
+    pub fn try_clone(&self) -> Result<OwnedRawImage> {
+        Ok(Self {
+            // SAFETY: we own the data that self.data references, so it is all accessible.
+            // Moreover, it is initialized and try_clone creates a copy, so the resulting data is
+            // owned and initialized.
+            data: unsafe { self.data.try_clone()? },
+            offset: self.offset,
+            padding: self.padding,
+        })
+    }
+}
+
+impl Drop for OwnedRawImage {
+    fn drop(&mut self) {
+        // SAFETY: we own the data referenced by self.data, and it was allocated by
+        // RawImageBuffer::try_allocate.
+        unsafe {
+            self.data.deallocate();
+        }
+    }
+}
+
+#[derive(Clone, Copy)]
+pub struct RawImageRect<'a> {
+    // Safety invariant: all the accessible bytes of `self.data` are initialized.
+    pub(super) data: RawImageBuffer,
+    _ph: PhantomData<&'a u8>,
+}
+
+impl<'a> RawImageRect<'a> {
+    #[inline(always)]
+    pub fn row(&self, row: usize) -> &[u8] {
+        // SAFETY: we have shared access to the accessible bytes of `self.data`.
+        let row = unsafe { self.data.row(row) };
+        // SAFETY: MaybeUninit<u8> and u8 have the same size and layout, and our safety invariant
+        // guarantees the data is initialized.
+        unsafe { std::slice::from_raw_parts(row.as_ptr() as *const u8, row.len()) }
+    }
+
+    pub fn rect(&self, rect: Rect) -> RawImageRect<'a> {
+        Self {
+            // Safety note: correctness ensured by the fact that the return value still borrows
+            // from the original data source.
+            data: self.data.rect(rect),
+            _ph: PhantomData,
+        }
+    }
+
+    pub fn byte_size(&self) -> (usize, usize) {
+        self.data.byte_size()
+    }
+}
+
+pub struct RawImageRectMut<'a> {
+    // Safety invariant: all the accessible bytes of `self.data` are initialized and we have
+    // exclusive access to them.
+    pub(super) data: RawImageBuffer,
+    _ph: PhantomData<&'a mut u8>,
+}
+
+impl<'a> RawImageRectMut<'a> {
+    #[inline(always)]
+    pub fn row(&mut self, row: usize) -> &mut [u8] {
+        // SAFETY: we don't write uninit data to `row`, and we have exclusive access to the accessible
+        // bytes of `self.data`.
+        let row = unsafe { self.data.row_mut(row) };
+        // SAFETY: MaybeUninit<u8> and u8 have the same size and layout, and our safety invariant
+        // guarantees the data is initialized.
+        unsafe { std::slice::from_raw_parts_mut(row.as_mut_ptr() as *mut u8, row.len()) }
+    }
+
+    pub fn rect_mut(&'_ mut self, rect: Rect) -> RawImageRectMut<'_> {
+        Self {
+            // Safety note: we are lending ownership to the returned RawImageRectMut, and Rust's
+            // type system ensures correctness.
+            data: self.data.rect(rect),
+            _ph: PhantomData,
+        }
+    }
+
+    pub fn as_rect(&'_ self) -> RawImageRect<'_> {
+        RawImageRect {
+            // Safety note: correctness ensured by the return value borrowing from self.
+            data: self.data,
+            _ph: PhantomData,
+        }
+    }
+
+    pub fn byte_size(&self) -> (usize, usize) {
+        self.data.byte_size()
+    }
+}
+
+impl Debug for OwnedRawImage {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "raw {}x{}", self.byte_size().0, self.byte_size().1)
+    }
+}
+
+impl Debug for RawImageRect<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "raw rect {}x{}", self.byte_size().0, self.byte_size().1)
+    }
+}
+
+impl Debug for RawImageRectMut<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "raw mutrect {}x{}",
+            self.byte_size().0,
+            self.byte_size().1
+        )
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/rect.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/rect.rs
new file mode 100644
index 0000000..f511d21
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/rect.rs
@@ -0,0 +1,59 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use super::DataTypeTag;
+
+#[derive(Clone, Copy, Debug)]
+pub struct Rect {
+    pub origin: (usize, usize),
+    // width, height
+    pub size: (usize, usize),
+}
+
+impl Rect {
+    pub fn check_within(&self, size: (usize, usize)) {
+        if self.origin.0.checked_add(self.size.0).unwrap() > size.0
+            || self.origin.1.checked_add(self.size.1).unwrap() > size.1
+        {
+            panic!(
+                "Rect out of bounds: {}x{}+{}+{} rect in {}x{} view",
+                self.size.0, self.size.1, self.origin.0, self.origin.1, size.0, size.1
+            );
+        }
+    }
+
+    pub fn to_byte_rect(&self, data_type: DataTypeTag) -> Rect {
+        self.to_byte_rect_sz(data_type.size())
+    }
+
+    pub fn to_byte_rect_sz(&self, sz: usize) -> Rect {
+        Rect {
+            origin: (self.origin.0 * sz, self.origin.1),
+            size: (self.size.0 * sz, self.size.1),
+        }
+    }
+
+    pub fn downsample(&self, downsample: (u8, u8)) -> Rect {
+        Rect {
+            origin: (self.origin.0 >> downsample.0, self.origin.1 >> downsample.1),
+            size: (self.size.0 >> downsample.0, self.size.1 >> downsample.1),
+        }
+    }
+
+    pub fn end(&self) -> (usize, usize) {
+        (self.origin.0 + self.size.0, self.origin.1 + self.size.1)
+    }
+
+    pub fn clip(&self, size: (usize, usize)) -> Rect {
+        let end = self.end();
+        Rect {
+            origin: self.origin,
+            size: (
+                end.0.min(size.0).saturating_sub(self.origin.0),
+                end.1.min(size.1).saturating_sub(self.origin.1),
+            ),
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/test.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/test.rs
new file mode 100644
index 0000000..b70735c
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/test.rs
@@ -0,0 +1,117 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use arbtest::arbitrary::Arbitrary;
+
+use crate::error::Result;
+
+use super::{Image, ImageDataType, Rect};
+
+impl<T: ImageDataType> Image<T> {
+    #[cfg(test)]
+    pub fn new_random<R: rand::Rng>(size: (usize, usize), rng: &mut R) -> Result<Image<T>> {
+        let mut img = Self::new(size)?;
+        for y in 0..size.1 {
+            img.row_mut(y).iter_mut().for_each(|x| *x = T::random(rng));
+        }
+        Ok(img)
+    }
+
+    #[cfg(test)]
+    pub fn new_range(size: (usize, usize), start: f32, step: f32) -> Result<Image<T>> {
+        let mut img = Self::new(size)?;
+        for y in 0..size.1 {
+            img.row_mut(y).iter_mut().enumerate().for_each(|(x, val)| {
+                *val = T::from_f64((start + step * (y * size.0 + x) as f32) as f64)
+            });
+        }
+        Ok(img)
+    }
+}
+
+#[test]
+fn huge_image() {
+    assert!(Image::<u8>::new((1 << 28, 1 << 28)).is_err());
+}
+
+#[test]
+fn rect_basic() -> Result<()> {
+    let mut image = Image::<u8>::new((32, 42))?;
+    assert_eq!(
+        image
+            .get_rect_mut(Rect {
+                origin: (31, 40),
+                size: (1, 1)
+            })
+            .size(),
+        (1, 1)
+    );
+    assert_eq!(
+        image
+            .get_rect_mut(Rect {
+                origin: (0, 0),
+                size: (1, 1)
+            })
+            .size(),
+        (1, 1)
+    );
+    image
+        .get_rect_mut(Rect {
+            origin: (30, 30),
+            size: (1, 1),
+        })
+        .row(0)[0] = 1;
+    assert_eq!(image.row(30)[30], 1);
+    Ok(())
+}
+
+fn f64_conversions<T: ImageDataType + Eq + for<'a> Arbitrary<'a>>() {
+    arbtest::arbtest(|u| {
+        let t = T::arbitrary(u)?;
+        assert_eq!(t, T::from_f64(t.to_f64()));
+        Ok(())
+    });
+}
+
+#[test]
+fn u8_f64_conv() {
+    f64_conversions::<u8>();
+}
+
+#[test]
+fn u16_f64_conv() {
+    f64_conversions::<u16>();
+}
+
+#[test]
+fn u32_f64_conv() {
+    f64_conversions::<u32>();
+}
+
+#[test]
+fn i8_f64_conv() {
+    f64_conversions::<i8>();
+}
+
+#[test]
+fn i16_f64_conv() {
+    f64_conversions::<i16>();
+}
+
+#[test]
+fn i32_f64_conv() {
+    f64_conversions::<i32>();
+}
+
+#[test]
+fn f32_f64_conv() {
+    arbtest::arbtest(|u| {
+        let t = f32::arbitrary(u)?;
+        if !t.is_nan() {
+            assert_eq!(t, f32::from_f64(t.to_f64()));
+        }
+        Ok(())
+    });
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/typed.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/typed.rs
new file mode 100644
index 0000000..98f7fc8
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/typed.rs
@@ -0,0 +1,306 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::{fmt::Debug, marker::PhantomData};
+
+use crate::{
+    error::Result,
+    image::internal::DistinctRowsIndexes,
+    util::{CACHE_LINE_BYTE_SIZE, tracing_wrappers::*},
+};
+
+use super::{ImageDataType, OwnedRawImage, RawImageRect, RawImageRectMut, Rect};
+
+#[repr(transparent)]
+pub struct Image<T: ImageDataType> {
+    // Safety invariant: self.raw.data.is_aligned(T::DATA_TYPE_ID.size()) is true.
+    raw: OwnedRawImage,
+    _ph: PhantomData<T>,
+}
+
+impl<T: ImageDataType> Image<T> {
+    #[instrument(ret, err)]
+    pub fn new_with_padding(
+        size: (usize, usize),
+        offset: (usize, usize),
+        padding: (usize, usize),
+    ) -> Result<Image<T>> {
+        let s = T::DATA_TYPE_ID.size();
+        let img = OwnedRawImage::new_zeroed_with_padding(
+            (size.0 * s, size.1),
+            (offset.0 * s, offset.1),
+            (padding.0 * s, padding.1),
+        )?;
+        Ok(Self::from_raw(img))
+    }
+
+    #[instrument(ret, err)]
+    pub fn new(size: (usize, usize)) -> Result<Image<T>> {
+        Self::new_with_padding(size, (0, 0), (0, 0))
+    }
+
+    pub fn new_with_value(size: (usize, usize), value: T) -> Result<Image<T>> {
+        // TODO(veluca): skip zero-initializing the allocation if this becomes
+        // performance-sensitive.
+        let mut ret = Self::new(size)?;
+        ret.fill(value);
+        Ok(ret)
+    }
+
+    pub fn size(&self) -> (usize, usize) {
+        (
+            self.raw.byte_size().0 / T::DATA_TYPE_ID.size(),
+            self.raw.byte_size().1,
+        )
+    }
+
+    pub fn offset(&self) -> (usize, usize) {
+        (
+            self.raw.byte_offset().0 / T::DATA_TYPE_ID.size(),
+            self.raw.byte_offset().1,
+        )
+    }
+
+    pub fn padding(&self) -> (usize, usize) {
+        (
+            self.raw.byte_padding().0 / T::DATA_TYPE_ID.size(),
+            self.raw.byte_padding().1,
+        )
+    }
+
+    pub fn fill(&mut self, v: T) {
+        if self.size().0 == 0 {
+            return;
+        }
+        for y in 0..self.size().1 {
+            self.row_mut(y).fill(v);
+        }
+    }
+
+    pub fn get_rect_including_padding_mut(&mut self, rect: Rect) -> ImageRectMut<'_, T> {
+        ImageRectMut::from_raw(
+            self.raw
+                .get_rect_including_padding_mut(rect.to_byte_rect(T::DATA_TYPE_ID)),
+        )
+    }
+
+    pub fn get_rect_including_padding(&mut self, rect: Rect) -> ImageRect<'_, T> {
+        ImageRect::from_raw(
+            self.raw
+                .get_rect_including_padding(rect.to_byte_rect(T::DATA_TYPE_ID)),
+        )
+    }
+
+    pub fn get_rect_mut(&mut self, rect: Rect) -> ImageRectMut<'_, T> {
+        ImageRectMut::from_raw(self.raw.get_rect_mut(rect.to_byte_rect(T::DATA_TYPE_ID)))
+    }
+
+    pub fn get_rect(&self, rect: Rect) -> ImageRect<'_, T> {
+        ImageRect::from_raw(self.raw.get_rect(rect.to_byte_rect(T::DATA_TYPE_ID)))
+    }
+
+    pub fn try_clone(&self) -> Result<Self> {
+        Ok(Self::from_raw(self.raw.try_clone()?))
+    }
+
+    pub fn into_raw(self) -> OwnedRawImage {
+        self.raw
+    }
+
+    pub fn from_raw(raw: OwnedRawImage) -> Self {
+        const { assert!(CACHE_LINE_BYTE_SIZE.is_multiple_of(T::DATA_TYPE_ID.size())) };
+        assert!(raw.data.is_aligned(T::DATA_TYPE_ID.size()));
+        Image {
+            // Safety note: we just checked alignment.
+            raw,
+            _ph: PhantomData,
+        }
+    }
+
+    #[inline(always)]
+    pub fn row(&self, row: usize) -> &[T] {
+        let row = self.raw.row(row);
+        // SAFETY: Since self.raw.data.is_aligned(T::DATA_TYPE_ID.size()) by the safety invariant
+        // on `self`, the returned slice is aligned to T::DATA_TYPE_ID.size(), and sizeof(T) ==
+        // T::DATA_TYPE_ID.size() by the requirements of ImageDataType; moreover, ImageDataType
+        // requires T to be a bag-of-bits type with no padding, so the implicit transmute is not
+        // an issue.
+        unsafe {
+            std::slice::from_raw_parts(row.as_ptr() as *const T, row.len() / T::DATA_TYPE_ID.size())
+        }
+    }
+
+    #[inline(always)]
+    pub fn row_mut(&mut self, row: usize) -> &mut [T] {
+        let row = self.raw.row_mut(row);
+        // SAFETY: Since self.raw.data.is_aligned(T::DATA_TYPE_ID.size()) by the safety invariant
+        // on `self`, the returned slice is aligned to T::DATA_TYPE_ID.size(), and sizeof(T) ==
+        // T::DATA_TYPE_ID.size() by the requirements of ImageDataType; moreover, ImageDataType
+        // requires T to be a bag-of-bits type with no padding, so the implicit transmute is not
+        // an issue.
+        unsafe {
+            std::slice::from_raw_parts_mut(
+                row.as_mut_ptr() as *mut T,
+                row.len() / T::DATA_TYPE_ID.size(),
+            )
+        }
+    }
+
+    /// Note: this is quadratic in the number of rows. Indexing *ignores any padding rows*, i.e.
+    /// the row at index 0 will be the first row of the *padding*, unlike with all the other row
+    /// accessors.
+    #[inline(always)]
+    pub fn distinct_full_rows_mut<I: DistinctRowsIndexes>(&mut self, rows: I) -> I::Output<'_, T> {
+        // SAFETY: we don't write uninit data to the returned `rows`, and `self.raw` has ownership
+        // of the accessible bytes of `self.raw.data`.
+        let rows = unsafe { self.raw.data.distinct_rows_mut(rows) };
+        // SAFETY: Since self.raw.data.is_aligned(T::DATA_TYPE_ID.size()) by the safety invariant
+        // on `self`, the returned slices are aligned to T::DATA_TYPE_ID.size(), and sizeof(T)
+        // == T::DATA_TYPE_ID.size() by the requirements of ImageDataType; moreover, ImageDataType
+        // requires T to be a bag-of-bits type with no padding and `self.raw` guarantees its
+        // accessible bytes are initialized, so the transmute is not an issue.
+        unsafe { I::transmute_rows(rows) }
+    }
+}
+
+#[derive(Clone, Copy)]
+pub struct ImageRect<'a, T: ImageDataType> {
+    // Safety invariant: self.raw.data.is_aligned(T::DATA_TYPE_ID.size()) is true.
+    raw: RawImageRect<'a>,
+    _ph: PhantomData<T>,
+}
+
+impl<'a, T: ImageDataType> ImageRect<'a, T> {
+    pub fn rect(&self, rect: Rect) -> ImageRect<'a, T> {
+        Self::from_raw(self.raw.rect(rect.to_byte_rect(T::DATA_TYPE_ID)))
+    }
+
+    pub fn size(&self) -> (usize, usize) {
+        (
+            self.raw.byte_size().0 / T::DATA_TYPE_ID.size(),
+            self.raw.byte_size().1,
+        )
+    }
+
+    #[inline(always)]
+    pub fn row(&self, row: usize) -> &'a [T] {
+        let row = self.raw.row(row);
+        // SAFETY: Since self.raw.data.is_aligned(T::DATA_TYPE_ID.size()) by the safety invariant
+        // on `self`, the returned slice is aligned to T::DATA_TYPE_ID.size(), and sizeof(T) ==
+        // T::DATA_TYPE_ID.size() by the requirements of ImageDataType; moreover, ImageDataType
+        // requires T to be a bag-of-bits type with no padding, so the implicit transmute is not
+        // an issue.
+        unsafe {
+            std::slice::from_raw_parts(row.as_ptr() as *const T, row.len() / T::DATA_TYPE_ID.size())
+        }
+    }
+
+    pub fn iter(&self) -> impl Iterator<Item = T> + '_ {
+        (0..self.size().1).flat_map(|x| self.row(x).iter().cloned())
+    }
+
+    pub fn into_raw(self) -> RawImageRect<'a> {
+        self.raw
+    }
+
+    pub fn from_raw(raw: RawImageRect<'a>) -> Self {
+        const { assert!(CACHE_LINE_BYTE_SIZE.is_multiple_of(T::DATA_TYPE_ID.size())) };
+        assert!(raw.data.is_aligned(T::DATA_TYPE_ID.size()));
+        ImageRect {
+            // Safety note: we just checked alignment.
+            raw,
+            _ph: PhantomData,
+        }
+    }
+}
+
+pub struct ImageRectMut<'a, T: ImageDataType> {
+    // Safety invariant: self.raw.data.is_aligned(T::DATA_TYPE_ID.size()) is true.
+    raw: RawImageRectMut<'a>,
+    _ph: PhantomData<T>,
+}
+
+impl<'a, T: ImageDataType> ImageRectMut<'a, T> {
+    pub fn rect(&'a mut self, rect: Rect) -> ImageRectMut<'a, T> {
+        Self::from_raw(self.raw.rect_mut(rect.to_byte_rect(T::DATA_TYPE_ID)))
+    }
+
+    pub fn size(&self) -> (usize, usize) {
+        (
+            self.raw.byte_size().0 / T::DATA_TYPE_ID.size(),
+            self.raw.byte_size().1,
+        )
+    }
+
+    #[inline(always)]
+    pub fn row(&mut self, row: usize) -> &mut [T] {
+        let row = self.raw.row(row);
+        // SAFETY: Since self.raw.data.is_aligned(T::DATA_TYPE_ID.size()) by the safety invariant
+        // on `self`, the returned slice is aligned to T::DATA_TYPE_ID.size(), and sizeof(T) ==
+        // T::DATA_TYPE_ID.size() by the requirements of ImageDataType; moreover, ImageDataType
+        // requires T to be a bag-of-bits type with no padding, so the implicit transmute is not
+        // an issue.
+        unsafe {
+            std::slice::from_raw_parts_mut(
+                row.as_mut_ptr() as *mut T,
+                row.len() / T::DATA_TYPE_ID.size(),
+            )
+        }
+    }
+
+    pub fn as_rect(&'a self) -> ImageRect<'a, T> {
+        ImageRect::from_raw(self.raw.as_rect())
+    }
+
+    pub fn into_raw(self) -> RawImageRectMut<'a> {
+        self.raw
+    }
+
+    pub fn from_raw(raw: RawImageRectMut<'a>) -> Self {
+        const { assert!(CACHE_LINE_BYTE_SIZE.is_multiple_of(T::DATA_TYPE_ID.size())) };
+        assert!(raw.data.is_aligned(T::DATA_TYPE_ID.size()));
+        ImageRectMut {
+            // Safety note: we just checked alignment.
+            raw,
+            _ph: PhantomData,
+        }
+    }
+}
+
+impl<T: ImageDataType> Debug for Image<T> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "{:?} {}x{}",
+            T::DATA_TYPE_ID,
+            self.size().0,
+            self.size().1
+        )
+    }
+}
+
+impl<T: ImageDataType> Debug for ImageRect<'_, T> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "{:?} rect {}x{}",
+            T::DATA_TYPE_ID,
+            self.size().0,
+            self.size().1
+        )
+    }
+}
+
+impl<T: ImageDataType> Debug for ImageRectMut<'_, T> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "{:?} mutrect {}x{}",
+            T::DATA_TYPE_ID,
+            self.size().0,
+            self.size().1
+        )
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/lib.rs
new file mode 100644
index 0000000..6787b0b2
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/lib.rs
@@ -0,0 +1,26 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![deny(unsafe_code)]
+pub mod api;
+pub mod bit_reader;
+pub mod color;
+pub mod container;
+pub mod entropy_coding;
+pub mod error;
+pub mod features;
+pub mod frame;
+pub mod headers;
+pub mod icc;
+pub mod image;
+pub mod render;
+pub mod util;
+
+// TODO: Move these to a more appropriate location.
+const GROUP_DIM: usize = 256;
+const BLOCK_DIM: usize = 8;
+const BLOCK_SIZE: usize = BLOCK_DIM * BLOCK_DIM;
+#[allow(clippy::excessive_precision)]
+const MIN_SIGMA: f32 = -3.90524291751269967465540850526868;
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/buffer_splitter.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/buffer_splitter.rs
new file mode 100644
index 0000000..28e54bcd
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/buffer_splitter.rs
@@ -0,0 +1,97 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{api::JxlOutputBuffer, headers::Orientation, image::Rect, util::ShiftRightCeil};
+
+// Information for splitting the output buffers.
+pub(super) struct SaveStageBufferInfo {
+    pub(super) downsample: (u8, u8),
+    pub(super) orientation: Orientation,
+    pub(super) byte_size: usize,
+    pub(super) after_extend: bool,
+}
+
+/// Data structure responsible for handing out access to portions of the output buffers.
+pub struct BufferSplitter<'a, 'b>(&'a mut [Option<JxlOutputBuffer<'b>>]);
+
+impl<'a, 'b> BufferSplitter<'a, 'b> {
+    pub fn new(bufs: &'a mut [Option<JxlOutputBuffer<'b>>]) -> Self {
+        Self(bufs)
+    }
+
+    pub(super) fn get_local_buffers(
+        &mut self,
+        save_buffer_info: &[Option<SaveStageBufferInfo>],
+        rect: Rect,
+        outside_current_frame: bool,
+        frame_size: (usize, usize),
+        full_image_size: (usize, usize),
+        frame_origin: (isize, isize),
+    ) -> Vec<Option<JxlOutputBuffer<'_>>> {
+        let mut local_buffers = vec![];
+        let buffers = &mut *self.0;
+        local_buffers.reserve(buffers.len());
+        for _ in 0..buffers.len() {
+            local_buffers.push(None::<JxlOutputBuffer>);
+        }
+        for (i, (info, buf)) in save_buffer_info.iter().zip(buffers.iter_mut()).enumerate() {
+            let Some(bi) = info else {
+                // We never write to this buffer.
+                continue;
+            };
+            let Some(buf) = buf.as_mut() else {
+                // The buffer to write into was not provided.
+                continue;
+            };
+            if outside_current_frame && !bi.after_extend {
+                // Before-extend stages do not write to rects outside the current frame.
+                continue;
+            }
+            let mut channel_rect = rect.downsample(bi.downsample);
+            if !outside_current_frame {
+                let frame_size = (
+                    frame_size.0.shrc(bi.downsample.0),
+                    frame_size.1.shrc(bi.downsample.1),
+                );
+                channel_rect = channel_rect.clip(frame_size);
+                if bi.after_extend {
+                    // clip this rect to its visible area in the full image (in full image coordinates).
+                    let origin = (
+                        rect.origin.0 as isize + frame_origin.0,
+                        rect.origin.1 as isize + frame_origin.1,
+                    );
+                    let end = (
+                        origin.0 + rect.size.0 as isize,
+                        origin.1 + rect.size.1 as isize,
+                    );
+                    let origin = (origin.0.max(0) as usize, origin.1.max(0) as usize);
+                    let end = (
+                        end.0.min(full_image_size.0 as isize).max(0) as usize,
+                        end.1.min(full_image_size.1 as isize).max(0) as usize,
+                    );
+                    channel_rect = Rect {
+                        origin,
+                        size: (
+                            end.0.saturating_sub(origin.0),
+                            end.1.saturating_sub(origin.1),
+                        ),
+                    };
+                }
+            }
+            if channel_rect.size.0 == 0 || channel_rect.size.1 == 0 {
+                // Buffer would be empty anyway.
+                continue;
+            }
+            let channel_rect = bi.orientation.display_rect(channel_rect, full_image_size);
+            let channel_rect = channel_rect.to_byte_rect_sz(bi.byte_size);
+            local_buffers[i] = Some(buf.rect(channel_rect));
+        }
+        local_buffers
+    }
+
+    pub fn get_full_buffers(&mut self) -> &mut [Option<JxlOutputBuffer<'b>>] {
+        &mut *self.0
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/builder.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/builder.rs
new file mode 100644
index 0000000..7a8338af
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/builder.rs
@@ -0,0 +1,243 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::api::{JxlColorType, JxlDataFormat};
+use crate::error::{Error, Result};
+use crate::headers::Orientation;
+use crate::render::internal::ChannelInfo;
+use crate::render::save::SaveStage;
+use crate::util::{ShiftRightCeil, tracing_wrappers::*};
+
+use super::internal::{RenderPipelineShared, Stage};
+use super::stages::ExtendToImageDimensionsStage;
+use super::{RenderPipeline, RenderPipelineInOutStage, RenderPipelineInPlaceStage};
+
+pub(crate) struct RenderPipelineBuilder<Pipeline: RenderPipeline> {
+    shared: RenderPipelineShared<Pipeline::Buffer>,
+}
+
+impl<Pipeline: RenderPipeline> RenderPipelineBuilder<Pipeline> {
+    #[instrument(level = "debug")]
+    pub(super) fn new_with_chunk_size(
+        num_channels: usize,
+        size: (usize, usize),
+        downsampling_shift: usize,
+        mut log_group_size: usize,
+        num_passes: usize,
+        chunk_size: usize,
+    ) -> Self {
+        info!("creating render pipeline");
+        assert!(chunk_size <= u16::MAX as usize);
+        assert_ne!(chunk_size, 0);
+        // The number of pixels that a group encompasses in the final, upsampled image along one
+        // dimension is effectively multiplied by the upsampling factor.
+        log_group_size += downsampling_shift;
+        Self {
+            shared: RenderPipelineShared {
+                channel_info: vec![vec![
+                    ChannelInfo {
+                        ty: None,
+                        downsample: (0, 0)
+                    };
+                    num_channels
+                ]],
+                input_size: size,
+                log_group_size,
+                group_count: (size.0.shrc(log_group_size), size.1.shrc(log_group_size)),
+                stages: vec![],
+                group_chan_ready_passes: vec![
+                    vec![0; num_channels];
+                    size.0.shrc(log_group_size)
+                        * size.1.shrc(log_group_size)
+                ],
+                num_passes,
+                chunk_size,
+                extend_stage_index: None,
+            },
+        }
+    }
+
+    pub(super) fn add_stage_internal(mut self, stage: Stage<Pipeline::Buffer>) -> Result<Self> {
+        let input_type = stage.input_type();
+        let output_type = stage.output_type();
+        let shift = stage.shift();
+        let border = stage.border();
+        let is_extend = matches!(stage, Stage::Extend(_));
+        let current_info = self.shared.channel_info.last().unwrap().clone();
+        debug!(
+            last_stage_channel_info = ?current_info,
+            extend_stage_index= ?self.shared.extend_stage_index,
+            "adding stage '{stage}'",
+        );
+        let mut after_info = vec![];
+        for (c, info) in current_info.iter().enumerate() {
+            if !stage.uses_channel(c) {
+                after_info.push(ChannelInfo {
+                    ty: info.ty,
+                    downsample: (0, 0),
+                });
+            } else {
+                if let Some(ty) = info.ty
+                    && ty != input_type
+                {
+                    return Err(Error::PipelineChannelTypeMismatch(
+                        stage.to_string(),
+                        c,
+                        input_type,
+                        ty,
+                    ));
+                }
+                after_info.push(ChannelInfo {
+                    ty: Some(output_type.unwrap_or(input_type)),
+                    downsample: shift,
+                });
+            }
+        }
+        if self.shared.extend_stage_index.is_some()
+            && (shift != (0, 0) || border != (0, 0) || is_extend)
+        {
+            return Err(Error::PipelineInvalidStageAfterExtend(stage.to_string()));
+        }
+        if is_extend {
+            self.shared.extend_stage_index = Some(self.shared.stages.len());
+        }
+        debug!(
+            new_channel_info = ?after_info,
+            extend_stage_index= ?self.shared.extend_stage_index,
+            "added stage '{stage}'",
+        );
+        self.shared.channel_info.push(after_info);
+        self.shared.stages.push(stage);
+        Ok(self)
+    }
+
+    pub fn new(
+        num_channels: usize,
+        size: (usize, usize),
+        downsampling_shift: usize,
+        log_group_size: usize,
+        num_passes: usize,
+    ) -> Self {
+        Self::new_with_chunk_size(
+            num_channels,
+            size,
+            downsampling_shift,
+            log_group_size,
+            num_passes,
+            1 << (log_group_size + downsampling_shift),
+        )
+    }
+
+    #[instrument(skip_all, err)]
+    pub fn add_save_stage(
+        self,
+        channels: &[usize],
+        orientation: Orientation,
+        output_buffer_index: usize,
+        color_type: JxlColorType,
+        data_format: JxlDataFormat,
+    ) -> Result<Self> {
+        let stage = SaveStage::new(
+            channels,
+            orientation,
+            output_buffer_index,
+            color_type,
+            data_format,
+        );
+        self.add_stage_internal(Stage::Save(stage))
+    }
+
+    #[instrument(skip_all, err)]
+    pub fn add_extend_stage(self, extend: ExtendToImageDimensionsStage) -> Result<Self> {
+        self.add_stage_internal(Stage::Extend(extend))
+    }
+
+    #[instrument(skip_all, err)]
+    pub fn add_inplace_stage<S: RenderPipelineInPlaceStage>(self, stage: S) -> Result<Self> {
+        self.add_stage_internal(Stage::InPlace(Pipeline::box_inplace_stage(stage)))
+    }
+
+    #[instrument(skip_all, err)]
+    pub fn add_inout_stage<S: RenderPipelineInOutStage>(self, stage: S) -> Result<Self> {
+        self.add_stage_internal(Stage::InOut(Pipeline::box_inout_stage(stage)))
+    }
+
+    #[instrument(skip_all, err)]
+    pub fn build(mut self) -> Result<Box<Pipeline>> {
+        let channel_info = &mut self.shared.channel_info;
+        let num_channels = channel_info[0].len();
+        let mut cur_downsamples = vec![(0u8, 0u8); num_channels];
+        for (s, stage) in self.shared.stages.iter().enumerate().rev() {
+            let [current_info, next_info, ..] = &mut channel_info[s..] else {
+                unreachable!()
+            };
+            let mut save_downsample = None;
+            for chan in 0..num_channels {
+                let cur_chan = &mut current_info[chan];
+                let next_chan = &mut next_info[chan];
+                let uses_channel = stage.uses_channel(chan);
+                let input_type = stage.input_type();
+
+                if cur_chan.ty.is_none() {
+                    cur_chan.ty = if uses_channel {
+                        Some(input_type)
+                    } else {
+                        next_chan.ty
+                    }
+                }
+                // Arithmetic overflows here should be very uncommon, so custom error variants
+                // are probably unwarranted.
+                let cur_downsample = &mut cur_downsamples[chan];
+                if matches!(stage, Stage::Save(_))
+                    && save_downsample.is_some_and(|x| x != *cur_downsample)
+                {
+                    save_downsample = Some(*cur_downsample);
+                    return Err(Error::SaveDifferentDownsample(
+                        save_downsample.unwrap(),
+                        *cur_downsample,
+                    ));
+                }
+                let next_downsample = &mut next_chan.downsample;
+                let next_total_downsample = *cur_downsample;
+                cur_downsample.0 = cur_downsample
+                    .0
+                    .checked_add(next_downsample.0)
+                    .ok_or(Error::ArithmeticOverflow)?;
+                cur_downsample.1 = cur_downsample
+                    .1
+                    .checked_add(next_downsample.1)
+                    .ok_or(Error::ArithmeticOverflow)?;
+                *next_downsample = next_total_downsample;
+            }
+        }
+        for (chan, cur_downsample) in cur_downsamples.iter().enumerate() {
+            channel_info[0][chan].downsample = *cur_downsample;
+        }
+        #[cfg(feature = "tracing")]
+        {
+            for (s, (current_info, stage)) in channel_info
+                .iter()
+                .zip(self.shared.stages.iter())
+                .enumerate()
+            {
+                debug!("final channel info before stage {s} '{stage}': {current_info:?}");
+            }
+            debug!(
+                "final channel info after all stages {:?}",
+                channel_info.last().unwrap()
+            );
+        }
+
+        // Ensure all channels have been used, so that we know the types of all buffers at all
+        // stages.
+        for (c, chinfo) in channel_info.iter().flat_map(|x| x.iter().enumerate()) {
+            if chinfo.ty.is_none() {
+                return Err(Error::PipelineChannelUnused(c));
+            }
+        }
+
+        Ok(Box::new(Pipeline::new_from_shared(self.shared)?))
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/channels.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/channels.rs
new file mode 100644
index 0000000..97bb170
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/channels.rs
@@ -0,0 +1,146 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/// Multi-row channel accessor for immutable access.
+///
+/// Provides 2D indexing where `channels[ch]` returns `&[&[T]]` (all rows for a channel),
+/// and `channels[ch][row]` returns `&[T]` (pixels for a specific row).
+///
+/// This eliminates nested Vec collections while maintaining the same indexing syntax.
+pub struct Channels<'a, T> {
+    pub(crate) row_data: Vec<&'a [T]>,
+    num_channels: usize,
+    pub(crate) rows_per_channel: usize,
+}
+
+impl<'a, T> Channels<'a, T> {
+    /// Create a new Channels accessor.
+    ///
+    /// # Arguments
+    /// * `row_data` - Flat vector of all rows for all channels (length = num_channels * rows_per_channel)
+    /// * `num_channels` - Number of channels
+    /// * `rows_per_channel` - Number of rows per channel (typically 2*BORDER+1)
+    pub fn new(row_data: Vec<&'a [T]>, num_channels: usize, rows_per_channel: usize) -> Self {
+        debug_assert_eq!(
+            row_data.len(),
+            num_channels * rows_per_channel,
+            "row_data length must equal num_channels * rows_per_channel"
+        );
+        Self {
+            row_data,
+            num_channels,
+            rows_per_channel,
+        }
+    }
+
+    /// Returns the number of channels.
+    pub fn len(&self) -> usize {
+        self.num_channels
+    }
+
+    /// Returns true if there are no channels.
+    pub fn is_empty(&self) -> bool {
+        self.num_channels == 0
+    }
+
+    /// Returns an iterator over channel slices.
+    pub fn iter(&self) -> impl Iterator<Item = &[&'a [T]]> {
+        (0..self.num_channels).map(move |ch| &self[ch])
+    }
+}
+
+/// Implement indexing: channels[ch] returns &[&[T]]
+impl<'a, T> std::ops::Index<usize> for Channels<'a, T> {
+    type Output = [&'a [T]];
+
+    fn index(&self, ch: usize) -> &[&'a [T]] {
+        let start = ch * self.rows_per_channel;
+        &self.row_data[start..start + self.rows_per_channel]
+    }
+}
+
+/// Multi-row channel accessor for mutable access.
+///
+/// Provides 2D indexing where `channels[ch]` returns `&[&mut [T]]` or `&mut [&mut [T]]`,
+/// and `channels[ch][row]` returns `&mut [T]` (pixels for a specific row).
+pub struct ChannelsMut<'a, T> {
+    pub(crate) row_data: Vec<&'a mut [T]>,
+    num_channels: usize,
+    pub(crate) rows_per_channel: usize,
+}
+
+impl<'a, T> ChannelsMut<'a, T> {
+    /// Create a new ChannelsMut accessor.
+    ///
+    /// # Arguments
+    /// * `row_data` - Flat vector of all mutable rows for all channels
+    /// * `num_channels` - Number of channels
+    /// * `rows_per_channel` - Number of rows per channel (typically 1 << SHIFT)
+    pub fn new(row_data: Vec<&'a mut [T]>, num_channels: usize, rows_per_channel: usize) -> Self {
+        debug_assert_eq!(
+            row_data.len(),
+            num_channels * rows_per_channel,
+            "row_data length must equal num_channels * rows_per_channel"
+        );
+        Self {
+            row_data,
+            num_channels,
+            rows_per_channel,
+        }
+    }
+
+    /// Returns the number of channels.
+    pub fn len(&self) -> usize {
+        self.num_channels
+    }
+
+    /// Returns true if there are no channels.
+    pub fn is_empty(&self) -> bool {
+        self.num_channels == 0
+    }
+
+    /// Splits the first 3 channels into separate mutable slices.
+    /// Returns a tuple containing mutable references to each channel's rows.
+    #[allow(clippy::type_complexity)]
+    pub fn split_first_3_mut(
+        &mut self,
+    ) -> (&mut [&'a mut [T]], &mut [&'a mut [T]], &mut [&'a mut [T]]) {
+        assert!(
+            3 <= self.num_channels,
+            "requested 3 channels but only have {}",
+            self.num_channels
+        );
+        let rpc = self.rows_per_channel;
+        let (first, rest) = self.row_data.split_at_mut(rpc);
+        let (second, rest) = rest.split_at_mut(rpc);
+        let (third, _) = rest.split_at_mut(rpc);
+        (first, second, third)
+    }
+
+    /// Returns a mutable iterator over all channels.
+    /// Each item is a mutable slice of rows for that channel.
+    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut [&'a mut [T]]> {
+        let rpc = self.rows_per_channel;
+        self.row_data.chunks_mut(rpc)
+    }
+}
+
+/// Implement immutable indexing: channels[ch] returns &[&mut [T]]
+impl<'a, T> std::ops::Index<usize> for ChannelsMut<'a, T> {
+    type Output = [&'a mut [T]];
+
+    fn index(&self, ch: usize) -> &[&'a mut [T]] {
+        let start = ch * self.rows_per_channel;
+        &self.row_data[start..start + self.rows_per_channel]
+    }
+}
+
+/// Implement mutable indexing: &mut channels[ch] returns &mut [&mut [T]]
+impl<'a, T> std::ops::IndexMut<usize> for ChannelsMut<'a, T> {
+    fn index_mut(&mut self, ch: usize) -> &mut [&'a mut [T]] {
+        let start = ch * self.rows_per_channel;
+        &mut self.row_data[start..start + self.rows_per_channel]
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/internal.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/internal.rs
new file mode 100644
index 0000000..f81c033ae
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/internal.rs
@@ -0,0 +1,227 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::any::Any;
+use std::fmt::Display;
+
+use crate::error::Result;
+use crate::image::{DataTypeTag, ImageDataType};
+
+use super::save::SaveStage;
+use super::stages::ExtendToImageDimensionsStage;
+use super::{RenderPipelineInOutStage, RenderPipelineInPlaceStage};
+
+pub enum Stage<Buffer> {
+    InPlace(Box<dyn RunInPlaceStage<Buffer>>),
+    InOut(Box<dyn RunInOutStage<Buffer>>),
+    Save(SaveStage),
+    Extend(ExtendToImageDimensionsStage),
+}
+
+impl<Buffer: 'static> Stage<Buffer> {
+    pub(super) fn init_local_state(&self) -> Result<Option<Box<dyn Any>>> {
+        match self {
+            Stage::InPlace(s) => s.init_local_state(),
+            Stage::InOut(s) => s.init_local_state(),
+            _ => Ok(None),
+        }
+    }
+
+    pub(super) fn shift(&self) -> (u8, u8) {
+        match self {
+            Stage::InOut(s) => s.shift(),
+            _ => (0, 0),
+        }
+    }
+
+    pub(super) fn border(&self) -> (u8, u8) {
+        match self {
+            Stage::InOut(s) => s.border(),
+            _ => (0, 0),
+        }
+    }
+
+    #[cfg(test)]
+    pub(super) fn new_size(&self, size: (usize, usize)) -> (usize, usize) {
+        match self {
+            Stage::Extend(e) => e.image_size,
+            _ => size,
+        }
+    }
+
+    pub(super) fn uses_channel(&self, c: usize) -> bool {
+        match self {
+            Stage::Extend(_) => true,
+            Stage::InPlace(s) => s.uses_channel(c),
+            Stage::InOut(s) => s.uses_channel(c),
+            Stage::Save(s) => s.uses_channel(c),
+        }
+    }
+    pub(super) fn input_type(&self) -> DataTypeTag {
+        match self {
+            Stage::Extend(_) => DataTypeTag::F32,
+            Stage::InPlace(s) => s.ty(),
+            Stage::InOut(s) => s.input_type(),
+            Stage::Save(s) => s.input_type(),
+        }
+    }
+    pub(super) fn output_type(&self) -> Option<DataTypeTag> {
+        match self {
+            Stage::InOut(s) => Some(s.output_type()),
+            _ => None,
+        }
+    }
+}
+
+impl<Buffer> Display for Stage<Buffer> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Stage::InOut(s) => write!(f, "{}", s),
+            Stage::InPlace(s) => write!(f, "{}", s),
+            Stage::Save(s) => write!(f, "{}", s),
+            Stage::Extend(e) => write!(f, "{}", e),
+        }
+    }
+}
+
+#[derive(Clone, Debug)]
+pub struct ChannelInfo {
+    pub ty: Option<DataTypeTag>,
+    pub downsample: (u8, u8),
+}
+
+pub struct RenderPipelineShared<Buffer> {
+    pub channel_info: Vec<Vec<ChannelInfo>>,
+    pub input_size: (usize, usize),
+    pub log_group_size: usize,
+    pub group_count: (usize, usize),
+    pub group_chan_ready_passes: Vec<Vec<usize>>,
+    pub num_passes: usize,
+    pub chunk_size: usize,
+    pub stages: Vec<Stage<Buffer>>,
+    pub extend_stage_index: Option<usize>,
+}
+
+impl<Buffer> RenderPipelineShared<Buffer> {
+    pub fn group_position(&self, group_id: usize) -> (usize, usize) {
+        (group_id % self.group_count.0, group_id / self.group_count.0)
+    }
+
+    pub fn group_offset(&self, group_id: usize) -> (usize, usize) {
+        let group = self.group_position(group_id);
+        (
+            group.0 << self.log_group_size,
+            group.1 << self.log_group_size,
+        )
+    }
+
+    pub fn group_size(&self, group_id: usize) -> (usize, usize) {
+        let goffset = self.group_offset(group_id);
+        (
+            self.input_size
+                .0
+                .min(goffset.0 + (1 << self.log_group_size))
+                - goffset.0,
+            self.input_size
+                .1
+                .min(goffset.1 + (1 << self.log_group_size))
+                - goffset.1,
+        )
+    }
+
+    pub fn group_size_for_channel(
+        &self,
+        channel: usize,
+        requested_data_type: DataTypeTag,
+    ) -> (usize, usize) {
+        let ChannelInfo { downsample, ty } = self.channel_info[0][channel];
+        if ty.unwrap() != requested_data_type {
+            panic!(
+                "Invalid pipeline usage: incorrect channel type, requested {:?}, but pipeline wants {ty:?}",
+                requested_data_type
+            );
+        }
+        (
+            1 << (self.log_group_size - downsample.0 as usize),
+            1 << (self.log_group_size - downsample.1 as usize),
+        )
+    }
+
+    pub fn num_channels(&self) -> usize {
+        self.channel_info[0].len()
+    }
+}
+
+pub trait PipelineBuffer {
+    type InPlaceExtraInfo;
+    type InOutExtraInfo;
+}
+
+pub trait InPlaceStage: Any + Display {
+    fn init_local_state(&self) -> Result<Option<Box<dyn Any>>>;
+    fn uses_channel(&self, c: usize) -> bool;
+    fn ty(&self) -> DataTypeTag;
+}
+
+pub trait RunInPlaceStage<Buffer: PipelineBuffer>: InPlaceStage {
+    fn run_stage_on(
+        &self,
+        info: Buffer::InPlaceExtraInfo,
+        buffers: &mut [&mut Buffer],
+        state: Option<&mut dyn Any>,
+    );
+}
+
+impl<T: RenderPipelineInPlaceStage> InPlaceStage for T {
+    fn init_local_state(&self) -> Result<Option<Box<dyn Any>>> {
+        self.init_local_state()
+    }
+    fn uses_channel(&self, c: usize) -> bool {
+        self.uses_channel(c)
+    }
+    fn ty(&self) -> DataTypeTag {
+        T::Type::DATA_TYPE_ID
+    }
+}
+
+pub trait InOutStage: Any + Display {
+    fn init_local_state(&self) -> Result<Option<Box<dyn Any>>>;
+    fn shift(&self) -> (u8, u8);
+    fn border(&self) -> (u8, u8);
+    fn uses_channel(&self, c: usize) -> bool;
+    fn input_type(&self) -> DataTypeTag;
+    fn output_type(&self) -> DataTypeTag;
+}
+
+impl<T: RenderPipelineInOutStage> InOutStage for T {
+    fn init_local_state(&self) -> Result<Option<Box<dyn Any>>> {
+        self.init_local_state()
+    }
+    fn uses_channel(&self, c: usize) -> bool {
+        self.uses_channel(c)
+    }
+    fn shift(&self) -> (u8, u8) {
+        T::SHIFT
+    }
+    fn border(&self) -> (u8, u8) {
+        T::BORDER
+    }
+    fn input_type(&self) -> DataTypeTag {
+        T::InputT::DATA_TYPE_ID
+    }
+    fn output_type(&self) -> DataTypeTag {
+        T::OutputT::DATA_TYPE_ID
+    }
+}
+
+pub trait RunInOutStage<Buffer: PipelineBuffer>: InOutStage {
+    fn run_stage_on(
+        &self,
+        info: Buffer::InOutExtraInfo,
+        input_buffers: &[&Buffer],
+        output_buffers: &mut [&mut Buffer],
+        state: Option<&mut dyn Any>,
+    );
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/helpers.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/helpers.rs
new file mode 100644
index 0000000..a86c442
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/helpers.rs
@@ -0,0 +1,54 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/// Returns a vector of f(&mut vals[idx[i].0][idx[i].1]). Panics if any of the indices are out of
+/// bounds or idx[i] == idx[j] for i != j.
+pub(super) fn get_distinct_indices<'a, T>(
+    vals: &'a mut [impl AsMut<[T]>],
+    idx: &[(usize, usize)],
+) -> Vec<&'a mut T> {
+    let mut sorted_with_pos: Vec<_> = idx.iter().copied().enumerate().collect();
+    sorted_with_pos.sort_by_key(|x| x.1);
+
+    let mut answer_buffer = vec![];
+    for _ in 0..idx.len() {
+        answer_buffer.push(None);
+    }
+
+    let mut targets = sorted_with_pos.into_iter();
+    let mut target = targets.next().unwrap();
+    'outer: for (aa, bufs) in vals.iter_mut().enumerate() {
+        for (bb, buf) in bufs.as_mut().iter_mut().enumerate() {
+            let (pos, (a, b)) = target;
+            if aa == a && bb == b {
+                answer_buffer[pos] = Some(buf);
+                if let Some(t) = targets.next() {
+                    target = t;
+                } else {
+                    break 'outer;
+                }
+            }
+        }
+    }
+
+    answer_buffer
+        .into_iter()
+        .map(|x| x.expect("Not all elements were found"))
+        .collect()
+}
+
+/// Mirror-reflects a value v to fit in a [0; s) range.
+pub(super) fn mirror(mut v: isize, s: usize) -> usize {
+    // TODO(veluca): consider speeding this up if needed.
+    loop {
+        if v < 0 {
+            v = -v - 1;
+        } else if v >= s as isize {
+            v = s as isize * 2 - v - 1;
+        } else {
+            return v as usize;
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/mod.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/mod.rs
new file mode 100644
index 0000000..d3d5cbe
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/mod.rs
@@ -0,0 +1,474 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(clippy::needless_range_loop)]
+
+use std::any::Any;
+
+use row_buffers::RowBuffer;
+
+use crate::api::JxlOutputBuffer;
+use crate::error::Result;
+use crate::image::{Image, ImageDataType, OwnedRawImage, Rect};
+use crate::render::MAX_BORDER;
+use crate::render::buffer_splitter::{BufferSplitter, SaveStageBufferInfo};
+use crate::render::internal::Stage;
+use crate::util::{ShiftRightCeil, tracing_wrappers::*};
+
+use super::RenderPipeline;
+use super::internal::{RenderPipelineShared, RunInOutStage, RunInPlaceStage};
+
+mod helpers;
+mod render_group;
+pub(super) mod row_buffers;
+mod run_stage;
+mod save;
+
+struct InputBuffer {
+    // One buffer per channel.
+    data: Vec<Option<OwnedRawImage>>,
+    completed_passes: usize,
+}
+
+pub struct LowMemoryRenderPipeline {
+    shared: RenderPipelineShared<RowBuffer>,
+    input_buffers: Vec<InputBuffer>,
+    row_buffers: Vec<Vec<RowBuffer>>,
+    save_buffer_info: Vec<Option<SaveStageBufferInfo>>,
+    // The input buffer that each channel of each stage should use.
+    // This is indexed both by stage index (0 corresponds to input data, 1 to stage[0], etc) and by
+    // channel index (as only used channels have a buffer).
+    stage_input_buffer_index: Vec<Vec<(usize, usize)>>,
+    // Tracks whether we already rendered the padding around the core frame (if any).
+    padding_was_rendered: bool,
+    // The amount of pixels that each stage needs to *output* around the current group to
+    // run future stages correctly.
+    stage_output_border_pixels: Vec<(usize, usize)>,
+    // The amount of pixels that we need to read (for every channel) in non-edge groups to run all
+    // stages correctly.
+    input_border_pixels: Vec<(usize, usize)>,
+    has_nontrivial_border: bool,
+    // For every stage, the downsampling level of *any* channel that the stage uses at that point.
+    // Note that this must be equal across all the used channels.
+    downsampling_for_stage: Vec<(usize, usize)>,
+    // Local states of each stage, if any.
+    local_states: Vec<Option<Box<dyn Any>>>,
+}
+
+impl LowMemoryRenderPipeline {
+    // TODO(veluca): most of this logic will need to change to ensure better cache utilization and
+    // lower memory usage.
+    fn render_with_new_group(
+        &mut self,
+        new_group_id: usize,
+        buffer_splitter: &mut BufferSplitter,
+    ) -> Result<()> {
+        let (gx, gy) = self.shared.group_position(new_group_id);
+
+        // We put groups that are 2 afar here, because even if they could not have become
+        // renderable, they might have become freeable.
+        let mut possible_groups = vec![];
+        for dy in -2..=2 {
+            let igy = gy as isize + dy;
+            if igy < 0 || igy >= self.shared.group_count.1 as isize {
+                continue;
+            }
+            for dx in -2..=2 {
+                let igx = gx as isize + dx;
+                if igx < 0 || igx >= self.shared.group_count.0 as isize {
+                    continue;
+                }
+                possible_groups.push(igy as usize * self.shared.group_count.0 + igx as usize);
+            }
+        }
+
+        // First, render all groups that have made progress; only check those that *could* have
+        // made progress.
+        for g in possible_groups.iter().copied() {
+            let ready_passes = self.shared.group_chan_ready_passes[g]
+                .iter()
+                .copied()
+                .min()
+                .unwrap();
+            if self.input_buffers[g].completed_passes < ready_passes {
+                let (gx, gy) = self.shared.group_position(g);
+                let mut fully_ready_passes = ready_passes;
+                // Here we assume that we never need more than one group worth of border.
+                if self.has_nontrivial_border {
+                    for dy in -1..=1 {
+                        let igy = gy as isize + dy;
+                        if igy < 0 || igy >= self.shared.group_count.1 as isize {
+                            continue;
+                        }
+                        for dx in -1..=1 {
+                            let igx = gx as isize + dx;
+                            if igx < 0 || igx >= self.shared.group_count.0 as isize {
+                                continue;
+                            }
+                            let ig = (igy as usize) * self.shared.group_count.0 + igx as usize;
+                            let ready_passes = self.shared.group_chan_ready_passes[ig]
+                                .iter()
+                                .copied()
+                                .min()
+                                .unwrap();
+                            fully_ready_passes = fully_ready_passes.min(ready_passes);
+                        }
+                    }
+                }
+                if self.input_buffers[g].completed_passes >= fully_ready_passes {
+                    continue;
+                }
+                debug!(
+                    "new ready passes for group {gx},{gy} ({} completed, \
+                    {ready_passes} ready, {fully_ready_passes} ready including neighbours)",
+                    self.input_buffers[g].completed_passes
+                );
+
+                // Prepare output buffers for the group.
+                let (origin, size) = if let Some(e) = self.shared.extend_stage_index {
+                    let Stage::Extend(e) = &self.shared.stages[e] else {
+                        unreachable!("extend stage is not an extend stage");
+                    };
+                    (e.frame_origin, e.image_size)
+                } else {
+                    ((0, 0), self.shared.input_size)
+                };
+                let gsz = (
+                    1 << self.shared.log_group_size,
+                    1 << self.shared.log_group_size,
+                );
+                let rect_to_render = Rect {
+                    size: gsz,
+                    origin: (gsz.0 * gx, gsz.1 * gy),
+                };
+                let mut local_buffers = buffer_splitter.get_local_buffers(
+                    &self.save_buffer_info,
+                    rect_to_render,
+                    false,
+                    self.shared.input_size,
+                    size,
+                    origin,
+                );
+
+                self.render_group((gx, gy), &mut local_buffers)?;
+
+                self.input_buffers[g].completed_passes = fully_ready_passes;
+            }
+        }
+
+        // Clear buffers that will not be used again.
+        for g in possible_groups.iter().copied() {
+            let (gx, gy) = self.shared.group_position(g);
+            let mut neigh_complete_passes = self.input_buffers[g].completed_passes;
+            if self.has_nontrivial_border {
+                for dy in -1..=1 {
+                    let igy = gy as isize + dy;
+                    if igy < 0 || igy >= self.shared.group_count.1 as isize {
+                        continue;
+                    }
+                    for dx in -1..=1 {
+                        let igx = gx as isize + dx;
+                        if igx < 0 || igx >= self.shared.group_count.0 as isize {
+                            continue;
+                        }
+                        let ig = (igy as usize) * self.shared.group_count.0 + igx as usize;
+                        neigh_complete_passes = self.input_buffers[ig]
+                            .completed_passes
+                            .min(neigh_complete_passes);
+                    }
+                }
+            }
+            if self.shared.num_passes <= neigh_complete_passes {
+                for b in self.input_buffers[g].data.iter_mut() {
+                    *b = None;
+                }
+            }
+        }
+        Ok(())
+    }
+}
+
+impl RenderPipeline for LowMemoryRenderPipeline {
+    type Buffer = RowBuffer;
+
+    fn new_from_shared(shared: RenderPipelineShared<Self::Buffer>) -> Result<Self> {
+        let mut input_buffers = vec![];
+        for _ in 0..shared.group_chan_ready_passes.len() {
+            input_buffers.push(InputBuffer {
+                data: vec![],
+                completed_passes: 0,
+            });
+            for _ in 0..shared.group_chan_ready_passes[0].len() {
+                input_buffers.last_mut().unwrap().data.push(None);
+            }
+        }
+        let nc = shared.channel_info[0].len();
+        let mut previous_inout: Vec<_> = (0..nc).map(|x| (0usize, x)).collect();
+        let mut stage_input_buffer_index = vec![];
+        let mut next_border_and_cur_downsample = vec![vec![]];
+
+        for ci in shared.channel_info[0].iter() {
+            next_border_and_cur_downsample[0].push((0, ci.downsample));
+        }
+
+        // For each stage, compute in which stage its input was buffered (the previous InOut
+        // stage). Also, compute for each InOut stage and channel the border with which the stage
+        // output is used; this will used to allocate buffers of the correct size.
+        for (i, stage) in shared.stages.iter().enumerate() {
+            stage_input_buffer_index.push(previous_inout.clone());
+            next_border_and_cur_downsample.push(vec![]);
+            if let Stage::InOut(p) = stage {
+                for (chan, (ps, pc)) in previous_inout.iter_mut().enumerate() {
+                    if !p.uses_channel(chan) {
+                        continue;
+                    }
+                    next_border_and_cur_downsample[*ps][*pc].0 = p.border().1;
+                    *ps = i + 1;
+                    *pc = next_border_and_cur_downsample[i + 1].len();
+                    next_border_and_cur_downsample[i + 1]
+                        .push((0, shared.channel_info[i + 1][chan].downsample));
+                }
+            }
+        }
+
+        let mut initial_buffers = vec![];
+        for chan in 0..nc {
+            initial_buffers.push(RowBuffer::new(
+                shared.channel_info[0][chan].ty.unwrap(),
+                next_border_and_cur_downsample[0][chan].0 as usize,
+                0,
+                shared.chunk_size >> shared.channel_info[0][chan].downsample.0,
+            )?);
+        }
+        let mut row_buffers = vec![initial_buffers];
+
+        // Allocate buffers.
+        for (i, stage) in shared.stages.iter().enumerate() {
+            let mut stage_buffers = vec![];
+            for (next_y_border, (dsx, _)) in next_border_and_cur_downsample[i + 1].iter() {
+                stage_buffers.push(RowBuffer::new(
+                    stage.output_type().unwrap(),
+                    *next_y_border as usize,
+                    stage.shift().1 as usize,
+                    shared.chunk_size >> *dsx,
+                )?);
+            }
+            row_buffers.push(stage_buffers);
+        }
+        // Compute information to be used to compute sub-rects for "save" stages to operate on
+        // rects.
+        let mut save_buffer_info = vec![];
+        'stage: for (i, (s, ci)) in shared
+            .stages
+            .iter()
+            .zip(shared.channel_info.iter())
+            .enumerate()
+        {
+            let Stage::Save(s) = s else {
+                continue;
+            };
+            for (c, ci) in ci.iter().enumerate() {
+                if s.uses_channel(c) {
+                    let info = SaveStageBufferInfo {
+                        downsample: ci.downsample,
+                        orientation: s.orientation,
+                        byte_size: s.data_format.bytes_per_sample() * s.channels.len(),
+                        after_extend: shared.extend_stage_index.is_some_and(|e| i > e),
+                    };
+                    while save_buffer_info.len() <= s.output_buffer_index {
+                        save_buffer_info.push(None);
+                    }
+                    save_buffer_info[s.output_buffer_index] = Some(info);
+                    continue 'stage;
+                }
+            }
+        }
+
+        // Compute the amount of border pixels needed per channel, per stage.
+        let mut border_pixels = vec![(0usize, 0usize); nc];
+        let mut border_pixels_per_stage = vec![];
+        for s in shared.stages.iter().rev() {
+            let mut stage_max = (0, 0);
+            for (c, bp) in border_pixels.iter_mut().enumerate() {
+                if !s.uses_channel(c) {
+                    continue;
+                }
+                stage_max.0 = stage_max.0.max(bp.0);
+                stage_max.1 = stage_max.1.max(bp.1);
+
+                bp.0 = bp.0.shrc(s.shift().0) + s.border().0 as usize;
+                bp.1 = bp.1.shrc(s.shift().1) + s.border().1 as usize;
+            }
+            border_pixels_per_stage.push(stage_max);
+        }
+        border_pixels_per_stage.reverse();
+
+        assert!(border_pixels_per_stage[0].0 <= MAX_BORDER);
+
+        let downsampling_for_stage = shared
+            .stages
+            .iter()
+            .zip(shared.channel_info.iter())
+            .map(|(s, ci)| {
+                let dowsamplings: Vec<_> = (0..nc)
+                    .filter_map(|c| {
+                        if s.uses_channel(c) {
+                            Some(ci[c].downsample)
+                        } else {
+                            None
+                        }
+                    })
+                    .collect();
+                for &d in dowsamplings.iter() {
+                    assert_eq!(d, dowsamplings[0]);
+                }
+                (dowsamplings[0].0 as usize, dowsamplings[0].1 as usize)
+            })
+            .collect();
+
+        Ok(Self {
+            input_buffers,
+            stage_input_buffer_index,
+            row_buffers,
+            padding_was_rendered: false,
+            save_buffer_info,
+            stage_output_border_pixels: border_pixels_per_stage,
+            has_nontrivial_border: border_pixels.iter().any(|x| *x != (0, 0)),
+            input_border_pixels: border_pixels,
+            local_states: shared
+                .stages
+                .iter()
+                .map(|x| x.init_local_state())
+                .collect::<Result<_>>()?,
+            shared,
+            downsampling_for_stage,
+        })
+    }
+
+    #[instrument(skip_all, err)]
+    fn get_buffer<T: ImageDataType>(&mut self, channel: usize) -> Result<Image<T>> {
+        let sz = self.shared.group_size_for_channel(channel, T::DATA_TYPE_ID);
+        Image::<T>::new(sz)
+    }
+
+    fn set_buffer_for_group<T: ImageDataType>(
+        &mut self,
+        channel: usize,
+        group_id: usize,
+        num_passes: usize,
+        buf: Image<T>,
+        buffer_splitter: &mut BufferSplitter,
+    ) -> Result<()> {
+        debug!(
+            "filling data for group {}, channel {}, using type {:?}",
+            group_id,
+            channel,
+            T::DATA_TYPE_ID,
+        );
+        self.input_buffers[group_id].data[channel] = Some(buf.into_raw());
+        self.shared.group_chan_ready_passes[group_id][channel] += num_passes;
+
+        self.render_with_new_group(group_id, buffer_splitter)
+    }
+
+    fn check_buffer_sizes(&self, buffers: &mut [Option<JxlOutputBuffer>]) -> Result<()> {
+        // Check that buffer sizes are correct.
+        let mut size = self.shared.input_size;
+        for (i, s) in self.shared.stages.iter().enumerate() {
+            match s {
+                Stage::Extend(e) => size = e.image_size,
+                Stage::Save(s) => {
+                    let (dx, dy) = self.downsampling_for_stage[i];
+                    s.check_buffer_size(
+                        (size.0 >> dx, size.1 >> dy),
+                        buffers[s.output_buffer_index].as_ref(),
+                    )?
+                }
+                _ => {}
+            }
+        }
+        Ok(())
+    }
+
+    fn render_outside_frame(&mut self, buffer_splitter: &mut BufferSplitter) -> Result<()> {
+        if self.shared.extend_stage_index.is_none() || self.padding_was_rendered {
+            return Ok(());
+        }
+        self.padding_was_rendered = true;
+        // TODO(veluca): consider pre-computing those strips at pipeline construction and making
+        // smaller strips.
+        let e = self.shared.extend_stage_index.unwrap();
+        let Stage::Extend(e) = &self.shared.stages[e] else {
+            unreachable!("extend stage is not an extend stage");
+        };
+        // Split the full image area in 4 strips: left and right of the frame, and above and below.
+        // We divide each part further in strips of width self.shared.chunk_size.
+        let mut strips = vec![];
+        if e.frame_origin.0 > 0 {
+            let xend = e.frame_origin.0 as usize;
+            for x in (0..xend).step_by(self.shared.chunk_size) {
+                let xe = (x + self.shared.chunk_size).min(xend);
+                strips.push((x..xe, 0..e.image_size.1));
+            }
+        }
+        if e.frame_origin.1 > 0 {
+            let xstart = e.frame_origin.0.max(0) as usize;
+            let xend = ((e.frame_origin.0 + self.shared.input_size.0 as isize) as usize)
+                .min(e.image_size.0);
+            for x in (xstart..xend).step_by(self.shared.chunk_size) {
+                let xe = (x + self.shared.chunk_size).min(xend);
+                strips.push((x..xe, 0..e.frame_origin.1 as usize));
+            }
+        }
+        if e.frame_origin.1 + (self.shared.input_size.1 as isize) < e.image_size.1 as isize {
+            let ystart = (e.frame_origin.1 + (self.shared.input_size.1 as isize)).max(0) as usize;
+            let yend = e.image_size.1;
+            let xstart = e.frame_origin.0.max(0) as usize;
+            let xend = ((e.frame_origin.0 + self.shared.input_size.0 as isize) as usize)
+                .min(e.image_size.0);
+            for x in (xstart..xend).step_by(self.shared.chunk_size) {
+                let xe = (x + self.shared.chunk_size).min(xend);
+                strips.push((x..xe, ystart..yend));
+            }
+        }
+        if e.frame_origin.0 + (self.shared.input_size.0 as isize) < e.image_size.0 as isize {
+            let xstart = (e.frame_origin.0 + (self.shared.input_size.0 as isize)).max(0) as usize;
+            let xend = e.image_size.0;
+            for x in (xstart..xend).step_by(self.shared.chunk_size) {
+                let xe = (x + self.shared.chunk_size).min(xend);
+                strips.push((x..xe, 0..e.image_size.1));
+            }
+        }
+        let full_image_size = e.image_size;
+        for (xrange, yrange) in strips {
+            let rect_to_render = Rect {
+                origin: (xrange.start, yrange.start),
+                size: (xrange.clone().count(), yrange.clone().count()),
+            };
+            let mut local_buffers = buffer_splitter.get_local_buffers(
+                &self.save_buffer_info,
+                rect_to_render,
+                true,
+                full_image_size,
+                full_image_size,
+                (0, 0),
+            );
+            self.render_outside_frame(xrange, yrange, &mut local_buffers)?;
+        }
+        Ok(())
+    }
+
+    fn box_inout_stage<S: super::RenderPipelineInOutStage>(
+        stage: S,
+    ) -> Box<dyn RunInOutStage<Self::Buffer>> {
+        Box::new(stage)
+    }
+
+    fn box_inplace_stage<S: super::RenderPipelineInPlaceStage>(
+        stage: S,
+    ) -> Box<dyn RunInPlaceStage<Self::Buffer>> {
+        Box::new(stage)
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/render_group.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/render_group.rs
new file mode 100644
index 0000000..2db060d
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/render_group.rs
@@ -0,0 +1,428 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::ops::Range;
+
+use crate::{
+    api::JxlOutputBuffer,
+    error::Result,
+    image::DataTypeTag,
+    render::{
+        internal::Stage,
+        low_memory_pipeline::{
+            helpers::{get_distinct_indices, mirror},
+            run_stage::ExtraInfo,
+        },
+    },
+    util::{ShiftRightCeil, tracing_wrappers::*},
+};
+
+use super::{LowMemoryRenderPipeline, row_buffers::RowBuffer};
+
+fn apply_x_padding(
+    input_type: DataTypeTag,
+    row: &mut [u8],
+    to_pad: Range<isize>,
+    valid_pixels: Range<isize>,
+) {
+    let x0_offset = RowBuffer::x0_byte_offset() as isize;
+    let num_valid = valid_pixels.clone().count();
+    let sz = input_type.size();
+    match sz {
+        1 => {
+            for x in to_pad {
+                let sx = mirror(x - valid_pixels.start, num_valid) as isize + valid_pixels.start;
+                let from = (x0_offset + sx) as usize;
+                let to = (x0_offset + x) as usize;
+                row[to] = row[from];
+            }
+        }
+        2 => {
+            for x in to_pad {
+                let sx = mirror(x - valid_pixels.start, num_valid) as isize + valid_pixels.start;
+                let from = (x0_offset + sx * 2) as usize;
+                let to = (x0_offset + x * 2) as usize;
+                row[to] = row[from];
+                row[to + 1] = row[from + 1];
+            }
+        }
+        4 => {
+            for x in to_pad {
+                let sx = mirror(x - valid_pixels.start, num_valid) as isize + valid_pixels.start;
+                let from = (x0_offset + sx * 4) as usize;
+                let to = (x0_offset + x * 4) as usize;
+                row[to] = row[from];
+                row[to + 1] = row[from + 1];
+                row[to + 2] = row[from + 2];
+                row[to + 3] = row[from + 3];
+            }
+        }
+        _ => {
+            unimplemented!("only 1, 2 or 4 byte data types supported");
+        }
+    }
+}
+
+impl LowMemoryRenderPipeline {
+    fn fill_initial_buffers(&mut self, c: usize, y: usize, y0: usize, (gx, gy): (usize, usize)) {
+        let ty = self.shared.channel_info[0][c]
+            .ty
+            .expect("Channel info should be populated at this point");
+        let gys = 1
+            << (self.shared.log_group_size - self.shared.channel_info[0][c].downsample.1 as usize);
+
+        let (input_y, igy) = if y < y0 {
+            (y + gys - y0, gy - 1)
+        } else if y >= y0 + gys {
+            (y - y0 - gys, gy + 1)
+        } else {
+            (y - y0, gy)
+        };
+
+        let output_row = self.row_buffers[0][c].get_row_mut::<u8>(y);
+        // Both are in units of bytes.
+        let x0_offset = RowBuffer::x0_byte_offset();
+        let extrax = self.input_border_pixels[c].0 * ty.size();
+
+        let base_gid = igy * self.shared.group_count.0 + gx;
+
+        // Previous group horizontally, if any.
+        if gx > 0 && extrax != 0 {
+            let input_buf = self.input_buffers[base_gid - 1].data[c].as_ref().unwrap();
+            let input_row = input_buf.row(input_y);
+            output_row[x0_offset - extrax..x0_offset]
+                .copy_from_slice(&input_row[input_buf.byte_size().0 - extrax..]);
+        }
+        let input_buf = self.input_buffers[base_gid].data[c].as_ref().unwrap();
+        let input_row = input_buf.row(input_y);
+        let gxs = input_buf.byte_size().0; // bytes
+        output_row[x0_offset..x0_offset + gxs].copy_from_slice(input_row);
+        // Next group horizontally, if any.
+        if gx + 1 < self.shared.group_count.0 && extrax != 0 {
+            let input_buf = self.input_buffers[base_gid + 1].data[c].as_ref().unwrap();
+            let input_row = input_buf.row(input_y);
+            let dx = self.shared.channel_info[0][c].downsample.0;
+            let gid = gy * self.shared.group_count.0 + gx;
+            let next_group_xsize = self.shared.group_size(gid + 1).0.shrc(dx);
+            let border_x = extrax.min(next_group_xsize * ty.size());
+            output_row[gxs + x0_offset..gxs + x0_offset + border_x]
+                .copy_from_slice(&input_row[..border_x]);
+            if border_x < extrax {
+                let pad_from = ((gxs + border_x) / ty.size()) as isize;
+                let pad_to = ((gxs + extrax) / ty.size()) as isize;
+                apply_x_padding(ty, output_row, pad_from..pad_to, 0..pad_from);
+            }
+        }
+    }
+
+    // Renders a single group worth of data.
+    #[instrument(skip(self, buffers))]
+    pub(super) fn render_group(
+        &mut self,
+        (gx, gy): (usize, usize),
+        buffers: &mut [Option<JxlOutputBuffer>],
+    ) -> Result<()> {
+        let gid = gy * self.shared.group_count.0 + gx;
+        let (xsize, num_rows) = self.shared.group_size(gid);
+        let (x0, y0) = self.shared.group_offset(gid);
+
+        let num_channels = self.shared.num_channels();
+        let mut num_extra_rows = 0;
+
+        for c in 0..num_channels {
+            num_extra_rows = num_extra_rows
+                .max(self.input_border_pixels[c].1 << self.shared.channel_info[0][c].downsample.1);
+        }
+        for s in 0..self.shared.stages.len() {
+            num_extra_rows = num_extra_rows
+                .max(self.stage_output_border_pixels[s].1 << self.downsampling_for_stage[s].1);
+        }
+
+        // This follows the same implementation strategy as the C++ code in libjxl.
+        // We pretend that every stage has a vertical shift of 0, i.e. it is as tall
+        // as the final image.
+        // We call each such row a "virtual" row, because it may or may not correspond
+        // to an actual row of the current processing stage; actual processing happens
+        // when vy % (1<<vshift) == 0.
+
+        let vy0 = y0.saturating_sub(num_extra_rows);
+        let vy1 = y0 + num_rows + num_extra_rows;
+
+        for vy in vy0..vy1 {
+            let mut current_origin = (0, 0);
+            let mut current_size = self.shared.input_size;
+
+            // Step 1: read input channels.
+            for c in 0..num_channels {
+                // Same logic as below, but adapted to the input stage.
+                let dy = self.shared.channel_info[0][c].downsample.1;
+                let scaled_y_border = self.input_border_pixels[c].1 << dy;
+                let stage_vy = vy as isize - num_extra_rows as isize + scaled_y_border as isize;
+                if stage_vy % (1 << dy) != 0 {
+                    continue;
+                }
+                if stage_vy - (y0 as isize) < -(scaled_y_border as isize) {
+                    continue;
+                }
+                let y = stage_vy >> dy;
+                // Do not produce rows in out-of-bounds areas.
+                if y < 0 || y >= self.shared.input_size.1.shrc(dy) as isize {
+                    continue;
+                }
+                let y = y as usize;
+                self.fill_initial_buffers(c, y, y0 >> dy, (gx, gy));
+            }
+            // Step 2: go through stages one by one.
+            for (i, stage) in self.shared.stages.iter().enumerate() {
+                let (dx, dy) = self.downsampling_for_stage[i];
+                // The logic below uses *virtual* y coordinates, so we need to convert the border
+                // amount appropriately.
+                let scaled_y_border = self.stage_output_border_pixels[i].1 << dy;
+                // I knew the reason behind this formula at some point, but now I don't.
+                let stage_vy = vy as isize - num_extra_rows as isize + scaled_y_border as isize;
+                if stage_vy % (1 << dy) != 0 {
+                    continue;
+                }
+                if stage_vy - (y0 as isize) < -(scaled_y_border as isize) {
+                    continue;
+                }
+                let y = stage_vy >> dy;
+                let shifted_ysize = self.shared.input_size.1.shrc(dy);
+                // Do not produce rows in out-of-bounds areas.
+                if y < 0 || y >= shifted_ysize as isize {
+                    continue;
+                }
+                let y = y as usize;
+
+                let out_extra_x = self.stage_output_border_pixels[i].0;
+                let shifted_xsize = xsize.shrc(dx);
+
+                match stage {
+                    Stage::InPlace(s) => {
+                        let buffer_indices: Vec<_> = (0..num_channels)
+                            .filter(|c| s.uses_channel(*c))
+                            .map(|x| self.stage_input_buffer_index[i][x])
+                            .collect();
+                        let mut buffers =
+                            get_distinct_indices(&mut self.row_buffers, &buffer_indices);
+                        s.run_stage_on(
+                            ExtraInfo {
+                                xsize: shifted_xsize,
+                                current_row: y,
+                                group_x0: x0 >> dx,
+                                out_extra_x,
+                                is_first_xgroup: gx == 0,
+                                is_last_xgroup: gx + 1 == self.shared.group_count.0,
+                                image_height: shifted_ysize,
+                            },
+                            &mut buffers,
+                            self.local_states[i].as_deref_mut(),
+                        );
+                    }
+                    Stage::Save(s) => {
+                        // Find buffers for channels that will be saved.
+                        let input_data: Vec<_> = s
+                            .channels
+                            .iter()
+                            .map(|c| {
+                                let (si, ci) = self.stage_input_buffer_index[i][*c];
+                                &self.row_buffers[si][ci]
+                            })
+                            .collect();
+                        s.save_lowmem(
+                            &input_data,
+                            &mut *buffers,
+                            (xsize >> dx, num_rows >> dy),
+                            y,
+                            (x0 >> dx, y0 >> dy),
+                            current_size,
+                            current_origin,
+                        )?;
+                    }
+                    Stage::Extend(s) => {
+                        current_size = s.image_size;
+                        current_origin = s.frame_origin;
+                    }
+                    Stage::InOut(s) => {
+                        let borderx = s.border().0 as usize;
+                        let bordery = s.border().1 as isize;
+                        // Apply x padding.
+                        if gx == 0 && borderx != 0 {
+                            for c in 0..num_channels {
+                                if !s.uses_channel(c) {
+                                    continue;
+                                }
+                                let (si, ci) = self.stage_input_buffer_index[i][c];
+                                for iy in -bordery..=bordery {
+                                    let y = mirror(y as isize + iy, shifted_ysize);
+                                    apply_x_padding(
+                                        s.input_type(),
+                                        self.row_buffers[si][ci].get_row_mut::<u8>(y),
+                                        -(borderx as isize)..0,
+                                        // Either xsize is the actual size of the image, or it is
+                                        // much larger than borderx, so this works out either way.
+                                        0..shifted_xsize as isize,
+                                    );
+                                }
+                            }
+                        }
+                        if gx + 1 == self.shared.group_count.0 && borderx != 0 {
+                            for c in 0..num_channels {
+                                if !s.uses_channel(c) {
+                                    continue;
+                                }
+                                let (si, ci) = self.stage_input_buffer_index[i][c];
+                                for iy in -bordery..=bordery {
+                                    let y = mirror(y as isize + iy, shifted_ysize);
+                                    apply_x_padding(
+                                        s.input_type(),
+                                        self.row_buffers[si][ci].get_row_mut::<u8>(y),
+                                        shifted_xsize as isize..(shifted_xsize + borderx) as isize,
+                                        // borderx..0 is either data from the neighbouring group or
+                                        // data that was filled in by the iteration above.
+                                        -(borderx as isize)..shifted_xsize as isize,
+                                    );
+                                }
+                            }
+                        }
+                        let (inb, outb) = self.row_buffers.split_at_mut(i + 1);
+                        // Prepare pointers to input and output buffers.
+                        let input_data: Vec<_> = (0..num_channels)
+                            .filter(|c| s.uses_channel(*c))
+                            .map(|c| {
+                                let (si, ci) = self.stage_input_buffer_index[i][c];
+                                &inb[si][ci]
+                            })
+                            .collect();
+                        let mut outb: Vec<_> = outb[0].iter_mut().collect();
+                        s.run_stage_on(
+                            ExtraInfo {
+                                xsize: shifted_xsize,
+                                current_row: y,
+                                group_x0: x0 >> dx,
+                                out_extra_x,
+                                is_first_xgroup: gx == 0,
+                                is_last_xgroup: gx + 1 == self.shared.group_count.0,
+                                image_height: shifted_ysize,
+                            },
+                            &input_data,
+                            &mut outb[..],
+                            self.local_states[i].as_deref_mut(),
+                        );
+                    }
+                }
+            }
+        }
+        Ok(())
+    }
+
+    // Renders a chunk of data outside the current frame.
+    #[instrument(skip(self, buffers))]
+    pub(super) fn render_outside_frame(
+        &mut self,
+        xrange: Range<usize>,
+        yrange: Range<usize>,
+        buffers: &mut [Option<JxlOutputBuffer>],
+    ) -> Result<()> {
+        let num_channels = self.shared.num_channels();
+        let x0 = xrange.start;
+        let y0 = yrange.start;
+        let xsize = xrange.clone().count();
+        let ysize = yrange.clone().count();
+        // Significantly simplified version of render_group.
+        for y in yrange.clone() {
+            let extend = self.shared.extend_stage_index.unwrap();
+            // Step 1: get padding from extend stage.
+            for c in 0..num_channels {
+                let (si, ci) = self.stage_input_buffer_index[extend][c];
+                let buffer = &mut self.row_buffers[si][ci];
+                let Stage::Extend(extend) = &self.shared.stages[extend] else {
+                    unreachable!("extend stage is not an extend stage");
+                };
+                let row = &mut buffer.get_row_mut(y)[RowBuffer::x0_offset::<f32>()..];
+                extend.process_row_chunk((x0, y), xsize, c, row);
+            }
+            // Step 2: go through remaining stages one by one.
+            for (i, stage) in self.shared.stages.iter().enumerate().skip(extend + 1) {
+                assert_eq!(self.downsampling_for_stage[i], (0, 0));
+
+                match stage {
+                    Stage::InPlace(s) => {
+                        let buffer_indices: Vec<_> = (0..num_channels)
+                            .filter(|c| s.uses_channel(*c))
+                            .map(|x| self.stage_input_buffer_index[i][x])
+                            .collect();
+                        let mut buffers =
+                            get_distinct_indices(&mut self.row_buffers, &buffer_indices);
+                        s.run_stage_on(
+                            ExtraInfo {
+                                xsize,
+                                current_row: y,
+                                group_x0: x0,
+                                out_extra_x: 0,
+                                is_first_xgroup: false,
+                                is_last_xgroup: false,
+                                image_height: self.shared.input_size.1,
+                            },
+                            &mut buffers,
+                            self.local_states[i].as_deref_mut(),
+                        );
+                    }
+                    Stage::Save(s) => {
+                        // Find buffers for channels that will be saved.
+                        let input_data: Vec<_> = s
+                            .channels
+                            .iter()
+                            .map(|c| {
+                                let (si, ci) = self.stage_input_buffer_index[i][*c];
+                                &self.row_buffers[si][ci]
+                            })
+                            .collect();
+                        s.save_lowmem(
+                            &input_data,
+                            &mut *buffers,
+                            (xsize, ysize),
+                            y,
+                            (x0, y0),
+                            (xrange.end, yrange.end), // this is not true, but works out correctly.
+                            (0, 0),
+                        )?;
+                    }
+                    Stage::Extend(_) => {
+                        unreachable!("duplicate extend stage");
+                    }
+                    Stage::InOut(s) => {
+                        assert_eq!(s.border(), (0, 0));
+                        let (inb, outb) = self.row_buffers.split_at_mut(i + 1);
+                        // Prepare pointers to input and output buffers.
+                        let input_data: Vec<_> = (0..num_channels)
+                            .filter(|c| s.uses_channel(*c))
+                            .map(|c| {
+                                let (si, ci) = self.stage_input_buffer_index[i][c];
+                                &inb[si][ci]
+                            })
+                            .collect();
+                        let mut outb: Vec<_> = outb[0].iter_mut().collect();
+                        s.run_stage_on(
+                            ExtraInfo {
+                                xsize,
+                                current_row: y,
+                                group_x0: x0,
+                                out_extra_x: 0,
+                                is_first_xgroup: false,
+                                is_last_xgroup: false,
+                                image_height: self.shared.input_size.1,
+                            },
+                            &input_data,
+                            &mut outb[..],
+                            self.local_states[i].as_deref_mut(),
+                        );
+                    }
+                }
+            }
+        }
+        Ok(())
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/row_buffers.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/row_buffers.rs
new file mode 100644
index 0000000..109f26d
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/row_buffers.rs
@@ -0,0 +1,96 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::ops::Range;
+
+use crate::{
+    error::Result,
+    image::{DataTypeTag, ImageDataType},
+    render::MAX_BORDER,
+    util::{
+        CACHE_LINE_BYTE_SIZE, CacheLine, num_per_cache_line, slice_from_cachelines,
+        slice_from_cachelines_mut,
+    },
+};
+
+/// Temporary storage for data rows. Note that the first pixel of the group is expected to be
+/// located *one cacheline worth of data* inside the row.
+pub struct RowBuffer {
+    buffer: Box<[CacheLine]>,
+    // Distance (in number of *cache lines*) between the start of two rows.
+    row_stride: usize,
+    // Number of rows that are actually stored.
+    // TODO(veluca): consider padding this to a power of 2 and using & here. In *most* cases,
+    // that's not a huge loss in memory usage (for most images, num_rows is 1/3/5/7, which would
+    // become 1/4/8/8).
+    num_rows: usize,
+}
+
+impl RowBuffer {
+    pub fn new(
+        data_type: DataTypeTag,
+        next_y_border: usize,
+        y_shift: usize,
+        row_len: usize,
+    ) -> Result<Self> {
+        let num_rows = (1 << y_shift) + 2 * next_y_border;
+        // Input offset is at *one* cacheline, and we need up to *two* cachelines on the other
+        // side as the data might exceed xsize slightly.
+        let row_stride = (row_len * data_type.size()).div_ceil(CACHE_LINE_BYTE_SIZE) + 3;
+        let mut buffer = Vec::<CacheLine>::new();
+        buffer.try_reserve_exact(row_stride * num_rows)?;
+        buffer.resize(row_stride * num_rows, CacheLine::default());
+        let buffer = buffer.into_boxed_slice();
+        Ok(Self {
+            buffer,
+            row_stride,
+            num_rows,
+        })
+    }
+
+    pub fn get_row<T: ImageDataType>(&self, row: usize) -> &[T] {
+        let row_idx = row % self.num_rows;
+        let start = row_idx * self.row_stride;
+        slice_from_cachelines(&self.buffer[start..start + self.row_stride])
+    }
+
+    pub fn get_row_mut<T: ImageDataType>(&mut self, row: usize) -> &mut [T] {
+        let row_idx = row % self.num_rows;
+        let stride = self.row_stride;
+        let start = row_idx * stride;
+        slice_from_cachelines_mut(&mut self.buffer[start..start + stride])
+    }
+
+    // TODO(veluca): use some kind of smallvec.
+    pub fn get_rows_mut<T: ImageDataType>(
+        &mut self,
+        y: Range<usize>,
+        xoffset: usize,
+    ) -> Vec<&mut [T]> {
+        assert!(y.clone().count() <= self.num_rows);
+        let first_row_idx = y.start % self.num_rows;
+        let stride = self.row_stride;
+        let start = first_row_idx * stride;
+        let num_pre = (y.clone().count() + first_row_idx).saturating_sub(self.num_rows);
+        let num_post = y.clone().count() - num_pre;
+        let buf = &mut self.buffer[..];
+        let (pre, post) = buf.split_at_mut(start);
+        let pre_rows = pre.chunks_exact_mut(stride).take(num_pre);
+        let post_rows = post.chunks_exact_mut(stride).take(num_post);
+        post_rows
+            .chain(pre_rows)
+            .map(|x| &mut slice_from_cachelines_mut(x)[xoffset..])
+            .collect()
+    }
+
+    pub const fn x0_offset<T: ImageDataType>() -> usize {
+        assert!(num_per_cache_line::<T>() >= MAX_BORDER);
+        num_per_cache_line::<T>()
+    }
+
+    pub const fn x0_byte_offset() -> usize {
+        CACHE_LINE_BYTE_SIZE
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/run_stage.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/run_stage.rs
new file mode 100644
index 0000000..52cd9b1
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/run_stage.rs
@@ -0,0 +1,145 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::any::Any;
+
+use crate::{
+    render::{
+        Channels, ChannelsMut, RunInPlaceStage,
+        internal::{PipelineBuffer, RunInOutStage},
+        low_memory_pipeline::helpers::mirror,
+    },
+    util::{ShiftRightCeil, tracing_wrappers::*},
+};
+
+use super::{
+    super::{RenderPipelineInOutStage, RenderPipelineInPlaceStage},
+    row_buffers::RowBuffer,
+};
+
+pub struct ExtraInfo {
+    // Number of *input* pixels to process (ignoring additional border pixels).
+    pub(super) xsize: usize,
+    // Additional border pixels requested in the output on each side, if not first/last xgroup.
+    pub(super) out_extra_x: usize,
+    pub(super) current_row: usize,
+    pub(super) group_x0: usize,
+    pub(super) is_first_xgroup: bool,
+    pub(super) is_last_xgroup: bool,
+    pub(super) image_height: usize,
+}
+
+impl PipelineBuffer for RowBuffer {
+    type InPlaceExtraInfo = ExtraInfo;
+    type InOutExtraInfo = ExtraInfo;
+}
+
+impl<T: RenderPipelineInPlaceStage> RunInPlaceStage<RowBuffer> for T {
+    #[instrument(skip_all)]
+    fn run_stage_on(
+        &self,
+        ExtraInfo {
+            xsize,
+            current_row,
+            group_x0,
+            out_extra_x,
+            image_height: _,
+            is_first_xgroup,
+            is_last_xgroup,
+        }: ExtraInfo,
+        buffers: &mut [&mut RowBuffer],
+        state: Option<&mut dyn Any>,
+    ) {
+        let x0 = RowBuffer::x0_offset::<T::Type>();
+        let xpre = if is_first_xgroup { 0 } else { out_extra_x };
+        let xstart = x0 - xpre;
+        let xend = x0 + xsize + if is_last_xgroup { 0 } else { out_extra_x };
+        let mut rows: Vec<_> = buffers
+            .iter_mut()
+            .map(|x| &mut x.get_row_mut::<T::Type>(current_row)[xstart..])
+            .collect();
+
+        self.process_row_chunk(
+            (group_x0 - xpre, current_row),
+            xend - xstart,
+            &mut rows[..],
+            state,
+        );
+    }
+}
+
+impl<T: RenderPipelineInOutStage> RunInOutStage<RowBuffer> for T {
+    #[instrument(skip_all)]
+    fn run_stage_on(
+        &self,
+        ExtraInfo {
+            xsize,
+            current_row,
+            group_x0,
+            out_extra_x,
+            image_height,
+            is_first_xgroup,
+            is_last_xgroup,
+        }: ExtraInfo,
+        input_buffers: &[&RowBuffer],
+        output_buffers: &mut [&mut RowBuffer],
+        state: Option<&mut dyn Any>,
+    ) {
+        let ibordery = Self::BORDER.1 as isize;
+        let x0 = RowBuffer::x0_offset::<T::InputT>();
+        let xpre = if is_first_xgroup {
+            0
+        } else {
+            out_extra_x.shrc(T::SHIFT.0)
+        };
+        let xstart = x0 - xpre;
+        let xend = x0
+            + xsize
+            + if is_last_xgroup {
+                0
+            } else {
+                out_extra_x.shrc(T::SHIFT.0)
+            };
+
+        // Build flat input rows: all rows for all channels in one Vec
+        let input_rows_per_channel = (2 * Self::BORDER.1 + 1) as usize;
+        let num_channels = input_buffers.len();
+        let mut input_row_data = Vec::with_capacity(num_channels * input_rows_per_channel);
+        for x in input_buffers.iter() {
+            for iy in -ibordery..=ibordery {
+                input_row_data.push(
+                    &x.get_row::<T::InputT>(mirror(current_row as isize + iy, image_height))
+                        [xstart - Self::BORDER.0 as usize..],
+                );
+            }
+        }
+        let input_rows = Channels::new(input_row_data, num_channels, input_rows_per_channel);
+
+        // Build flat output rows: all rows for all channels in one Vec
+        let output_rows_per_channel = 1 << T::SHIFT.1;
+        let num_output_channels = output_buffers.len();
+        let mut output_row_data = Vec::with_capacity(num_output_channels * output_rows_per_channel);
+        for x in output_buffers.iter_mut() {
+            let rows = x.get_rows_mut::<T::OutputT>(
+                (current_row << T::SHIFT.1)..((current_row + 1) << T::SHIFT.1),
+                RowBuffer::x0_offset::<T::OutputT>() - (xpre << T::SHIFT.0),
+            );
+            output_row_data.extend(rows);
+        }
+        let mut output_rows = ChannelsMut::new(
+            output_row_data,
+            num_output_channels,
+            output_rows_per_channel,
+        );
+
+        self.process_row_chunk(
+            (group_x0 - xpre, current_row),
+            xend - xstart,
+            &input_rows,
+            &mut output_rows,
+            state,
+        );
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/save/identity.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/save/identity.rs
new file mode 100644
index 0000000..6a9a4b6
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/save/identity.rs
@@ -0,0 +1,76 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(unsafe_code)]
+
+use std::ops::Range;
+
+use crate::{
+    api::{Endianness, JxlDataFormat, JxlOutputBuffer},
+    render::low_memory_pipeline::row_buffers::RowBuffer,
+};
+
+pub(super) fn store(
+    input_buf: &[&RowBuffer],
+    input_y: usize,
+    xrange: Range<usize>,
+    output_buf: &mut JxlOutputBuffer,
+    output_y: usize,
+    data_format: JxlDataFormat,
+) -> usize {
+    let byte_start = xrange.start * data_format.bytes_per_sample() + RowBuffer::x0_byte_offset();
+    let byte_end = xrange.end * data_format.bytes_per_sample() + RowBuffer::x0_byte_offset();
+    let is_native_endian = match data_format {
+        JxlDataFormat::U8 { .. } => true,
+        JxlDataFormat::F16 { endianness, .. }
+        | JxlDataFormat::U16 { endianness, .. }
+        | JxlDataFormat::F32 { endianness, .. } => endianness == Endianness::native(),
+    };
+    // SAFETY: we never write uninit memory to the `output_row`.
+    let output_buf = unsafe { output_buf.row_mut(output_y) };
+    let output_buf = &mut output_buf[0..(byte_end - byte_start) * input_buf.len()];
+    match (
+        input_buf.len(),
+        data_format.bytes_per_sample(),
+        is_native_endian,
+    ) {
+        (1, _, true) => {
+            // We can just do a memcpy.
+            let input_buf = &input_buf[0].get_row::<u8>(input_y)[byte_start..byte_end];
+            assert_eq!(input_buf.len(), output_buf.len());
+            // SAFETY: we are copying `u8`s, which have an alignment of 1, from a slice of [u8] to
+            // a slice of [MaybeUninit<u8>] of the same length (as we checked just above). u8 and
+            // MaybeUninit<u8> have the same layout, and aliasing rules guarantee that the two
+            // slices are non-overlapping.
+            unsafe {
+                std::ptr::copy_nonoverlapping(
+                    input_buf.as_ptr(),
+                    output_buf.as_mut_ptr() as *mut u8,
+                    output_buf.len(),
+                );
+            }
+            input_buf.len() / data_format.bytes_per_sample()
+        }
+        (3, 4, true) => {
+            #[cfg(target_arch = "x86_64")]
+            {
+                let [a, b, c] = input_buf else { unreachable!() };
+                super::x86_64::interleave3_32b(
+                    &[
+                        &a.get_row(input_y)[byte_start..byte_end],
+                        &b.get_row(input_y)[byte_start..byte_end],
+                        &c.get_row(input_y)[byte_start..byte_end],
+                    ],
+                    output_buf,
+                )
+            }
+            #[cfg(not(target_arch = "x86_64"))]
+            {
+                0
+            }
+        }
+        _ => 0,
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/save/mod.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/save/mod.rs
new file mode 100644
index 0000000..e72c6835
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/save/mod.rs
@@ -0,0 +1,141 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{
+    api::{Endianness, JxlDataFormat, JxlOutputBuffer},
+    error::Result,
+    headers::Orientation,
+    render::save::SaveStage,
+};
+
+use super::row_buffers::RowBuffer;
+
+mod identity;
+
+// TODO(veluca): at the moment, integrating the interleaving logic in crate::simd seems more hassle
+// than is worth. Consider re-evaluating later.
+#[cfg(target_arch = "x86_64")]
+mod x86_64;
+
+// Placeholder slow implementation.
+impl SaveStage {
+    // Takes as input only those channels that are *actually* saved.
+    #[allow(clippy::too_many_arguments)]
+    pub(super) fn save_lowmem(
+        &self,
+        data: &[&RowBuffer],
+        buffers: &mut [Option<JxlOutputBuffer>],
+        group_size: (usize, usize),
+        frame_y: usize,
+        group_origin: (usize, usize),
+        full_image_size: (usize, usize),
+        frame_origin: (isize, isize),
+    ) -> Result<()> {
+        let Some(buf) = buffers[self.output_buffer_index].as_mut() else {
+            return Ok(());
+        };
+
+        let group_y = frame_y - group_origin.1;
+
+        let relative_full_image_start = (
+            -frame_origin.0 - (group_origin.0 as isize),
+            -frame_origin.1 - (group_origin.1 as isize),
+        );
+
+        let relative_full_image_end = (
+            relative_full_image_start.0 + full_image_size.0 as isize,
+            relative_full_image_start.1 + full_image_size.1 as isize,
+        );
+
+        let save_start = (
+            relative_full_image_start.0.max(0) as usize,
+            relative_full_image_start.1.max(0) as usize,
+        );
+
+        let save_end = (
+            relative_full_image_end.0.clamp(0, group_size.0 as isize) as usize,
+            relative_full_image_end.1.clamp(0, group_size.1 as isize) as usize,
+        );
+
+        // If the visible area were empty, we'd have gotten None for the buffer.
+        assert!(save_start.0 < save_end.0);
+        assert!(save_start.1 < save_end.1);
+
+        if !(save_start.1..save_end.1).contains(&group_y) {
+            // The current row is outside the visible area - skip rendering it.
+            return Ok(());
+        }
+
+        let relative_y = group_y - save_start.1;
+
+        let save_size = (save_end.0 - save_start.0, save_end.1 - save_start.1);
+
+        let num_fast = match self.orientation {
+            Orientation::Identity => identity::store(
+                data,
+                frame_y,
+                save_start.0..save_end.0,
+                buf,
+                relative_y,
+                self.data_format,
+            ),
+            _ => 0,
+        };
+
+        // TODO(veluca): this is very slow, implement more fast paths.
+
+        macro_rules! write_pixel {
+            ($px: expr, $endianness: expr, $y: expr, $x: expr) => {
+                let px = $px;
+                let px_bytes = if $endianness == Endianness::LittleEndian {
+                    px.to_le_bytes()
+                } else {
+                    px.to_be_bytes()
+                };
+                buf.write_bytes($y, $x, &px_bytes);
+            };
+        }
+
+        for (c, d) in data.iter().enumerate() {
+            let nc = self.channels.len();
+            let (x0, y0) = self.orientation.display_pixel((0, relative_y), save_size);
+            let (x1, y1) = self.orientation.display_pixel((1, relative_y), save_size);
+            let x0 = x0 as isize;
+            let y0 = y0 as isize;
+            let dx = x1 as isize - x0;
+            let dy = y1 as isize - y0;
+            match self.data_format {
+                JxlDataFormat::U8 { .. } => {
+                    let src_row = d.get_row::<u8>(frame_y);
+                    for ix in (save_start.0..save_end.0).skip(num_fast) {
+                        let px = src_row[RowBuffer::x0_offset::<u8>() + ix];
+                        let y = (y0 + (dy * (ix - save_start.0) as isize)) as usize;
+                        let x = (x0 + (dx * (ix - save_start.0) as isize)) as usize;
+                        write_pixel!(px, Endianness::LittleEndian, y, x * nc + c);
+                    }
+                }
+                JxlDataFormat::U16 { endianness, .. } | JxlDataFormat::F16 { endianness, .. } => {
+                    let src_row = d.get_row::<u16>(frame_y);
+                    for ix in (save_start.0..save_end.0).skip(num_fast) {
+                        let px = src_row[RowBuffer::x0_offset::<u16>() + ix];
+                        let y = (y0 + (dy * (ix - save_start.0) as isize)) as usize;
+                        let x = (x0 + (dx * (ix - save_start.0) as isize)) as usize;
+                        write_pixel!(px, endianness, y, (x * nc + c) * 2);
+                    }
+                }
+                JxlDataFormat::F32 { endianness, .. } => {
+                    let src_row = d.get_row::<f32>(frame_y);
+                    for ix in (save_start.0..save_end.0).skip(num_fast) {
+                        let px = src_row[RowBuffer::x0_offset::<f32>() + ix];
+                        let y = (y0 + (dy * (ix - save_start.0) as isize)) as usize;
+                        let x = (x0 + (dx * (ix - save_start.0) as isize)) as usize;
+                        write_pixel!(px, endianness, y, (x * nc + c) * 4);
+                    }
+                }
+            }
+        }
+        Ok(())
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/save/x86_64.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/save/x86_64.rs
new file mode 100644
index 0000000..0ab4d4b7
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/save/x86_64.rs
@@ -0,0 +1,168 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(unsafe_code)]
+
+use std::{
+    arch::x86_64::{
+        __m256i, __m512i, _mm256_add_epi32, _mm256_blend_epi32, _mm256_loadu_si256,
+        _mm256_permutevar8x32_epi32, _mm256_set1_epi32, _mm256_storeu_si256, _mm512_loadu_si512,
+        _mm512_mask_permutevar_epi32, _mm512_permutex2var_epi32, _mm512_storeu_si512,
+    },
+    mem::MaybeUninit,
+};
+
+#[target_feature(enable = "avx2")]
+fn load_avx2_u32(data: &[u32; 8]) -> __m256i {
+    // SAFETY: `data` has the correct size.
+    unsafe { _mm256_loadu_si256(data.as_ptr() as *const _) }
+}
+
+#[target_feature(enable = "avx2")]
+fn load_avx2(data: &[u8; 32]) -> __m256i {
+    // SAFETY: `data` has the correct size.
+    unsafe { _mm256_loadu_si256(data.as_ptr() as *const _) }
+}
+
+#[target_feature(enable = "avx2")]
+fn store_avx2(data: __m256i, out: &mut [MaybeUninit<u8>; 32]) {
+    // SAFETY: `data` has the correct size.
+    unsafe { _mm256_storeu_si256(out.as_mut_ptr() as *mut _, data) }
+}
+
+#[target_feature(enable = "avx512f")]
+fn load_avx512_u32(data: &[u32; 16]) -> __m512i {
+    // SAFETY: `data` has the correct size.
+    unsafe { _mm512_loadu_si512(data.as_ptr() as *const _) }
+}
+
+#[target_feature(enable = "avx512f")]
+fn load_avx512(data: &[u8; 64]) -> __m512i {
+    // SAFETY: `data` has the correct size.
+    unsafe { _mm512_loadu_si512(data.as_ptr() as *const _) }
+}
+
+#[target_feature(enable = "avx512f")]
+fn store_avx512(data: __m512i, out: &mut [MaybeUninit<u8>; 64]) {
+    // SAFETY: `data` has the correct size.
+    unsafe { _mm512_storeu_si512(out.as_mut_ptr() as *mut _, data) }
+}
+
+#[target_feature(enable = "avx2")]
+fn interleave3_32b_avx2(inp: &[&[u8]; 3], out: &mut [MaybeUninit<u8>]) -> usize {
+    let [a, b, c] = inp;
+
+    let idx_a0 = load_avx2_u32(&[0, 0, 0, 1, 0, 0, 2, 0]);
+    // c1 = idx_a0 + 2
+    // b2 = idx_a0 + 5
+
+    let idx_b0 = load_avx2_u32(&[0, 0, 0, 0, 1, 0, 0, 2]);
+    // a1 = idx_b0 + 3
+    // c2 = idx_b0 + 5
+
+    let idx_c0 = load_avx2_u32(&[0, 0, 0, 0, 0, 1, 0, 0]);
+    // b1 = idx_c0 + 3
+    // a2 = idx_c0 + 6
+
+    let two = _mm256_set1_epi32(2);
+    let three = _mm256_set1_epi32(3);
+    let five = _mm256_set1_epi32(5);
+    let six = _mm256_set1_epi32(6);
+
+    const LEN: usize = 32;
+    let mut processed = 0;
+    for (((a, b), c), out) in a
+        .chunks_exact(LEN)
+        .zip(b.chunks_exact(LEN))
+        .zip(c.chunks_exact(LEN))
+        .zip(out.chunks_exact_mut(LEN * 3))
+    {
+        let a = load_avx2(a.try_into().unwrap());
+        let b = load_avx2(b.try_into().unwrap());
+        let c = load_avx2(c.try_into().unwrap());
+
+        let a0 = _mm256_permutevar8x32_epi32(a, idx_a0);
+        let b0 = _mm256_permutevar8x32_epi32(b, idx_b0);
+        let c0 = _mm256_permutevar8x32_epi32(c, idx_c0);
+        let out0 = _mm256_blend_epi32::<0b10010010>(a0, b0);
+        let out0 = _mm256_blend_epi32::<0b00100100>(out0, c0);
+
+        let a1 = _mm256_permutevar8x32_epi32(a, _mm256_add_epi32(idx_b0, three));
+        let b1 = _mm256_permutevar8x32_epi32(b, _mm256_add_epi32(idx_c0, three));
+        let c1 = _mm256_permutevar8x32_epi32(c, _mm256_add_epi32(idx_a0, two));
+        let out1 = _mm256_blend_epi32::<0b00100100>(a1, b1);
+        let out1 = _mm256_blend_epi32::<0b01001001>(out1, c1);
+
+        let a2 = _mm256_permutevar8x32_epi32(a, _mm256_add_epi32(idx_c0, six));
+        let b2 = _mm256_permutevar8x32_epi32(b, _mm256_add_epi32(idx_a0, five));
+        let c2 = _mm256_permutevar8x32_epi32(c, _mm256_add_epi32(idx_b0, five));
+        let out2 = _mm256_blend_epi32::<0b01001001>(a2, b2);
+        let out2 = _mm256_blend_epi32::<0b10010010>(out2, c2);
+
+        store_avx2(out0, (&mut out[0..LEN]).try_into().unwrap());
+        store_avx2(out1, (&mut out[LEN..2 * LEN]).try_into().unwrap());
+        store_avx2(out2, (&mut out[2 * LEN..3 * LEN]).try_into().unwrap());
+        processed += LEN / 4;
+    }
+
+    processed
+}
+
+#[inline(never)]
+#[target_feature(enable = "avx512f")]
+fn interleave3_32b_avx512(inp: &[&[u8]; 3], out: &mut [MaybeUninit<u8>]) -> usize {
+    let [a, b, c] = inp;
+
+    let idx_ab0 = load_avx512_u32(&[0, 16, 0, 1, 17, 0, 2, 18, 0, 3, 19, 0, 4, 20, 0, 5]);
+    let idx_c0 = load_avx512_u32(&[0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 3, 0, 0, 4, 0]);
+
+    let idx_ab1 = load_avx512_u32(&[21, 0, 6, 22, 0, 7, 23, 0, 8, 24, 0, 9, 25, 0, 10, 26]);
+    let idx_c1 = load_avx512_u32(&[0, 5, 0, 0, 6, 0, 0, 7, 0, 0, 8, 0, 0, 9, 0, 0]);
+
+    let idx_ab2 = load_avx512_u32(&[0, 11, 27, 0, 12, 28, 0, 13, 29, 0, 14, 30, 0, 15, 31, 0]);
+    let idx_c2 = load_avx512_u32(&[10, 0, 0, 11, 0, 0, 12, 0, 0, 13, 0, 0, 14, 0, 0, 15]);
+
+    const LEN: usize = 64;
+    let mut processed = 0;
+    for (((a, b), c), out) in a
+        .chunks_exact(LEN)
+        .zip(b.chunks_exact(LEN))
+        .zip(c.chunks_exact(LEN))
+        .zip(out.chunks_exact_mut(LEN * 3))
+    {
+        let a = load_avx512(a.try_into().unwrap());
+        let b = load_avx512(b.try_into().unwrap());
+        let c = load_avx512(c.try_into().unwrap());
+
+        let out0 = _mm512_permutex2var_epi32(a, idx_ab0, b);
+        let out0 = _mm512_mask_permutevar_epi32(out0, 0b0100100100100100, idx_c0, c);
+
+        let out1 = _mm512_permutex2var_epi32(a, idx_ab1, b);
+        let out1 = _mm512_mask_permutevar_epi32(out1, 0b0010010010010010, idx_c1, c);
+
+        let out2 = _mm512_permutex2var_epi32(a, idx_ab2, b);
+        let out2 = _mm512_mask_permutevar_epi32(out2, 0b1001001001001001, idx_c2, c);
+
+        store_avx512(out0, (&mut out[0..LEN]).try_into().unwrap());
+        store_avx512(out1, (&mut out[LEN..2 * LEN]).try_into().unwrap());
+        store_avx512(out2, (&mut out[2 * LEN..3 * LEN]).try_into().unwrap());
+        processed += LEN / 4;
+    }
+
+    processed
+}
+
+/// Safety note: does not write uninit data in `out`.
+pub(super) fn interleave3_32b(inp: &[&[u8]; 3], out: &mut [MaybeUninit<u8>]) -> usize {
+    if is_x86_feature_detected!("avx512f") {
+        // SAFETY: we just checked for avx512f.
+        unsafe { interleave3_32b_avx512(inp, out) }
+    } else if is_x86_feature_detected!("avx2") {
+        // SAFETY: we just checked for avx2.
+        unsafe { interleave3_32b_avx2(inp, out) }
+    } else {
+        0
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/mod.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/mod.rs
new file mode 100644
index 0000000..dd11f74
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/mod.rs
@@ -0,0 +1,140 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use internal::{RenderPipelineShared, RunInOutStage, RunInPlaceStage};
+use std::any::Any;
+
+use crate::{
+    api::JxlOutputBuffer,
+    error::Result,
+    image::{Image, ImageDataType},
+    render::buffer_splitter::BufferSplitter,
+};
+
+pub mod buffer_splitter;
+mod builder;
+mod channels;
+mod internal;
+mod low_memory_pipeline;
+mod save;
+#[cfg(test)]
+mod simple_pipeline;
+pub mod stages;
+#[cfg(test)]
+mod test;
+
+// Interesting border amounts:
+// - 0 (lossless)
+// - 1 (420 JPEG recompression)
+// - 4 (Gaborish + EPF 1 + EPF 2)
+// - 7 (Gaborish + EPF 0 + EPF 1 + EPF 2)
+// - 9 (Gaborish + EPF 0/1/2 + upsampling)
+// Note: adding 420 does *not* increase this value, because on chroma channels we get
+// 9.div_ceil(2)+1 = 6 pixels of border, below the 9 for luma.
+const MAX_BORDER: usize = 9;
+
+pub(crate) use builder::RenderPipelineBuilder;
+pub(crate) use channels::{Channels, ChannelsMut};
+pub(crate) use low_memory_pipeline::LowMemoryRenderPipeline;
+#[cfg(test)]
+pub(crate) use simple_pipeline::SimpleRenderPipeline;
+
+/// Modifies channels in-place.
+pub trait RenderPipelineInPlaceStage: Any + std::fmt::Display {
+    type Type: ImageDataType;
+
+    fn process_row_chunk(
+        &self,
+        position: (usize, usize),
+        xsize: usize,
+        // one for each channel
+        row: &mut [&mut [Self::Type]],
+        state: Option<&mut dyn Any>,
+    );
+
+    fn init_local_state(&self) -> Result<Option<Box<dyn Any>>> {
+        Ok(None)
+    }
+
+    fn uses_channel(&self, c: usize) -> bool;
+}
+
+/// Modifies data and writes it to a new buffer, of possibly different type.
+///
+/// BORDER.0 and BORDER.1 represent the amount of padding required on the input side.
+/// SHIFT.0 and SHIFT.1 represent the base 2 log of the number of rows/columns produced
+/// for each row/column of input.
+///
+/// For each channel:
+///  - the input slice contains 1 + BORDER.1 * 2 slices, each of length
+///    xsize + BORDER.0 * 2, i.e. covering one input row and up to BORDER pixels of
+///    padding on either side.
+///  - the output slice contains 1 << SHIFT.1 slices, each of length xsize << SHIFT.0, the
+///    corresponding output pixels.
+pub trait RenderPipelineInOutStage: Any + std::fmt::Display {
+    type InputT: ImageDataType;
+    type OutputT: ImageDataType;
+
+    const BORDER: (u8, u8);
+    const SHIFT: (u8, u8);
+
+    fn process_row_chunk(
+        &self,
+        position: (usize, usize),
+        xsize: usize,
+        // channel, row, column
+        input_rows: &Channels<Self::InputT>,
+        // channel, row, column
+        output_rows: &mut ChannelsMut<Self::OutputT>,
+        state: Option<&mut dyn Any>,
+    );
+
+    fn init_local_state(&self) -> Result<Option<Box<dyn Any>>> {
+        Ok(None)
+    }
+
+    fn uses_channel(&self, c: usize) -> bool;
+}
+
+// TODO(veluca): find a way to reduce the generated code due to having two builders, to integrate
+// SIMD dispatch in the pipeline, and to test consistency across instruction sets in the pipeline.
+pub(crate) trait RenderPipeline: Sized {
+    type Buffer: 'static;
+
+    fn new_from_shared(shared: RenderPipelineShared<Self::Buffer>) -> Result<Self>;
+
+    /// Obtains a buffer suitable for storing the input in channel `channel`.
+    /// This *might* be a buffer that was used to store that channel for that group in a previous
+    /// pass, a new buffer, or a re-used buffer from i.e. previously decoded frames.
+    fn get_buffer<T: ImageDataType>(&mut self, channel: usize) -> Result<Image<T>>;
+
+    /// Gives back the buffer for a channel and group to the render pipeline, marking that
+    /// `num_passes` additional passes (wrt. the previous call to this method for the same channel
+    /// and group, or 0 if no previous call happend) were rendered into the input buffer.
+    fn set_buffer_for_group<T: ImageDataType>(
+        &mut self,
+        channel: usize,
+        group_id: usize,
+        num_passes: usize,
+        buf: Image<T>,
+        buffer_splitter: &mut BufferSplitter,
+    ) -> Result<()>;
+
+    /// Checks whether the provided buffer sizes are correct.
+    fn check_buffer_sizes(&self, buffers: &mut [Option<JxlOutputBuffer>]) -> Result<()>;
+
+    /// Renders any data outside the frame that would not be rendered by calls to
+    /// set_buffer_for_group. Can be called multiple times - it is up to the pipeline
+    /// implementation to ensure rendering only happens once.
+    fn render_outside_frame(&mut self, buffer_splitter: &mut BufferSplitter) -> Result<()>;
+
+    fn box_inout_stage<S: RenderPipelineInOutStage>(
+        stage: S,
+    ) -> Box<dyn RunInOutStage<Self::Buffer>>;
+
+    fn box_inplace_stage<S: RenderPipelineInPlaceStage>(
+        stage: S,
+    ) -> Box<dyn RunInPlaceStage<Self::Buffer>>;
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/save.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/save.rs
new file mode 100644
index 0000000..26898f1
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/save.rs
@@ -0,0 +1,89 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{
+    api::{JxlColorType, JxlDataFormat, JxlOutputBuffer},
+    error::{Error, Result},
+    headers::Orientation,
+    image::DataTypeTag,
+};
+
+pub struct SaveStage {
+    pub(super) channels: Vec<usize>,
+    pub(super) orientation: Orientation,
+    pub(super) output_buffer_index: usize,
+    pub(super) color_type: JxlColorType,
+    pub(super) data_format: JxlDataFormat,
+}
+
+impl SaveStage {
+    pub fn new(
+        channels: &[usize],
+        orientation: Orientation,
+        output_buffer_index: usize,
+        mut color_type: JxlColorType,
+        data_format: JxlDataFormat,
+    ) -> SaveStage {
+        let mut channels = channels.to_vec();
+        if color_type == JxlColorType::Bgr {
+            color_type = JxlColorType::Rgb;
+            channels.swap(0, 2);
+        }
+        if color_type == JxlColorType::Bgra {
+            color_type = JxlColorType::Rgba;
+            channels.swap(0, 2);
+        }
+        Self {
+            channels,
+            orientation,
+            output_buffer_index,
+            color_type,
+            data_format,
+        }
+    }
+
+    pub fn uses_channel(&self, c: usize) -> bool {
+        self.channels.contains(&c)
+    }
+
+    pub fn input_type(&self) -> DataTypeTag {
+        self.data_format.data_type()
+    }
+
+    pub fn check_buffer_size(
+        &self,
+        size: (usize, usize),
+        buffer: Option<&JxlOutputBuffer>,
+    ) -> Result<()> {
+        let Some(buf) = buffer else {
+            return Ok(());
+        };
+        let osize = self.orientation.map_size(size);
+
+        let expected_w = self.channels.len() * self.data_format.bytes_per_sample() * osize.0;
+
+        if buf.byte_size() != (expected_w, osize.1) {
+            return Err(Error::InvalidOutputBufferSize(
+                buf.byte_size().0,
+                buf.byte_size().1,
+                osize.0,
+                osize.1,
+                self.color_type,
+                self.data_format,
+            ));
+        }
+        Ok(())
+    }
+}
+
+impl std::fmt::Display for SaveStage {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "save channels {:?} (type {:?} {:?})",
+            self.channels, self.color_type, self.data_format
+        )
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/simple_pipeline/extend.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/simple_pipeline/extend.rs
new file mode 100644
index 0000000..8299b372
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/simple_pipeline/extend.rs
@@ -0,0 +1,94 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{
+    image::{Image, ImageDataType},
+    render::stages::ExtendToImageDimensionsStage,
+    util::{round_up_size_to_cache_line, tracing_wrappers::*},
+};
+
+impl ExtendToImageDimensionsStage {
+    #[instrument(skip_all)]
+    pub(super) fn extend_simple(
+        &self,
+        chunk_size: usize,
+        input_buffers: &[Image<f64>],
+        output_buffers: &mut [Image<f64>],
+    ) {
+        debug!("running extend stage '{self}' in simple pipeline");
+        let numc = input_buffers.len();
+        if numc == 0 {
+            return;
+        }
+        assert_eq!(output_buffers.len(), numc);
+        let input_size = input_buffers[0].size();
+        let output_size = output_buffers[0].size();
+        for c in 1..numc {
+            assert_eq!(input_size, input_buffers[c].size());
+            assert_eq!(output_size, output_buffers[c].size());
+        }
+        assert_eq!(output_size, self.image_size);
+        let origin = self.frame_origin;
+        assert!(origin.0 <= output_size.0 as isize);
+        assert!(origin.1 <= output_size.1 as isize);
+        assert!(origin.0 + input_size.0 as isize >= 0);
+        assert!(origin.1 + input_size.1 as isize >= 0);
+        debug!("input_size = {input_size:?} output_size = {output_size:?} origin = {origin:?}");
+        // Compute the input rectangle
+        let x0 = origin.0.max(0) as usize;
+        let y0 = origin.1.max(0) as usize;
+        let x1 = (origin.0 + input_size.0 as isize).min(output_size.0 as isize) as usize;
+        let y1 = (origin.1 + input_size.1 as isize).min(output_size.1 as isize) as usize;
+        debug!("x0 = {x0} x1 = {x1} y0 = {y0} y1 = {y1}");
+        let in_x0 = (x0 as isize - origin.0) as usize;
+        let in_x1 = (x1 as isize - origin.0) as usize;
+        let in_y0 = (y0 as isize - origin.1) as usize;
+        let in_y1 = (y1 as isize - origin.1) as usize;
+        debug!("in_x0 = {in_x0} in_x1 = {in_x1} in_y0 = {in_y0} in_y1 = {in_y1}");
+        // First, copy the data in the middle.
+        for c in 0..numc {
+            for in_y in in_y0..in_y1 {
+                debug!("copy row: {in_y}");
+                let in_row = input_buffers[c].row(in_y);
+                let y = (in_y as isize + origin.1) as usize;
+                output_buffers[c].row_mut(y)[x0..x1].copy_from_slice(&in_row[in_x0..in_x1]);
+            }
+        }
+        // Fill in rows above and below the original data.
+        let mut buffer = vec![f32::default(); round_up_size_to_cache_line::<f32>(chunk_size)];
+        for y in (0..y0).chain(y1..output_size.1) {
+            for x in (0..output_size.0).step_by(chunk_size) {
+                let xsize = output_size.0.min(x + chunk_size) - x;
+                debug!("position above/below: ({x},{y}) xsize: {xsize}");
+                for (c, buf) in output_buffers.iter_mut().enumerate() {
+                    self.process_row_chunk((x, y), xsize, c, &mut buffer);
+                    for (ix, px) in buffer.iter().enumerate().take(xsize) {
+                        buf.row_mut(y)[x + ix] = px.to_f64();
+                    }
+                }
+            }
+        }
+        // Fill in left and right of the original data.
+        for y in y0..y1 {
+            for (x, xsize) in (0..x0)
+                .step_by(chunk_size)
+                .map(|x| (x, x0.min(x + chunk_size) - x))
+                .chain(
+                    (x1..output_size.0)
+                        .step_by(chunk_size)
+                        .map(|x| (x, output_size.0.min(x + chunk_size) - x)),
+                )
+            {
+                debug!("position on the side: ({x},{y}) xsize: {xsize}");
+                for (c, buf) in output_buffers.iter_mut().enumerate() {
+                    self.process_row_chunk((x, y), xsize, c, &mut buffer);
+                    for (ix, px) in buffer.iter().enumerate().take(xsize) {
+                        buf.row_mut(y)[x + ix] = px.to_f64();
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/simple_pipeline/mod.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/simple_pipeline/mod.rs
new file mode 100644
index 0000000..327fd3ef
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/simple_pipeline/mod.rs
@@ -0,0 +1,214 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{
+    api::JxlOutputBuffer,
+    error::Result,
+    image::{Image, ImageDataType},
+    render::{buffer_splitter::BufferSplitter, internal::ChannelInfo},
+    util::{ShiftRightCeil, tracing_wrappers::*},
+};
+
+use super::{
+    RenderPipeline, RenderPipelineInOutStage, RenderPipelineInPlaceStage,
+    internal::{RenderPipelineShared, Stage},
+};
+
+mod extend;
+mod run_stage;
+mod save;
+
+/// A RenderPipeline that waits for all input of a pass to be ready before doing any rendering, and
+/// prioritizes simplicity over memory usage and computational efficiency.
+/// Eventually meant to be used only for verification purposes.
+pub struct SimpleRenderPipeline {
+    shared: RenderPipelineShared<Image<f64>>,
+    input_buffers: Vec<Image<f64>>,
+    completed_passes: usize,
+}
+
+impl SimpleRenderPipeline {
+    #[instrument(skip_all, err)]
+    fn do_render(&mut self, buffer_splitter: &mut BufferSplitter) -> Result<()> {
+        let ready_passes = self
+            .shared
+            .group_chan_ready_passes
+            .iter()
+            .flat_map(|x| x.iter())
+            .copied()
+            .min()
+            .unwrap();
+        if ready_passes <= self.completed_passes {
+            debug!(
+                "no more ready passes ({} completed, {ready_passes} ready)",
+                self.completed_passes
+            );
+            return Ok(());
+        }
+        debug!(
+            "new ready passes ({} completed, {ready_passes} ready)",
+            self.completed_passes
+        );
+
+        let mut current_buffers = clone_images(&self.input_buffers)?;
+
+        let mut current_size = self.shared.input_size;
+
+        for (i, stage) in self.shared.stages.iter().enumerate() {
+            debug!("running stage {i}: {stage}");
+            let mut output_buffers = clone_images(&current_buffers)?;
+            if stage.shift() != (0, 0) || stage.new_size(current_size) != current_size {
+                // Replace buffers of different sizes.
+                current_size = stage.new_size(current_size);
+                for (c, info) in self.shared.channel_info[i + 1].iter().enumerate() {
+                    if stage.uses_channel(c) {
+                        let xsize = current_size.0.shrc(info.downsample.0);
+                        let ysize = current_size.1.shrc(info.downsample.1);
+                        debug!("reallocating channel {c} to new size {xsize}x{ysize}");
+                        output_buffers[c] = Image::new((xsize, ysize))?;
+                    }
+                }
+            }
+            match stage {
+                Stage::InOut(stage) => {
+                    let input_buf: Vec<_> = current_buffers
+                        .iter()
+                        .enumerate()
+                        .filter(|x| stage.uses_channel(x.0))
+                        .map(|x| x.1)
+                        .collect();
+                    let mut output_buf: Vec<_> = output_buffers
+                        .iter_mut()
+                        .enumerate()
+                        .filter(|x| stage.uses_channel(x.0))
+                        .map(|x| x.1)
+                        .collect();
+                    let mut state = stage.init_local_state()?;
+                    stage.run_stage_on(
+                        self.shared.chunk_size,
+                        &input_buf,
+                        &mut output_buf,
+                        state.as_deref_mut(),
+                    );
+                }
+                Stage::InPlace(stage) => {
+                    let mut output_buf: Vec<_> = output_buffers
+                        .iter_mut()
+                        .enumerate()
+                        .filter(|x| stage.uses_channel(x.0))
+                        .map(|x| x.1)
+                        .collect();
+                    let mut state = stage.init_local_state()?;
+                    stage.run_stage_on(
+                        self.shared.chunk_size,
+                        &mut output_buf,
+                        state.as_deref_mut(),
+                    );
+                }
+                Stage::Extend(e) => {
+                    e.extend_simple(
+                        self.shared.chunk_size,
+                        &current_buffers,
+                        &mut output_buffers,
+                    );
+                }
+                Stage::Save(stage) => {
+                    stage.save_simple(&output_buffers, buffer_splitter.get_full_buffers())?;
+                }
+            }
+            current_buffers = output_buffers;
+        }
+
+        self.completed_passes = ready_passes;
+        Ok(())
+    }
+}
+
+fn clone_images<T: ImageDataType>(images: &[Image<T>]) -> Result<Vec<Image<T>>> {
+    images.iter().map(|x| x.try_clone()).collect()
+}
+
+impl RenderPipeline for SimpleRenderPipeline {
+    type Buffer = Image<f64>;
+
+    fn new_from_shared(shared: RenderPipelineShared<Self::Buffer>) -> Result<Self> {
+        let input_buffers = shared.channel_info[0]
+            .iter()
+            .map(|x| {
+                let xsize = shared.input_size.0.shrc(x.downsample.0);
+                let ysize = shared.input_size.1.shrc(x.downsample.1);
+                Image::new((xsize, ysize))
+            })
+            .collect::<Result<Vec<_>>>()?;
+
+        Ok(Self {
+            shared,
+            input_buffers,
+            completed_passes: 0,
+        })
+    }
+
+    #[instrument(skip_all, err)]
+    fn get_buffer<T: ImageDataType>(&mut self, channel: usize) -> Result<Image<T>> {
+        let sz = self.shared.group_size_for_channel(channel, T::DATA_TYPE_ID);
+        Image::<T>::new(sz)
+    }
+
+    fn set_buffer_for_group<T: ImageDataType>(
+        &mut self,
+        channel: usize,
+        group_id: usize,
+        num_passes: usize,
+        buf: Image<T>,
+        buffer_splitter: &mut BufferSplitter,
+    ) -> Result<()> {
+        debug!(
+            "filling data for group {}, channel {}, using type {:?}",
+            group_id,
+            channel,
+            T::DATA_TYPE_ID,
+        );
+        let sz = self.shared.group_size_for_channel(channel, T::DATA_TYPE_ID);
+        let goffset = self.shared.group_offset(group_id);
+        let ChannelInfo { ty, downsample } = self.shared.channel_info[0][channel];
+        let off = (goffset.0 >> downsample.0, goffset.1 >> downsample.1);
+        debug!(?sz, input_buffers_sz=?self.input_buffers[channel].size(), offset=?off, ?downsample, ?goffset);
+        let ty = ty.unwrap();
+        assert_eq!(ty, T::DATA_TYPE_ID);
+        let total_sz = self.input_buffers[channel].size();
+        for y in 0..sz.1.min(total_sz.1 - off.1) {
+            let row_in = buf.row(y);
+            let row_out = self.input_buffers[channel].row_mut(y + off.1);
+            for x in 0..sz.0.min(total_sz.0 - off.0) {
+                row_out[x + off.0] = row_in[x].to_f64();
+            }
+        }
+        self.shared.group_chan_ready_passes[group_id][channel] += num_passes;
+
+        self.do_render(buffer_splitter)
+    }
+
+    fn check_buffer_sizes(&self, _buffers: &mut [Option<JxlOutputBuffer>]) -> Result<()> {
+        // This will be checked during rendering.
+        Ok(())
+    }
+
+    fn render_outside_frame(&mut self, _buffer_splitter: &mut BufferSplitter) -> Result<()> {
+        // Nothing to do in the simple pipeline.
+        Ok(())
+    }
+
+    fn box_inout_stage<S: RenderPipelineInOutStage>(
+        stage: S,
+    ) -> Box<dyn super::RunInOutStage<Self::Buffer>> {
+        Box::new(stage)
+    }
+
+    fn box_inplace_stage<S: RenderPipelineInPlaceStage>(
+        stage: S,
+    ) -> Box<dyn super::RunInPlaceStage<Self::Buffer>> {
+        Box::new(stage)
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/simple_pipeline/run_stage.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/simple_pipeline/run_stage.rs
new file mode 100644
index 0000000..284834a
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/simple_pipeline/run_stage.rs
@@ -0,0 +1,213 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(clippy::needless_range_loop)]
+
+use std::any::Any;
+
+use crate::{
+    image::{Image, ImageDataType},
+    render::{
+        RenderPipelineInOutStage, RenderPipelineInPlaceStage, RunInOutStage, RunInPlaceStage,
+        internal::PipelineBuffer,
+    },
+    util::{round_up_size_to_cache_line, tracing_wrappers::*},
+};
+
+impl PipelineBuffer for Image<f64> {
+    type InPlaceExtraInfo = usize;
+    type InOutExtraInfo = usize;
+}
+
+impl<T: RenderPipelineInPlaceStage> RunInPlaceStage<Image<f64>> for T {
+    fn run_stage_on(
+        &self,
+        chunk_size: usize,
+        buffers: &mut [&mut Image<f64>],
+        mut state: Option<&mut dyn Any>,
+    ) {
+        debug!("running inplace stage '{self}' in simple pipeline");
+        let numc = buffers.len();
+        if numc == 0 {
+            return;
+        }
+        let size = buffers[0].size();
+        for b in buffers.iter() {
+            assert_eq!(size, b.size());
+        }
+        let mut buffer =
+            vec![
+                vec![T::Type::default(); round_up_size_to_cache_line::<T::Type>(chunk_size)];
+                numc
+            ];
+        for y in 0..size.1 {
+            for x in (0..size.0).step_by(chunk_size) {
+                let xsize = size.0.min(x + chunk_size) - x;
+                debug!("position: {x}x{y} xsize: {xsize}");
+                for c in 0..numc {
+                    let in_row = buffers[c].row(y);
+                    for ix in 0..xsize {
+                        buffer[c][ix] = T::Type::from_f64(in_row[x + ix]);
+                    }
+                }
+                let mut row: Vec<_> = buffer.iter_mut().map(|x| x as &mut [_]).collect();
+                self.process_row_chunk((x, y), xsize, &mut row, state.as_deref_mut());
+                for c in 0..numc {
+                    let out_row = buffers[c].row_mut(y);
+                    for ix in 0..xsize {
+                        out_row[x + ix] = buffer[c][ix].to_f64();
+                    }
+                }
+            }
+        }
+    }
+}
+
+impl<T: RenderPipelineInOutStage> RunInOutStage<Image<f64>> for T {
+    #[instrument(skip_all)]
+    fn run_stage_on(
+        &self,
+        chunk_size: usize,
+        input_buffers: &[&Image<f64>],
+        output_buffers: &mut [&mut Image<f64>],
+        mut state: Option<&mut dyn Any>,
+    ) {
+        assert_ne!(chunk_size, 0);
+        debug!("running inout stage '{self}' in simple pipeline");
+        let numc = input_buffers.len();
+        if numc == 0 {
+            return;
+        }
+        assert_eq!(output_buffers.len(), numc);
+        let input_size = input_buffers[0].size();
+        let output_size = output_buffers[0].size();
+        for c in 1..numc {
+            assert_eq!(input_size, input_buffers[c].size());
+            assert_eq!(output_size, output_buffers[c].size());
+        }
+        debug!(
+            ?input_size,
+            ?output_size,
+            SHIFT = ?Self::SHIFT,
+            BORDER = ?Self::BORDER,
+            numc
+        );
+        assert_eq!(input_size.0, output_size.0.div_ceil(1 << Self::SHIFT.0));
+        assert_eq!(input_size.1, output_size.1.div_ceil(1 << Self::SHIFT.1));
+        let mut buffer_in = vec![
+            vec![
+                vec![
+                    T::InputT::default();
+                    // Double rounding make sure that we always have enough buffer for reading a whole SIMD lane.
+                    round_up_size_to_cache_line::<T::OutputT>(
+                        round_up_size_to_cache_line::<T::OutputT>(chunk_size)
+                            + T::BORDER.0 as usize * 2
+                    )
+                ];
+                T::BORDER.1 as usize * 2 + 1
+            ];
+            numc
+        ];
+        let mut buffer_out = vec![
+            vec![
+                vec![
+                    T::OutputT::default();
+                    round_up_size_to_cache_line::<T::OutputT>(chunk_size)
+                        << T::SHIFT.0
+                ];
+                1 << T::SHIFT.1
+            ];
+            numc
+        ];
+
+        let mirror = |mut v: i64, size: i64| {
+            while v < 0 || v >= size {
+                if v < 0 {
+                    v = -v - 1;
+                }
+                if v >= size {
+                    v = size + (size - v) - 1;
+                }
+            }
+            v as usize
+        };
+        for y in 0..input_size.1 {
+            for x in (0..input_size.0).step_by(chunk_size) {
+                let border_x = Self::BORDER.0 as i64;
+                let border_y = Self::BORDER.1 as i64;
+                let xsize = input_size.0.min(x + chunk_size) - x;
+                let xs = xsize as i64;
+                debug!("position: {x}x{y} xsize: {xsize}");
+                for c in 0..numc {
+                    for iy in -border_y..=border_y {
+                        let imgy = mirror(y as i64 + iy, input_size.1 as i64);
+                        let in_row = input_buffers[c].row(imgy);
+                        let buf_in_row = &mut buffer_in[c][(iy + border_y) as usize];
+                        for ix in (-border_x..0).chain(xs..xs + border_x) {
+                            let imgx = mirror(x as i64 + ix, input_size.0 as i64);
+                            buf_in_row[(ix + border_x) as usize] =
+                                T::InputT::from_f64(in_row[imgx]);
+                        }
+                        for ix in 0..xsize {
+                            buf_in_row[ix + border_x as usize] =
+                                T::InputT::from_f64(in_row[x + ix]);
+                        }
+                    }
+                }
+                // Build flat input rows: all rows for all channels in one Vec
+                let num_input_channels = buffer_in.len();
+                let input_rows_per_channel = buffer_in[0].len();
+                let mut input_row_data =
+                    Vec::with_capacity(num_input_channels * input_rows_per_channel);
+                for ch_buf in buffer_in.iter() {
+                    for row in ch_buf.iter() {
+                        input_row_data.push(row as &[_]);
+                    }
+                }
+                let input_rows = crate::render::Channels::new(
+                    input_row_data,
+                    num_input_channels,
+                    input_rows_per_channel,
+                );
+
+                // Build flat output rows: all rows for all channels in one Vec
+                let num_output_channels = buffer_out.len();
+                let output_rows_per_channel = buffer_out[0].len();
+                let mut output_row_data =
+                    Vec::with_capacity(num_output_channels * output_rows_per_channel);
+                for ch_buf in buffer_out.iter_mut() {
+                    for row in ch_buf.iter_mut() {
+                        output_row_data.push(row as &mut [_]);
+                    }
+                }
+                let mut output_rows = crate::render::ChannelsMut::new(
+                    output_row_data,
+                    num_output_channels,
+                    output_rows_per_channel,
+                );
+
+                self.process_row_chunk(
+                    (x, y),
+                    xsize,
+                    &input_rows,
+                    &mut output_rows,
+                    state.as_deref_mut(),
+                );
+                let stripe_xsize =
+                    (xsize << Self::SHIFT.0).min(output_size.0 - (x << Self::SHIFT.0));
+                let stripe_ysize =
+                    (1usize << Self::SHIFT.1).min(output_size.1 - (y << Self::SHIFT.1));
+                for c in 0..numc {
+                    for iy in 0..stripe_ysize {
+                        let out_row = output_buffers[c].row_mut((y << Self::SHIFT.1) + iy);
+                        for ix in 0..stripe_xsize {
+                            out_row[(x << Self::SHIFT.0) + ix] = buffer_out[c][iy][ix].to_f64();
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/simple_pipeline/save.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/simple_pipeline/save.rs
new file mode 100644
index 0000000..54b8a81
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/simple_pipeline/save.rs
@@ -0,0 +1,222 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::util::f16;
+
+use crate::{
+    api::{Endianness, JxlDataFormat, JxlOutputBuffer},
+    error::Result,
+    image::Image,
+    render::save::SaveStage,
+};
+
+impl SaveStage {
+    pub(super) fn save_simple(
+        &self,
+        data: &[Image<f64>],
+        buffers: &mut [Option<JxlOutputBuffer>],
+    ) -> Result<()> {
+        for i in self.channels.iter().skip(1) {
+            assert_eq!(data[self.channels[0]].size(), data[*i].size());
+        }
+        let Some(buf) = buffers[self.output_buffer_index].as_mut() else {
+            return Ok(());
+        };
+        let size = data[0].size();
+
+        self.check_buffer_size(size, Some(buf))?;
+
+        for (c, &chan) in self.channels.iter().enumerate() {
+            for y in 0..size.1 {
+                let src_row = data[chan].row(y);
+                for (x, &px) in src_row.iter().enumerate() {
+                    let (dx, dy) = self.orientation.display_pixel((x, y), size);
+                    let dx = dx * self.channels.len() + c;
+                    let bps = self.data_format.bytes_per_sample();
+
+                    macro_rules! write_pixel {
+                        ($px: expr, $endianness: expr) => {
+                            let px = $px;
+                            let px_bytes = if $endianness == Endianness::LittleEndian {
+                                px.to_le_bytes()
+                            } else {
+                                px.to_be_bytes()
+                            };
+                            buf.write_bytes(dy, dx * bps, &px_bytes);
+                        };
+                    }
+
+                    match self.data_format {
+                        JxlDataFormat::U8 { .. } => {
+                            // Conversion stages already handle bit depth scaling
+                            write_pixel!(px as u8, Endianness::LittleEndian);
+                        }
+                        JxlDataFormat::U16 { endianness, .. } => {
+                            // Conversion stages already handle bit depth scaling
+                            write_pixel!(px as u16, endianness);
+                        }
+                        JxlDataFormat::F32 { endianness } => {
+                            write_pixel!(px as f32, endianness);
+                        }
+                        JxlDataFormat::F16 { endianness } => {
+                            write_pixel!(f16::from_f64(px), endianness);
+                        }
+                    }
+                }
+            }
+        }
+        Ok(())
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use crate::{
+        api::JxlColorType, headers::Orientation, image::Rect, util::test::assert_almost_eq,
+    };
+    use rand::SeedableRng;
+    use rand_xorshift::XorShiftRng;
+    use test_log::test;
+
+    #[test]
+    fn save_stage() -> Result<()> {
+        let save_stage = SaveStage::new(
+            &[0],
+            Orientation::Identity,
+            0,
+            JxlColorType::Grayscale,
+            JxlDataFormat::U8 { bit_depth: 8 },
+        );
+        let mut rng = XorShiftRng::seed_from_u64(0);
+        let src = [Image::<f64>::new_random((128, 128), &mut rng)?];
+        let mut dst = Image::<u8>::new_random((128, 128), &mut rng)?;
+
+        save_stage.save_simple(
+            &src,
+            &mut [Some(JxlOutputBuffer::from_image_rect_mut(
+                dst.get_rect_mut(Rect {
+                    size: (128, 128),
+                    origin: (0, 0),
+                })
+                .into_raw(),
+            ))],
+        )?;
+
+        for y in 0..128 {
+            for x in 0..128 {
+                // Conversion stages handle bit depth scaling, save stage just casts
+                let expected = src[0].row(y)[x] as u8;
+                assert_eq!(expected, dst.row(y)[x]);
+            }
+        }
+
+        Ok(())
+    }
+
+    fn do_test_orientation(
+        orientation: Orientation,
+        transform: impl Fn(usize, usize, usize, usize) -> (usize, usize),
+    ) -> Result<()> {
+        let (w, h) = (32, 16);
+        let mut rng = XorShiftRng::seed_from_u64(0);
+        let src = [Image::<f64>::new_random((w, h), &mut rng)?];
+
+        let (ow, oh) = if orientation.is_transposing() {
+            (h, w)
+        } else {
+            (w, h)
+        };
+
+        let save_stage = SaveStage::new(
+            &[0],
+            orientation,
+            0,
+            JxlColorType::Grayscale,
+            JxlDataFormat::f32(),
+        );
+
+        let mut rng = XorShiftRng::seed_from_u64(0);
+        let mut dst = Image::<f32>::new_random((ow, oh), &mut rng)?;
+
+        save_stage.save_simple(
+            &src,
+            &mut [Some(JxlOutputBuffer::from_image_rect_mut(
+                dst.get_rect_mut(Rect {
+                    origin: (0, 0),
+                    size: (ow, oh),
+                })
+                .into_raw(),
+            ))],
+        )?;
+
+        // Iterate over the DESTINATION image pixels.
+        for y_dest in 0..oh {
+            for x_dest in 0..ow {
+                // For each destination pixel, find its corresponding source pixel.
+                let (src_x, src_y) = transform(x_dest, y_dest, w, h);
+                assert_almost_eq(
+                    dst.row(y_dest)[x_dest],
+                    src[0].row(src_y)[src_x] as f32,
+                    1e-5,
+                    1e-5,
+                );
+            }
+        }
+
+        Ok(())
+    }
+
+    #[test]
+    fn orientation_identity() -> Result<()> {
+        do_test_orientation(Orientation::Identity, |x, y, _, _| (x, y))
+    }
+
+    #[test]
+    fn orientation_flip_horizontal() -> Result<()> {
+        do_test_orientation(Orientation::FlipHorizontal, |x, y, w, _| (w - 1 - x, y))
+    }
+
+    #[test]
+    fn orientation_flip_vertical() -> Result<()> {
+        do_test_orientation(Orientation::FlipVertical, |x, y, _, h| (x, h - 1 - y))
+    }
+
+    #[test]
+    fn orientation_rotate_180() -> Result<()> {
+        do_test_orientation(Orientation::Rotate180, |x, y, w, h| (w - 1 - x, h - 1 - y))
+    }
+
+    // transposing orientations
+
+    #[test]
+    fn orientation_transpose() -> Result<()> {
+        do_test_orientation(Orientation::Transpose, |x_dest, y_dest, _, _| {
+            (y_dest, x_dest)
+        })
+    }
+
+    #[test]
+    fn orientation_rotate_90_cw() -> Result<()> {
+        do_test_orientation(Orientation::Rotate90Cw, |x_dest, y_dest, _, h_src| {
+            (y_dest, h_src - 1 - x_dest)
+        })
+    }
+
+    #[test]
+    fn orientation_anti_transpose() -> Result<()> {
+        do_test_orientation(
+            Orientation::AntiTranspose,
+            |x_dest, y_dest, w_src, h_src| (w_src - 1 - y_dest, h_src - 1 - x_dest),
+        )
+    }
+
+    #[test]
+    fn orientation_rotate_90_ccw() -> Result<()> {
+        do_test_orientation(Orientation::Rotate90Ccw, |x_dest, y_dest, w_src, _| {
+            (w_src - 1 - y_dest, x_dest)
+        })
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/blending.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/blending.rs
new file mode 100644
index 0000000..8aca8deb
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/blending.rs
@@ -0,0 +1,185 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::sync::Arc;
+
+use crate::{
+    error::Result,
+    features::{
+        blending::perform_blending,
+        patches::{PatchBlendMode, PatchBlending},
+    },
+    frame::ReferenceFrame,
+    headers::{FileHeader, extra_channels::ExtraChannelInfo, frame_header::*},
+    render::RenderPipelineInPlaceStage,
+    util::slice,
+};
+
+pub struct BlendingStage {
+    pub frame_origin: (isize, isize),
+    pub image_size: (isize, isize),
+    pub blending_info: BlendingInfo,
+    pub ec_blending_info: Vec<BlendingInfo>,
+    pub extra_channels: Vec<ExtraChannelInfo>,
+    pub reference_frames: Arc<[Option<ReferenceFrame>; 4]>,
+    pub zeros: Vec<f32>,
+}
+
+impl From<&BlendingInfo> for PatchBlending {
+    fn from(info: &BlendingInfo) -> Self {
+        let mode = match info.mode {
+            BlendingMode::Replace => PatchBlendMode::None,
+            BlendingMode::Add => PatchBlendMode::Add,
+            BlendingMode::Mul => PatchBlendMode::Mul,
+            BlendingMode::Blend => PatchBlendMode::BlendBelow,
+            BlendingMode::AlphaWeightedAdd => PatchBlendMode::AlphaWeightedAddBelow,
+        };
+        PatchBlending {
+            mode,
+            alpha_channel: info.alpha_channel as usize,
+            clamp: info.clamp,
+        }
+    }
+}
+
+impl BlendingStage {
+    pub fn new(
+        frame_header: &FrameHeader,
+        file_header: &FileHeader,
+        reference_frames: Arc<[Option<ReferenceFrame>; 4]>,
+    ) -> Result<BlendingStage> {
+        Ok(BlendingStage {
+            frame_origin: (frame_header.x0 as isize, frame_header.y0 as isize),
+            image_size: (
+                file_header.size.xsize() as isize,
+                file_header.size.ysize() as isize,
+            ),
+            blending_info: frame_header.blending_info.clone(),
+            ec_blending_info: frame_header.ec_blending_info.clone(),
+            extra_channels: file_header.image_metadata.extra_channel_info.clone(),
+            reference_frames,
+            zeros: vec![0f32; file_header.size.xsize() as usize],
+        })
+    }
+}
+
+impl std::fmt::Display for BlendingStage {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "blending")
+    }
+}
+
+impl RenderPipelineInPlaceStage for BlendingStage {
+    type Type = f32;
+
+    fn uses_channel(&self, c: usize) -> bool {
+        c < 3 + self.extra_channels.len()
+    }
+
+    fn process_row_chunk(
+        &self,
+        position: (usize, usize),
+        xsize: usize,
+        row: &mut [&mut [f32]],
+        _state: Option<&mut dyn std::any::Any>,
+    ) {
+        let num_ec = self.extra_channels.len();
+        let fg_y0 = self.frame_origin.1 + position.1 as isize;
+        let mut fg_x0 = self.frame_origin.0 + position.0 as isize;
+        let mut fg_x1 = fg_x0 + xsize as isize;
+        let mut bg_x0: isize = 0;
+        let mut bg_x1: isize = xsize as isize;
+
+        if fg_x1 <= 0 || fg_x0 >= self.image_size.0 || fg_y0 < 0 || fg_y0 >= self.image_size.1 {
+            return;
+        }
+
+        if fg_x0 < 0 {
+            bg_x0 -= fg_x0;
+            fg_x0 = 0;
+        }
+        if fg_x1 > self.image_size.0 {
+            bg_x1 = bg_x0 + self.image_size.0 - fg_x0;
+            fg_x1 = self.image_size.0;
+        }
+
+        let fg_x0: usize = fg_x0 as usize;
+        let fg_x1: usize = fg_x1 as usize;
+        let bg_x0: usize = bg_x0 as usize;
+        let bg_x1: usize = bg_x1 as usize;
+        let fg_y0: usize = fg_y0 as usize;
+
+        // TODO(szabadka): Allocate a buffer for this when building the stage instead of when
+        // executing it.
+        let mut out = row
+            .iter_mut()
+            .map(|s| &mut s[..xsize])
+            .collect::<Vec<&mut [f32]>>();
+
+        let mut fg = vec![self.zeros.as_slice(); 3 + num_ec];
+
+        for (c, fg_ptr) in fg.iter_mut().enumerate().take(3) {
+            if self.reference_frames[self.blending_info.source as usize].is_some() {
+                *fg_ptr = &(self.reference_frames[self.blending_info.source as usize]
+                    .as_ref()
+                    .unwrap()
+                    .frame[c]
+                    .row(fg_y0)[fg_x0..fg_x1]);
+            }
+        }
+        for i in 0..num_ec {
+            if self.reference_frames[self.ec_blending_info[i].source as usize].is_some() {
+                fg[3 + i] = &(self.reference_frames[self.ec_blending_info[i].source as usize]
+                    .as_ref()
+                    .unwrap()
+                    .frame[3 + i]
+                    .row(fg_y0)[fg_x0..fg_x1]);
+            }
+        }
+
+        let blending_info = PatchBlending::from(&self.blending_info);
+        let ec_blending_info: Vec<PatchBlending> = self
+            .ec_blending_info
+            .iter()
+            .map(PatchBlending::from)
+            .collect();
+
+        perform_blending(
+            &mut slice!(&mut out, .., bg_x0..bg_x1),
+            &fg,
+            &blending_info,
+            &ec_blending_info,
+            &self.extra_channels,
+        );
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use rand::SeedableRng;
+    use test_log::test;
+
+    use super::*;
+    use crate::error::Result;
+    use crate::util::test::read_headers_and_toc;
+
+    #[test]
+    fn blending_consistency() -> Result<()> {
+        let (file_header, frame_header, _) =
+            read_headers_and_toc(include_bytes!("../../../resources/test/basic.jxl")).unwrap();
+        let mut rng = rand_xorshift::XorShiftRng::seed_from_u64(0);
+        let reference_frames = Arc::new([
+            Some(ReferenceFrame::random(&mut rng, 500, 500, 4, false)?),
+            Some(ReferenceFrame::random(&mut rng, 500, 500, 4, false)?),
+            Some(ReferenceFrame::random(&mut rng, 500, 500, 4, false)?),
+            Some(ReferenceFrame::random(&mut rng, 500, 500, 4, false)?),
+        ]);
+        crate::render::test::test_stage_consistency(
+            || BlendingStage::new(&frame_header, &file_header, reference_frames.clone()).unwrap(),
+            (500, 500),
+            4,
+        )
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/chroma_upsample.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/chroma_upsample.rs
new file mode 100644
index 0000000..cb185d6
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/chroma_upsample.rs
@@ -0,0 +1,159 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::render::{Channels, ChannelsMut, RenderPipelineInOutStage};
+
+pub struct HorizontalChromaUpsample {
+    channel: usize,
+}
+
+impl HorizontalChromaUpsample {
+    pub fn new(channel: usize) -> HorizontalChromaUpsample {
+        HorizontalChromaUpsample { channel }
+    }
+}
+
+impl std::fmt::Display for HorizontalChromaUpsample {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "chroma upsample of channel {}, horizontally",
+            self.channel
+        )
+    }
+}
+
+impl RenderPipelineInOutStage for HorizontalChromaUpsample {
+    type InputT = f32;
+    type OutputT = f32;
+    const SHIFT: (u8, u8) = (1, 0);
+    const BORDER: (u8, u8) = (1, 0);
+
+    fn uses_channel(&self, c: usize) -> bool {
+        c == self.channel
+    }
+
+    fn process_row_chunk(
+        &self,
+        _position: (usize, usize),
+        xsize: usize,
+        input_rows: &Channels<f32>,
+        output_rows: &mut ChannelsMut<f32>,
+        _state: Option<&mut dyn std::any::Any>,
+    ) {
+        let input = &input_rows[0];
+        for i in 0..xsize {
+            let scaled_cur = input[0][i + 1] * 0.75;
+            let prev = input[0][i];
+            let next = input[0][i + 2];
+            let left = 0.25 * prev + scaled_cur;
+            let right = 0.25 * next + scaled_cur;
+            output_rows[0][0][2 * i] = left;
+            output_rows[0][0][2 * i + 1] = right;
+        }
+    }
+}
+
+pub struct VerticalChromaUpsample {
+    channel: usize,
+}
+
+impl VerticalChromaUpsample {
+    pub fn new(channel: usize) -> VerticalChromaUpsample {
+        VerticalChromaUpsample { channel }
+    }
+}
+
+impl std::fmt::Display for VerticalChromaUpsample {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "chroma upsample of channel {}, vertically", self.channel)
+    }
+}
+
+impl RenderPipelineInOutStage for VerticalChromaUpsample {
+    type InputT = f32;
+    type OutputT = f32;
+    const SHIFT: (u8, u8) = (0, 1);
+    const BORDER: (u8, u8) = (0, 1);
+
+    fn uses_channel(&self, c: usize) -> bool {
+        c == self.channel
+    }
+
+    fn process_row_chunk(
+        &self,
+        _position: (usize, usize),
+        xsize: usize,
+        input_rows: &Channels<f32>,
+        output_rows: &mut ChannelsMut<f32>,
+        _state: Option<&mut dyn std::any::Any>,
+    ) {
+        let input = &input_rows[0];
+        let output = &mut output_rows[0];
+        for i in 0..xsize {
+            let scaled_cur = input[1][i] * 0.75;
+            let prev = input[0][i];
+            let next = input[2][i];
+            let up = 0.25 * prev + scaled_cur;
+            let down = 0.25 * next + scaled_cur;
+            output[0][i] = up;
+            output[1][i] = down;
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use crate::{error::Result, image::Image, render::test::make_and_run_simple_pipeline};
+    use test_log::test;
+
+    #[test]
+    fn hchr_consistency() -> Result<()> {
+        crate::render::test::test_stage_consistency(
+            || HorizontalChromaUpsample::new(0),
+            (500, 500),
+            1,
+        )
+    }
+
+    #[test]
+    fn test_hchr() -> Result<()> {
+        let mut input = Image::new((3, 1))?;
+        input.row_mut(0).copy_from_slice(&[1.0f32, 2.0, 4.0]);
+        let stage = HorizontalChromaUpsample::new(0);
+        let output: Vec<Image<f32>> =
+            make_and_run_simple_pipeline(stage, &[input], (6, 1), 0, 256)?;
+        assert_eq!(output[0].row(0), [1.0, 1.25, 1.75, 2.5, 3.5, 4.0]);
+        Ok(())
+    }
+
+    #[test]
+    fn vchr_consistency() -> Result<()> {
+        crate::render::test::test_stage_consistency(
+            || VerticalChromaUpsample::new(0),
+            (500, 500),
+            1,
+        )
+    }
+
+    #[test]
+    fn test_vchr() -> Result<()> {
+        let mut input = Image::new((1, 3))?;
+        input.row_mut(0)[0] = 1.0f32;
+        input.row_mut(1)[0] = 2.0f32;
+        input.row_mut(2)[0] = 4.0f32;
+        let stage = VerticalChromaUpsample::new(0);
+        let output: Vec<Image<f32>> =
+            make_and_run_simple_pipeline(stage, &[input], (1, 6), 0, 256)?;
+        assert_eq!(output[0].row(0)[0], 1.0);
+        assert_eq!(output[0].row(1)[0], 1.25);
+        assert_eq!(output[0].row(2)[0], 1.75);
+        assert_eq!(output[0].row(3)[0], 2.5);
+        assert_eq!(output[0].row(4)[0], 3.5);
+        assert_eq!(output[0].row(5)[0], 4.0);
+        Ok(())
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/convert.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/convert.rs
new file mode 100644
index 0000000..687491c
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/convert.rs
@@ -0,0 +1,402 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{
+    frame::quantizer::LfQuantFactors,
+    headers::bit_depth::BitDepth,
+    render::{Channels, ChannelsMut, RenderPipelineInOutStage},
+};
+
+pub struct ConvertU8F32Stage {
+    channel: usize,
+}
+
+impl ConvertU8F32Stage {
+    pub fn new(channel: usize) -> ConvertU8F32Stage {
+        ConvertU8F32Stage { channel }
+    }
+}
+
+impl std::fmt::Display for ConvertU8F32Stage {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "convert U8 data to F32 in channel {}", self.channel)
+    }
+}
+
+impl RenderPipelineInOutStage for ConvertU8F32Stage {
+    type InputT = u8;
+    type OutputT = f32;
+    const SHIFT: (u8, u8) = (0, 0);
+    const BORDER: (u8, u8) = (0, 0);
+
+    fn uses_channel(&self, c: usize) -> bool {
+        c == self.channel
+    }
+
+    fn process_row_chunk(
+        &self,
+        _position: (usize, usize),
+        xsize: usize,
+        input_rows: &Channels<u8>,
+        output_rows: &mut ChannelsMut<f32>,
+        _state: Option<&mut dyn std::any::Any>,
+    ) {
+        let input = &input_rows[0];
+        for i in 0..xsize {
+            output_rows[0][0][i] = input[0][i] as f32 * (1.0 / 255.0);
+        }
+    }
+}
+
+pub struct ConvertModularXYBToF32Stage {
+    first_channel: usize,
+    scale: [f32; 3],
+}
+
+impl ConvertModularXYBToF32Stage {
+    pub fn new(first_channel: usize, lf_quant: &LfQuantFactors) -> ConvertModularXYBToF32Stage {
+        ConvertModularXYBToF32Stage {
+            first_channel,
+            scale: lf_quant.quant_factors,
+        }
+    }
+}
+
+impl std::fmt::Display for ConvertModularXYBToF32Stage {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "convert modular xyb data to F32 in channels {}..{} with scales {:?}",
+            self.first_channel,
+            self.first_channel + 2,
+            self.scale
+        )
+    }
+}
+
+impl RenderPipelineInOutStage for ConvertModularXYBToF32Stage {
+    type InputT = i32;
+    type OutputT = f32;
+    const SHIFT: (u8, u8) = (0, 0);
+    const BORDER: (u8, u8) = (0, 0);
+
+    fn uses_channel(&self, c: usize) -> bool {
+        (self.first_channel..self.first_channel + 3).contains(&c)
+    }
+
+    fn process_row_chunk(
+        &self,
+        _position: (usize, usize),
+        xsize: usize,
+        input_rows: &Channels<i32>,
+        output_rows: &mut ChannelsMut<f32>,
+        _state: Option<&mut dyn std::any::Any>,
+    ) {
+        let [scale_x, scale_y, scale_b] = self.scale;
+        assert_eq!(
+            input_rows.len(),
+            3,
+            "incorrect number of channels; expected 3, found {}",
+            input_rows.len()
+        );
+        // Input channels: [Y, X, B] (modular XYB order)
+        // Output channels: [X, Y, B] (standard XYB order)
+        let (input_y, input_x, input_b) = (&input_rows[0], &input_rows[1], &input_rows[2]);
+        let (output_x, output_y, output_b) = output_rows.split_first_3_mut();
+        for i in 0..xsize {
+            output_x[0][i] = input_x[0][i] as f32 * scale_x;
+            output_y[0][i] = input_y[0][i] as f32 * scale_y;
+            output_b[0][i] = (input_b[0][i] + input_y[0][i]) as f32 * scale_b;
+        }
+    }
+}
+
+pub struct ConvertModularToF32Stage {
+    channel: usize,
+    bit_depth: BitDepth,
+}
+
+impl ConvertModularToF32Stage {
+    pub fn new(channel: usize, bit_depth: BitDepth) -> ConvertModularToF32Stage {
+        ConvertModularToF32Stage { channel, bit_depth }
+    }
+}
+
+impl std::fmt::Display for ConvertModularToF32Stage {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "convert modular data to F32 in channel {} with bit depth {:?}",
+            self.channel, self.bit_depth
+        )
+    }
+}
+
+// Converts custom [bits]-bit float (with [exp_bits] exponent bits) stored as
+// int back to binary32 float.
+// TODO(sboukortt): SIMD
+fn int_to_float(input: &[i32], output: &mut [f32], bit_depth: &BitDepth) {
+    assert_eq!(input.len(), output.len());
+    let bits = bit_depth.bits_per_sample();
+    let exp_bits = bit_depth.exponent_bits_per_sample();
+    if bits == 32 {
+        assert_eq!(exp_bits, 8);
+        for (&in_val, out_val) in input.iter().zip(output) {
+            *out_val = f32::from_bits(in_val as u32);
+        }
+        return;
+    }
+    let exp_bias = (1 << (exp_bits - 1)) - 1;
+    let sign_shift = bits - 1;
+    let mant_bits = bits - exp_bits - 1;
+    let mant_shift = 23 - mant_bits;
+    for (&in_val, out_val) in input.iter().zip(output) {
+        let mut f = in_val as u32;
+        let signbit = (f >> sign_shift) != 0;
+        f &= (1 << sign_shift) - 1;
+        if f == 0 {
+            *out_val = if signbit { -0.0 } else { 0.0 };
+            continue;
+        }
+        let mut exp = (f >> mant_bits) as i32;
+        let mut mantissa = f & ((1 << mant_bits) - 1);
+        if exp == (1 << exp_bits) - 1 {
+            // NaN or infinity
+            f = if signbit { 0x80000000 } else { 0 };
+            f |= 0b11111111 << 23;
+            f |= mantissa << mant_shift;
+            *out_val = f32::from_bits(f);
+            continue;
+        }
+        mantissa <<= mant_shift;
+        // Try to normalize only if there is space for maneuver.
+        if exp == 0 && exp_bits < 8 {
+            // subnormal number
+            while (mantissa & 0x800000) == 0 {
+                mantissa <<= 1;
+                exp -= 1;
+            }
+            exp += 1;
+            // remove leading 1 because it is implicit now
+            mantissa &= 0x7fffff;
+        }
+        exp -= exp_bias;
+        // broke up the arbitrary float into its parts, now reassemble into
+        // binary32
+        exp += 127;
+        assert!(exp >= 0);
+        f = if signbit { 0x80000000 } else { 0 };
+        f |= (exp as u32) << 23;
+        f |= mantissa;
+        *out_val = f32::from_bits(f);
+    }
+}
+
+impl RenderPipelineInOutStage for ConvertModularToF32Stage {
+    type InputT = i32;
+    type OutputT = f32;
+    const SHIFT: (u8, u8) = (0, 0);
+    const BORDER: (u8, u8) = (0, 0);
+
+    fn uses_channel(&self, c: usize) -> bool {
+        c == self.channel
+    }
+
+    fn process_row_chunk(
+        &self,
+        _position: (usize, usize),
+        xsize: usize,
+        input_rows: &Channels<i32>,
+        output_rows: &mut ChannelsMut<f32>,
+        _state: Option<&mut dyn std::any::Any>,
+    ) {
+        let input = &input_rows[0];
+        if self.bit_depth.floating_point_sample() {
+            int_to_float(
+                &input[0][..xsize],
+                &mut output_rows[0][0][..xsize],
+                &self.bit_depth,
+            );
+        } else {
+            let scale = 1.0 / ((1u64 << self.bit_depth.bits_per_sample()) - 1) as f32;
+            for i in 0..xsize {
+                output_rows[0][0][i] = input[0][i] as f32 * scale;
+            }
+        }
+    }
+}
+
+/// Stage that converts f32 values in [0, 1] range to u8 values.
+pub struct ConvertF32ToU8Stage {
+    channel: usize,
+    bit_depth: u8,
+}
+
+impl ConvertF32ToU8Stage {
+    pub fn new(channel: usize, bit_depth: u8) -> ConvertF32ToU8Stage {
+        ConvertF32ToU8Stage { channel, bit_depth }
+    }
+}
+
+impl std::fmt::Display for ConvertF32ToU8Stage {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "convert F32 to U8 in channel {} with bit depth {}",
+            self.channel, self.bit_depth
+        )
+    }
+}
+
+impl RenderPipelineInOutStage for ConvertF32ToU8Stage {
+    type InputT = f32;
+    type OutputT = u8;
+    const SHIFT: (u8, u8) = (0, 0);
+    const BORDER: (u8, u8) = (0, 0);
+
+    fn uses_channel(&self, c: usize) -> bool {
+        c == self.channel
+    }
+
+    fn process_row_chunk(
+        &self,
+        _position: (usize, usize),
+        xsize: usize,
+        input_rows: &Channels<f32>,
+        output_rows: &mut ChannelsMut<u8>,
+        _state: Option<&mut dyn std::any::Any>,
+    ) {
+        let input = &input_rows[0];
+        let max = ((1u32 << self.bit_depth) - 1) as f32;
+        for i in 0..xsize {
+            output_rows[0][0][i] = (input[0][i].clamp(0.0, 1.0) * max).round() as u8;
+        }
+    }
+}
+
+/// Stage that converts f32 values in [0, 1] range to u16 values.
+pub struct ConvertF32ToU16Stage {
+    channel: usize,
+    bit_depth: u8,
+}
+
+impl ConvertF32ToU16Stage {
+    pub fn new(channel: usize, bit_depth: u8) -> ConvertF32ToU16Stage {
+        ConvertF32ToU16Stage { channel, bit_depth }
+    }
+}
+
+impl std::fmt::Display for ConvertF32ToU16Stage {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "convert F32 to U16 in channel {} with bit depth {}",
+            self.channel, self.bit_depth
+        )
+    }
+}
+
+impl RenderPipelineInOutStage for ConvertF32ToU16Stage {
+    type InputT = f32;
+    type OutputT = u16;
+    const SHIFT: (u8, u8) = (0, 0);
+    const BORDER: (u8, u8) = (0, 0);
+
+    fn uses_channel(&self, c: usize) -> bool {
+        c == self.channel
+    }
+
+    fn process_row_chunk(
+        &self,
+        _position: (usize, usize),
+        xsize: usize,
+        input_rows: &Channels<f32>,
+        output_rows: &mut ChannelsMut<u16>,
+        _state: Option<&mut dyn std::any::Any>,
+    ) {
+        let input = &input_rows[0];
+        let max = ((1u32 << self.bit_depth) - 1) as f32;
+        for i in 0..xsize {
+            output_rows[0][0][i] = (input[0][i].clamp(0.0, 1.0) * max).round() as u16;
+        }
+    }
+}
+
+/// Stage that converts f32 values to f16 (half-precision float) values.
+pub struct ConvertF32ToF16Stage {
+    channel: usize,
+}
+
+impl ConvertF32ToF16Stage {
+    pub fn new(channel: usize) -> ConvertF32ToF16Stage {
+        ConvertF32ToF16Stage { channel }
+    }
+}
+
+impl std::fmt::Display for ConvertF32ToF16Stage {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "convert F32 to F16 in channel {}", self.channel)
+    }
+}
+
+impl RenderPipelineInOutStage for ConvertF32ToF16Stage {
+    type InputT = f32;
+    type OutputT = crate::util::f16;
+    const SHIFT: (u8, u8) = (0, 0);
+    const BORDER: (u8, u8) = (0, 0);
+
+    fn uses_channel(&self, c: usize) -> bool {
+        c == self.channel
+    }
+
+    fn process_row_chunk(
+        &self,
+        _position: (usize, usize),
+        xsize: usize,
+        input_rows: &Channels<f32>,
+        output_rows: &mut ChannelsMut<crate::util::f16>,
+        _state: Option<&mut dyn std::any::Any>,
+    ) {
+        let input = &input_rows[0];
+        for i in 0..xsize {
+            output_rows[0][0][i] = crate::util::f16::from_f32(input[0][i]);
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use crate::error::Result;
+    use test_log::test;
+
+    #[test]
+    fn u8_consistency() -> Result<()> {
+        crate::render::test::test_stage_consistency(|| ConvertU8F32Stage::new(0), (500, 500), 1)
+    }
+
+    #[test]
+    fn f32_to_u8_consistency() -> Result<()> {
+        crate::render::test::test_stage_consistency(
+            || ConvertF32ToU8Stage::new(0, 8),
+            (500, 500),
+            1,
+        )
+    }
+
+    #[test]
+    fn f32_to_u16_consistency() -> Result<()> {
+        crate::render::test::test_stage_consistency(
+            || ConvertF32ToU16Stage::new(0, 16),
+            (500, 500),
+            1,
+        )
+    }
+
+    #[test]
+    fn f32_to_f16_consistency() -> Result<()> {
+        crate::render::test::test_stage_consistency(|| ConvertF32ToF16Stage::new(0), (500, 500), 1)
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/epf/common.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/epf/common.rs
new file mode 100644
index 0000000..f044c3e9
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/epf/common.rs
@@ -0,0 +1,50 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::BLOCK_DIM;
+
+use jxl_simd::{F32SimdVec, I32SimdVec, SimdDescriptor, SimdMask};
+
+#[inline(always)]
+pub(super) fn prepare_sad_mul_storage(x: usize, y: usize, sm: f32, bsm: f32) -> [f32; 24] {
+    let mut sad_mul_storage = [bsm; 24];
+    if ![0, BLOCK_DIM - 1].contains(&(y % BLOCK_DIM)) {
+        for (i, s) in sad_mul_storage.iter_mut().enumerate().take(16) {
+            if ![0, BLOCK_DIM - 1].contains(&((x + i) % BLOCK_DIM)) {
+                *s = sm;
+            }
+        }
+    }
+    sad_mul_storage
+}
+
+#[inline(always)]
+pub(super) fn get_sigma<D: SimdDescriptor>(d: D, x: usize, row_sigma: &[f32]) -> D::F32Vec {
+    const { assert!(BLOCK_DIM == 8) }
+    const { assert!(D::F32Vec::LEN <= 16) }
+    let iota = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
+    let iota = D::I32Vec::load(d, &iota);
+    let sigma_start = x / BLOCK_DIM;
+    let offset = D::I32Vec::splat(d, (x - sigma_start * BLOCK_DIM) as i32) + iota;
+    if D::F32Vec::LEN > 8 {
+        let [sigma0, sigma1, sigma2, ..] = row_sigma[sigma_start..] else {
+            unreachable!();
+        };
+        let sigma0 = D::F32Vec::splat(d, sigma0);
+        let sigma1 = D::F32Vec::splat(d, sigma1);
+        let sigma2 = D::F32Vec::splat(d, sigma2);
+        let above_8 = offset.gt(D::I32Vec::splat(d, 7));
+        let above_16 = offset.gt(D::I32Vec::splat(d, 15));
+        above_16.if_then_else_f32(sigma2, above_8.if_then_else_f32(sigma1, sigma0))
+    } else {
+        let [sigma0, sigma1, ..] = row_sigma[sigma_start..] else {
+            unreachable!();
+        };
+        let sigma0 = D::F32Vec::splat(d, sigma0);
+        let sigma1 = D::F32Vec::splat(d, sigma1);
+        let above_8 = offset.gt(D::I32Vec::splat(d, 7));
+        above_8.if_then_else_f32(sigma1, sigma0)
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/epf/epf0.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/epf/epf0.rs
new file mode 100644
index 0000000..d8e64088f
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/epf/epf0.rs
@@ -0,0 +1,234 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::sync::Arc;
+
+use crate::{
+    BLOCK_DIM, MIN_SIGMA,
+    image::Image,
+    render::{
+        Channels, ChannelsMut, RenderPipelineInOutStage,
+        stages::epf::common::{get_sigma, prepare_sad_mul_storage},
+    },
+};
+
+use jxl_simd::{F32SimdVec, SimdMask, simd_function};
+
+/// 5x5 plus-shaped kernel with 5 SADs per pixel (3x3 plus-shaped). So this makes this filter a 7x7 filter.
+pub struct Epf0Stage {
+    /// Multiplier for sigma in pass 0
+    sigma_scale: f32,
+    /// (inverse) multiplier for sigma on borders
+    border_sad_mul: f32,
+    channel_scale: [f32; 3],
+    sigma: Arc<Image<f32>>,
+}
+
+impl std::fmt::Display for Epf0Stage {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "EPF stage 0 with sigma scale: {}, border_sad_mul: {}",
+            self.sigma_scale, self.border_sad_mul
+        )
+    }
+}
+
+impl Epf0Stage {
+    pub fn new(
+        sigma_scale: f32,
+        border_sad_mul: f32,
+        channel_scale: [f32; 3],
+        sigma: Arc<Image<f32>>,
+    ) -> Self {
+        Self {
+            sigma,
+            sigma_scale,
+            channel_scale,
+            border_sad_mul,
+        }
+    }
+}
+
+simd_function!(
+    epf0_process_row_chunk_dispatch,
+    d: D,
+    fn epf0_process_row_chunk_simd(
+    stage: &Epf0Stage,
+    pos: (usize, usize),
+    xsize: usize,
+    input_rows: &Channels<f32>,
+    output_rows: &mut ChannelsMut<f32>,
+) {
+    let (xpos, ypos) = pos;
+    assert_eq!(input_rows.len(), 3);
+    assert_eq!(output_rows.len(), 3);
+
+    let row_sigma = stage.sigma.row(ypos / BLOCK_DIM);
+
+    const { assert!(D::F32Vec::LEN <= 16) };
+
+    let sm = stage.sigma_scale * 1.65;
+    let bsm = sm * stage.border_sad_mul;
+    let sad_mul_storage = prepare_sad_mul_storage(xpos, ypos, sm, bsm);
+
+    for x in (0..xsize).step_by(D::F32Vec::LEN) {
+        let sigma = get_sigma(d, x + xpos, row_sigma);
+        let sad_mul = D::F32Vec::load(d, &sad_mul_storage[x % 8..]);
+
+        if D::F32Vec::splat(d, MIN_SIGMA).gt(sigma).all() {
+            for (input_c, output_c) in input_rows.iter().zip(output_rows.iter_mut()) {
+                D::F32Vec::load(d, &input_c[3][3 + x..]).store(&mut output_c[0][x..]);
+            }
+            continue;
+        }
+
+        // Compute SADs
+        let mut sads = [D::F32Vec::splat(d, 0.0); 12];
+        for (input_c, scale) in input_rows.iter().zip(stage.channel_scale) {
+            let scale = D::F32Vec::splat(d, scale);
+
+            let p30 = D::F32Vec::load(d, &input_c[0][3 + x..]);
+            let p21 = D::F32Vec::load(d, &input_c[1][2 + x..]);
+            let p31 = D::F32Vec::load(d, &input_c[1][3 + x..]);
+            let p41 = D::F32Vec::load(d, &input_c[1][4 + x..]);
+            let p12 = D::F32Vec::load(d, &input_c[2][1 + x..]);
+            let p22 = D::F32Vec::load(d, &input_c[2][2 + x..]);
+            let p32 = D::F32Vec::load(d, &input_c[2][3 + x..]);
+            let p42 = D::F32Vec::load(d, &input_c[2][4 + x..]);
+            let p52 = D::F32Vec::load(d, &input_c[2][5 + x..]);
+            let p03 = D::F32Vec::load(d, &input_c[3][x..]);
+            let p13 = D::F32Vec::load(d, &input_c[3][1 + x..]);
+            let p23 = D::F32Vec::load(d, &input_c[3][2 + x..]);
+            let p33 = D::F32Vec::load(d, &input_c[3][3 + x..]);
+            let p43 = D::F32Vec::load(d, &input_c[3][4 + x..]);
+            let p53 = D::F32Vec::load(d, &input_c[3][5 + x..]);
+            let p63 = D::F32Vec::load(d, &input_c[3][6 + x..]);
+            let p14 = D::F32Vec::load(d, &input_c[4][1 + x..]);
+            let p24 = D::F32Vec::load(d, &input_c[4][2 + x..]);
+            let p34 = D::F32Vec::load(d, &input_c[4][3 + x..]);
+            let p44 = D::F32Vec::load(d, &input_c[4][4 + x..]);
+            let p54 = D::F32Vec::load(d, &input_c[4][5 + x..]);
+            let p25 = D::F32Vec::load(d, &input_c[5][2 + x..]);
+            let p35 = D::F32Vec::load(d, &input_c[5][3 + x..]);
+            let p45 = D::F32Vec::load(d, &input_c[5][4 + x..]);
+            let p36 = D::F32Vec::load(d, &input_c[6][3 + x..]);
+            let d32_30 = (p32 - p30).abs();
+            let d32_21 = (p32 - p21).abs();
+            let d32_31 = (p32 - p31).abs();
+            let d32_41 = (p32 - p41).abs();
+            let d32_12 = (p32 - p12).abs();
+            let d32_22 = (p32 - p22).abs();
+            let d32_42 = (p32 - p42).abs();
+            let d32_52 = (p32 - p52).abs();
+            let d32_23 = (p32 - p23).abs();
+            let d32_34 = (p32 - p34).abs();
+            let d32_43 = (p32 - p43).abs();
+            let d32_33 = (p32 - p33).abs();
+            let d23_21 = (p23 - p21).abs();
+            let d23_12 = (p23 - p12).abs();
+            let d23_22 = (p23 - p22).abs();
+            let d23_03 = (p23 - p03).abs();
+            let d23_13 = (p23 - p13).abs();
+            let d23_33 = (p23 - p33).abs();
+            let d23_43 = (p23 - p43).abs();
+            let d23_14 = (p23 - p14).abs();
+            let d23_24 = (p23 - p24).abs();
+            let d23_34 = (p23 - p34).abs();
+            let d23_25 = (p23 - p25).abs();
+            let d33_31 = (p33 - p31).abs();
+            let d33_22 = (p33 - p22).abs();
+            let d33_42 = (p33 - p42).abs();
+            let d33_13 = (p33 - p13).abs();
+            let d33_43 = (p33 - p43).abs();
+            let d33_53 = (p33 - p53).abs();
+            let d33_24 = (p33 - p24).abs();
+            let d33_34 = (p33 - p34).abs();
+            let d33_44 = (p33 - p44).abs();
+            let d33_35 = (p33 - p35).abs();
+            let d43_41 = (p43 - p41).abs();
+            let d43_42 = (p43 - p42).abs();
+            let d43_52 = (p43 - p52).abs();
+            let d43_53 = (p43 - p53).abs();
+            let d43_63 = (p43 - p63).abs();
+            let d43_34 = (p43 - p34).abs();
+            let d43_44 = (p43 - p44).abs();
+            let d43_54 = (p43 - p54).abs();
+            let d43_45 = (p43 - p45).abs();
+            let d34_14 = (p34 - p14).abs();
+            let d34_24 = (p34 - p24).abs();
+            let d34_44 = (p34 - p44).abs();
+            let d34_54 = (p34 - p54).abs();
+            let d34_25 = (p34 - p25).abs();
+            let d34_35 = (p34 - p35).abs();
+            let d34_45 = (p34 - p45).abs();
+            let d34_36 = (p34 - p36).abs();
+            sads[0] = scale.mul_add(d32_30 + d23_21 + d33_31 + d43_41 + d32_34, sads[0]);
+            sads[1] = scale.mul_add(d32_21 + d23_12 + d33_22 + d32_43 + d23_34, sads[1]);
+            sads[2] = scale.mul_add(d32_31 + d23_22 + d32_33 + d43_42 + d33_34, sads[2]);
+            sads[3] = scale.mul_add(d32_41 + d32_23 + d33_42 + d43_52 + d43_34, sads[3]);
+            sads[4] = scale.mul_add(d32_12 + d23_03 + d33_13 + d23_43 + d34_14, sads[4]);
+            sads[5] = scale.mul_add(d32_22 + d23_13 + d23_33 + d33_43 + d34_24, sads[5]);
+            sads[6] = scale.mul_add(d32_42 + d23_33 + d33_43 + d43_53 + d34_44, sads[6]);
+            sads[7] = scale.mul_add(d32_52 + d23_43 + d33_53 + d43_63 + d34_54, sads[7]);
+            sads[8] = scale.mul_add(d32_23 + d23_14 + d33_24 + d43_34 + d34_25, sads[8]);
+            sads[9] = scale.mul_add(d32_33 + d23_24 + d33_34 + d43_44 + d34_35, sads[9]);
+            sads[10] = scale.mul_add(d32_43 + d23_34 + d33_44 + d43_54 + d34_45, sads[10]);
+            sads[11] = scale.mul_add(d32_34 + d23_25 + d33_35 + d43_45 + d34_36, sads[11]);
+        }
+        // Compute output based on SADs
+        let inv_sigma = sigma * sad_mul;
+        let mut w = D::F32Vec::splat(d, 1.0);
+        for sad in sads.iter_mut() {
+            *sad = sad
+                .mul_add(inv_sigma, D::F32Vec::splat(d, 1.0))
+                .max(D::F32Vec::splat(d, 0.0));
+            w += *sad;
+        }
+        let inv_w = D::F32Vec::splat(d, 1.0) / w;
+        for (input_c, output_c) in input_rows.iter().zip(output_rows.iter_mut()) {
+            let mut out = D::F32Vec::load(d, &input_c[3][3 + x..]);
+            for (row_idx, col_idx, sad_idx) in [
+                (5, 3+x, 11),
+                (4, 4+x, 10),
+                (4, 3+x, 9),
+                (4, 2+x, 8),
+                (3, 5+x, 7),
+                (3, 4+x, 6),
+                (3, 2+x, 5),
+                (3, 1+x, 4),
+                (2, 4+x, 3),
+                (2, 3+x, 2),
+                (2, 2+x, 1),
+                (1, 3+x, 0),
+            ] {
+                out = D::F32Vec::load(d, &input_c[row_idx][col_idx..]).mul_add(sads[sad_idx], out);
+            }
+            (out * inv_w).store(&mut output_c[0][x..]);
+        }
+    }
+});
+
+impl RenderPipelineInOutStage for Epf0Stage {
+    type InputT = f32;
+    type OutputT = f32;
+    const SHIFT: (u8, u8) = (0, 0);
+    const BORDER: (u8, u8) = (3, 3);
+
+    fn uses_channel(&self, c: usize) -> bool {
+        c < 3
+    }
+
+    fn process_row_chunk(
+        &self,
+        (xpos, ypos): (usize, usize),
+        xsize: usize,
+        input_rows: &Channels<f32>,
+        output_rows: &mut ChannelsMut<f32>,
+        _state: Option<&mut dyn std::any::Any>,
+    ) {
+        epf0_process_row_chunk_dispatch(self, (xpos, ypos), xsize, input_rows, output_rows);
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/epf/epf1.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/epf/epf1.rs
new file mode 100644
index 0000000..17ff391
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/epf/epf1.rs
@@ -0,0 +1,170 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::sync::Arc;
+
+use crate::{
+    BLOCK_DIM, MIN_SIGMA,
+    image::Image,
+    render::{
+        Channels, ChannelsMut, RenderPipelineInOutStage,
+        stages::epf::common::{get_sigma, prepare_sad_mul_storage},
+    },
+};
+
+use jxl_simd::{F32SimdVec, SimdMask, simd_function};
+
+/// 3x3 plus-shaped kernel with 5 SADs per pixel (3x3 plus-shaped). So this makes this filter a 5x5 filter.
+pub struct Epf1Stage {
+    /// Multiplier for sigma in pass 1
+    sigma_scale: f32,
+    /// (inverse) multiplier for sigma on borders
+    border_sad_mul: f32,
+    channel_scale: [f32; 3],
+    sigma: Arc<Image<f32>>,
+}
+
+impl std::fmt::Display for Epf1Stage {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "EPF stage 1 with sigma scale: {}, border_sad_mul: {}",
+            self.sigma_scale, self.border_sad_mul
+        )
+    }
+}
+
+impl Epf1Stage {
+    pub fn new(
+        sigma_scale: f32,
+        border_sad_mul: f32,
+        channel_scale: [f32; 3],
+        sigma: Arc<Image<f32>>,
+    ) -> Self {
+        Self {
+            sigma,
+            sigma_scale,
+            channel_scale,
+            border_sad_mul,
+        }
+    }
+}
+
+simd_function!(
+epf1_process_row_chunk_dispatch,
+d: D,
+fn epf1_process_row_chunk(
+    stage: &Epf1Stage,
+    pos: (usize, usize),
+    xsize: usize,
+    input_rows: &Channels<f32>,
+    output_rows: &mut ChannelsMut<f32>,
+) {
+    let (xpos, ypos) = pos;
+    assert_eq!(input_rows.len(), 3);
+    assert_eq!(output_rows.len(), 3);
+
+    let row_sigma = stage.sigma.row(ypos / BLOCK_DIM);
+
+    let sm = stage.sigma_scale * 1.65;
+    let bsm = sm * stage.border_sad_mul;
+    let sad_mul_storage = prepare_sad_mul_storage(xpos, ypos, sm, bsm);
+
+    for x in (0..xsize).step_by(D::F32Vec::LEN) {
+        let sigma = get_sigma(d, x + xpos, row_sigma);
+        let sad_mul = D::F32Vec::load(d, &sad_mul_storage[x % 8..]);
+
+        if D::F32Vec::splat(d, MIN_SIGMA).gt(sigma).all() {
+            for (input_c, output_c) in input_rows.iter().zip(output_rows.iter_mut()) {
+                D::F32Vec::load(d, &input_c[2][2 + x..]).store(&mut output_c[0][x..]);
+            }
+            continue;
+        }
+
+        // Compute SADs
+        let mut sads = [D::F32Vec::splat(d, 0.0); 4];
+        for (input_c, scale) in input_rows.iter().zip(stage.channel_scale) {
+            let scale = D::F32Vec::splat(d, scale);
+            let p20 = D::F32Vec::load(d, &input_c[0][2 + x..]);
+            let p11 = D::F32Vec::load(d, &input_c[1][1 + x..]);
+            let p21 = D::F32Vec::load(d, &input_c[1][2 + x..]);
+            let p31 = D::F32Vec::load(d, &input_c[1][3 + x..]);
+            let p02 = D::F32Vec::load(d, &input_c[2][x..]);
+            let p12 = D::F32Vec::load(d, &input_c[2][1 + x..]);
+            let p22 = D::F32Vec::load(d, &input_c[2][2 + x..]);
+            let p32 = D::F32Vec::load(d, &input_c[2][3 + x..]);
+            let p42 = D::F32Vec::load(d, &input_c[2][4 + x..]);
+            let p13 = D::F32Vec::load(d, &input_c[3][1 + x..]);
+            let p23 = D::F32Vec::load(d, &input_c[3][2 + x..]);
+            let p33 = D::F32Vec::load(d, &input_c[3][3 + x..]);
+            let p24 = D::F32Vec::load(d, &input_c[4][2 + x..]);
+            let d20_21 = (p20 - p21).abs();
+            let d11_21 = (p11 - p21).abs();
+            let d22_21 = (p22 - p21).abs();
+            let d31_21 = (p31 - p21).abs();
+            let d02_12 = (p02 - p12).abs();
+            let d11_12 = (p11 - p12).abs();
+            let d12_22 = (p22 - p12).abs();
+            let d31_32 = (p31 - p32).abs();
+            let d22_32 = (p22 - p32).abs();
+            let d42_32 = (p42 - p32).abs();
+            let d13_12 = (p13 - p12).abs();
+            let d22_23 = (p22 - p23).abs();
+            let d13_23 = (p13 - p23).abs();
+            let d33_23 = (p33 - p23).abs();
+            let d33_32 = (p33 - p32).abs();
+            let d24_23 = (p24 - p23).abs();
+            sads[0] = (d20_21 + d11_12 + d22_21 + d31_32 + d22_23).mul_add(scale, sads[0]);
+            sads[1] = (d11_21 + d02_12 + d12_22 + d22_32 + d13_23).mul_add(scale, sads[1]);
+            sads[2] = (d31_21 + d12_22 + d22_32 + d42_32 + d33_23).mul_add(scale, sads[2]);
+            sads[3] = (d22_21 + d13_12 + d22_23 + d33_32 + d24_23).mul_add(scale, sads[3]);
+        }
+
+        // Compute output based on SADs
+        let inv_sigma = sigma * sad_mul;
+        let mut w = D::F32Vec::splat(d, 1.0);
+        for sad in sads.iter_mut() {
+            *sad = sad
+                .mul_add(inv_sigma, D::F32Vec::splat(d, 1.0))
+                .max(D::F32Vec::splat(d, 0.0));
+            w += *sad;
+        }
+        let inv_w = D::F32Vec::splat(d, 1.0) / w;
+        for (input_c, output_c) in input_rows.iter().zip(output_rows.iter_mut()) {
+            let mut out = D::F32Vec::load(d, &input_c[2][2 + x..]);
+            for (row_idx, col_idx, sad_idx) in [
+                (3, 2+x, 3),
+                (2, 3+x, 2),
+                (2, 1+x, 1),
+                (1, 2+x, 0),
+            ] {
+                out = D::F32Vec::load(d, &input_c[row_idx][col_idx..]).mul_add(sads[sad_idx], out);
+            }
+            (out * inv_w).store(&mut output_c[0][x..]);
+        }
+    }
+});
+
+impl RenderPipelineInOutStage for Epf1Stage {
+    type InputT = f32;
+    type OutputT = f32;
+    const SHIFT: (u8, u8) = (0, 0);
+    const BORDER: (u8, u8) = (2, 2);
+
+    fn uses_channel(&self, c: usize) -> bool {
+        c < 3
+    }
+
+    fn process_row_chunk(
+        &self,
+        (xpos, ypos): (usize, usize),
+        xsize: usize,
+        input_rows: &Channels<f32>,
+        output_rows: &mut ChannelsMut<f32>,
+        _state: Option<&mut dyn std::any::Any>,
+    ) {
+        epf1_process_row_chunk_dispatch(self, (xpos, ypos), xsize, input_rows, output_rows);
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/epf/epf2.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/epf/epf2.rs
new file mode 100644
index 0000000..6691b56
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/epf/epf2.rs
@@ -0,0 +1,150 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::sync::Arc;
+
+use crate::{
+    BLOCK_DIM, MIN_SIGMA,
+    image::Image,
+    render::{
+        Channels, ChannelsMut, RenderPipelineInOutStage,
+        stages::epf::common::{get_sigma, prepare_sad_mul_storage},
+    },
+};
+
+use jxl_simd::{F32SimdVec, SimdMask, simd_function};
+
+/// 3x3 plus-shaped kernel with 1 SAD per pixel. So this makes this filter a 3x3 filter.
+pub struct Epf2Stage {
+    /// Multiplier for sigma in pass 2
+    sigma_scale: f32,
+    /// (inverse) multiplier for sigma on borders
+    border_sad_mul: f32,
+    channel_scale: [f32; 3],
+    sigma: Arc<Image<f32>>,
+}
+
+impl std::fmt::Display for Epf2Stage {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "EPF stage 2 with sigma scale: {}, border_sad_mul: {}",
+            self.sigma_scale, self.border_sad_mul
+        )
+    }
+}
+
+impl Epf2Stage {
+    pub fn new(
+        sigma_scale: f32,
+        border_sad_mul: f32,
+        channel_scale: [f32; 3],
+        sigma: Arc<Image<f32>>,
+    ) -> Self {
+        Self {
+            sigma,
+            sigma_scale,
+            channel_scale,
+            border_sad_mul,
+        }
+    }
+}
+
+simd_function!(
+epf2_process_row_chunk_dispatch,
+d: D,
+fn epf2_process_row_chunk(
+    stage: &Epf2Stage,
+    pos: (usize, usize),
+    xsize: usize,
+    input_rows: &Channels<f32>,
+    output_rows: &mut ChannelsMut<f32>,
+) {
+    let (xpos, ypos) = pos;
+    assert_eq!(input_rows.len(), 3, "Expected 3 channels, got {}", input_rows.len());
+    let (input_x, input_y, input_b) = (&input_rows[0], &input_rows[1], &input_rows[2]);
+    let (output_x, output_y, output_b) = output_rows.split_first_3_mut();
+
+    let row_sigma = stage.sigma.row(ypos / BLOCK_DIM);
+
+    const { assert!(D::F32Vec::LEN <= 16) };
+
+    let sm = stage.sigma_scale * 1.65;
+    let bsm = sm * stage.border_sad_mul;
+    let sad_mul_storage = prepare_sad_mul_storage(xpos, ypos, sm, bsm);
+
+    for x in (0..xsize).step_by(D::F32Vec::LEN) {
+        let sigma = get_sigma(d, x + xpos, row_sigma);
+        let sad_mul = D::F32Vec::load(d, &sad_mul_storage[x % 8..]);
+
+        if D::F32Vec::splat(d, MIN_SIGMA).gt(sigma).all() {
+            D::F32Vec::load(d, &input_x[1][1 + x..]).store(&mut output_x[0][x..]);
+            D::F32Vec::load(d, &input_y[1][1 + x..]).store(&mut output_y[0][x..]);
+            D::F32Vec::load(d, &input_b[1][1 + x..]).store(&mut output_b[0][x..]);
+            continue;
+        }
+
+        let inv_sigma = sigma * sad_mul;
+
+        let x_cc = D::F32Vec::load(d, &input_x[1][1 + x..]);
+        let y_cc = D::F32Vec::load(d, &input_y[1][1 + x..]);
+        let b_cc = D::F32Vec::load(d, &input_b[1][1 + x..]);
+
+        let mut w_acc = D::F32Vec::splat(d, 1.0);
+        let mut x_acc = x_cc;
+        let mut y_acc = y_cc;
+        let mut b_acc = b_cc;
+
+        for (y_off, x_off) in [(0, 1), (1, 0), (1, 2), (2, 1)] {
+            let (cx, cy, cb) = (
+                D::F32Vec::load(d, &input_x[y_off as usize][x_off + x..]),
+                D::F32Vec::load(d, &input_y[y_off as usize][x_off + x..]),
+                D::F32Vec::load(d, &input_b[y_off as usize][x_off + x..]),
+            );
+            let sad = (cx - x_cc).abs().mul_add(
+                D::F32Vec::splat(d, stage.channel_scale[0]),
+                (cy - y_cc).abs().mul_add(
+                    D::F32Vec::splat(d, stage.channel_scale[1]),
+                    (cb - b_cc).abs() * D::F32Vec::splat(d, stage.channel_scale[2]),
+                ),
+            );
+            let weight = sad
+                .mul_add(inv_sigma, D::F32Vec::splat(d, 1.0))
+                .max(D::F32Vec::splat(d, 0.0));
+            w_acc += weight;
+            x_acc = weight.mul_add(cx, x_acc);
+            y_acc = weight.mul_add(cy, y_acc);
+            b_acc = weight.mul_add(cb, b_acc);
+        }
+
+        let inv_w = D::F32Vec::splat(d, 1.0) / w_acc;
+
+        (x_acc * inv_w).store(&mut output_x[0][x..]);
+        (y_acc * inv_w).store(&mut output_y[0][x..]);
+        (b_acc * inv_w).store(&mut output_b[0][x..]);
+    }
+});
+
+impl RenderPipelineInOutStage for Epf2Stage {
+    type InputT = f32;
+    type OutputT = f32;
+    const SHIFT: (u8, u8) = (0, 0);
+    const BORDER: (u8, u8) = (1, 1);
+
+    fn uses_channel(&self, c: usize) -> bool {
+        c < 3
+    }
+
+    fn process_row_chunk(
+        &self,
+        (xpos, ypos): (usize, usize),
+        xsize: usize,
+        input_rows: &Channels<f32>,
+        output_rows: &mut ChannelsMut<f32>,
+        _state: Option<&mut dyn std::any::Any>,
+    ) {
+        epf2_process_row_chunk_dispatch(self, (xpos, ypos), xsize, input_rows, output_rows);
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/epf/mod.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/epf/mod.rs
new file mode 100644
index 0000000..e927f48
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/epf/mod.rs
@@ -0,0 +1,16 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+mod common;
+mod epf0;
+mod epf1;
+mod epf2;
+
+pub use epf0::Epf0Stage;
+pub use epf1::Epf1Stage;
+pub use epf2::Epf2Stage;
+
+#[cfg(test)]
+mod test;
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/epf/test.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/epf/test.rs
new file mode 100644
index 0000000..a74ecb3
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/epf/test.rs
@@ -0,0 +1,45 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::sync::Arc;
+
+use rand::SeedableRng;
+use test_log::test;
+
+use super::*;
+use crate::{error::Result, image::Image};
+
+#[test]
+fn epf0_consistency() -> Result<()> {
+    let mut rng = rand_xorshift::XorShiftRng::seed_from_u64(0);
+    let sigma = Arc::new(Image::new_random((128, 128), &mut rng).unwrap());
+    crate::render::test::test_stage_consistency(
+        || Epf0Stage::new(0.9, 2.3 / 3.0, [40.0, 5.0, 3.5], sigma.clone()),
+        (512, 512),
+        4,
+    )
+}
+
+#[test]
+fn epf1_consistency() -> Result<()> {
+    let mut rng = rand_xorshift::XorShiftRng::seed_from_u64(0);
+    let sigma = Arc::new(Image::new_random((128, 128), &mut rng).unwrap());
+    crate::render::test::test_stage_consistency(
+        || Epf1Stage::new(1.0, 2.3 / 3.0, [40.0, 5.0, 3.5], sigma.clone()),
+        (512, 512),
+        4,
+    )
+}
+
+#[test]
+fn epf2_consistency() -> Result<()> {
+    let mut rng = rand_xorshift::XorShiftRng::seed_from_u64(0);
+    let sigma = Arc::new(Image::new_random((128, 128), &mut rng).unwrap());
+    crate::render::test::test_stage_consistency(
+        || Epf2Stage::new(6.5, 2.3 / 3.0, [40.0, 5.0, 3.5], sigma.clone()),
+        (512, 512),
+        4,
+    )
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/extend.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/extend.rs
new file mode 100644
index 0000000..5d74179
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/extend.rs
@@ -0,0 +1,114 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::sync::Arc;
+
+use crate::{
+    error::Result,
+    frame::ReferenceFrame,
+    headers::{FileHeader, extra_channels::ExtraChannelInfo, frame_header::*},
+};
+
+/// Does not directly modify the current image pixels, but extends the current image with
+/// additional data.
+///
+/// `uses_channel` must always return true, and stages of this type should override
+/// `new_size` and `original_data_origin`.
+/// `process_row_chunk` will be called with the *new* image coordinates, and will only be called
+/// on row chunks outside of the original image data.
+/// After stages of this type, no stage can have a non-0 SHIFT_X, SHIFT_Y, BORDER_X or BORDER_Y.
+/// There can be at most one extend stage per image.
+pub struct ExtendToImageDimensionsStage {
+    pub frame_origin: (isize, isize),
+    pub image_size: (usize, usize),
+    pub blending_info: BlendingInfo,
+    pub ec_blending_info: Vec<BlendingInfo>,
+    pub extra_channels: Vec<ExtraChannelInfo>,
+    pub reference_frames: Arc<[Option<ReferenceFrame>; 4]>,
+    pub zeros: Vec<f32>,
+}
+
+impl ExtendToImageDimensionsStage {
+    // TODO(veluca): should this return a Result?
+    pub fn new(
+        frame_header: &FrameHeader,
+        file_header: &FileHeader,
+        reference_frames: Arc<[Option<ReferenceFrame>; 4]>,
+    ) -> Result<ExtendToImageDimensionsStage> {
+        Ok(ExtendToImageDimensionsStage {
+            frame_origin: (frame_header.x0 as isize, frame_header.y0 as isize),
+            image_size: (
+                file_header.size.xsize() as usize,
+                file_header.size.ysize() as usize,
+            ),
+            blending_info: frame_header.blending_info.clone(),
+            ec_blending_info: frame_header.ec_blending_info.clone(),
+            extra_channels: file_header.image_metadata.extra_channel_info.clone(),
+            reference_frames,
+            zeros: vec![0f32; file_header.size.xsize() as usize],
+        })
+    }
+}
+
+impl std::fmt::Display for ExtendToImageDimensionsStage {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "extend-to-image-dims")
+    }
+}
+
+impl ExtendToImageDimensionsStage {
+    pub(in crate::render) fn process_row_chunk(
+        &self,
+        position: (usize, usize),
+        xsize: usize,
+        c: usize,
+        row: &mut [f32],
+    ) {
+        let x0 = position.0;
+        let x1 = x0 + xsize;
+        let y0 = position.1;
+        let source = if c < 3 {
+            self.blending_info.source as usize
+        } else {
+            self.ec_blending_info[c - 3].source as usize
+        };
+        let bg = if let Some(bg) = self.reference_frames[source].as_ref() {
+            bg.frame[c].row(y0)
+        } else {
+            self.zeros.as_slice()
+        };
+        row[0..xsize].copy_from_slice(&bg[x0..x1]);
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use std::sync::Arc;
+
+    use test_log::test;
+
+    use super::*;
+    use crate::error::Result;
+    use crate::util::test::read_headers_and_toc;
+
+    #[test]
+    fn extend_consistency() -> Result<()> {
+        let (file_header, frame_header, _) =
+            read_headers_and_toc(include_bytes!("../../../resources/test/basic.jxl")).unwrap();
+        let reference_frames = Arc::new([None, None, None, None]);
+        crate::render::test::test_stage_consistency(
+            || {
+                ExtendToImageDimensionsStage::new(
+                    &frame_header,
+                    &file_header,
+                    reference_frames.clone(),
+                )
+                .unwrap()
+            },
+            (500, 500),
+            4,
+        )
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/from_linear.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/from_linear.rs
new file mode 100644
index 0000000..98c8bd01d
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/from_linear.rs
@@ -0,0 +1,262 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::color::tf;
+use crate::headers::color_encoding::CustomTransferFunction;
+use crate::render::RenderPipelineInPlaceStage;
+use jxl_simd::{F32SimdVec, simd_function};
+
+/// Apply transfer function to display-referred linear color samples.
+#[derive(Debug)]
+pub struct FromLinearStage {
+    first_channel: usize,
+    tf: TransferFunction,
+}
+
+impl FromLinearStage {
+    pub fn new(first_channel: usize, tf: TransferFunction) -> Self {
+        Self { first_channel, tf }
+    }
+
+    pub fn sdr(first_channel: usize, tf: CustomTransferFunction) -> Self {
+        let tf = TransferFunction::try_from(tf).expect("transfer function is not an SDR one");
+        Self::new(first_channel, tf)
+    }
+
+    pub fn pq(first_channel: usize, intensity_target: f32) -> Self {
+        let tf = TransferFunction::Pq { intensity_target };
+        Self::new(first_channel, tf)
+    }
+
+    pub fn hlg(first_channel: usize, intensity_target: f32, luminance_rgb: [f32; 3]) -> Self {
+        let tf = TransferFunction::Hlg {
+            intensity_target,
+            luminance_rgb,
+        };
+        Self::new(first_channel, tf)
+    }
+}
+
+impl std::fmt::Display for FromLinearStage {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let channel = self.first_channel;
+        write!(
+            f,
+            "Apply transfer function {:?} to channel [{},{},{}]",
+            self.tf,
+            channel,
+            channel + 1,
+            channel + 2
+        )
+    }
+}
+
+simd_function!(
+from_linear_process_dispatch,
+d: D,
+fn from_linear_process(tf: &TransferFunction, xsize: usize, row: &mut [&mut [f32]]) {
+    let [row_r, row_g, row_b] = row else {
+        panic!(
+            "incorrect number of channels; expected 3, found {}",
+            row.len()
+        );
+    };
+
+    match *tf {
+        TransferFunction::Bt709 => {
+            for row in row {
+                tf::linear_to_bt709_simd(d, &mut row[..xsize.next_multiple_of(D::F32Vec::LEN)]);
+            }
+        }
+        TransferFunction::Srgb => {
+            for row in row {
+                tf::linear_to_srgb_simd(d, &mut row[..xsize.next_multiple_of(D::F32Vec::LEN)]);
+            }
+        }
+        TransferFunction::Pq { intensity_target } => {
+            for row in row {
+                tf::linear_to_pq(intensity_target, &mut row[..xsize]);
+            }
+        }
+        TransferFunction::Hlg {
+            intensity_target,
+            luminance_rgb,
+        } => {
+            let rows = [
+                &mut row_r[..xsize],
+                &mut row_g[..xsize],
+                &mut row_b[..xsize],
+            ];
+            tf::hlg_display_to_scene(intensity_target, luminance_rgb, rows);
+
+            tf::scene_to_hlg(&mut row_r[..xsize]);
+            tf::scene_to_hlg(&mut row_g[..xsize]);
+            tf::scene_to_hlg(&mut row_b[..xsize]);
+        }
+        TransferFunction::Gamma(g) => {
+            for row in row {
+                for values in row[..xsize.next_multiple_of(D::F32Vec::LEN)]
+                    .chunks_exact_mut(D::F32Vec::LEN)
+                {
+                    let v = D::F32Vec::load(d, values);
+                    crate::util::fast_powf_simd(d, v.abs(), D::F32Vec::splat(d, g))
+                        .copysign(v)
+                        .store(values);
+                }
+            }
+        }
+    }
+});
+
+impl RenderPipelineInPlaceStage for FromLinearStage {
+    type Type = f32;
+
+    fn uses_channel(&self, c: usize) -> bool {
+        (self.first_channel..self.first_channel + 3).contains(&c)
+    }
+
+    fn process_row_chunk(
+        &self,
+        _position: (usize, usize),
+        xsize: usize,
+        row: &mut [&mut [f32]],
+        _state: Option<&mut dyn std::any::Any>,
+    ) {
+        from_linear_process_dispatch(&self.tf, xsize, row)
+    }
+}
+
+#[derive(Clone, Debug)]
+pub enum TransferFunction {
+    Bt709,
+    Srgb,
+    Pq {
+        intensity_target: f32,
+    },
+    Hlg {
+        intensity_target: f32,
+        luminance_rgb: [f32; 3],
+    },
+    /// Inverse gamma in range `(0, 1]`
+    Gamma(f32),
+}
+
+impl TryFrom<CustomTransferFunction> for TransferFunction {
+    type Error = ();
+
+    fn try_from(ctf: CustomTransferFunction) -> Result<Self, ()> {
+        use crate::headers::color_encoding::TransferFunction;
+
+        if ctf.have_gamma {
+            Ok(Self::Gamma(ctf.gamma()))
+        } else {
+            match ctf.transfer_function {
+                TransferFunction::BT709 => Ok(Self::Bt709),
+                TransferFunction::Unknown => Err(()),
+                TransferFunction::Linear => Ok(Self::Gamma(1.0)),
+                TransferFunction::SRGB => Ok(Self::Srgb),
+                TransferFunction::PQ => Err(()),
+                TransferFunction::DCI => Ok(Self::Gamma(2.6_f32.recip())),
+                TransferFunction::HLG => Err(()),
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use test_log::test;
+
+    use super::*;
+    use crate::error::Result;
+    use crate::image::Image;
+    use crate::render::test::make_and_run_simple_pipeline;
+    use crate::util::test::assert_all_almost_abs_eq;
+
+    const LUMINANCE_BT2020: [f32; 3] = [0.2627, 0.678, 0.0593];
+
+    #[test]
+    fn consistency_hlg() -> Result<()> {
+        crate::render::test::test_stage_consistency(
+            || FromLinearStage::hlg(0, 1000f32, LUMINANCE_BT2020),
+            (500, 500),
+            3,
+        )
+    }
+
+    #[test]
+    fn consistency_pq() -> Result<()> {
+        crate::render::test::test_stage_consistency(
+            || FromLinearStage::pq(0, 10000f32),
+            (500, 500),
+            3,
+        )
+    }
+
+    #[test]
+    fn consistency_srgb() -> Result<()> {
+        crate::render::test::test_stage_consistency(
+            || FromLinearStage::new(0, TransferFunction::Srgb),
+            (500, 500),
+            3,
+        )
+    }
+
+    #[test]
+    fn consistency_bt709() -> Result<()> {
+        crate::render::test::test_stage_consistency(
+            || FromLinearStage::new(0, TransferFunction::Bt709),
+            (500, 500),
+            3,
+        )
+    }
+
+    #[test]
+    fn consistency_gamma22() -> Result<()> {
+        crate::render::test::test_stage_consistency(
+            || FromLinearStage::new(0, TransferFunction::Gamma(0.4545455)),
+            (500, 500),
+            3,
+        )
+    }
+
+    #[test]
+    fn sdr_white_hlg() -> Result<()> {
+        let intensity_target = 1000f32;
+        let input_r = Image::new_with_value((1, 1), 0.203)?;
+        let input_g = Image::new_with_value((1, 1), 0.203)?;
+        let input_b = Image::new_with_value((1, 1), 0.203)?;
+
+        // 75% HLG
+        let stage = FromLinearStage::hlg(0, intensity_target, LUMINANCE_BT2020);
+        let output =
+            make_and_run_simple_pipeline(stage, &[input_r, input_g, input_b], (1, 1), 0, 256)?;
+
+        assert_all_almost_abs_eq(output[0].row(0), &[0.75], 1e-3);
+        assert_all_almost_abs_eq(output[1].row(0), &[0.75], 1e-3);
+        assert_all_almost_abs_eq(output[2].row(0), &[0.75], 1e-3);
+
+        Ok(())
+    }
+
+    #[test]
+    fn sdr_white_pq() -> Result<()> {
+        let intensity_target = 1000f32;
+        let input_r = Image::new_with_value((1, 1), 0.203)?;
+        let input_g = Image::new_with_value((1, 1), 0.203)?;
+        let input_b = Image::new_with_value((1, 1), 0.203)?;
+
+        // 58% PQ
+        let stage = FromLinearStage::pq(0, intensity_target);
+        let output =
+            make_and_run_simple_pipeline(stage, &[input_r, input_g, input_b], (1, 1), 0, 256)?;
+
+        assert_all_almost_abs_eq(output[0].row(0), &[0.58], 1e-3);
+        assert_all_almost_abs_eq(output[1].row(0), &[0.58], 1e-3);
+        assert_all_almost_abs_eq(output[2].row(0), &[0.58], 1e-3);
+
+        Ok(())
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/gaborish.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/gaborish.rs
new file mode 100644
index 0000000..eacd1059
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/gaborish.rs
@@ -0,0 +1,145 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::render::{Channels, ChannelsMut, RenderPipelineInOutStage};
+use jxl_simd::{F32SimdVec, simd_function};
+
+/// Apply Gabor-like filter to a channel.
+#[derive(Debug)]
+pub struct GaborishStage {
+    channel: usize,
+    weight0: f32,
+    weight1: f32,
+    weight2: f32,
+}
+
+impl GaborishStage {
+    pub fn new(channel: usize, weight1: f32, weight2: f32) -> Self {
+        let weight_total = 1.0 + weight1 * 4.0 + weight2 * 4.0;
+        Self {
+            channel,
+            weight0: 1.0 / weight_total,
+            weight1: weight1 / weight_total,
+            weight2: weight2 / weight_total,
+        }
+    }
+}
+
+impl std::fmt::Display for GaborishStage {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "Gaborish filter for channel {}", self.channel)
+    }
+}
+
+simd_function!(
+    gaborish_process_dispatch,
+    d: D,
+    fn gaborish_process(
+        stage: &GaborishStage,
+        xsize: usize,
+        input_rows: &Channels<f32>,
+        output_rows: &mut ChannelsMut<f32>,
+    ) {
+        let row_out = &mut output_rows[0][0];
+
+        let w0 = D::F32Vec::splat(d, stage.weight0);
+        let w1 = D::F32Vec::splat(d, stage.weight1);
+        let w2 = D::F32Vec::splat(d, stage.weight2);
+
+        let [row_top, row_center, row_bottom] = input_rows[0] else {
+            unreachable!();
+        };
+
+        // These asserts help the compiler skip checks in the loop.
+        assert_eq!(row_top.len(), row_center.len());
+        assert_eq!(row_top.len(), row_bottom.len());
+
+        let num_vec = xsize.div_ceil(D::F32Vec::LEN);
+
+        let len = D::F32Vec::LEN;
+        let window_len = len + 2;
+
+        for (((top, center), bottom), out) in row_top
+            .windows(window_len)
+            .step_by(len)
+            .zip(row_center.windows(window_len).step_by(len))
+            .zip(row_bottom.windows(window_len).step_by(len))
+            .zip(row_out.chunks_exact_mut(D::F32Vec::LEN))
+            .take(num_vec)
+        {
+            let p00 = D::F32Vec::load(d, top);
+            let p01 = D::F32Vec::load(d, &top[1..]);
+            let p02 = D::F32Vec::load(d, &top[2..]);
+            let p10 = D::F32Vec::load(d, center);
+            let p11 = D::F32Vec::load(d, &center[1..]);
+            let p12 = D::F32Vec::load(d, &center[2..]);
+            let p20 = D::F32Vec::load(d, bottom);
+            let p21 = D::F32Vec::load(d, &bottom[1..]);
+            let p22 = D::F32Vec::load(d, &bottom[2..]);
+
+            let sum = p11 * w0;
+            let sum = w1.mul_add(p01 + p10 + p21 + p12, sum);
+            let sum = w2.mul_add(p00 + p02 + p20 + p22, sum);
+            sum.store(out);
+        }
+    }
+);
+
+impl RenderPipelineInOutStage for GaborishStage {
+    type InputT = f32;
+    type OutputT = f32;
+    const SHIFT: (u8, u8) = (0, 0);
+    const BORDER: (u8, u8) = (1, 1);
+
+    fn uses_channel(&self, c: usize) -> bool {
+        c == self.channel
+    }
+
+    fn process_row_chunk(
+        &self,
+        _position: (usize, usize),
+        xsize: usize,
+        input_rows: &Channels<f32>,
+        output_rows: &mut ChannelsMut<f32>,
+        _state: Option<&mut dyn std::any::Any>,
+    ) {
+        gaborish_process_dispatch(self, xsize, input_rows, output_rows);
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use test_log::test;
+
+    use super::*;
+    use crate::error::Result;
+    use crate::image::Image;
+    use crate::render::test::make_and_run_simple_pipeline;
+    use crate::util::test::assert_all_almost_abs_eq;
+
+    #[test]
+    fn consistency() -> Result<()> {
+        crate::render::test::test_stage_consistency(
+            || GaborishStage::new(0, 0.115169525, 0.061248592),
+            (500, 500),
+            1,
+        )
+    }
+
+    #[test]
+    fn checkerboard() -> Result<()> {
+        let mut image = Image::new((2, 2))?;
+        image.row_mut(0).copy_from_slice(&[0.0, 1.0]);
+        image.row_mut(1).copy_from_slice(&[1.0, 0.0]);
+
+        let stage = GaborishStage::new(0, 0.115169525, 0.061248592);
+        let output = make_and_run_simple_pipeline(stage, &[image], (2, 2), 0, 256)?;
+
+        assert_all_almost_abs_eq(output[0].row(0), &[0.20686048, 0.7931395], 1e-6);
+        assert_all_almost_abs_eq(output[0].row(1), &[0.7931395, 0.20686048], 1e-6);
+
+        Ok(())
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/mod.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/mod.rs
new file mode 100644
index 0000000..b5ba806
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/mod.rs
@@ -0,0 +1,39 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+mod blending;
+mod chroma_upsample;
+mod convert;
+mod epf;
+mod extend;
+mod from_linear;
+mod gaborish;
+mod noise;
+mod patches;
+mod splines;
+mod spot;
+mod to_linear;
+mod upsample;
+mod xyb;
+mod ycbcr;
+
+#[cfg(test)]
+mod nearest_neighbor;
+
+pub use blending::*;
+pub use chroma_upsample::*;
+pub use convert::*;
+pub use epf::*;
+pub use extend::*;
+pub use from_linear::*;
+pub use gaborish::*;
+pub use noise::*;
+pub use patches::*;
+pub use splines::*;
+pub use spot::*;
+pub use to_linear::{ToLinearStage, TransferFunction as ToLinearTransferFunction};
+pub use upsample::*;
+pub use xyb::*;
+pub use ycbcr::*;
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/nearest_neighbor.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/nearest_neighbor.rs
new file mode 100644
index 0000000..8e48b1e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/nearest_neighbor.rs
@@ -0,0 +1,97 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::render::{Channels, ChannelsMut, RenderPipelineInOutStage};
+pub struct NearestNeighbourUpsample {
+    channel: usize,
+}
+
+impl NearestNeighbourUpsample {
+    pub fn new(channel: usize) -> NearestNeighbourUpsample {
+        NearestNeighbourUpsample { channel }
+    }
+}
+
+impl std::fmt::Display for NearestNeighbourUpsample {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "2x2 nearest neighbour upsample of channel {}",
+            self.channel
+        )
+    }
+}
+
+impl RenderPipelineInOutStage for NearestNeighbourUpsample {
+    type InputT = f32;
+    type OutputT = f32;
+    const SHIFT: (u8, u8) = (1, 1);
+    const BORDER: (u8, u8) = (0, 0);
+
+    fn uses_channel(&self, c: usize) -> bool {
+        c == self.channel
+    }
+
+    fn process_row_chunk(
+        &self,
+        _position: (usize, usize),
+        xsize: usize,
+        input_rows: &Channels<f32>,
+        output_rows: &mut ChannelsMut<f32>,
+        _state: Option<&mut dyn std::any::Any>,
+    ) {
+        let input = &input_rows[0];
+        let output = &mut output_rows[0];
+        for i in 0..xsize {
+            output[0][i * 2] = input[0][i];
+            output[0][i * 2 + 1] = input[0][i];
+            output[1][i * 2] = input[0][i];
+            output[1][i * 2 + 1] = input[0][i];
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use crate::{error::Result, image::Image, render::test::make_and_run_simple_pipeline};
+    use rand::SeedableRng;
+    use test_log::test;
+
+    #[test]
+    fn nn_consistency() -> Result<()> {
+        crate::render::test::test_stage_consistency(
+            || NearestNeighbourUpsample::new(0),
+            (500, 500),
+            1,
+        )
+    }
+
+    #[test]
+    fn test_nn() -> Result<()> {
+        let image_size = (500, 400);
+        let input_size = (image_size.0 / 2, image_size.1 / 2);
+        let mut rng = rand_xorshift::XorShiftRng::seed_from_u64(0);
+        let input = vec![Image::<f32>::new_random(input_size, &mut rng)?];
+        let stage = NearestNeighbourUpsample::new(0);
+        let output: Vec<Image<f32>> =
+            make_and_run_simple_pipeline(stage, &input, image_size, 0, 256)?;
+        assert_eq!(image_size, output[0].size());
+        for y in 0..image_size.1 {
+            for x in 0..image_size.0 {
+                let ix = x / 2;
+                let iy = y / 2;
+                let i = input[0].row(iy)[ix];
+                let o = output[0].row(y)[x];
+                assert_eq!(
+                    i, o,
+                    "mismatch at output position {x}x{y}: {i} vs output {o}"
+                );
+            }
+        }
+
+        Ok(())
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/noise.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/noise.rs
new file mode 100644
index 0000000..ea41f3a
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/noise.rs
@@ -0,0 +1,301 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(clippy::needless_range_loop)]
+
+use crate::{
+    features::noise::Noise,
+    frame::color_correlation_map::ColorCorrelationParams,
+    render::{Channels, ChannelsMut, RenderPipelineInOutStage, RenderPipelineInPlaceStage},
+};
+
+pub struct ConvolveNoiseStage {
+    channel: usize,
+}
+
+impl ConvolveNoiseStage {
+    pub fn new(channel: usize) -> ConvolveNoiseStage {
+        ConvolveNoiseStage { channel }
+    }
+}
+
+impl std::fmt::Display for ConvolveNoiseStage {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "convolve noise for channel {}", self.channel,)
+    }
+}
+
+impl RenderPipelineInOutStage for ConvolveNoiseStage {
+    type InputT = f32;
+    type OutputT = f32;
+    const SHIFT: (u8, u8) = (0, 0);
+    const BORDER: (u8, u8) = (2, 2);
+
+    fn uses_channel(&self, c: usize) -> bool {
+        c == self.channel
+    }
+
+    fn process_row_chunk(
+        &self,
+        _position: (usize, usize),
+        xsize: usize,
+        input_rows: &Channels<f32>,
+        output_rows: &mut ChannelsMut<f32>,
+        _state: Option<&mut dyn std::any::Any>,
+    ) {
+        let input = &input_rows[0];
+        for x in 0..xsize {
+            let mut others = 0.0;
+            for i in 0..5 {
+                let offset = (x as i32 + i) as usize;
+                others += input[0][offset];
+                others += input[1][offset];
+                others += input[3][offset];
+                others += input[4][offset];
+            }
+            others += input[2][x];
+            others += input[2][x + 1];
+            others += input[2][x + 3];
+            others += input[2][x + 4];
+            output_rows[0][0][x] = others * 0.16 + input[2][x + 2] * -3.84;
+        }
+    }
+}
+
+pub struct AddNoiseStage {
+    noise: Noise,
+    first_channel: usize,
+    color_correlation: ColorCorrelationParams,
+}
+
+impl AddNoiseStage {
+    #[allow(dead_code)]
+    pub fn new(
+        noise: Noise,
+        color_correlation: ColorCorrelationParams,
+        first_channel: usize,
+    ) -> AddNoiseStage {
+        assert!(first_channel > 2);
+        AddNoiseStage {
+            noise,
+            first_channel,
+            color_correlation,
+        }
+    }
+}
+
+impl std::fmt::Display for AddNoiseStage {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "add noise for channels [{},{},{}]",
+            self.first_channel,
+            self.first_channel + 1,
+            self.first_channel + 2
+        )
+    }
+}
+
+impl RenderPipelineInPlaceStage for AddNoiseStage {
+    type Type = f32;
+
+    fn uses_channel(&self, c: usize) -> bool {
+        c < 3 || (c >= self.first_channel && c < self.first_channel + 3)
+    }
+
+    fn process_row_chunk(
+        &self,
+        _position: (usize, usize),
+        xsize: usize,
+        row: &mut [&mut [f32]],
+        _state: Option<&mut dyn std::any::Any>,
+    ) {
+        let norm_const = 0.22;
+        let ytox = self.color_correlation.y_to_x_lf();
+        let ytob = self.color_correlation.y_to_b_lf();
+        for x in 0..xsize {
+            let row_rnd_r = row[3][x];
+            let row_rnd_g = row[4][x];
+            let row_rnd_c = row[5][x];
+            let vx = row[0][x];
+            let vy = row[1][x];
+            let in_g = vy - vx;
+            let in_r = vy + vx;
+            let noise_strength_g = self.noise.strength(in_g * 0.5);
+            let noise_strength_r = self.noise.strength(in_r * 0.5);
+            let addit_rnd_noise_red = row_rnd_r * norm_const;
+            let addit_rnd_noise_green = row_rnd_g * norm_const;
+            let addit_rnd_noise_correlated = row_rnd_c * norm_const;
+            let k_rg_corr = 0.9921875;
+            let k_rgn_corr = 0.0078125;
+            let red_noise = noise_strength_r
+                * (k_rgn_corr * addit_rnd_noise_red + k_rg_corr * addit_rnd_noise_correlated);
+            let green_noise = noise_strength_g
+                * (k_rgn_corr * addit_rnd_noise_green + k_rg_corr * addit_rnd_noise_correlated);
+            let rg_noise = red_noise + green_noise;
+            row[0][x] += ytox * rg_noise + red_noise - green_noise;
+            row[1][x] += rg_noise;
+            row[2][x] += ytob * rg_noise;
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use crate::{
+        error::Result,
+        features::noise::Noise,
+        frame::color_correlation_map::ColorCorrelationParams,
+        image::Image,
+        render::{
+            stages::noise::{AddNoiseStage, ConvolveNoiseStage},
+            test::make_and_run_simple_pipeline,
+        },
+        util::test::assert_almost_abs_eq,
+    };
+    use test_log::test;
+
+    // TODO(firsching): Add more relevant ConvolveNoise tests as per discussions in https://github.com/libjxl/jxl-rs/pull/60.
+
+    #[test]
+    fn convolve_noise_process_row_chunk() -> Result<()> {
+        let input: Image<f32> = Image::new_range((2, 2), 0.0, 1.0)?;
+        let stage = ConvolveNoiseStage::new(0);
+        let output: Vec<Image<f32>> =
+            make_and_run_simple_pipeline(stage, &[input], (2, 2), 0, 256)?;
+        assert_almost_abs_eq(output[0].row(0)[0], 7.2, 1e-6);
+        assert_almost_abs_eq(output[0].row(0)[1], 2.4, 1e-6);
+        assert_almost_abs_eq(output[0].row(1)[0], -2.4, 1e-6);
+        assert_almost_abs_eq(output[0].row(1)[1], -7.2, 1e-6);
+        Ok(())
+    }
+
+    #[test]
+    fn convolve_noise_consistency() -> Result<()> {
+        crate::render::test::test_stage_consistency(|| ConvolveNoiseStage::new(0), (500, 500), 1)
+    }
+
+    // TODO(firsching): Add more relevant AddNoise tests as per discussions in https://github.com/libjxl/jxl-rs/pull/60.
+
+    #[test]
+    fn add_noise_process_row_chunk() -> Result<()> {
+        let xsize = 8;
+        let ysize = 8;
+        let input_c0: Image<f32> = Image::new_range((xsize, ysize), 0.1, 0.1)?;
+        let input_c1: Image<f32> = Image::new_range((xsize, ysize), 0.1, 0.1)?;
+        let input_c2: Image<f32> = Image::new_range((xsize, ysize), 0.1, 0.1)?;
+        let input_c3: Image<f32> = Image::new_range((xsize, ysize), 0.1, 0.1)?;
+        let input_c4: Image<f32> = Image::new_range((xsize, ysize), 0.1, 0.1)?;
+        let input_c5: Image<f32> = Image::new_range((xsize, ysize), 0.1, 0.1)?;
+        let stage = AddNoiseStage::new(
+            Noise {
+                lut: [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0],
+            },
+            ColorCorrelationParams::default(),
+            3,
+        );
+        let output = make_and_run_simple_pipeline(
+            stage,
+            &[input_c0, input_c1, input_c2, input_c3, input_c4, input_c5],
+            (xsize, ysize),
+            0,
+            256,
+        )?;
+        // Golden data generated by libjxl.
+        let want_out = [
+            [
+                [
+                    0.100000, 0.200000, 0.300000, 0.400000, 0.500000, 0.600000, 0.700000, 0.800000,
+                ],
+                [0.900000, 1.000000, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6],
+                [1.7, 1.8, 1.9, 2.000000, 2.1, 2.2, 2.3, 2.4],
+                [
+                    2.5, 2.6, 2.7, 2.799999, 2.899999, 2.999999, 3.099999, 3.199999,
+                ],
+                [
+                    3.299999, 3.399999, 3.499999, 3.599999, 3.699999, 3.799999, 3.899998, 3.999998,
+                ],
+                [
+                    4.099998, 4.199998, 4.299998, 4.399998, 4.499998, 4.599998, 4.699998, 4.799998,
+                ],
+                [
+                    4.899998, 4.999998, 5.099998, 5.199997, 5.299997, 5.399997, 5.499997, 5.599997,
+                ],
+                [
+                    5.699997, 5.799997, 5.899997, 5.999997, 6.099997, 6.199996, 6.299996, 6.399996,
+                ],
+            ],
+            [
+                [
+                    0.144000, 0.288000, 0.432000, 0.576000, 0.720000, 0.864000, 1.008, 1.152,
+                ],
+                [1.296, 1.44, 1.584, 1.728, 1.872, 2.016, 2.16, 2.304],
+                [2.448, 2.592, 2.736001, 2.88, 3.024, 3.168, 3.312, 3.456],
+                [
+                    3.6, 3.743999, 3.888, 4.031999, 4.175999, 4.319999, 4.463999, 4.607999,
+                ],
+                [
+                    4.751998, 4.895998, 5.039998, 5.183998, 5.327998, 5.471998, 5.615998, 5.759997,
+                ],
+                [
+                    5.903998, 6.047997, 6.191998, 6.335998, 6.479997, 6.623997, 6.767997, 6.911997,
+                ],
+                [
+                    7.055997, 7.199996, 7.343997, 7.487996, 7.631996, 7.775996, 7.919996, 8.063995,
+                ],
+                [
+                    8.207995, 8.351995, 8.495996, 8.639996, 8.783995, 8.927995, 9.071995, 9.215995,
+                ],
+            ],
+            [
+                [
+                    0.144000, 0.288000, 0.432000, 0.576000, 0.720000, 0.864000, 1.008, 1.152,
+                ],
+                [1.296, 1.44, 1.584, 1.728, 1.872, 2.016, 2.16, 2.304],
+                [2.448, 2.592, 2.736001, 2.88, 3.024, 3.168, 3.312, 3.456],
+                [
+                    3.6, 3.743999, 3.888, 4.031999, 4.175999, 4.319999, 4.463999, 4.607999,
+                ],
+                [
+                    4.751998, 4.895998, 5.039998, 5.183998, 5.327998, 5.471998, 5.615998, 5.759997,
+                ],
+                [
+                    5.903998, 6.047997, 6.191998, 6.335998, 6.479997, 6.623997, 6.767997, 6.911997,
+                ],
+                [
+                    7.055997, 7.199996, 7.343997, 7.487996, 7.631996, 7.775996, 7.919996, 8.063995,
+                ],
+                [
+                    8.207995, 8.351995, 8.495996, 8.639996, 8.783995, 8.927995, 9.071995, 9.215995,
+                ],
+            ],
+        ];
+        for c in 0..3 {
+            for y in 0..output[c].size().1 {
+                for x in 0..output[c].size().0 {
+                    assert_almost_abs_eq(output[c].row(y)[x], want_out[c][y][x], 1e-5);
+                }
+            }
+        }
+        Ok(())
+    }
+
+    #[test]
+    fn add_noise_consistency() -> Result<()> {
+        crate::render::test::test_stage_consistency(
+            || {
+                AddNoiseStage::new(
+                    Noise {
+                        lut: [0.0, 2.0, 1.0, 0.0, 1.0, 3.0, 1.1, 2.3],
+                    },
+                    ColorCorrelationParams::default(),
+                    3,
+                )
+            },
+            (500, 500),
+            6,
+        )
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/patches.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/patches.rs
new file mode 100644
index 0000000..2dab32c
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/patches.rs
@@ -0,0 +1,96 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::{any::Any, sync::Arc};
+
+use crate::{
+    features::patches::PatchesDictionary, frame::ReferenceFrame,
+    headers::extra_channels::ExtraChannelInfo, render::RenderPipelineInPlaceStage,
+    util::NewWithCapacity as _,
+};
+
+pub struct PatchesStage {
+    pub patches: Arc<PatchesDictionary>,
+    pub extra_channels: Vec<ExtraChannelInfo>,
+    pub decoder_state: Arc<[Option<ReferenceFrame>; 4]>,
+}
+
+impl std::fmt::Display for PatchesStage {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "patches")
+    }
+}
+
+impl RenderPipelineInPlaceStage for PatchesStage {
+    type Type = f32;
+
+    fn uses_channel(&self, c: usize) -> bool {
+        c < 3 + self.extra_channels.len()
+    }
+
+    fn process_row_chunk(
+        &self,
+        position: (usize, usize),
+        xsize: usize,
+        row: &mut [&mut [f32]],
+        state: Option<&mut dyn Any>,
+    ) {
+        let state: &mut Vec<usize> = state.unwrap().downcast_mut().unwrap();
+        self.patches.add_one_row(
+            row,
+            position,
+            xsize,
+            &self.extra_channels,
+            &self.decoder_state[..],
+            state,
+        );
+    }
+
+    fn init_local_state(&self) -> crate::error::Result<Option<Box<dyn Any>>> {
+        let patches_for_row_result = Vec::<usize>::new_with_capacity(self.patches.positions.len())?;
+        Ok(Some(Box::new(patches_for_row_result) as Box<dyn Any>))
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use std::sync::Arc;
+
+    use rand::SeedableRng;
+    use test_log::test;
+
+    use super::*;
+    use crate::error::Result;
+    use crate::util::test::read_headers_and_toc;
+
+    #[test]
+    fn patches_consistency() -> Result<()> {
+        let (file_header, _, _) =
+            read_headers_and_toc(include_bytes!("../../../resources/test/basic.jxl")).unwrap();
+        let mut rng = rand_xorshift::XorShiftRng::seed_from_u64(0);
+        let patch_dict = Arc::new(PatchesDictionary::random(
+            (500, 500),
+            file_header.image_metadata.extra_channel_info.len(),
+            0,
+            4,
+            &mut rng,
+        ));
+        let reference_frames = Arc::new([
+            Some(ReferenceFrame::random(&mut rng, 500, 500, 4, false)?),
+            Some(ReferenceFrame::random(&mut rng, 500, 500, 4, false)?),
+            Some(ReferenceFrame::random(&mut rng, 500, 500, 4, false)?),
+            Some(ReferenceFrame::random(&mut rng, 500, 500, 4, false)?),
+        ]);
+        crate::render::test::test_stage_consistency(
+            || PatchesStage {
+                patches: patch_dict.clone(),
+                extra_channels: file_header.image_metadata.extra_channel_info.clone(),
+                decoder_state: reference_frames.clone(),
+            },
+            (500, 500),
+            4,
+        )
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/splines.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/splines.rs
new file mode 100644
index 0000000..76d68aa
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/splines.rs
@@ -0,0 +1,175 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{
+    features::spline::Splines, frame::color_correlation_map::ColorCorrelationParams,
+    render::RenderPipelineInPlaceStage,
+};
+
+pub struct SplinesStage {
+    splines: Splines,
+}
+
+impl SplinesStage {
+    // TODO(veluca): should this return a Result?
+    pub fn new(
+        mut splines: Splines,
+        frame_size: (usize, usize),
+        color_correlation_params: &ColorCorrelationParams,
+        high_precision: bool,
+    ) -> Self {
+        splines
+            .initialize_draw_cache(
+                frame_size.0 as u64,
+                frame_size.1 as u64,
+                color_correlation_params,
+                high_precision,
+            )
+            .unwrap();
+        SplinesStage { splines }
+    }
+}
+
+impl std::fmt::Display for SplinesStage {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "splines")
+    }
+}
+
+impl RenderPipelineInPlaceStage for SplinesStage {
+    type Type = f32;
+
+    fn uses_channel(&self, c: usize) -> bool {
+        c < 3
+    }
+
+    fn process_row_chunk(
+        &self,
+        position: (usize, usize),
+        xsize: usize,
+        row: &mut [&mut [f32]],
+        _state: Option<&mut dyn std::any::Any>,
+    ) {
+        self.splines.draw_segments(row, position, xsize);
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use crate::features::spline::{Point, QuantizedSpline, Splines};
+    use crate::frame::color_correlation_map::ColorCorrelationParams;
+    use crate::render::test::make_and_run_simple_pipeline;
+    use crate::util::test::{self, assert_all_almost_abs_eq, read_pfm};
+    use crate::{error::Result, image::Image, render::stages::splines::SplinesStage};
+    use test_log::test;
+
+    #[test]
+    fn splines_process_row_chunk() -> Result<(), test::Error> {
+        let want_image = read_pfm(include_bytes!("../../../resources/test/splines.pfm"))?;
+        let target_images = [
+            Image::<f32>::new((320, 320))?,
+            Image::<f32>::new((320, 320))?,
+            Image::<f32>::new((320, 320))?,
+        ];
+        let size = target_images[0].size();
+        let splines = Splines::create(
+            0,
+            vec![QuantizedSpline {
+                control_points: vec![
+                    (109, 105),
+                    (-130, -261),
+                    (-66, 193),
+                    (227, -52),
+                    (-170, 290),
+                ],
+                color_dct: [
+                    [
+                        168, 119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                        0, 0, 0, 0, 0, 0, 0, 0,
+                    ],
+                    [
+                        9, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                        0, 0, 0, 0, 0, 0, 0,
+                    ],
+                    [
+                        -10, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                        0, 0, 0, 0, 0, 0, 0, 0,
+                    ],
+                ],
+                sigma_dct: [
+                    4, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                    0, 0, 0, 0, 0, 0,
+                ],
+            }],
+            vec![Point { x: 9.0, y: 54.0 }],
+        );
+        let output: Vec<Image<f32>> = make_and_run_simple_pipeline(
+            SplinesStage::new(
+                splines.clone(),
+                size,
+                &ColorCorrelationParams::default(),
+                true,
+            ),
+            &target_images,
+            size,
+            0,
+            256,
+        )?;
+        for c in 0..3 {
+            for row in 0..size.1 {
+                assert_all_almost_abs_eq(output[c].row(row), want_image[c].row(row), 1e-3);
+            }
+        }
+        Ok(())
+    }
+
+    #[test]
+    fn splines_consistency() -> Result<()> {
+        let splines = Splines::create(
+            0,
+            vec![QuantizedSpline {
+                control_points: vec![
+                    (109, 105),
+                    (-130, -261),
+                    (-66, 193),
+                    (227, -52),
+                    (-170, 290),
+                ],
+                color_dct: [
+                    [
+                        168, 119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                        0, 0, 0, 0, 0, 0, 0, 0,
+                    ],
+                    [
+                        9, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                        0, 0, 0, 0, 0, 0, 0,
+                    ],
+                    [
+                        -10, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                        0, 0, 0, 0, 0, 0, 0, 0,
+                    ],
+                ],
+                sigma_dct: [
+                    4, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                    0, 0, 0, 0, 0, 0,
+                ],
+            }],
+            vec![Point { x: 9.0, y: 54.0 }],
+        );
+
+        crate::render::test::test_stage_consistency(
+            || {
+                SplinesStage::new(
+                    splines.clone(),
+                    (500, 500),
+                    &ColorCorrelationParams::default(),
+                    false,
+                )
+            },
+            (500, 500),
+            6,
+        )
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/spot.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/spot.rs
new file mode 100644
index 0000000..36b24ed
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/spot.rs
@@ -0,0 +1,115 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::render::RenderPipelineInPlaceStage;
+
+/// Render spot color
+pub struct SpotColorStage {
+    /// Spot color channel index
+    spot_c: usize,
+    /// Spot color in linear RGBA
+    spot_color: [f32; 4],
+}
+
+impl std::fmt::Display for SpotColorStage {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "spot color stage for channel {}", self.spot_c)
+    }
+}
+
+impl SpotColorStage {
+    #[allow(unused, reason = "remove once we actually use this")]
+    pub fn new(spot_c_offset: usize, spot_color: [f32; 4]) -> Self {
+        Self {
+            spot_c: 3 + spot_c_offset,
+            spot_color,
+        }
+    }
+}
+
+impl RenderPipelineInPlaceStage for SpotColorStage {
+    type Type = f32;
+
+    fn uses_channel(&self, c: usize) -> bool {
+        c < 3 || c == self.spot_c
+    }
+
+    // `row` should only contain color channels and the spot channel.
+    fn process_row_chunk(
+        &self,
+        _position: (usize, usize),
+        xsize: usize,
+        row: &mut [&mut [f32]],
+        _state: Option<&mut dyn std::any::Any>,
+    ) {
+        let [row_r, row_g, row_b, row_s] = row else {
+            panic!(
+                "incorrect number of channels; expected 4, found {}",
+                row.len()
+            );
+        };
+
+        let scale = self.spot_color[3];
+        assert!(
+            xsize <= row_r.len()
+                && xsize <= row_g.len()
+                && xsize <= row_b.len()
+                && xsize <= row_s.len()
+        );
+        for idx in 0..xsize {
+            let mix = scale * row_s[idx];
+            row_r[idx] = mix * self.spot_color[0] + (1.0 - mix) * row_r[idx];
+            row_g[idx] = mix * self.spot_color[1] + (1.0 - mix) * row_g[idx];
+            row_b[idx] = mix * self.spot_color[2] + (1.0 - mix) * row_b[idx];
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use test_log::test;
+
+    use super::*;
+    use crate::error::Result;
+    use crate::image::Image;
+    use crate::render::test::make_and_run_simple_pipeline;
+    use crate::util::test::assert_all_almost_abs_eq;
+
+    #[test]
+    fn consistency() -> Result<()> {
+        crate::render::test::test_stage_consistency(
+            || SpotColorStage::new(0, [0.0; 4]),
+            (500, 500),
+            4,
+        )
+    }
+
+    #[test]
+    fn srgb_primaries() -> Result<()> {
+        let mut input_r = Image::new((3, 1))?;
+        let mut input_g = Image::new((3, 1))?;
+        let mut input_b = Image::new((3, 1))?;
+        let mut input_s = Image::new((3, 1))?;
+        input_r.row_mut(0).copy_from_slice(&[1.0, 0.0, 0.0]);
+        input_g.row_mut(0).copy_from_slice(&[0.0, 1.0, 0.0]);
+        input_b.row_mut(0).copy_from_slice(&[0.0, 0.0, 1.0]);
+        input_s.row_mut(0).copy_from_slice(&[1.0, 1.0, 1.0]);
+
+        let stage = SpotColorStage::new(0, [0.5; 4]);
+        let output = make_and_run_simple_pipeline(
+            stage,
+            &[input_r, input_g, input_b, input_s],
+            (3, 1),
+            0,
+            256,
+        )?;
+
+        assert_all_almost_abs_eq(output[0].row(0), &[0.75, 0.25, 0.25], 1e-6);
+        assert_all_almost_abs_eq(output[1].row(0), &[0.25, 0.75, 0.25], 1e-6);
+        assert_all_almost_abs_eq(output[2].row(0), &[0.25, 0.25, 0.75], 1e-6);
+
+        Ok(())
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/to_linear.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/to_linear.rs
new file mode 100644
index 0000000..3a3811e6
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/to_linear.rs
@@ -0,0 +1,233 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::color::tf;
+use crate::headers::color_encoding::CustomTransferFunction;
+use crate::render::RenderPipelineInPlaceStage;
+use crate::render::stages::from_linear;
+use jxl_simd::{F32SimdVec, simd_function};
+
+/// Convert encoded non-linear color samples to display-referred linear color samples.
+#[derive(Debug)]
+pub struct ToLinearStage {
+    first_channel: usize,
+    tf: TransferFunction,
+}
+
+impl ToLinearStage {
+    pub fn new(first_channel: usize, tf: TransferFunction) -> Self {
+        Self { first_channel, tf }
+    }
+
+    #[allow(unused, reason = "tirr-c: remove once we use this!")]
+    pub fn sdr(first_channel: usize, tf: CustomTransferFunction) -> Self {
+        let tf = TransferFunction::try_from(tf).expect("transfer function is not an SDR one");
+        Self::new(first_channel, tf)
+    }
+
+    #[allow(unused, reason = "tirr-c: remove once we use this!")]
+    pub fn pq(first_channel: usize, intensity_target: f32) -> Self {
+        let tf = TransferFunction::Pq { intensity_target };
+        Self::new(first_channel, tf)
+    }
+
+    #[allow(unused, reason = "tirr-c: remove once we use this!")]
+    pub fn hlg(first_channel: usize, intensity_target: f32, luminance_rgb: [f32; 3]) -> Self {
+        let tf = TransferFunction::Hlg {
+            intensity_target,
+            luminance_rgb,
+        };
+        Self::new(first_channel, tf)
+    }
+}
+
+impl std::fmt::Display for ToLinearStage {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let channel = self.first_channel;
+        write!(
+            f,
+            "Convert transfer function {:?} to display-referred linear TF for channel [{},{},{}]",
+            self.tf,
+            channel,
+            channel + 1,
+            channel + 2
+        )
+    }
+}
+
+simd_function!(
+to_linear_process_dispatch,
+d: D,
+fn to_linear_process(tf: &TransferFunction, xsize: usize, row: &mut [&mut [f32]]) {
+    let [row_r, row_g, row_b] = row else {
+        panic!(
+            "incorrect number of channels; expected 3, found {}",
+            row.len()
+        );
+    };
+
+    match *tf {
+        TransferFunction::Bt709 => {
+            for row in row {
+                tf::bt709_to_linear(&mut row[..xsize]);
+            }
+        }
+        TransferFunction::Srgb => {
+            for row in row {
+                tf::srgb_to_linear_simd(d, &mut row[..xsize.next_multiple_of(D::F32Vec::LEN)]);
+            }
+        }
+        TransferFunction::Pq { intensity_target } => {
+            for row in row {
+                tf::pq_to_linear(intensity_target, &mut row[..xsize]);
+            }
+        }
+        TransferFunction::Hlg {
+            intensity_target,
+            luminance_rgb,
+        } => {
+            tf::hlg_to_scene(&mut row_r[..xsize]);
+            tf::hlg_to_scene(&mut row_g[..xsize]);
+            tf::hlg_to_scene(&mut row_b[..xsize]);
+
+            let rows = [
+                &mut row_r[..xsize],
+                &mut row_g[..xsize],
+                &mut row_b[..xsize],
+            ];
+            tf::hlg_scene_to_display(intensity_target, luminance_rgb, rows);
+        }
+        TransferFunction::Gamma(g) => {
+            for row in row {
+                for values in
+                    row[..xsize.next_multiple_of(D::F32Vec::LEN)].chunks_exact_mut(D::F32Vec::LEN)
+                {
+                    let v = D::F32Vec::load(d, values);
+                    crate::util::fast_powf_simd(d, v.abs(), D::F32Vec::splat(d, g))
+                        .copysign(v)
+                        .store(values);
+                }
+            }
+        }
+    }
+});
+
+impl RenderPipelineInPlaceStage for ToLinearStage {
+    type Type = f32;
+
+    fn uses_channel(&self, c: usize) -> bool {
+        (self.first_channel..self.first_channel + 3).contains(&c)
+    }
+
+    fn process_row_chunk(
+        &self,
+        _position: (usize, usize),
+        xsize: usize,
+        row: &mut [&mut [f32]],
+        _state: Option<&mut dyn std::any::Any>,
+    ) {
+        to_linear_process_dispatch(&self.tf, xsize, row)
+    }
+}
+
+pub type TransferFunction = from_linear::TransferFunction;
+
+#[cfg(test)]
+mod test {
+    use test_log::test;
+
+    use super::*;
+    use crate::error::Result;
+    use crate::image::Image;
+    use crate::render::test::make_and_run_simple_pipeline;
+    use crate::util::test::assert_all_almost_abs_eq;
+
+    const LUMINANCE_BT2020: [f32; 3] = [0.2627, 0.678, 0.0593];
+
+    #[test]
+    fn consistency_hlg() -> Result<()> {
+        crate::render::test::test_stage_consistency(
+            || ToLinearStage::hlg(0, 1000f32, LUMINANCE_BT2020),
+            (500, 500),
+            3,
+        )
+    }
+
+    #[test]
+    fn consistency_pq() -> Result<()> {
+        crate::render::test::test_stage_consistency(
+            || ToLinearStage::pq(0, 10000f32),
+            (500, 500),
+            3,
+        )
+    }
+
+    #[test]
+    fn consistency_srgb() -> Result<()> {
+        crate::render::test::test_stage_consistency(
+            || ToLinearStage::new(0, TransferFunction::Srgb),
+            (500, 500),
+            3,
+        )
+    }
+
+    #[test]
+    fn consistency_bt709() -> Result<()> {
+        crate::render::test::test_stage_consistency(
+            || ToLinearStage::new(0, TransferFunction::Bt709),
+            (500, 500),
+            3,
+        )
+    }
+
+    #[test]
+    fn consistency_gamma22() -> Result<()> {
+        crate::render::test::test_stage_consistency(
+            || ToLinearStage::new(0, TransferFunction::Gamma(0.4545455)),
+            (500, 500),
+            3,
+        )
+    }
+
+    #[test]
+    fn sdr_white_hlg() -> Result<()> {
+        let intensity_target = 1000f32;
+        // Reversed version of FromLinear test
+        let input_r = Image::new_with_value((1, 1), 0.75)?;
+        let input_g = Image::new_with_value((1, 1), 0.75)?;
+        let input_b = Image::new_with_value((1, 1), 0.75)?;
+
+        // 75% HLG
+        let stage = ToLinearStage::hlg(0, intensity_target, LUMINANCE_BT2020);
+        let output =
+            make_and_run_simple_pipeline(stage, &[input_r, input_g, input_b], (1, 1), 0, 256)?;
+
+        assert_all_almost_abs_eq(output[0].row(0), &[0.203], 1e-3);
+        assert_all_almost_abs_eq(output[1].row(0), &[0.203], 1e-3);
+        assert_all_almost_abs_eq(output[2].row(0), &[0.203], 1e-3);
+
+        Ok(())
+    }
+
+    #[test]
+    fn sdr_white_pq() -> Result<()> {
+        let intensity_target = 1000f32;
+        // Reversed version of FromLinear test
+        let input_r = Image::new_with_value((1, 1), 0.5807)?;
+        let input_g = Image::new_with_value((1, 1), 0.5807)?;
+        let input_b = Image::new_with_value((1, 1), 0.5807)?;
+
+        // 58% PQ
+        let stage = ToLinearStage::pq(0, intensity_target);
+        let output =
+            make_and_run_simple_pipeline(stage, &[input_r, input_g, input_b], (1, 1), 0, 256)?;
+
+        assert_all_almost_abs_eq(output[0].row(0), &[0.203], 1e-3);
+        assert_all_almost_abs_eq(output[1].row(0), &[0.203], 1e-3);
+        assert_all_almost_abs_eq(output[2].row(0), &[0.203], 1e-3);
+
+        Ok(())
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/upsample.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/upsample.rs
new file mode 100644
index 0000000..7254673
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/upsample.rs
@@ -0,0 +1,502 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(clippy::needless_range_loop)]
+
+use crate::{
+    headers::CustomTransformData,
+    render::{Channels, ChannelsMut, RenderPipelineInOutStage},
+};
+
+pub struct Upsample<const N: usize, const SHIFT: u8> {
+    kernel: [[[[f32; 5]; 5]; N]; N],
+    channel: usize,
+}
+
+impl<const N: usize, const SHIFT: u8> Upsample<N, SHIFT> {
+    pub fn new(ups_factors: &CustomTransformData, channel: usize) -> Self {
+        const { assert!(SHIFT >= 1 && SHIFT <= 3) }
+        const { assert!(1 << SHIFT == N) }
+
+        let weights: &[f32] = match N {
+            2 => &ups_factors.weights2,
+            4 => &ups_factors.weights4,
+            8 => &ups_factors.weights8,
+            _ => unreachable!(),
+        };
+
+        let mut kernel = [[[[0.0; 5]; 5]; N]; N];
+        let n = N / 2;
+        for i in 0..5 * n {
+            for j in 0..5 * n {
+                let y = i.min(j);
+                let x = i.max(j);
+                let y = y as isize;
+                let x = x as isize;
+                let n = n as isize;
+                let index = (5 * n * y - y * (y - 1) / 2 + x - y) as usize;
+                // Filling in the top left corner from the weights
+                kernel[j / 5][i / 5][j % 5][i % 5] = weights[index];
+                // Mirroring to get the rest of the kernel.
+                kernel[(2 * n as usize - 1) - j / 5][i / 5][4 - (j % 5)][i % 5] = weights[index];
+                kernel[j / 5][(2 * n as usize - 1) - i / 5][j % 5][4 - (i % 5)] = weights[index];
+                kernel[(2 * n as usize - 1) - j / 5][(2 * n as usize - 1) - i / 5][4 - (j % 5)]
+                    [4 - (i % 5)] = weights[index];
+            }
+        }
+
+        Self { kernel, channel }
+    }
+}
+
+impl<const N: usize, const SHIFT: u8> std::fmt::Display for Upsample<N, SHIFT> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{N}x{N} upsampling of channel {}", self.channel)
+    }
+}
+
+impl<const N: usize, const SHIFT: u8> RenderPipelineInOutStage for Upsample<N, SHIFT> {
+    type InputT = f32;
+    type OutputT = f32;
+    const SHIFT: (u8, u8) = (SHIFT, SHIFT);
+    const BORDER: (u8, u8) = (2, 2);
+
+    fn uses_channel(&self, c: usize) -> bool {
+        c == self.channel
+    }
+    /// Processes a chunk of a row, applying NxN upsampling using a 5x5 kernel.
+    /// Each input value expands into a NxN region in the output, based on neighboring inputs.
+    fn process_row_chunk(
+        &self,
+        _position: (usize, usize),
+        xsize: usize,
+        input_rows: &Channels<f32>,
+        output_rows: &mut ChannelsMut<f32>,
+        _state: Option<&mut dyn std::any::Any>,
+    ) {
+        let input = &input_rows[0];
+
+        for x in 0..xsize {
+            // Upsample this input value into a NxN region in the output
+            let mut minval = input[0][x];
+            let mut maxval = minval;
+            for di in 0..N {
+                for dj in 0..N {
+                    // Iterate over the input rows and columns
+                    let mut output_val = 0.0;
+                    #[allow(clippy::needless_range_loop)]
+                    for i in 0..5 {
+                        for j in 0..5 {
+                            let input_value = input[i][j + x];
+                            output_val += input_value * self.kernel[di][dj][i % 5][j % 5];
+                            minval = input_value.min(minval);
+                            maxval = input_value.max(maxval);
+                        }
+                    }
+                    output_rows[0][di][dj + N * x] = output_val.clamp(minval, maxval);
+                }
+            }
+        }
+    }
+}
+
+pub type Upsample2x = Upsample<2, 1>;
+pub type Upsample4x = Upsample<4, 2>;
+pub type Upsample8x = Upsample<8, 3>;
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use crate::{
+        error::Result, headers::CustomTransformDataNonserialized, image::Image,
+        render::test::make_and_run_simple_pipeline, util::test::assert_almost_abs_eq,
+    };
+    use test_log::test;
+
+    fn ups_factors() -> CustomTransformData {
+        CustomTransformData::default(&CustomTransformDataNonserialized { xyb_encoded: true })
+    }
+
+    #[test]
+    fn upsample2x_consistency() -> Result<()> {
+        crate::render::test::test_stage_consistency(
+            || Upsample2x::new(&ups_factors(), 0),
+            (500, 500),
+            1,
+        )
+    }
+
+    #[test]
+    fn upsample4x_consistency() -> Result<()> {
+        crate::render::test::test_stage_consistency(
+            || Upsample4x::new(&ups_factors(), 0),
+            (500, 500),
+            1,
+        )
+    }
+
+    #[test]
+    fn upsample8x_consistency() -> Result<()> {
+        crate::render::test::test_stage_consistency(
+            || Upsample8x::new(&ups_factors(), 0),
+            (504, 504),
+            1,
+        )
+    }
+
+    #[test]
+    fn upsample2x_constant() -> Result<()> {
+        let image_size = (238, 412);
+        let input_size = (image_size.0 / 2, image_size.1 / 2);
+        let val = 0.777f32;
+        let input = Image::new_with_value(input_size, val)?;
+        let stage = Upsample2x::new(&ups_factors(), 0);
+        let output: Vec<Image<f32>> =
+            make_and_run_simple_pipeline(stage, &[input], image_size, 0, 123)?;
+        for x in 0..image_size.0 {
+            for y in 0..image_size.1 {
+                assert_almost_abs_eq(output[0].row(y)[x], val, 0.0000001);
+            }
+        }
+        Ok(())
+    }
+
+    #[test]
+    fn upsample4x_constant() -> Result<()> {
+        let image_size = (240, 412);
+        let input_size = (image_size.0 / 4, image_size.1 / 4);
+        let val = 0.777f32;
+        let input = Image::new_with_value(input_size, val)?;
+        let stage = Upsample4x::new(&ups_factors(), 0);
+        let output: Vec<Image<f32>> =
+            make_and_run_simple_pipeline(stage, &[input], image_size, 0, 123)?;
+        for x in 0..image_size.0 {
+            for y in 0..image_size.1 {
+                assert_almost_abs_eq(output[0].row(y)[x], val, 0.00001);
+            }
+        }
+        Ok(())
+    }
+
+    #[test]
+    fn upsample8x_constant() -> Result<()> {
+        let image_size = (240, 416);
+        let input_size = (image_size.0 / 8, image_size.1 / 8);
+        let val = 0.777f32;
+        let input = Image::new_with_value(input_size, val)?;
+        let stage = Upsample8x::new(&ups_factors(), 0);
+        let output: Vec<Image<f32>> =
+            make_and_run_simple_pipeline(stage, &[input], image_size, 0, 123)?;
+        for x in 0..image_size.0 {
+            for y in 0..image_size.1 {
+                assert_almost_abs_eq(output[0].row(y)[x], val, 0.00001);
+            }
+        }
+        Ok(())
+    }
+
+    #[test]
+    fn test_upsample2() -> Result<()> {
+        let eps = 0.0000001;
+        let mut input = Image::new((7, 7))?;
+        // Put a single "1.0" in the middle of the image.
+        input.row_mut(3)[3] = 1.0f32;
+        let ups_factors = ups_factors();
+        let stage = Upsample2x::new(&ups_factors, 0);
+        let output: Vec<Image<f32>> =
+            make_and_run_simple_pipeline(stage, &[input], (14, 14), 0, 77)?;
+        assert_eq!(output[0].size(), (14, 14));
+        // Check we have a border with zeros
+        for i in 0..14 {
+            for j in 0..2 {
+                assert_almost_abs_eq(output[0].row(j)[i], 0.0, eps);
+                assert_almost_abs_eq(output[0].row(i)[j], 0.0, eps);
+                assert_almost_abs_eq(output[0].row(13 - j)[i], 0.0, eps);
+                assert_almost_abs_eq(output[0].row(i)[13 - j], 0.0, eps);
+            }
+        }
+        // Define the mapping for the symmetric top-left kernel
+        let index_map = [
+            [0, 1, 2, 3, 4],
+            [1, 5, 6, 7, 8],
+            [2, 6, 9, 10, 11],
+            [3, 7, 10, 12, 13],
+            [4, 8, 11, 13, 14],
+        ];
+
+        // Validate weights from the kernel
+        let kernel_size = 5;
+        let kernel_offset = 2;
+        let weights = &ups_factors.weights2;
+        for di in 0..2 {
+            for dj in 0..2 {
+                for i in 0..kernel_size {
+                    for j in 0..kernel_size {
+                        let output_value =
+                            output[0].row(kernel_offset + di + 2 * i)[kernel_offset + dj + 2 * j];
+                        let mapped_i = if di == 0 { kernel_size - 1 - i } else { i };
+                        let mapped_j = if dj == 0 { kernel_size - 1 - j } else { j };
+                        let weight_index = index_map[mapped_i][mapped_j];
+                        assert_almost_abs_eq(
+                            output_value,
+                            weights[weight_index].clamp(0.0, 1.0),
+                            eps,
+                        );
+                    }
+                }
+            }
+        }
+
+        Ok(())
+    }
+
+    #[test]
+    fn test_upsample4() -> Result<()> {
+        let eps = 0.0000001;
+        let mut input = Image::new((7, 7))?;
+        // Put a single "1.0" in the middle of the image.
+        input.row_mut(3)[3] = 1.0f32;
+        let ups_factors = ups_factors();
+        let stage = Upsample4x::new(&ups_factors, 0);
+        let output: Vec<Image<f32>> =
+            make_and_run_simple_pipeline(stage, &[input], (28, 28), 0, 1024)?;
+
+        assert_eq!(output[0].size(), (28, 28));
+
+        // Check we have a border with zeros
+        for i in 0..28 {
+            for j in 0..4 {
+                assert_almost_abs_eq(output[0].row(j)[i], 0.0, eps);
+                assert_almost_abs_eq(output[0].row(i)[j], 0.0, eps);
+                assert_almost_abs_eq(output[0].row(27 - j)[i], 0.0, eps);
+                assert_almost_abs_eq(output[0].row(i)[27 - j], 0.0, eps);
+            }
+        }
+
+        // Define the mapping for the symmetric top-left kernel
+        let index_map = [
+            [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
+            [1, 10, 11, 12, 13, 14, 15, 16, 17, 18],
+            [2, 11, 19, 20, 21, 22, 23, 24, 25, 26],
+            [3, 12, 20, 27, 28, 29, 30, 31, 32, 33],
+            [4, 13, 21, 28, 34, 35, 36, 37, 38, 39],
+            [5, 14, 22, 29, 35, 40, 41, 42, 43, 44],
+            [6, 15, 23, 30, 36, 41, 45, 46, 47, 48],
+            [7, 16, 24, 31, 37, 42, 46, 49, 50, 51],
+            [8, 17, 25, 32, 38, 43, 47, 50, 52, 53],
+            [9, 18, 26, 33, 39, 44, 48, 51, 53, 54],
+        ];
+
+        // Validate weights from the kernel
+        let kernel_size = 5;
+        let kernel_offset = 4;
+        let weights = &ups_factors.weights4;
+        let row_size = output[0].size().0;
+        let column_size = row_size;
+        for di in 0..4 {
+            for dj in 0..4 {
+                for ki in 0..kernel_size {
+                    for kj in 0..kernel_size {
+                        let i = kernel_size * di + ki;
+                        let j = kernel_size * dj + kj;
+                        let offset_i = kernel_offset + i;
+                        let offset_j = kernel_offset + j;
+                        // Testing symmetry
+                        let output_value = output[0].row(offset_i)[offset_j];
+                        let output_value_mirrored_right =
+                            output[0].row(row_size - offset_i - 1)[offset_j];
+                        let output_value_mirrored_down =
+                            output[0].row(row_size - offset_i - 1)[column_size - offset_j - 1];
+                        let output_value_mirrored_down_right =
+                            output[0].row(row_size - offset_i - 1)[column_size - offset_j - 1];
+
+                        assert_almost_abs_eq(output_value, output_value_mirrored_right, eps);
+                        assert_almost_abs_eq(output_value, output_value_mirrored_down, eps);
+                        assert_almost_abs_eq(output_value, output_value_mirrored_down_right, eps);
+
+                        // Testing if we get the expected weights, appropriately mapped.
+                        let mapped_i = if (i % 4) < 2 {
+                            4 - (i / 4) + (i % 2) * 5
+                        } else {
+                            i / 4 + (1 - (i % 2)) * 5
+                        };
+                        let mapped_j = if (j % 4) < 2 {
+                            4 - (j / 4) + (j % 2) * 5
+                        } else {
+                            j / 4 + (1 - (j % 2)) * 5
+                        };
+                        let weight_index = index_map[mapped_i][mapped_j];
+                        assert_almost_abs_eq(
+                            output_value,
+                            weights[weight_index].clamp(0.0, 1.0),
+                            eps,
+                        );
+                    }
+                }
+            }
+        }
+
+        Ok(())
+    }
+
+    #[test]
+    fn test_upsample8() -> Result<()> {
+        let eps = 0.0000001;
+        let mut input = Image::new((7, 7))?;
+        // Put a single "1.0" in the middle of the image.
+        input.row_mut(3)[3] = 1.0f32;
+        let ups_factors = ups_factors();
+        let stage = Upsample8x::new(&ups_factors, 0);
+        let output: Vec<Image<f32>> =
+            make_and_run_simple_pipeline(stage, &[input], (56, 56), 0, 1024)?;
+
+        assert_eq!(output[0].size(), (56, 56));
+
+        // Check we have a border with zeros
+        for i in 0..56 {
+            for j in 0..8 {
+                assert_almost_abs_eq(output[0].row(j)[i], 0.0, eps);
+                assert_almost_abs_eq(output[0].row(i)[j], 0.0, eps);
+                assert_almost_abs_eq(output[0].row(55 - j)[i], 0.0, eps);
+                assert_almost_abs_eq(output[0].row(i)[55 - j], 0.0, eps);
+            }
+        }
+
+        // Define the mapping for the symmetric top-left kernel
+        let index_map = [
+            [
+                0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
+                0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
+            ],
+            [
+                0x01, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+                0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
+            ],
+            [
+                0x02, 0x15, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32,
+                0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+            ],
+            [
+                0x03, 0x16, 0x28, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43,
+                0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+            ],
+            [
+                0x04, 0x17, 0x29, 0x3a, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53,
+                0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+            ],
+            [
+                0x05, 0x18, 0x2a, 0x3b, 0x4b, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62,
+                0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+            ],
+            [
+                0x06, 0x19, 0x2b, 0x3c, 0x4c, 0x5b, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
+                0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
+            ],
+            [
+                0x07, 0x1a, 0x2c, 0x3d, 0x4d, 0x5c, 0x6a, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d,
+                0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
+            ],
+            [
+                0x08, 0x1b, 0x2d, 0x3e, 0x4e, 0x5d, 0x6b, 0x78, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+                0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+            ],
+            [
+                0x09, 0x1c, 0x2e, 0x3f, 0x4f, 0x5e, 0x6c, 0x79, 0x85, 0x90, 0x91, 0x92, 0x93, 0x94,
+                0x95, 0x96, 0x97, 0x98, 0x99, 0x9a,
+            ],
+            [
+                0x0a, 0x1d, 0x2f, 0x40, 0x50, 0x5f, 0x6d, 0x7a, 0x86, 0x91, 0x9b, 0x9c, 0x9d, 0x9e,
+                0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
+            ],
+            [
+                0x0b, 0x1e, 0x30, 0x41, 0x51, 0x60, 0x6e, 0x7b, 0x87, 0x92, 0x9c, 0xa5, 0xa6, 0xa7,
+                0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad,
+            ],
+            [
+                0x0c, 0x1f, 0x31, 0x42, 0x52, 0x61, 0x6f, 0x7c, 0x88, 0x93, 0x9d, 0xa6, 0xae, 0xaf,
+                0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
+            ],
+            [
+                0x0d, 0x20, 0x32, 0x43, 0x53, 0x62, 0x70, 0x7d, 0x89, 0x94, 0x9e, 0xa7, 0xaf, 0xb6,
+                0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc,
+            ],
+            [
+                0x0e, 0x21, 0x33, 0x44, 0x54, 0x63, 0x71, 0x7e, 0x8a, 0x95, 0x9f, 0xa8, 0xb0, 0xb7,
+                0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2,
+            ],
+            [
+                0x0f, 0x22, 0x34, 0x45, 0x55, 0x64, 0x72, 0x7f, 0x8b, 0x96, 0xa0, 0xa9, 0xb1, 0xb8,
+                0xbe, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+            ],
+            [
+                0x10, 0x23, 0x35, 0x46, 0x56, 0x65, 0x73, 0x80, 0x8c, 0x97, 0xa1, 0xaa, 0xb2, 0xb9,
+                0xbf, 0xc4, 0xc8, 0xc9, 0xca, 0xcb,
+            ],
+            [
+                0x11, 0x24, 0x36, 0x47, 0x57, 0x66, 0x74, 0x81, 0x8d, 0x98, 0xa2, 0xab, 0xb3, 0xba,
+                0xc0, 0xc5, 0xc9, 0xcc, 0xcd, 0xce,
+            ],
+            [
+                0x12, 0x25, 0x37, 0x48, 0x58, 0x67, 0x75, 0x82, 0x8e, 0x99, 0xa3, 0xac, 0xb4, 0xbb,
+                0xc1, 0xc6, 0xca, 0xcd, 0xcf, 0xd0,
+            ],
+            [
+                0x13, 0x26, 0x38, 0x49, 0x59, 0x68, 0x76, 0x83, 0x8f, 0x9a, 0xa4, 0xad, 0xb5, 0xbc,
+                0xc2, 0xc7, 0xcb, 0xce, 0xd0, 0xd1,
+            ],
+        ];
+
+        // Validate weights from the kernel
+        let kernel_size = 5;
+        let kernel_offset = 8;
+        let weights = &ups_factors.weights8;
+        let row_size = output[0].size().0;
+        let column_size = row_size;
+        for di in 0..8 {
+            for dj in 0..8 {
+                for ki in 0..kernel_size {
+                    for kj in 0..kernel_size {
+                        let i = kernel_size * di + ki;
+                        let j = kernel_size * dj + kj;
+                        let offset_i = kernel_offset + i;
+                        let offset_j = kernel_offset + j;
+                        // Testing symmetry
+                        let output_value = output[0].row(offset_i)[offset_j];
+                        let output_value_mirrored_right =
+                            output[0].row(row_size - offset_i - 1)[offset_j];
+                        let output_value_mirrored_down =
+                            output[0].row(row_size - offset_i - 1)[column_size - offset_j - 1];
+                        let output_value_mirrored_down_right =
+                            output[0].row(row_size - offset_i - 1)[column_size - offset_j - 1];
+
+                        assert_almost_abs_eq(output_value, output_value_mirrored_right, eps);
+                        assert_almost_abs_eq(output_value, output_value_mirrored_down, eps);
+                        assert_almost_abs_eq(output_value, output_value_mirrored_down_right, eps);
+
+                        // Testing if we get the expected weights, appropriately mapped.
+                        let mapped_i = if (i % 8) < 4 {
+                            4 - (i / 8) + (i % 4) * 5
+                        } else {
+                            i / 8 + (3 - (i % 4)) * 5
+                        };
+                        let mapped_j = if (j % 8) < 4 {
+                            4 - (j / 8) + (j % 4) * 5
+                        } else {
+                            j / 8 + (3 - (j % 4)) * 5
+                        };
+                        let weight_index = index_map[mapped_i][mapped_j];
+                        assert_almost_abs_eq(
+                            output_value,
+                            weights[weight_index].clamp(0.0, 1.0),
+                            eps,
+                        );
+                    }
+                }
+            }
+        }
+
+        Ok(())
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/xyb.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/xyb.rs
new file mode 100644
index 0000000..bd3330b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/xyb.rs
@@ -0,0 +1,368 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::api::{
+    JxlColorEncoding, JxlPrimaries, JxlTransferFunction, JxlWhitePoint, adapt_to_xyz_d50,
+    primaries_to_xyz, primaries_to_xyz_d50,
+};
+use crate::error::Result;
+use crate::headers::{FileHeader, OpsinInverseMatrix};
+use crate::render::RenderPipelineInPlaceStage;
+use crate::render::stages::from_linear;
+use crate::util::{Matrix3x3, inv_3x3_matrix, mul_3x3_matrix};
+use jxl_simd::{F32SimdVec, simd_function};
+
+const SRGB_LUMINANCES: [f32; 3] = [0.2126, 0.7152, 0.0722];
+
+#[derive(Clone)]
+pub struct OutputColorInfo {
+    // Luminance of each primary.
+    pub luminances: [f32; 3],
+    pub intensity_target: f32,
+    pub opsin: OpsinInverseMatrix,
+    pub tf: from_linear::TransferFunction,
+}
+
+#[cfg(test)]
+impl Default for OutputColorInfo {
+    fn default() -> Self {
+        use crate::headers::encodings::Empty;
+        Self {
+            luminances: SRGB_LUMINANCES,
+            intensity_target: 255.0,
+            opsin: OpsinInverseMatrix::default(&Empty {}),
+            tf: from_linear::TransferFunction::Srgb,
+        }
+    }
+}
+
+impl OutputColorInfo {
+    fn opsin_matrix_to_matrix3x3(matrix: [f32; 9]) -> Matrix3x3<f64> {
+        [
+            [matrix[0] as f64, matrix[1] as f64, matrix[2] as f64],
+            [matrix[3] as f64, matrix[4] as f64, matrix[5] as f64],
+            [matrix[6] as f64, matrix[7] as f64, matrix[8] as f64],
+        ]
+    }
+
+    fn matrix3x3_to_opsin_matrix(matrix: Matrix3x3<f64>) -> [f32; 9] {
+        [
+            matrix[0][0] as f32,
+            matrix[0][1] as f32,
+            matrix[0][2] as f32,
+            matrix[1][0] as f32,
+            matrix[1][1] as f32,
+            matrix[1][2] as f32,
+            matrix[2][0] as f32,
+            matrix[2][1] as f32,
+            matrix[2][2] as f32,
+        ]
+    }
+
+    pub fn from_header(header: &FileHeader) -> Result<Self> {
+        let srgb_output = OutputColorInfo {
+            luminances: SRGB_LUMINANCES,
+            intensity_target: header.image_metadata.tone_mapping.intensity_target,
+            opsin: header.transform_data.opsin_inverse_matrix.clone(),
+            tf: from_linear::TransferFunction::Srgb,
+        };
+        if header.image_metadata.color_encoding.want_icc {
+            return Ok(srgb_output);
+        }
+
+        let tf;
+        let mut inverse_matrix = Self::opsin_matrix_to_matrix3x3(
+            header.transform_data.opsin_inverse_matrix.inverse_matrix,
+        );
+        let mut luminances = SRGB_LUMINANCES;
+        let desired_colorspace =
+            JxlColorEncoding::from_internal(&header.image_metadata.color_encoding)?;
+        match &desired_colorspace {
+            JxlColorEncoding::XYB { .. } => {
+                return Ok(srgb_output);
+            }
+            JxlColorEncoding::RgbColorSpace {
+                white_point,
+                primaries,
+                transfer_function,
+                ..
+            } => {
+                tf = transfer_function;
+                if *primaries != JxlPrimaries::SRGB || *white_point != JxlWhitePoint::D65 {
+                    let [r, g, b] = JxlPrimaries::SRGB.to_xy_coords();
+                    let w = JxlWhitePoint::D65.to_xy_coords();
+                    let srgb_to_xyzd50 =
+                        primaries_to_xyz_d50(r.0, r.1, g.0, g.1, b.0, b.1, w.0, w.1)?;
+                    let [r, g, b] = primaries.to_xy_coords();
+                    let w = white_point.to_xy_coords();
+                    let original_to_xyz = primaries_to_xyz(r.0, r.1, g.0, g.1, b.0, b.1, w.0, w.1)?;
+                    luminances = original_to_xyz[1].map(|lum| lum as f32);
+                    let adapt_to_d50 = adapt_to_xyz_d50(w.0, w.1)?;
+                    let original_to_xyzd50 = mul_3x3_matrix(&adapt_to_d50, &original_to_xyz);
+                    let xyzd50_to_original = inv_3x3_matrix(&original_to_xyzd50)?;
+                    let srgb_to_original = mul_3x3_matrix(&xyzd50_to_original, &srgb_to_xyzd50);
+                    inverse_matrix = mul_3x3_matrix(&srgb_to_original, &inverse_matrix);
+                }
+            }
+
+            JxlColorEncoding::GrayscaleColorSpace {
+                transfer_function, ..
+            } => {
+                tf = transfer_function;
+                let f64_luminances = luminances.map(|lum| lum as f64);
+                let srgb_to_luminance: Matrix3x3<f64> =
+                    [f64_luminances, f64_luminances, f64_luminances];
+                inverse_matrix = mul_3x3_matrix(&srgb_to_luminance, &inverse_matrix);
+            }
+        }
+
+        let mut opsin = header.transform_data.opsin_inverse_matrix.clone();
+        opsin.inverse_matrix = Self::matrix3x3_to_opsin_matrix(inverse_matrix);
+        let intensity_target = header.image_metadata.tone_mapping.intensity_target;
+        let from_linear_tf = match tf {
+            JxlTransferFunction::PQ => from_linear::TransferFunction::Pq { intensity_target },
+            JxlTransferFunction::HLG => from_linear::TransferFunction::Hlg {
+                intensity_target,
+                luminance_rgb: luminances,
+            },
+            JxlTransferFunction::BT709 => from_linear::TransferFunction::Bt709,
+            JxlTransferFunction::Linear => from_linear::TransferFunction::Gamma(1.0),
+            JxlTransferFunction::SRGB => from_linear::TransferFunction::Srgb,
+            JxlTransferFunction::DCI => from_linear::TransferFunction::Gamma(2.6_f32.recip()),
+            JxlTransferFunction::Gamma(g) => from_linear::TransferFunction::Gamma(*g),
+        };
+        Ok(OutputColorInfo {
+            luminances,
+            intensity_target,
+            opsin,
+            tf: from_linear_tf,
+        })
+    }
+}
+
+/// Convert XYB to linear RGB with appropriate primaries, where 1.0 corresponds to `intensity_target` nits.
+pub struct XybStage {
+    first_channel: usize,
+    output_color_info: OutputColorInfo,
+}
+
+impl XybStage {
+    pub fn new(first_channel: usize, output_color_info: OutputColorInfo) -> Self {
+        Self {
+            first_channel,
+            output_color_info,
+        }
+    }
+}
+
+impl std::fmt::Display for XybStage {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let channel = self.first_channel;
+        write!(
+            f,
+            "XYB to linear for channel [{},{},{}]",
+            channel,
+            channel + 1,
+            channel + 2
+        )
+    }
+}
+
+simd_function!(
+    xyb_process_dispatch,
+    d: D,
+    fn xyb_process(
+        opsin: &OpsinInverseMatrix,
+        intensity_target: f32,
+        xsize: usize,
+        row_x: &mut [f32],
+        row_y: &mut [f32],
+        row_b: &mut [f32],
+    ) {
+        let OpsinInverseMatrix {
+            inverse_matrix: mat,
+            opsin_biases: bias,
+            ..
+        } = opsin;
+        // TODO(veluca): consider computing the cbrt in advance.
+        let bias_cbrt = bias.map(|x| D::F32Vec::splat(d, x.cbrt()));
+        let intensity_scale = 255.0 / intensity_target;
+        let scaled_bias = bias.map(|x| D::F32Vec::splat(d, x * intensity_scale));
+        let mat = mat.map(|x| D::F32Vec::splat(d, x));
+        let intensity_scale = D::F32Vec::splat(d, intensity_scale);
+
+        for idx in (0..xsize).step_by(D::F32Vec::LEN) {
+            let x = D::F32Vec::load(d, &row_x[idx..]);
+            let y = D::F32Vec::load(d, &row_y[idx..]);
+            let b = D::F32Vec::load(d, &row_b[idx..]);
+
+            // Mix and apply bias
+            let l = y + x - bias_cbrt[0];
+            let m = y - x - bias_cbrt[1];
+            let s = b - bias_cbrt[2];
+
+            // Apply biased inverse gamma and scale (1.0 corresponds to `intensity_target` nits)
+            let l2 = l * l;
+            let m2 = m * m;
+            let s2 = s * s;
+            let scaled_l = l * intensity_scale;
+            let scaled_m = m * intensity_scale;
+            let scaled_s = s * intensity_scale;
+            let l = l2.mul_add(scaled_l, scaled_bias[0]);
+            let m = m2.mul_add(scaled_m, scaled_bias[1]);
+            let s = s2.mul_add(scaled_s, scaled_bias[2]);
+
+            // Apply opsin inverse matrix (linear LMS to linear sRGB)
+            let r = mat[0].mul_add(l, mat[1].mul_add(m, mat[2] * s));
+            let g = mat[3].mul_add(l, mat[4].mul_add(m, mat[5] * s));
+            let b = mat[6].mul_add(l, mat[7].mul_add(m, mat[8] * s));
+            r.store(&mut row_x[idx..]);
+            g.store(&mut row_y[idx..]);
+            b.store(&mut row_b[idx..]);
+        }
+    }
+);
+
+impl RenderPipelineInPlaceStage for XybStage {
+    type Type = f32;
+
+    fn uses_channel(&self, c: usize) -> bool {
+        (self.first_channel..self.first_channel + 3).contains(&c)
+    }
+
+    fn process_row_chunk(
+        &self,
+        _position: (usize, usize),
+        xsize: usize,
+        row: &mut [&mut [f32]],
+        _state: Option<&mut dyn std::any::Any>,
+    ) {
+        let [row_x, row_y, row_b] = row else {
+            panic!(
+                "incorrect number of channels; expected 3, found {}",
+                row.len()
+            );
+        };
+
+        xyb_process_dispatch(
+            &self.output_color_info.opsin,
+            self.output_color_info.intensity_target,
+            xsize,
+            row_x,
+            row_y,
+            row_b,
+        );
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use test_log::test;
+
+    use super::*;
+    use crate::error::Result;
+    use crate::headers::encodings::Empty;
+    use crate::image::Image;
+    use crate::render::test::make_and_run_simple_pipeline;
+    use crate::util::round_up_size_to_cache_line;
+    use crate::util::test::assert_all_almost_abs_eq;
+    use jxl_simd::{ScalarDescriptor, SimdDescriptor, test_all_instruction_sets};
+
+    #[test]
+    fn consistency() -> Result<()> {
+        crate::render::test::test_stage_consistency(
+            || XybStage::new(0, OutputColorInfo::default()),
+            (500, 500),
+            3,
+        )
+    }
+
+    #[test]
+    fn srgb_primaries() -> Result<()> {
+        let mut input_x = Image::new((3, 1))?;
+        let mut input_y = Image::new((3, 1))?;
+        let mut input_b = Image::new((3, 1))?;
+        input_x
+            .row_mut(0)
+            .copy_from_slice(&[0.028100073, -0.015386105, 0.0]);
+        input_y
+            .row_mut(0)
+            .copy_from_slice(&[0.4881882, 0.71478134, 0.2781282]);
+        input_b
+            .row_mut(0)
+            .copy_from_slice(&[0.471659, 0.43707693, 0.66613984]);
+
+        let stage = XybStage::new(0, OutputColorInfo::default());
+        let output =
+            make_and_run_simple_pipeline(stage, &[input_x, input_y, input_b], (3, 1), 0, 256)?;
+
+        assert_all_almost_abs_eq(output[0].row(0), &[1.0, 0.0, 0.0], 1e-6);
+        assert_all_almost_abs_eq(output[1].row(0), &[0.0, 1.0, 0.0], 1e-6);
+        assert_all_almost_abs_eq(output[2].row(0), &[0.0, 0.0, 1.0], 1e-6);
+
+        Ok(())
+    }
+
+    fn xyb_process_scalar_equivalent<D: SimdDescriptor>(d: D) {
+        let opsin = OpsinInverseMatrix::default(&Empty {});
+        arbtest::arbtest(|u| {
+            let xsize = u.arbitrary_len::<usize>()?;
+            let intensity_target = u.arbitrary::<u8>()? as f32 * 2.0 + 1.0;
+            let mut row_x = vec![0.0; round_up_size_to_cache_line::<f32>(xsize)];
+            let mut row_y = vec![0.0; round_up_size_to_cache_line::<f32>(xsize)];
+            let mut row_b = vec![0.0; round_up_size_to_cache_line::<f32>(xsize)];
+
+            for i in 0..xsize {
+                row_x[i] = u.arbitrary::<i16>()? as f32 * (0.07 / i16::MAX as f32);
+                row_y[i] = u.arbitrary::<u16>()? as f32 * (1.0 / u16::MAX as f32);
+                row_b[i] = u.arbitrary::<u16>()? as f32 * (1.0 / u16::MAX as f32);
+            }
+
+            let mut scalar_x = row_x.clone();
+            let mut scalar_y = row_y.clone();
+            let mut scalar_b = row_b.clone();
+
+            xyb_process(
+                d,
+                &opsin,
+                intensity_target,
+                xsize,
+                &mut row_x,
+                &mut row_y,
+                &mut row_b,
+            );
+
+            xyb_process(
+                ScalarDescriptor::new().unwrap(),
+                &opsin,
+                intensity_target,
+                xsize,
+                &mut scalar_x,
+                &mut scalar_y,
+                &mut scalar_b,
+            );
+
+            for i in 0..xsize {
+                for (simd, scalar) in [
+                    (row_x[i], scalar_x[i]),
+                    (row_y[i], scalar_y[i]),
+                    (row_b[i], scalar_b[i]),
+                ] {
+                    let abs = (simd - scalar).abs();
+                    let max = simd.abs().max(scalar.abs());
+                    let rel = abs / max;
+                    assert!(
+                        abs < 1e-3 || rel < 1e-3,
+                        "simd {simd}, scalar {scalar}, abs {abs:?} rel {rel:?}",
+                    );
+                }
+            }
+
+            Ok(())
+        });
+    }
+
+    test_all_instruction_sets!(xyb_process_scalar_equivalent);
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/ycbcr.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/ycbcr.rs
new file mode 100644
index 0000000..7156572
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/ycbcr.rs
@@ -0,0 +1,112 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::render::RenderPipelineInPlaceStage;
+
+/// Convert YCbCr to RGB
+pub struct YcbcrToRgbStage {
+    first_channel: usize,
+}
+
+impl YcbcrToRgbStage {
+    pub fn new(first_channel: usize) -> Self {
+        Self { first_channel }
+    }
+}
+
+impl std::fmt::Display for YcbcrToRgbStage {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let channel = self.first_channel;
+        write!(
+            f,
+            "YCbCr to RGB for channel [{},{},{}]",
+            channel,
+            channel + 1,
+            channel + 2
+        )
+    }
+}
+
+impl RenderPipelineInPlaceStage for YcbcrToRgbStage {
+    type Type = f32;
+
+    fn uses_channel(&self, c: usize) -> bool {
+        (self.first_channel..self.first_channel + 3).contains(&c)
+    }
+
+    fn process_row_chunk(
+        &self,
+        _position: (usize, usize),
+        xsize: usize,
+        row: &mut [&mut [f32]],
+        _state: Option<&mut dyn std::any::Any>,
+    ) {
+        // pixels are stored in `Cb Y Cr` order to mimic XYB colorspace
+        let [row_cb, row_y, row_cr] = row else {
+            panic!(
+                "incorrect number of channels; expected 3, found {}",
+                row.len()
+            );
+        };
+
+        assert!(xsize <= row_cb.len() && xsize <= row_y.len() && xsize <= row_cr.len());
+        for idx in 0..xsize {
+            let y = row_y[idx] + 128.0 / 255.0; // shift Y from [-0.5, 0.5] to [0, 1], matching JPEG spec
+            let cb = row_cb[idx];
+            let cr = row_cr[idx];
+
+            // Full-range BT.601 as defined by JFIF Clause 7:
+            // https://www.itu.int/rec/T-REC-T.871-201105-I/en
+            row_cb[idx] = cr.mul_add(1.402, y);
+            row_y[idx] = cr.mul_add(
+                -0.299 * 1.402 / 0.587,
+                cb.mul_add(-0.114 * 1.772 / 0.587, y),
+            );
+            row_cr[idx] = cb.mul_add(1.772, y);
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use test_log::test;
+
+    use super::*;
+    use crate::error::Result;
+    use crate::image::Image;
+    use crate::render::test::make_and_run_simple_pipeline;
+    use crate::util::test::assert_all_almost_abs_eq;
+
+    #[test]
+    fn consistency() -> Result<()> {
+        crate::render::test::test_stage_consistency(|| YcbcrToRgbStage::new(0), (500, 500), 3)
+    }
+
+    #[test]
+    fn srgb_primaries() -> Result<()> {
+        let mut input_y = Image::new((3, 1))?;
+        let mut input_cb = Image::new((3, 1))?;
+        let mut input_cr = Image::new((3, 1))?;
+        input_y
+            .row_mut(0)
+            .copy_from_slice(&[-0.20296079, 0.08503921, -0.3879608]);
+        input_cb
+            .row_mut(0)
+            .copy_from_slice(&[-0.16873589, -0.3312641, 0.5]);
+        input_cr
+            .row_mut(0)
+            .copy_from_slice(&[0.5, -0.41868758, -0.08131241]);
+
+        let stage = YcbcrToRgbStage::new(0);
+        let output =
+            make_and_run_simple_pipeline(stage, &[input_cb, input_y, input_cr], (3, 1), 0, 256)?;
+
+        assert_all_almost_abs_eq(output[0].row(0), &[1.0, 0.0, 0.0], 1e-6);
+        assert_all_almost_abs_eq(output[1].row(0), &[0.0, 1.0, 0.0], 1e-6);
+        assert_all_almost_abs_eq(output[2].row(0), &[0.0, 0.0, 1.0], 1e-6);
+
+        Ok(())
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/test.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/test.rs
new file mode 100644
index 0000000..cc51a91
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/test.rs
@@ -0,0 +1,241 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{
+    api::{Endianness, JxlColorType, JxlDataFormat, JxlOutputBuffer},
+    error::Result,
+    headers::Orientation,
+    image::{DataTypeTag, Image, ImageDataType, Rect},
+    render::{SimpleRenderPipeline, buffer_splitter::BufferSplitter},
+    util::{
+        ShiftRightCeil,
+        test::check_equal_images,
+        tracing_wrappers::{instrument, trace},
+    },
+};
+use rand::SeedableRng;
+
+use super::{
+    RenderPipeline, RenderPipelineBuilder, RenderPipelineInOutStage, RenderPipelineInPlaceStage,
+    internal::Stage, stages::ExtendToImageDimensionsStage,
+};
+
+pub(super) trait RenderPipelineTestableStage<V> {
+    type InputT: ImageDataType;
+    type OutputT: ImageDataType;
+    fn into_stage(self) -> Stage<Image<f64>>;
+}
+
+impl RenderPipelineTestableStage<()> for ExtendToImageDimensionsStage {
+    type InputT = f32;
+    type OutputT = f32;
+    fn into_stage(self) -> Stage<Image<f64>> {
+        Stage::Extend(self)
+    }
+}
+
+impl<T: RenderPipelineInOutStage> RenderPipelineTestableStage<()> for T {
+    type InputT = T::InputT;
+    type OutputT = T::OutputT;
+    fn into_stage(self) -> Stage<Image<f64>> {
+        Stage::InOut(Box::new(self))
+    }
+}
+
+pub(super) struct Empty {}
+
+impl<T: RenderPipelineInPlaceStage> RenderPipelineTestableStage<Empty> for T {
+    type InputT = T::Type;
+    type OutputT = T::Type;
+    fn into_stage(self) -> Stage<Image<f64>> {
+        Stage::InPlace(Box::new(self))
+    }
+}
+
+fn extract_group_rect<T: ImageDataType>(
+    image: &Image<T>,
+    group_id: usize,
+    log_group_size: (usize, usize),
+) -> Result<Image<T>> {
+    let xgroups = image.size().0.shrc(log_group_size.0);
+    let group = (group_id % xgroups, group_id / xgroups);
+    let origin = (group.0 << log_group_size.0, group.1 << log_group_size.1);
+    let size = (
+        (image.size().0 - origin.0).min(1 << log_group_size.0),
+        (image.size().1 - origin.1).min(1 << log_group_size.1),
+    );
+    trace!(
+        "making rect {}x{}+{}+{} for group {group_id} in image of size {:?}, log group sizes {:?}",
+        size.0,
+        size.1,
+        origin.0,
+        origin.1,
+        image.size(),
+        log_group_size
+    );
+    let rect = image.get_rect(Rect { origin, size });
+    let mut out = Image::new(rect.size()).unwrap();
+    for y in 0..out.size().1 {
+        out.row_mut(y).copy_from_slice(rect.row(y));
+    }
+    Ok(out)
+}
+
+fn make_and_run_simple_pipeline_impl<InputT: ImageDataType, OutputT: ImageDataType>(
+    stage: Stage<Image<f64>>,
+    input_images: &[Image<InputT>],
+    image_size: (usize, usize),
+    downsampling_shift: usize,
+    chunk_size: usize,
+) -> Result<Vec<Image<OutputT>>> {
+    let shift = stage.shift();
+    let final_size = stage.new_size(image_size);
+    const LOG_GROUP_SIZE: usize = 8;
+    let all_channels = (0..input_images.len()).collect::<Vec<_>>();
+    let uses_channel: Vec<_> = all_channels
+        .iter()
+        .map(|x| stage.uses_channel(*x))
+        .collect();
+    let mut pipeline = RenderPipelineBuilder::<SimpleRenderPipeline>::new_with_chunk_size(
+        input_images.len(),
+        image_size,
+        downsampling_shift,
+        LOG_GROUP_SIZE,
+        1,
+        chunk_size,
+    )
+    .add_stage_internal(stage)?;
+
+    let jxl_data_type = match OutputT::DATA_TYPE_ID {
+        DataTypeTag::U8 | DataTypeTag::I8 => JxlDataFormat::U8 { bit_depth: 8 },
+        DataTypeTag::U16 | DataTypeTag::I16 => JxlDataFormat::U16 {
+            bit_depth: 16,
+            endianness: Endianness::native(),
+        },
+        DataTypeTag::F32 => JxlDataFormat::f32(),
+        DataTypeTag::F16 => JxlDataFormat::F16 {
+            endianness: Endianness::native(),
+        },
+        _ => unimplemented!("unsupported data type"),
+    };
+
+    for i in 0..input_images.len() {
+        pipeline = pipeline.add_save_stage(
+            &[i],
+            Orientation::Identity,
+            i,
+            JxlColorType::Grayscale,
+            jxl_data_type,
+        )?;
+    }
+    let mut pipeline = pipeline.build()?;
+
+    let num_groups = image_size.0.shrc(LOG_GROUP_SIZE) * image_size.1.shrc(LOG_GROUP_SIZE);
+
+    let mut outputs = (0..input_images.len())
+        .map(|_| Image::<OutputT>::new(final_size))
+        .collect::<Result<Vec<_>, _>>()?;
+
+    let mut buf_ptrs: Vec<_> = outputs
+        .iter_mut()
+        .map(|x| {
+            let size = x.size();
+            Some(JxlOutputBuffer::from_image_rect_mut(
+                x.get_rect_mut(Rect {
+                    size,
+                    origin: (0, 0),
+                })
+                .into_raw(),
+            ))
+        })
+        .collect();
+
+    let mut buffer_splitter = BufferSplitter::new(&mut buf_ptrs);
+
+    for g in 0..num_groups {
+        for &c in all_channels.iter() {
+            let log_group_size = if uses_channel[c] {
+                (
+                    LOG_GROUP_SIZE - shift.0 as usize,
+                    LOG_GROUP_SIZE - shift.1 as usize,
+                )
+            } else {
+                (LOG_GROUP_SIZE, LOG_GROUP_SIZE)
+            };
+            pipeline.set_buffer_for_group(
+                c,
+                g,
+                1,
+                extract_group_rect(&input_images[c], g, log_group_size)?,
+                &mut buffer_splitter,
+            )?;
+        }
+    }
+
+    Ok(outputs)
+}
+
+pub(super) fn make_and_run_simple_pipeline<S: RenderPipelineTestableStage<V>, V>(
+    stage: S,
+    input_images: &[Image<S::InputT>],
+    image_size: (usize, usize),
+    downsampling_shift: usize,
+    chunk_size: usize,
+) -> Result<Vec<Image<S::OutputT>>> {
+    make_and_run_simple_pipeline_impl(
+        stage.into_stage(),
+        input_images,
+        image_size,
+        downsampling_shift,
+        chunk_size,
+    )
+}
+
+#[instrument(skip(make_stage), err)]
+pub(super) fn test_stage_consistency<S: RenderPipelineTestableStage<V>, V>(
+    make_stage: impl Fn() -> S,
+    image_size: (usize, usize),
+    num_image_channels: usize,
+) -> Result<()> {
+    let mut rng = rand_xorshift::XorShiftRng::seed_from_u64(0);
+    let stage = make_stage().into_stage();
+    let images: Result<Vec<_>> = (0..num_image_channels)
+        .map(|c| {
+            let size = if stage.uses_channel(c) {
+                (
+                    image_size.0.shrc(stage.shift().0),
+                    image_size.1.shrc(stage.shift().1),
+                )
+            } else {
+                image_size
+            };
+            Image::new_random(size, &mut rng)
+        })
+        .collect();
+    let images = images?;
+
+    let base_output = make_and_run_simple_pipeline_impl::<S::InputT, S::OutputT>(
+        stage, &images, image_size, 0, 256,
+    )?;
+
+    arbtest::arbtest(move |p| {
+        let chunk_size = p.arbitrary::<u16>()?.saturating_add(1) as usize;
+        let output = make_and_run_simple_pipeline_impl::<S::InputT, S::OutputT>(
+            make_stage().into_stage(),
+            &images,
+            image_size,
+            0,
+            chunk_size,
+        )
+        .unwrap_or_else(|_| panic!("error running pipeline with chunk size {chunk_size}"));
+
+        for (o, bo) in output.iter().zip(base_output.iter()) {
+            check_equal_images(bo, o);
+        }
+
+        Ok(())
+    });
+    Ok(())
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/bits.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/bits.rs
new file mode 100644
index 0000000..fe578ea8
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/bits.rs
@@ -0,0 +1,23 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+pub fn value_of_lowest_1_bit(t: u32) -> u32 {
+    t & t.wrapping_neg()
+}
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn test_value_of_lowest_1_bit() {
+        assert_eq!(value_of_lowest_1_bit(0b0001), 1);
+        assert_eq!(value_of_lowest_1_bit(0b1111), 1);
+        assert_eq!(value_of_lowest_1_bit(0b0010), 2);
+        assert_eq!(value_of_lowest_1_bit(0b0100), 4);
+        assert_eq!(value_of_lowest_1_bit(0b1010), 2);
+        assert_eq!(value_of_lowest_1_bit(0b1000_0000), 128);
+        assert_eq!(value_of_lowest_1_bit(0), 0);
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/cacheline.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/cacheline.rs
new file mode 100644
index 0000000..3eb490d
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/cacheline.rs
@@ -0,0 +1,67 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(unsafe_code)]
+
+use crate::image::ImageDataType;
+
+pub const CACHE_LINE_BYTE_SIZE: usize = 64;
+
+pub const fn num_per_cache_line<T>() -> usize {
+    // Post-mono check that T is smaller than a cache line and has size a power of 2.
+    // This prevents some of the silliest mistakes.
+    const {
+        assert!(std::mem::size_of::<T>() <= CACHE_LINE_BYTE_SIZE);
+        assert!(std::mem::size_of::<T>().is_power_of_two());
+    }
+    CACHE_LINE_BYTE_SIZE / std::mem::size_of::<T>()
+}
+
+pub fn round_up_size_to_cache_line<T>(size: usize) -> usize {
+    let n = const { num_per_cache_line::<T>() };
+    size.div_ceil(n) * n
+}
+
+#[derive(Clone)]
+#[repr(C, align(64))]
+pub struct CacheLine([u8; CACHE_LINE_BYTE_SIZE]);
+
+impl Default for CacheLine {
+    fn default() -> Self {
+        CacheLine([0; CACHE_LINE_BYTE_SIZE])
+    }
+}
+
+pub fn slice_from_cachelines<T: ImageDataType>(slice: &[CacheLine]) -> &[T] {
+    const { assert!(64usize.is_multiple_of(std::mem::align_of::<T>())) };
+    const { assert!(CACHE_LINE_BYTE_SIZE.is_multiple_of(std::mem::size_of::<T>())) };
+    const { assert!(CACHE_LINE_BYTE_SIZE == 64) };
+    // SAFETY: CacheLine is 64 bytes with no padding, with higher alignment requirements than T.
+    // T is guaranteed to be a bag-of-bits type by the safety requirements of ImageDataType.
+    // The other safety requirements follow from the data pointer and length being obtained from a
+    // slice.
+    unsafe {
+        std::slice::from_raw_parts(
+            slice.as_ptr() as *const T,
+            slice.len() * (CACHE_LINE_BYTE_SIZE / std::mem::size_of::<T>()),
+        )
+    }
+}
+
+pub fn slice_from_cachelines_mut<T: ImageDataType>(slice: &mut [CacheLine]) -> &mut [T] {
+    const { assert!(64usize.is_multiple_of(std::mem::align_of::<T>())) };
+    const { assert!(CACHE_LINE_BYTE_SIZE.is_multiple_of(std::mem::size_of::<T>())) };
+    const { assert!(CACHE_LINE_BYTE_SIZE == 64) };
+    // SAFETY: CacheLine is 64 bytes with no padding, with higher alignment requirements than T.
+    // T is guaranteed to be a bag-of-bits type by the safety requirements of ImageDataType.
+    // The other safety requirements follow from the data pointer and length being obtained from a
+    // slice.
+    unsafe {
+        std::slice::from_raw_parts_mut(
+            slice.as_ptr() as *mut T,
+            slice.len() * (CACHE_LINE_BYTE_SIZE / std::mem::size_of::<T>()),
+        )
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/concat_slice.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/concat_slice.rs
new file mode 100644
index 0000000..39f016d
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/concat_slice.rs
@@ -0,0 +1,123 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::error::Error;
+
+pub struct ConcatSlice<'first, 'second> {
+    slices: (&'first [u8], &'second [u8]),
+    ptr: usize,
+}
+
+impl<'first, 'second> ConcatSlice<'first, 'second> {
+    pub fn new(slice0: &'first [u8], slice1: &'second [u8]) -> Self {
+        Self {
+            slices: (slice0, slice1),
+            ptr: 0,
+        }
+    }
+
+    #[allow(clippy::len_without_is_empty)]
+    pub fn len(&self) -> usize {
+        self.slices.0.len() + self.slices.1.len()
+    }
+
+    pub fn remaining_slices(&self) -> (&'first [u8], &'second [u8]) {
+        let (slice0, slice1) = self.slices;
+        let total_len = self.len();
+        let ptr = self.ptr;
+        if ptr >= total_len {
+            (&[], &[])
+        } else if let Some(second_slice_ptr) = ptr.checked_sub(slice0.len()) {
+            (&[], &slice1[second_slice_ptr..])
+        } else {
+            (&slice0[ptr..], slice1)
+        }
+    }
+
+    pub fn advance(&mut self, bytes: usize) {
+        self.ptr += bytes;
+    }
+
+    pub fn peek<'out>(&self, out_buf: &'out mut [u8]) -> &'out mut [u8] {
+        let (slice0, slice1) = self.remaining_slices();
+        let total_len = slice0.len() + slice1.len();
+
+        let out_bytes = out_buf.len().min(total_len);
+        let out_buf = &mut out_buf[..out_bytes];
+
+        if out_bytes <= slice0.len() {
+            out_buf.copy_from_slice(&slice0[..out_bytes]);
+        } else {
+            let (out_first, out_second) = out_buf.split_at_mut(slice0.len());
+            out_first.copy_from_slice(slice0);
+            out_second.copy_from_slice(&slice1[..out_second.len()]);
+        }
+
+        out_buf
+    }
+
+    pub fn fill_vec(&mut self, max_bytes: Option<usize>, v: &mut Vec<u8>) -> Result<usize, Error> {
+        let (slice0, slice1) = self.remaining_slices();
+        let total_len = slice0.len() + slice1.len();
+
+        let out_bytes = max_bytes.unwrap_or(usize::MAX).min(total_len);
+        v.try_reserve(out_bytes)?;
+
+        if out_bytes <= slice0.len() {
+            v.extend_from_slice(&slice0[..out_bytes]);
+        } else {
+            let second_slice_len = out_bytes - slice0.len();
+            v.extend_from_slice(slice0);
+            v.extend_from_slice(&slice1[..second_slice_len]);
+        }
+
+        self.advance(out_bytes);
+        Ok(out_bytes)
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn peek_advance() {
+        let mut reader = ConcatSlice::new(&[0, 1, 2, 3], &[4, 5, 6, 7]);
+        let mut buf = [0u8; 8];
+
+        let actual = reader.peek(&mut buf[..1]);
+        assert_eq!(actual, &[0]);
+        reader.advance(actual.len());
+
+        let actual = reader.peek(&mut buf[..2]);
+        assert_eq!(actual, &[1, 2]);
+        reader.advance(actual.len());
+
+        let actual = reader.peek(&mut buf[..3]);
+        assert_eq!(actual, &[3, 4, 5]);
+        reader.advance(actual.len());
+
+        let actual = reader.peek(&mut buf);
+        assert_eq!(actual, &[6, 7]);
+        reader.advance(actual.len());
+
+        let actual = reader.peek(&mut buf);
+        assert!(actual.is_empty());
+    }
+
+    #[test]
+    fn fill_vec() {
+        let mut reader = ConcatSlice::new(&[0, 1, 2, 3], &[4, 5, 6, 7]);
+        let mut v = Vec::new();
+
+        let count = reader.fill_vec(Some(3), &mut v).unwrap();
+        assert_eq!(count, 3);
+        assert_eq!(&v, &[0, 1, 2]);
+
+        let count = reader.fill_vec(None, &mut v).unwrap();
+        assert_eq!(count, 5);
+        assert_eq!(&v, &[0, 1, 2, 3, 4, 5, 6, 7]);
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/fast_math.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/fast_math.rs
new file mode 100644
index 0000000..35a5131
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/fast_math.rs
@@ -0,0 +1,227 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(clippy::excessive_precision)]
+
+use super::{eval_rational_poly, eval_rational_poly_simd};
+use jxl_simd::{F32SimdVec, I32SimdVec, SimdDescriptor, shl, shr};
+use std::f32::consts::{PI, SQRT_2};
+
+const POW2F_NUMER_COEFFS: [f32; 3] = [1.01749063e1, 4.88687798e1, 9.85506591e1];
+const POW2F_DENOM_COEFFS: [f32; 4] = [2.10242958e-1, -2.22328856e-2, -1.94414990e1, 9.85506633e1];
+
+#[inline]
+pub fn fast_cos(x: f32) -> f32 {
+    // Step 1: range reduction to [0, 2pi)
+    let pi2 = PI * 2.0;
+    let pi2_inv = 0.5 / PI;
+    let npi2 = (x * pi2_inv).floor() * pi2;
+    let xmodpi2 = x - npi2;
+    // Step 2: range reduction to [0, pi]
+    let x_pi = xmodpi2.min(pi2 - xmodpi2);
+    // Step 3: range reduction to [0, pi/2]
+    let above_pihalf = x_pi >= PI / 2.0;
+    let x_pihalf = if above_pihalf { PI - x_pi } else { x_pi };
+    // Step 4: Taylor-like approximation, scaled by 2**0.75 to make angle
+    // duplication steps faster, on x/4.
+    let xs = x_pihalf * 0.25;
+    let x2 = xs * xs;
+    let x4 = x2 * x2;
+    let cosx_prescaling = x4 * 0.06960438 + (x2 * -0.84087373 + 1.68179268);
+    // Step 5: angle duplication.
+    let cosx_scale1 = cosx_prescaling * cosx_prescaling - SQRT_2;
+    let cosx_scale2 = cosx_scale1 * cosx_scale1 - 1.0;
+    // Step 6: change sign if needed.
+    if above_pihalf {
+        -cosx_scale2
+    } else {
+        cosx_scale2
+    }
+}
+
+#[inline]
+pub fn fast_erff(x: f32) -> f32 {
+    // Formula from
+    // https://en.wikipedia.org/wiki/Error_function#Numerical_approximations
+    // but constants have been recomputed.
+    let absx = x.abs();
+    // Compute 1 - 1 / ((((x * a + b) * x + c) * x + d) * x + 1)**4
+    let denom1 = absx * 7.77394369e-02 + 2.05260015e-04;
+    let denom2 = denom1 * absx + 2.32120216e-01;
+    let denom3 = denom2 * absx + 2.77820801e-01;
+    let denom4 = denom3 * absx + 1.0;
+    let denom5 = denom4 * denom4;
+    let inv_denom5 = 1.0 / denom5;
+    let result = -inv_denom5 * inv_denom5 + 1.0;
+    result.copysign(x)
+}
+
+#[inline]
+pub fn fast_pow2f(x: f32) -> f32 {
+    let x_floor = x.floor();
+    let exp = f32::from_bits(((x_floor as i32 + 127) as u32) << 23);
+    let frac = x - x_floor;
+
+    let num = frac + POW2F_NUMER_COEFFS[0];
+    let num = num * frac + POW2F_NUMER_COEFFS[1];
+    let num = num * frac + POW2F_NUMER_COEFFS[2];
+    let num = num * exp;
+
+    let den = POW2F_DENOM_COEFFS[0] * frac + POW2F_DENOM_COEFFS[1];
+    let den = den * frac + POW2F_DENOM_COEFFS[2];
+    let den = den * frac + POW2F_DENOM_COEFFS[3];
+
+    num / den
+}
+
+#[inline(always)]
+pub fn fast_pow2f_simd<D: SimdDescriptor>(d: D, x: D::F32Vec) -> D::F32Vec {
+    let x_floor = x.floor();
+    let exp = shl!(x_floor.as_i32() + D::I32Vec::splat(d, 127), 23).bitcast_to_f32();
+    let frac = x - x_floor;
+
+    let num = frac + D::F32Vec::splat(d, POW2F_NUMER_COEFFS[0]);
+    let num = num.mul_add(frac, D::F32Vec::splat(d, POW2F_NUMER_COEFFS[1]));
+    let num = num.mul_add(frac, D::F32Vec::splat(d, POW2F_NUMER_COEFFS[2]));
+    let num = num * exp;
+
+    let den = D::F32Vec::splat(d, POW2F_DENOM_COEFFS[0])
+        .mul_add(frac, D::F32Vec::splat(d, POW2F_DENOM_COEFFS[1]));
+    let den = den.mul_add(frac, D::F32Vec::splat(d, POW2F_DENOM_COEFFS[2]));
+    let den = den.mul_add(frac, D::F32Vec::splat(d, POW2F_DENOM_COEFFS[3]));
+
+    num / den
+}
+
+const LOG2F_P: [f32; 3] = [
+    -1.8503833400518310e-6,
+    1.4287160470083755,
+    7.4245873327820566e-1,
+];
+const LOG2F_Q: [f32; 3] = [
+    9.9032814277590719e-1,
+    1.0096718572241148,
+    1.7409343003366853e-1,
+];
+
+#[inline]
+pub fn fast_log2f(x: f32) -> f32 {
+    let x_bits = x.to_bits() as i32;
+    let exp_bits = x_bits.wrapping_sub(0x3f2aaaab);
+    let exp_shifted = exp_bits >> 23;
+    let mantissa = f32::from_bits((x_bits.wrapping_sub(exp_shifted << 23)) as u32);
+    let exp_val = exp_shifted as f32;
+
+    let x = mantissa - 1.0;
+    eval_rational_poly(x, LOG2F_P, LOG2F_Q) + exp_val
+}
+
+#[inline(always)]
+pub fn fast_log2f_simd<D: SimdDescriptor>(d: D, x: D::F32Vec) -> D::F32Vec {
+    let x_bits = x.bitcast_to_i32();
+    let exp_bits = x_bits - D::I32Vec::splat(d, 0x3f2aaaab);
+    let exp_shifted = shr!(exp_bits, 23);
+    let mantissa = (x_bits - shl!(exp_shifted, 23)).bitcast_to_f32();
+    let exp_val = exp_shifted.as_f32();
+
+    let x = mantissa - D::F32Vec::splat(d, 1.0);
+    eval_rational_poly_simd(d, x, LOG2F_P, LOG2F_Q) + exp_val
+}
+
+// Max relative error: ~3e-5
+#[inline]
+pub fn fast_powf(base: f32, exp: f32) -> f32 {
+    fast_pow2f(fast_log2f(base) * exp)
+}
+
+#[inline]
+pub fn fast_powf_simd<D: SimdDescriptor>(d: D, base: D::F32Vec, exp: D::F32Vec) -> D::F32Vec {
+    fast_pow2f_simd(d, fast_log2f_simd(d, base) * exp)
+}
+
+pub fn floor_log2_nonzero<T: num_traits::Unsigned + num_traits::PrimInt>(x: T) -> u32 {
+    (size_of::<T>() * 8 - 1) as u32 ^ x.leading_zeros()
+}
+
+#[cfg(test)]
+mod test {
+    use test_log::test;
+
+    use crate::util::test::assert_almost_abs_eq;
+
+    use super::*;
+
+    #[test]
+    fn test_fast_erff() {
+        // Golden data copied from https://en.wikipedia.org/wiki/Error_function#Table_of_values.
+        let golden = [
+            (0.0, 0.0),
+            (0.02, 0.022564575),
+            (0.04, 0.045111106),
+            (0.06, 0.067621594),
+            (0.08, 0.090078126),
+            (0.1, 0.112462916),
+            (0.2, 0.222702589),
+            (0.3, 0.328626759),
+            (0.4, 0.428392355),
+            (0.5, 0.520499878),
+            (0.6, 0.603856091),
+            (0.7, 0.677801194),
+            (0.8, 0.742100965),
+            (0.9, 0.796908212),
+            (1.0, 0.842700793),
+            (1.1, 0.880205070),
+            (1.2, 0.910313978),
+            (1.3, 0.934007945),
+            (1.4, 0.952285120),
+            (1.5, 0.966105146),
+            (1.6, 0.976348383),
+            (1.7, 0.983790459),
+            (1.8, 0.989090502),
+            (1.9, 0.992790429),
+            (2.0, 0.995322265),
+            (2.1, 0.997020533),
+            (2.2, 0.998137154),
+            (2.3, 0.998856823),
+            (2.4, 0.999311486),
+            (2.5, 0.999593048),
+            (3.0, 0.999977910),
+            (3.5, 0.999999257),
+        ];
+        for (x, erf_x) in golden {
+            assert_almost_abs_eq(fast_erff(x), erf_x, 6e-4);
+            assert_almost_abs_eq(fast_erff(-x), -erf_x, 6e-4);
+        }
+    }
+
+    #[test]
+    fn test_fast_cos() {
+        for i in 0..100 {
+            let x = i as f32 / 100.0 * (5.0 * PI) - (2.5 * PI);
+            assert_almost_abs_eq(fast_cos(x), x.cos(), 1e-4);
+        }
+    }
+
+    #[test]
+    fn fast_powf_arb() {
+        arbtest::arbtest(|u| {
+            // (0.0, 128.0]
+            let base = u.int_in_range(1..=1 << 24)? as f32 / (1 << 17) as f32;
+            // [-4.0, 4.0]
+            let exp = u.int_in_range(-(1i32 << 22)..=1 << 22)? as f32 / (1 << 20) as f32;
+
+            let expected = base.powf(exp);
+            let actual = fast_powf(base, exp);
+            let abs_error = (actual - expected).abs();
+            let rel_error = abs_error / expected;
+            assert!(
+                rel_error < 3e-5,
+                "base: {base}, exp: {exp}, rel_error: {rel_error}, expected: {expected}, \
+		 actual: {actual}",
+            );
+            Ok(())
+        });
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/float16.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/float16.rs
new file mode 100644
index 0000000..711c37c
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/float16.rs
@@ -0,0 +1,311 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//! IEEE 754 half-precision (binary16) floating-point type.
+//!
+//! This is a minimal implementation providing only the operations needed for JPEG XL decoding,
+//! avoiding external dependencies like `half` which pulls in `zerocopy`.
+
+/// IEEE 754 binary16 half-precision floating-point type.
+///
+/// Format: 1 sign bit, 5 exponent bits (bias 15), 10 mantissa bits.
+#[allow(non_camel_case_types)]
+#[derive(Copy, Clone, Default, PartialEq, Eq, Hash)]
+#[repr(transparent)]
+pub struct f16(u16);
+
+impl f16 {
+    /// Positive zero.
+    pub const ZERO: Self = Self(0);
+
+    /// Creates an f16 from its raw bit representation.
+    #[inline]
+    pub const fn from_bits(bits: u16) -> Self {
+        Self(bits)
+    }
+
+    /// Returns the raw bit representation.
+    #[inline]
+    pub const fn to_bits(self) -> u16 {
+        self.0
+    }
+
+    /// Converts to f32.
+    #[inline]
+    pub fn to_f32(self) -> f32 {
+        let bits = self.0;
+        let sign = ((bits >> 15) & 1) as u32;
+        let exp = ((bits >> 10) & 0x1F) as u32;
+        let mant = (bits & 0x3FF) as u32;
+
+        let f32_bits = if exp == 0 {
+            if mant == 0 {
+                // Zero (signed)
+                sign << 31
+            } else {
+                // Denormal f16 -> normalized f32
+                // Find the leading 1 bit in mantissa
+                let mut m = mant;
+                let mut e = 0u32;
+                while (m & 0x400) == 0 {
+                    m <<= 1;
+                    e += 1;
+                }
+                m &= 0x3FF; // Remove the implicit leading 1
+                let new_exp = 127 - 15 - e; // Rebias: f16 bias=15, f32 bias=127
+                (sign << 31) | (new_exp << 23) | (m << 13)
+            }
+        } else if exp == 31 {
+            // Infinity or NaN
+            if mant == 0 {
+                // Infinity
+                (sign << 31) | (0xFF << 23)
+            } else {
+                // NaN - preserve some payload bits, ensure quiet NaN
+                (sign << 31) | (0xFF << 23) | (mant << 13) | 0x0040_0000
+            }
+        } else {
+            // Normal number
+            // Rebias: f16 uses bias 15, f32 uses bias 127
+            // new_exp = exp - 15 + 127 = exp + 112
+            let new_exp = exp + 112;
+            (sign << 31) | (new_exp << 23) | (mant << 13)
+        };
+
+        f32::from_bits(f32_bits)
+    }
+
+    /// Creates an f16 from an f32.
+    #[inline]
+    pub fn from_f32(f: f32) -> Self {
+        let bits = f.to_bits();
+        let sign = ((bits >> 31) & 1) as u16;
+        let exp = ((bits >> 23) & 0xFF) as i32;
+        let mant = bits & 0x007F_FFFF;
+
+        let h_bits = if exp == 0 {
+            // Zero or f32 denormal -> f16 zero (too small)
+            sign << 15
+        } else if exp == 255 {
+            // Infinity or NaN
+            if mant == 0 {
+                (sign << 15) | (0x1F << 10) // Infinity
+            } else {
+                (sign << 15) | (0x1F << 10) | 0x0200 // Quiet NaN
+            }
+        } else {
+            let unbiased = exp - 127;
+
+            if unbiased < -24 {
+                // Too small, underflow to zero
+                sign << 15
+            } else if unbiased < -14 {
+                // Denormal f16
+                let shift = (-14 - unbiased) as u32;
+                let m = ((mant | 0x0080_0000) >> (shift + 14)) as u16;
+                (sign << 15) | m
+            } else if unbiased > 15 {
+                // Overflow to infinity
+                (sign << 15) | (0x1F << 10)
+            } else {
+                // Normal f16
+                let h_exp = (unbiased + 15) as u16;
+                let h_mant = (mant >> 13) as u16;
+
+                // Round to nearest, ties to even
+                let round_bit = (mant >> 12) & 1;
+                let sticky = mant & 0x0FFF;
+                let h_mant = if round_bit == 1 && (sticky != 0 || (h_mant & 1) == 1) {
+                    h_mant + 1
+                } else {
+                    h_mant
+                };
+
+                // Handle mantissa overflow from rounding
+                if h_mant > 0x3FF {
+                    if h_exp >= 30 {
+                        // Overflow to infinity
+                        (sign << 15) | (0x1F << 10)
+                    } else {
+                        (sign << 15) | ((h_exp + 1) << 10)
+                    }
+                } else {
+                    (sign << 15) | (h_exp << 10) | h_mant
+                }
+            }
+        };
+
+        Self(h_bits)
+    }
+
+    /// Creates an f16 from an f64.
+    #[inline]
+    pub fn from_f64(f: f64) -> Self {
+        // Convert via f32 - sufficient precision for f16
+        Self::from_f32(f as f32)
+    }
+
+    /// Converts to f64.
+    #[inline]
+    pub fn to_f64(self) -> f64 {
+        self.to_f32() as f64
+    }
+
+    /// Returns true if this is neither infinite nor NaN.
+    #[inline]
+    pub fn is_finite(self) -> bool {
+        // Exponent of 31 means infinity or NaN
+        ((self.0 >> 10) & 0x1F) != 31
+    }
+
+    /// Returns the bytes in little-endian order.
+    #[inline]
+    pub const fn to_le_bytes(self) -> [u8; 2] {
+        self.0.to_le_bytes()
+    }
+
+    /// Returns the bytes in big-endian order.
+    #[inline]
+    pub const fn to_be_bytes(self) -> [u8; 2] {
+        self.0.to_be_bytes()
+    }
+}
+
+impl From<f16> for f32 {
+    #[inline]
+    fn from(f: f16) -> f32 {
+        f.to_f32()
+    }
+}
+
+impl From<f16> for f64 {
+    #[inline]
+    fn from(f: f16) -> f64 {
+        f.to_f64()
+    }
+}
+
+impl core::fmt::Debug for f16 {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        write!(f, "{}", self.to_f32())
+    }
+}
+
+impl core::fmt::Display for f16 {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        write!(f, "{}", self.to_f32())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_zero() {
+        let z = f16::ZERO;
+        assert_eq!(z.to_bits(), 0);
+        assert_eq!(z.to_f32(), 0.0);
+        assert!(z.is_finite());
+    }
+
+    #[test]
+    fn test_one() {
+        // 1.0 in f16: sign=0, exp=15 (biased), mant=0 -> 0x3C00
+        let one = f16::from_bits(0x3C00);
+        assert!((one.to_f32() - 1.0).abs() < 1e-6);
+        assert!(one.is_finite());
+    }
+
+    #[test]
+    fn test_negative_one() {
+        // -1.0 in f16: sign=1, exp=15, mant=0 -> 0xBC00
+        let neg_one = f16::from_bits(0xBC00);
+        assert!((neg_one.to_f32() - (-1.0)).abs() < 1e-6);
+    }
+
+    #[test]
+    fn test_infinity() {
+        // +Inf: sign=0, exp=31, mant=0 -> 0x7C00
+        let inf = f16::from_bits(0x7C00);
+        assert!(inf.to_f32().is_infinite());
+        assert!(!inf.is_finite());
+
+        // -Inf: 0xFC00
+        let neg_inf = f16::from_bits(0xFC00);
+        assert!(neg_inf.to_f32().is_infinite());
+        assert!(!neg_inf.is_finite());
+    }
+
+    #[test]
+    fn test_nan() {
+        // NaN: exp=31, mant!=0 -> 0x7C01 (or any mant != 0)
+        let nan = f16::from_bits(0x7C01);
+        assert!(nan.to_f32().is_nan());
+        assert!(!nan.is_finite());
+    }
+
+    #[test]
+    fn test_denormal() {
+        // Smallest positive denormal: 0x0001
+        let tiny = f16::from_bits(0x0001);
+        let val = tiny.to_f32();
+        assert!(val > 0.0);
+        assert!(val < 1e-6);
+        assert!(tiny.is_finite());
+    }
+
+    #[test]
+    fn test_roundtrip_normal() {
+        let test_values: [f32; 8] = [0.5, 1.0, 2.0, 100.0, 0.001, -0.5, -1.0, -100.0];
+        for &v in &test_values {
+            let h = f16::from_f32(v);
+            let back = h.to_f32();
+            // f16 has limited precision, allow ~0.1% error for normal values
+            let rel_err = ((v - back) / v).abs();
+            assert!(
+                rel_err < 0.002,
+                "Roundtrip failed for {}: got {}, rel_err {}",
+                v,
+                back,
+                rel_err
+            );
+        }
+    }
+
+    #[test]
+    fn test_roundtrip_special() {
+        // Zero
+        assert_eq!(f16::from_f32(0.0).to_f32(), 0.0);
+
+        // Infinity
+        assert!(f16::from_f32(f32::INFINITY).to_f32().is_infinite());
+        assert!(f16::from_f32(f32::NEG_INFINITY).to_f32().is_infinite());
+
+        // NaN
+        assert!(f16::from_f32(f32::NAN).to_f32().is_nan());
+    }
+
+    #[test]
+    fn test_overflow_to_infinity() {
+        // f16 max is ~65504, values above should overflow to infinity
+        let big = f16::from_f32(100000.0);
+        assert!(big.to_f32().is_infinite());
+    }
+
+    #[test]
+    fn test_underflow_to_zero() {
+        // Very small values should underflow to zero
+        let tiny = f16::from_f32(1e-10);
+        assert_eq!(tiny.to_f32(), 0.0);
+    }
+
+    #[test]
+    fn test_bytes() {
+        let h = f16::from_bits(0x1234);
+        assert_eq!(h.to_le_bytes(), [0x34, 0x12]);
+        assert_eq!(h.to_be_bytes(), [0x12, 0x34]);
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/linalg.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/linalg.rs
new file mode 100644
index 0000000..23524cd
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/linalg.rs
@@ -0,0 +1,140 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::error::Error;
+
+pub type Matrix3x3<T> = [[T; 3]; 3];
+pub type Vector3<T> = [T; 3];
+
+pub fn matmul3_vec(m: [f32; 9], v: [f32; 3]) -> [f32; 3] {
+    [
+        v[0] * m[0] + v[1] * m[1] + v[2] * m[2],
+        v[0] * m[3] + v[1] * m[4] + v[2] * m[5],
+        v[0] * m[6] + v[1] * m[7] + v[2] * m[8],
+    ]
+}
+
+pub fn mul_3x3_vector(matrix: &Matrix3x3<f64>, vector: &Vector3<f64>) -> Vector3<f64> {
+    std::array::from_fn(|i| {
+        matrix[i]
+            .iter()
+            .zip(vector.iter())
+            .map(|(&matrix_element, &vector_element)| matrix_element * vector_element)
+            .sum()
+    })
+}
+
+pub fn mul_3x3_matrix(mat1: &Matrix3x3<f64>, mat2: &Matrix3x3<f64>) -> Matrix3x3<f64> {
+    std::array::from_fn(|i| std::array::from_fn(|j| (0..3).map(|k| mat1[i][k] * mat2[k][j]).sum()))
+}
+
+fn det2x2(a: f64, b: f64, c: f64, d: f64) -> f64 {
+    a * d - b * c
+}
+
+fn calculate_cofactor(m: &Matrix3x3<f64>, r: usize, c: usize) -> f64 {
+    // Determine the actual row and column indices for the 2x2 submatrix
+    // by excluding the current row 'r' and column 'c'.
+    // Ensure they are taken in ascending order to form the submatrix consistently.
+    let mut sub_rows = [0; 2];
+    let mut sub_cols = [0; 2];
+
+    let mut current_idx = 0;
+    for i in 0..3 {
+        if i != r {
+            sub_rows[current_idx] = i;
+            current_idx += 1;
+        }
+    }
+
+    current_idx = 0;
+    for i in 0..3 {
+        if i != c {
+            sub_cols[current_idx] = i;
+            current_idx += 1;
+        }
+    }
+
+    let minor_val = det2x2(
+        m[sub_rows[0]][sub_cols[0]],
+        m[sub_rows[0]][sub_cols[1]],
+        m[sub_rows[1]][sub_cols[0]],
+        m[sub_rows[1]][sub_cols[1]],
+    );
+
+    // Apply the checkerboard pattern sign for the cofactor
+    if (r + c).is_multiple_of(2) {
+        minor_val
+    } else {
+        -minor_val
+    }
+}
+
+/// Calculates the inverse of a 3x3 matrix.
+pub fn inv_3x3_matrix(m: &Matrix3x3<f64>) -> Result<Matrix3x3<f64>, Error> {
+    let cofactor_matrix: [[f64; 3]; 3] = std::array::from_fn(|r_idx| {
+        std::array::from_fn(|c_idx| calculate_cofactor(m, r_idx, c_idx))
+    });
+
+    let det = m[0]
+        .iter()
+        .zip(cofactor_matrix[0].iter())
+        .map(|(&m_element, &cof_element)| m_element * cof_element)
+        .sum::<f64>();
+
+    // Check for numerical singularity.
+    const EPSILON: f64 = 1e-12;
+    if det.abs() < EPSILON {
+        return Err(Error::MatrixInversionFailed(det.abs()));
+    }
+
+    let inv_det = 1.0 / det;
+
+    let adjugate_matrix: [[f64; 3]; 3] =
+        std::array::from_fn(|r_idx| std::array::from_fn(|c_idx| cofactor_matrix[c_idx][r_idx]));
+
+    // Inverse matrix = (1/det) * Adjugate matrix.
+    Ok(std::array::from_fn(|r_idx| {
+        std::array::from_fn(|c_idx| adjugate_matrix[r_idx][c_idx] * inv_det)
+    }))
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    fn assert_matrix_eq(a: &Matrix3x3<f64>, b: &Matrix3x3<f64>, epsilon: f64) {
+        for r in 0..3 {
+            for c in 0..3 {
+                assert!(
+                    (a[r][c] - b[r][c]).abs() < epsilon,
+                    "Matrices differ at [{}][{}]: expected {}, got {}. Diff: {}",
+                    r,
+                    c,
+                    b[r][c],
+                    a[r][c],
+                    (a[r][c] - b[r][c]).abs()
+                );
+            }
+        }
+    }
+
+    #[test]
+    fn test_3x3_inverse() {
+        // Random matrix (https://xkcd.com/221/)
+        let m: Matrix3x3<f64> = [[1.0f64, -3.0, -2.0], [2.0, 2.0, 1.0], [2.0, 1.0, 1.0]];
+
+        let expected_inv: Matrix3x3<f64> = [[0.2, 0.2, 0.2], [0., 1., -1.], [-0.4, -1.4, 1.6]];
+
+        match inv_3x3_matrix(&m) {
+            Ok(inv_m) => {
+                assert_matrix_eq(&inv_m, &expected_inv, 1e-12);
+            }
+            Err(e) => {
+                panic!("Matrix inversion failed unexpectedly: {e:?}");
+            }
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/log2.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/log2.rs
new file mode 100644
index 0000000..6f8ba32
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/log2.rs
@@ -0,0 +1,85 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+pub trait FloorLog2 {
+    fn floor_log2(&self) -> Self;
+}
+
+pub trait CeilLog2 {
+    fn ceil_log2(&self) -> Self;
+}
+
+impl FloorLog2 for u32 {
+    fn floor_log2(&self) -> Self {
+        debug_assert_ne!(*self, 0);
+        0u32.leading_zeros() - self.leading_zeros() - 1
+    }
+}
+
+impl FloorLog2 for u64 {
+    fn floor_log2(&self) -> Self {
+        debug_assert_ne!(*self, 0);
+        (0u64.leading_zeros() - self.leading_zeros() - 1) as u64
+    }
+}
+
+impl FloorLog2 for usize {
+    fn floor_log2(&self) -> Self {
+        debug_assert_ne!(*self, 0);
+        (0usize.leading_zeros() - self.leading_zeros() - 1) as usize
+    }
+}
+
+impl<T> CeilLog2 for T
+where
+    T: FloorLog2,
+    T: std::ops::Add<Output = Self>,
+    T: std::ops::Sub<Output = Self>,
+    T: std::ops::BitAnd<Output = Self>,
+    T: std::cmp::PartialEq,
+    T: From<u8>,
+    T: Copy,
+{
+    fn ceil_log2(&self) -> Self {
+        if (*self & (*self - 1.into())) != 0.into() {
+            self.floor_log2() + 1.into()
+        } else {
+            self.floor_log2()
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    #[test]
+    fn test_floor() {
+        assert_eq!(0, 1u32.floor_log2());
+        assert_eq!(1, 2u32.floor_log2());
+        assert_eq!(1, 3u32.floor_log2());
+        assert_eq!(2, 4u32.floor_log2());
+    }
+    #[test]
+    fn test_ceil() {
+        assert_eq!(0, 1u32.ceil_log2());
+        assert_eq!(1, 2u32.ceil_log2());
+        assert_eq!(2, 3u32.ceil_log2());
+        assert_eq!(2, 4u32.ceil_log2());
+    }
+    #[test]
+    fn test_floor_us() {
+        assert_eq!(0, 1usize.floor_log2());
+        assert_eq!(1, 2usize.floor_log2());
+        assert_eq!(1, 3usize.floor_log2());
+        assert_eq!(2, 4usize.floor_log2());
+    }
+    #[test]
+    fn test_ceil_us() {
+        assert_eq!(0, 1usize.ceil_log2());
+        assert_eq!(1, 2usize.ceil_log2());
+        assert_eq!(2, 3usize.ceil_log2());
+        assert_eq!(2, 4usize.ceil_log2());
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/mod.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/mod.rs
new file mode 100644
index 0000000..f7e05e3b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/mod.rs
@@ -0,0 +1,34 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#[cfg(test)]
+pub mod test;
+
+mod bits;
+mod cacheline;
+mod concat_slice;
+mod fast_math;
+mod float16;
+mod linalg;
+mod log2;
+pub mod ndarray;
+mod rational_poly;
+mod shift_right_ceil;
+pub mod tracing_wrappers;
+mod vec_helpers;
+mod xorshift128plus;
+
+pub use bits::*;
+pub use cacheline::*;
+pub use concat_slice::*;
+pub use fast_math::*;
+pub use float16::f16;
+pub use linalg::*;
+pub use log2::*;
+pub(crate) use ndarray::*;
+pub use rational_poly::*;
+pub use shift_right_ceil::*;
+pub use vec_helpers::*;
+pub use xorshift128plus::*;
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/ndarray.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/ndarray.rs
new file mode 100644
index 0000000..5b2e8363
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/ndarray.rs
@@ -0,0 +1,24 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+macro_rules! slice {
+    (&$data:expr, $range:expr) => {
+        $data[$range]
+    };
+    (&mut $data:expr, $range:expr) => {
+        $data[$range]
+    };
+    (&mut $data:expr, $range:expr $(, $rest_ranges:expr)+) => {
+        $data[$range].iter_mut().map(|inner_data| {
+            &mut slice!(&inner_data, $($rest_ranges),+)
+        }).collect::<Vec<_>>()
+    };
+    (&$data:expr, $range:expr $(, $rest_ranges:expr)+) => {
+        $data[$range].iter().map(|inner_data| {
+            &slice!(&inner_data, $($rest_ranges),+)
+        }).collect::<Vec<_>>()
+    };
+}
+pub(crate) use slice;
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/rational_poly.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/rational_poly.rs
new file mode 100644
index 0000000..12f97fb
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/rational_poly.rs
@@ -0,0 +1,35 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use jxl_simd::{F32SimdVec, SimdDescriptor};
+
+/// Computes `(p0 + p1 x + p2 x^2 + ...) / (q0 + q1 x + q2 x^2 + ...)`.
+///
+/// # Panics
+/// Panics if either `P` or `Q` is zero.
+#[inline]
+pub fn eval_rational_poly<const P: usize, const Q: usize>(x: f32, p: [f32; P], q: [f32; Q]) -> f32 {
+    let yp = p.into_iter().rev().reduce(|yp, p| yp * x + p).unwrap();
+    let yq = q.into_iter().rev().reduce(|yq, q| yq * x + q).unwrap();
+    yp / yq
+}
+
+#[inline(always)]
+pub fn eval_rational_poly_simd<D: SimdDescriptor, const P: usize, const Q: usize>(
+    d: D,
+    x: D::F32Vec,
+    p: [f32; P],
+    q: [f32; Q],
+) -> D::F32Vec {
+    let mut yp = D::F32Vec::splat(d, p[P - 1]);
+    for i in (0..P - 1).rev() {
+        yp = yp.mul_add(x, D::F32Vec::splat(d, p[i]));
+    }
+    let mut yq = D::F32Vec::splat(d, q[Q - 1]);
+    for i in (0..Q - 1).rev() {
+        yq = yq.mul_add(x, D::F32Vec::splat(d, q[i]));
+    }
+    yp / yq
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/shift_right_ceil.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/shift_right_ceil.rs
new file mode 100644
index 0000000..3d756b2b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/shift_right_ceil.rs
@@ -0,0 +1,41 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::ops::{Add, Shl, Shr, Sub};
+
+pub trait ShiftRightCeil: Copy {
+    fn shrc<T: Copy>(self, rhs: T) -> Self
+    where
+        Self: Shr<T, Output = Self> + Shl<T, Output = Self>;
+}
+
+impl<S: Copy + Add<Self, Output = Self> + Sub<Self, Output = Self> + From<u8>> ShiftRightCeil
+    for S
+{
+    fn shrc<T: Copy>(self, rhs: T) -> Self
+    where
+        Self: Shr<T, Output = Self> + Shl<T, Output = Self>,
+    {
+        (self + (Self::from(1u8) << rhs) - Self::from(1u8)) >> rhs
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use crate::util::ShiftRightCeil;
+
+    #[test]
+    fn test_shrc() {
+        assert_eq!(1u8, 1u8.shrc(1u8));
+        assert_eq!(1u8, 2u8.shrc(1u8));
+        assert_eq!(2u8, 9u8.shrc(3u8));
+        assert_eq!(1u32, 1u32.shrc(1u32));
+        assert_eq!(1u32, 2u32.shrc(1u32));
+        assert_eq!(2u32, 9u32.shrc(3u32));
+        assert_eq!(1u32, 1u32.shrc(1u8));
+        assert_eq!(1u32, 2u32.shrc(1u8));
+        assert_eq!(2u32, 9u32.shrc(3u8));
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/test.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/test.rs
new file mode 100644
index 0000000..a9b3ca24
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/test.rs
@@ -0,0 +1,382 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::{
+    fmt::Debug,
+    io::{BufRead, BufReader, Cursor, Read, Write},
+    num::{ParseFloatError, ParseIntError},
+};
+
+use crate::{
+    bit_reader::BitReader,
+    container::ContainerParser,
+    error::Error as JXLError,
+    headers::{
+        FileHeader, JxlHeader,
+        encodings::*,
+        frame_header::FrameHeader,
+        toc::{Toc, TocNonserialized},
+    },
+    image::{Image, ImageDataType},
+};
+
+use num_traits::AsPrimitive;
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+pub enum Error {
+    #[error("Invalid PFM: {0}")]
+    InvalidPFM(String),
+}
+
+impl From<ParseFloatError> for Error {
+    fn from(value: ParseFloatError) -> Self {
+        Error::InvalidPFM(value.to_string())
+    }
+}
+
+impl From<ParseIntError> for Error {
+    fn from(value: ParseIntError) -> Self {
+        Error::InvalidPFM(value.to_string())
+    }
+}
+
+impl From<std::io::Error> for Error {
+    fn from(value: std::io::Error) -> Self {
+        Error::InvalidPFM(value.to_string())
+    }
+}
+
+impl From<JXLError> for Error {
+    fn from(value: JXLError) -> Self {
+        Error::InvalidPFM(value.to_string())
+    }
+}
+
+fn rel_error_gt<T: AsPrimitive<f64>>(left: T, right: T, max_rel_error: T) -> bool {
+    let left_f64: f64 = left.as_();
+    let right_f64: f64 = right.as_();
+    let error = (left_f64 - right_f64).abs();
+    matches!(
+        (2.0 * error / (left_f64.abs() + right_f64.abs() + 1e-16))
+            .partial_cmp(&max_rel_error.as_()),
+        Some(std::cmp::Ordering::Greater) | None
+    )
+}
+
+fn abs_error_gt<T: AsPrimitive<f64>>(left: T, right: T, max_abs_error: T) -> bool {
+    let left_f64: f64 = left.as_();
+    let right_f64: f64 = right.as_();
+    matches!(
+        (left_f64 - right_f64)
+            .abs()
+            .partial_cmp(&max_abs_error.as_()),
+        Some(std::cmp::Ordering::Greater) | None
+    )
+}
+
+pub fn assert_almost_eq<T: AsPrimitive<f64> + Debug + Copy>(
+    left: T,
+    right: T,
+    max_abs_error: T,
+    max_rel_error: T,
+) {
+    if abs_error_gt(left, right, max_abs_error) || rel_error_gt(left, right, max_rel_error) {
+        panic!(
+            "assertion failed: `(left ≈ right)`\n  left: `{left:?}`,\n right: `{right:?}`,\n max_abs_error: `{max_abs_error:?}`,\n max_rel_error: `{max_rel_error:?}`"
+        );
+    }
+}
+
+pub fn assert_almost_rel_eq<T: AsPrimitive<f64> + Debug + Copy>(
+    left: T,
+    right: T,
+    max_rel_error: T,
+) {
+    if rel_error_gt(left, right, max_rel_error) {
+        panic!(
+            "assertion failed: `(left ≈ right)`\n  left: `{left:?}`,\n right: `{right:?}`,\n max_rel_error: `{max_rel_error:?}`"
+        );
+    }
+}
+
+pub fn assert_almost_abs_eq<T: AsPrimitive<f64> + Debug + Copy>(
+    left: T,
+    right: T,
+    max_abs_error: T,
+) {
+    if abs_error_gt(left, right, max_abs_error) {
+        panic!(
+            "assertion failed: `(left ≈ right)`\n  left: `{left:?}`,\n right: `{right:?}`,\n max_abs_error: `{max_abs_error:?}`"
+        );
+    }
+}
+
+pub fn assert_almost_abs_eq_coords<T: AsPrimitive<f64> + Debug + Copy>(
+    left: T,
+    right: T,
+    max_abs_error: T,
+    pos: (usize, usize),
+    c: usize,
+) {
+    if abs_error_gt(left, right, max_abs_error) {
+        panic!(
+            "assertion failed @{pos:?}, c {c}: `(left ≈ right)`\n  left: `{left:?}`,\n right: `{right:?}`,\n abs error: `{:?}`\n max_abs_error: `{max_abs_error:?}`",
+            (left.as_() - right.as_()).abs()
+        );
+    }
+}
+
+fn assert_same_len<T: AsPrimitive<f64> + Debug + Copy>(left: &[T], right: &[T]) {
+    if left.as_ref().len() != right.as_ref().len() {
+        panic!(
+            "assertion failed: `(left ≈ right)`\n left.len(): `{}`,\n right.len(): `{}`",
+            left.as_ref().len(),
+            right.as_ref().len()
+        );
+    }
+}
+
+pub fn assert_all_almost_eq<T: AsPrimitive<f64> + Debug + Copy, V: AsRef<[T]> + Debug>(
+    left: V,
+    right: V,
+    max_abs_error: T,
+    max_rel_error: T,
+) {
+    assert_same_len(left.as_ref(), right.as_ref());
+    for (idx, (left_val, right_val)) in left
+        .as_ref()
+        .iter()
+        .copied()
+        .zip(right.as_ref().iter().copied())
+        .enumerate()
+    {
+        if abs_error_gt(left_val, right_val, max_abs_error)
+            || rel_error_gt(left_val, right_val, max_rel_error)
+        {
+            panic!(
+                "assertion failed: `(left ≈ right)`\n left: `{left:?}`,\n right: `{right:?}`,\n max_abs_error: `{max_abs_error:?}`,\n max_rel_error: `{max_rel_error:?}`,\n left[{idx}]: `{left_val:?}`,\n right[{idx}]: `{right_val:?}`",
+            );
+        }
+    }
+}
+
+pub fn assert_all_almost_rel_eq<T: AsPrimitive<f64> + Debug + Copy, V: AsRef<[T]> + Debug>(
+    left: V,
+    right: V,
+    max_rel_error: T,
+) {
+    assert_same_len(left.as_ref(), right.as_ref());
+    for (idx, (left_val, right_val)) in left
+        .as_ref()
+        .iter()
+        .copied()
+        .zip(right.as_ref().iter().copied())
+        .enumerate()
+    {
+        if rel_error_gt(left_val, right_val, max_rel_error) {
+            panic!(
+                "assertion failed: `(left ≈ right)`\n left: `{left:?}`,\n right: `{right:?}`,\n max_rel_error: `{max_rel_error:?}`,\n left[{idx}]: `{left_val:?}`,\n right[{idx}]: `{right_val:?}`",
+            );
+        }
+    }
+}
+
+pub fn assert_all_almost_abs_eq<T: AsPrimitive<f64> + Debug + Copy, V: AsRef<[T]> + Debug>(
+    left: V,
+    right: V,
+    max_abs_error: T,
+) {
+    assert_same_len(left.as_ref(), right.as_ref());
+    for (idx, (left_val, right_val)) in left
+        .as_ref()
+        .iter()
+        .copied()
+        .zip(right.as_ref().iter().copied())
+        .enumerate()
+    {
+        if abs_error_gt(left_val, right_val, max_abs_error) {
+            panic!(
+                "assertion failed: `(left ≈ right)`\n left: `{left:?}`,\n right: `{right:?}`,\n max_abs_error: `{max_abs_error:?}`,\n left[{idx}]: `{left_val:?}`,\n right[{idx}]: `{right_val:?}`",
+            );
+        }
+    }
+}
+
+pub fn check_equal_images<T: ImageDataType>(a: &Image<T>, b: &Image<T>) {
+    assert_eq!(a.size(), b.size());
+    let mismatch_info = |x: usize, y: usize| -> String {
+        let msg = format!(
+            "mismatch at position {x}x{y}, values {:?} and {:?}",
+            a.row(y)[x],
+            b.row(y)[x]
+        );
+        msg
+    };
+    for y in 0..a.size().1 {
+        for x in 0..a.size().0 {
+            assert_eq!(a.row(y)[x], b.row(y)[x], "{}", mismatch_info(x, y));
+        }
+    }
+}
+
+pub fn read_headers_and_toc(image: &[u8]) -> Result<(FileHeader, FrameHeader, Toc), JXLError> {
+    let codestream = ContainerParser::collect_codestream(image).unwrap();
+    let mut br = BitReader::new(&codestream);
+    let file_header = FileHeader::read(&mut br)?;
+
+    let frame_header =
+        FrameHeader::read_unconditional(&(), &mut br, &file_header.frame_header_nonserialized())?;
+    let num_toc_entries = frame_header.num_toc_entries();
+    let toc = Toc::read_unconditional(
+        &(),
+        &mut br,
+        &TocNonserialized {
+            num_entries: num_toc_entries as u32,
+        },
+    )?;
+    Ok((file_header, frame_header, toc))
+}
+
+pub fn write_pfm(image: Vec<Image<f32>>, mut buf: impl Write) -> Result<(), Error> {
+    if image.len() == 1 {
+        buf.write_all(b"Pf\n")?;
+    } else if image.len() == 3 {
+        buf.write_all(b"PF\n")?;
+    } else {
+        return Err(Error::InvalidPFM(format!(
+            "invalid number of channels: {}",
+            image.len()
+        )));
+    }
+    let size = image[0].size();
+    for c in image.iter().skip(1) {
+        assert_eq!(size, c.size());
+    }
+    buf.write_fmt(format_args!("{} {}\n", size.0, size.1))?;
+    buf.write_all(b"1.0\n")?;
+    let mut b: [u8; 4];
+    for row in 0..size.1 {
+        for col in 0..size.0 {
+            for c in image.iter() {
+                b = c.row(size.1 - row - 1)[col].to_be_bytes();
+                buf.write_all(&b)?;
+            }
+        }
+    }
+    buf.flush()?;
+    Ok(())
+}
+
+pub fn read_pfm(b: &[u8]) -> Result<Vec<Image<f32>>, Error> {
+    let mut bf = BufReader::new(Cursor::new(b));
+    let mut line = String::new();
+    bf.read_line(&mut line)?;
+    let channels = match line.trim() {
+        "Pf" => 1,
+        "PF" => 3,
+        &_ => return Err(Error::InvalidPFM(format!("invalid PFM type header {line}"))),
+    };
+    line.clear();
+    bf.read_line(&mut line)?;
+    let mut dims = line.split_whitespace();
+    let xres = if let Some(xres_str) = dims.next() {
+        xres_str.trim().parse()?
+    } else {
+        return Err(Error::InvalidPFM(format!(
+            "invalid PFM resolution header {line}",
+        )));
+    };
+    let yres = if let Some(yres_str) = dims.next() {
+        yres_str.trim().parse()?
+    } else {
+        return Err(Error::InvalidPFM(format!(
+            "invalid PFM resolution header {line}",
+        )));
+    };
+    line.clear();
+    bf.read_line(&mut line)?;
+    let endianness: f32 = line.trim().parse()?;
+
+    let mut res = Vec::<Image<f32>>::new();
+    for _ in 0..channels {
+        let img = Image::new((xres, yres))?;
+        res.push(img);
+    }
+
+    let mut buf = [0u8; 4];
+    for row in 0..yres {
+        for col in 0..xres {
+            for chan in res.iter_mut() {
+                bf.read_exact(&mut buf)?;
+                chan.row_mut(yres - row - 1)[col] = if endianness < 0.0 {
+                    f32::from_le_bytes(buf)
+                } else {
+                    f32::from_be_bytes(buf)
+                }
+            }
+        }
+    }
+
+    Ok(res)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_with_floats() {
+        assert_almost_abs_eq(1.0000001f64, 1.0000002, 0.000001);
+        assert_almost_abs_eq(1.0, 1.1, 0.2);
+    }
+
+    #[test]
+    fn test_with_integers() {
+        assert_almost_abs_eq(100, 101, 2);
+        assert_almost_abs_eq(777u32, 770, 7);
+        assert_almost_abs_eq(500i64, 498, 3);
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_panic_float() {
+        assert_almost_abs_eq(1.0, 1.2, 0.1);
+    }
+    #[test]
+    #[should_panic]
+    fn test_panic_integer() {
+        assert_almost_abs_eq(100, 105, 2);
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_nan_comparison() {
+        assert_almost_abs_eq(f64::NAN, f64::NAN, 0.1);
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_nan_tolerance() {
+        assert_almost_abs_eq(1.0, 1.0, f64::NAN);
+    }
+
+    #[test]
+    fn test_infinity_tolerance() {
+        assert_almost_abs_eq(1.0, 1.0, f64::INFINITY);
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_nan_comparison_with_infinity_tolerance() {
+        assert_almost_abs_eq(f32::NAN, f32::NAN, f32::INFINITY);
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_infinity_comparison_with_infinity_tolerance() {
+        assert_almost_abs_eq(f32::INFINITY, f32::INFINITY, f32::INFINITY);
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/tracing_wrappers.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/tracing_wrappers.rs
new file mode 100644
index 0000000..8d14a92
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/tracing_wrappers.rs
@@ -0,0 +1,26 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(unused_imports)]
+
+#[cfg(feature = "tracing")]
+mod private {
+    pub use tracing::{debug, error, info, instrument, trace, warn};
+}
+
+#[cfg(not(feature = "tracing"))]
+mod private {
+    macro_rules! fake_log {
+        ($($_: tt)*) => {};
+    }
+    pub(crate) use fake_log as debug;
+    pub(crate) use fake_log as error;
+    pub(crate) use fake_log as info;
+    pub(crate) use fake_log as trace;
+    pub(crate) use fake_log as warn;
+    pub use jxl_macros::noop as instrument;
+}
+
+pub use private::*;
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/vec_helpers.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/vec_helpers.rs
new file mode 100644
index 0000000..e9af8c8
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/vec_helpers.rs
@@ -0,0 +1,33 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TODO(firsching): as soon as "Vec::try_with_capacity" is available from the
+// standard library use this instead of the functions here.
+pub trait NewWithCapacity {
+    type Output;
+    type Error;
+    fn new_with_capacity(capacity: usize) -> Result<Self::Output, Self::Error>;
+}
+
+impl<T> NewWithCapacity for Vec<T> {
+    type Output = Vec<T>;
+    type Error = std::collections::TryReserveError;
+
+    fn new_with_capacity(capacity: usize) -> Result<Self::Output, Self::Error> {
+        let mut vec = Vec::new();
+        vec.try_reserve(capacity)?;
+        Ok(vec)
+    }
+}
+
+impl NewWithCapacity for String {
+    type Output = String;
+    type Error = std::collections::TryReserveError;
+    fn new_with_capacity(capacity: usize) -> Result<Self::Output, Self::Error> {
+        let mut s = String::new();
+        s.try_reserve(capacity)?;
+        Ok(s)
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/xorshift128plus.rs b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/xorshift128plus.rs
new file mode 100644
index 0000000..bf55805
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/xorshift128plus.rs
@@ -0,0 +1,733 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Adapted from https://github.com/vpxyz/xorshift/blob/master/xorshift128plus/
+// (MIT-license)
+
+pub struct Xorshift128Plus {
+    s0: [u64; Self::N],
+    s1: [u64; Self::N],
+}
+
+impl Xorshift128Plus {
+    pub const N: usize = 8;
+
+    pub fn new_with_seed(seed: u64) -> Self {
+        let mut s0 = [0; Self::N];
+        let mut s1 = [0; Self::N];
+
+        s0[0] = Self::split_mix_64(seed + 0x9E3779B97F4A7C15);
+        s1[0] = Self::split_mix_64(s0[0]);
+
+        for i in 1..Self::N {
+            s0[i] = Self::split_mix_64(s1[i - 1]);
+            s1[i] = Self::split_mix_64(s0[i]);
+        }
+
+        Self { s0, s1 }
+    }
+
+    pub fn new_with_seeds(seed1: u32, seed2: u32, seed3: u32, seed4: u32) -> Self {
+        let mut s0 = [0; Self::N];
+        let mut s1 = [0; Self::N];
+
+        s0[0] = Self::split_mix_64(
+            (((seed1 as u64) << 32) + seed2 as u64).wrapping_add(0x9E3779B97F4A7C15),
+        );
+        s1[0] = Self::split_mix_64(
+            (((seed3 as u64) << 32) + seed4 as u64).wrapping_add(0x9E3779B97F4A7C15),
+        );
+        for i in 1..Self::N {
+            s0[i] = Self::split_mix_64(s0[i - 1]);
+            s1[i] = Self::split_mix_64(s1[i - 1]);
+        }
+
+        Self { s0, s1 }
+    }
+
+    pub fn fill(&mut self, random_bits: &mut [u64; Self::N]) {
+        for ((s0, s1), random_bits) in self
+            .s0
+            .iter_mut()
+            .zip(self.s1.iter_mut())
+            .zip(random_bits.iter_mut())
+        {
+            let mut new_s1 = *s0;
+            *s0 = *s1;
+            let bits = new_s1.wrapping_add(*s0); // b, c
+            new_s1 ^= new_s1 << 23;
+            *random_bits = bits;
+            new_s1 ^= *s0 ^ (new_s1 >> 18) ^ (*s0 >> 5);
+            *s1 = new_s1;
+        }
+    }
+
+    fn split_mix_64(mut z: u64) -> u64 {
+        z = (z ^ (z >> 30)).wrapping_mul(0xBF58476D1CE4E5B9);
+        z = (z ^ (z >> 27)).wrapping_mul(0x94D049BB133111EB);
+        z ^ (z >> 31)
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use crate::util::xorshift128plus::Xorshift128Plus;
+
+    #[test]
+    fn xorshift128plus_golden() {
+        const NUM_VECTORS: usize = 64;
+        const EXPECTED: [[u64; Xorshift128Plus::N]; NUM_VECTORS] = [
+            [
+                0x6E901576D477CBB1,
+                0xE9E53789195DA2A2,
+                0xB681F6DDA5E0AE99,
+                0x8EFD18CE21FD6896,
+                0xA898A80DF75CF532,
+                0x50CEB2C9E2DE7E32,
+                0x3CA7C2FEB25C0DD0,
+                0xA4D0866B80B4D836,
+            ],
+            [
+                0x8CD6A1E6233D3A26,
+                0x3D4603ADE98B112D,
+                0xDC427AF674019E36,
+                0xE28B4D230705AC53,
+                0x7297E9BBA88783DD,
+                0x34D3D23CFCD9B41A,
+                0x5A223615ADBE96B8,
+                0xE5EB529027CFBD01,
+            ],
+            [
+                0xC1894CF00DFAC6A2,
+                0x18EDF8AE9085E404,
+                0x8E936625296B4CCD,
+                0x31971EF3A14A899B,
+                0xBE87535FCE0BF26A,
+                0x576F7A752BC6649F,
+                0xA44CBADCE0C6B937,
+                0x3DBA819BB17A353A,
+            ],
+            [
+                0x27CE38DFCC1C5EB6,
+                0x920BEB5606340256,
+                0x3986CBC40C9AFC2C,
+                0xE22BCB3EEB1E191E,
+                0x6E1FCDD3602A8FBA,
+                0x052CB044E5415A29,
+                0x46266646EFB9ECD7,
+                0x8F44914618D29335,
+            ],
+            [
+                0xDD30AEDF72A362C5,
+                0xBC1D824E16BB98F4,
+                0x9EA6009C2AA3D2F1,
+                0xF65C0FBBE17AF081,
+                0x22424D06A8738991,
+                0x8A62763F2B7611D2,
+                0x2F3E89F722637939,
+                0x84D338BEF50AFD50,
+            ],
+            [
+                0x00F46494898E2B0B,
+                0x81239DC4FB8E8003,
+                0x414AD93EC5773FE7,
+                0x791473C450E4110F,
+                0x87F127BF68C959AC,
+                0x6429282D695EF67B,
+                0x661082E11546CBA8,
+                0x5815D53FA5436BFD,
+            ],
+            [
+                0xB3DEADAB9BE6E0F9,
+                0xAA1B7B8F7CED0202,
+                0x4C5ED437699D279E,
+                0xA4471727F1CB39D3,
+                0xE439DA193F802F70,
+                0xF89401BB04FA6493,
+                0x3B08045A4FE898BA,
+                0x32137BFE98227950,
+            ],
+            [
+                0xFBAE4A092897FEF3,
+                0x0639F6CE56E71C8E,
+                0xF0AD6465C07F0C1E,
+                0xFF8E28563361DCE5,
+                0xC2013DB7F86BC6B9,
+                0x8EFCC0503330102F,
+                0x3F6B767EA5C4DA40,
+                0xB9864B950B2232E1,
+            ],
+            [
+                0x76EB58DE8E5EC22A,
+                0x9BBBF49A18B32F4F,
+                0xC8405F02B2B2FAB9,
+                0xC3E122A5F146BC34,
+                0xC90BB046660F5765,
+                0xB933981310DBECCF,
+                0x5A2A7BFC9126FD1C,
+                0x8BB388C94DF87901,
+            ],
+            [
+                0x753EB89AD63EF3C3,
+                0xF24AAF40C89D65AD,
+                0x23F68931C1A6AA6D,
+                0xF47E79BF702C6DD0,
+                0xA3AD113244EE7EAE,
+                0xD42CBEA28F793DC3,
+                0xD896FCF1820F497C,
+                0x042B86D2818948C1,
+            ],
+            [
+                0x8F2A4FC5A4265763,
+                0xEC499E6F95EAA10C,
+                0xE3786D4ECCD0DEB5,
+                0xC725C53D3AC4CC43,
+                0x065A4ACBBF83610E,
+                0x35C61C9FEF167129,
+                0x7B720AEAA7D70048,
+                0x14206B841377D039,
+            ],
+            [
+                0xAD27D78BF96055F6,
+                0x5F43B20FF47ADCD4,
+                0xE184C2401E2BF71E,
+                0x30B263D78990045D,
+                0xC22F00EBFF9BA201,
+                0xAE7F86522B53A562,
+                0x2853312BC039F0A4,
+                0x868D619E6549C3C8,
+            ],
+            [
+                0xFD5493D8AE9A8371,
+                0x773D5E224DF61B3B,
+                0x5377C54FBB1A8280,
+                0xCAD4DE3B8265CAFA,
+                0xCDF3F19C91EBD5F6,
+                0xC8EA0F182D73BD78,
+                0x220502D593433FF1,
+                0xB81205E612DC31B1,
+            ],
+            [
+                0x8F32A39EAEDA4C70,
+                0x1D4B0914AA4DAC7F,
+                0x56EF1570F3A8B405,
+                0x29812CB17404A592,
+                0x97A2AAF69CAE90F2,
+                0x12BF5E02778BBFE5,
+                0x9D4B55AD42A05FD2,
+                0x06C2BAB5E6086620,
+            ],
+            [
+                0x8DB4B9648302B253,
+                0xD756AD9E3AEA12C7,
+                0x68709B7F11D4B188,
+                0x7CC299DDCD707A4B,
+                0x97B860C370A7661D,
+                0xCECD314FC20E64F5,
+                0x55F412CDFB4C7EC3,
+                0x55EE97591193B525,
+            ],
+            [
+                0xCF70F3ACA96E6254,
+                0x022FEDECA2E09F46,
+                0x686823DB60AE1ECF,
+                0xFD36190D3739830E,
+                0x74E1C09027F68120,
+                0xB5883A835C093842,
+                0x93E1EFB927E9E4E3,
+                0xB2721E249D7E5EBE,
+            ],
+            [
+                0x69B6E21C44188CB8,
+                0x5D6CFB853655A7AA,
+                0x3E001A0B425A66DC,
+                0x8C57451103A5138F,
+                0x7BF8B4BE18EAB402,
+                0x494102EB8761A365,
+                0xB33796A9F6A81F0E,
+                0x10005AB3BCCFD960,
+            ],
+            [
+                0xB2CF25740AE965DC,
+                0x6F7C1DF7EF53D670,
+                0x648DD6087AC2251E,
+                0x040955D9851D487D,
+                0xBD550FC7E21A7F66,
+                0x57408F484DEB3AB5,
+                0x481E24C150B506C1,
+                0x72C0C3EAF91A40D6,
+            ],
+            [
+                0x1997A481858A5D39,
+                0x539718F4BEF50DC1,
+                0x2EC4DC4787E7E368,
+                0xFF1CE78879419845,
+                0xE219A93DD6F6DD30,
+                0x85328618D02FEC1A,
+                0xC86E02D969181B20,
+                0xEBEC8CD8BBA34E6E,
+            ],
+            [
+                0x28B55088A16CE947,
+                0xDD25AC11E6350195,
+                0xBD1F176694257B1C,
+                0x09459CCF9FCC9402,
+                0xF8047341E386C4E4,
+                0x7E8E9A9AD984C6C0,
+                0xA4661E95062AA092,
+                0x70A9947005ED1152,
+            ],
+            [
+                0x4C01CF75DBE98CCD,
+                0x0BA076CDFC7373B9,
+                0x6C5E7A004B57FB59,
+                0x336B82297FD3BC56,
+                0x7990C0BE74E8D60F,
+                0xF0275CC00EC5C8C8,
+                0x6CF29E682DFAD2E9,
+                0xFA4361524BD95D72,
+            ],
+            [
+                0x631D2A19FF62F018,
+                0x41C43863B985B3FA,
+                0xE052B2267038EFD9,
+                0xE2A535FAC575F430,
+                0xE004EEA90B1FF5B8,
+                0x42DFE2CA692A1F26,
+                0x90FB0BFC9A189ECC,
+                0x4484102BD3536BD0,
+            ],
+            [
+                0xD027134E9ACCA5A5,
+                0xBBAB4F966D476A9B,
+                0x713794A96E03D693,
+                0x9F6335E6B94CD44A,
+                0xC5090C80E7471617,
+                0x6D9C1B0C87B58E33,
+                0x1969CE82E31185A5,
+                0x2099B97E87754EBE,
+            ],
+            [
+                0x60EBAF4ED934350F,
+                0xC26FBF0BA5E6ECFF,
+                0x9E54150F0312EC57,
+                0x0973B48364ED0041,
+                0x800A523241426CFC,
+                0x03AB5EC055F75989,
+                0x8CF315935DEEB40A,
+                0x83D3FC0190BD1409,
+            ],
+            [
+                0x26D35394CF720A51,
+                0xCE9EAA15243CBAFE,
+                0xE2B45FBAF21B29E0,
+                0xDB92E98EDE73F9E0,
+                0x79B16F5101C26387,
+                0x1AC15959DE88C86F,
+                0x387633AEC6D6A580,
+                0xA6FC05807BFC5EB8,
+            ],
+            [
+                0x2D26C8E47C6BADA9,
+                0x820E6EC832D52D73,
+                0xB8432C3E0ED0EE5B,
+                0x0F84B3C4063AAA87,
+                0xF393E4366854F651,
+                0x749E1B4D2366A567,
+                0x805EACA43480D004,
+                0x244EBF3AA54400A5,
+            ],
+            [
+                0xBFDC3763AA79F75A,
+                0x9E3A74CC751F41DB,
+                0xF401302A149DBC55,
+                0x6B25F7973D7BF7BC,
+                0x13371D34FDBC3DAE,
+                0xC5E1998C8F484DCD,
+                0x7031B8AE5C364464,
+                0x3847F0C4F3DA2C25,
+            ],
+            [
+                0x24C6387D2C0F1225,
+                0x77CCE960255C67A4,
+                0x21A0947E497B10EB,
+                0xBB5DB73A825A9D7E,
+                0x26294A41999E553D,
+                0x3953E0089F87D925,
+                0x3DAE6E5D4E5EAAFE,
+                0x74B545460341A7AA,
+            ],
+            [
+                0x710E5EB08A7DB820,
+                0x7E43C4E77CAEA025,
+                0xD4C91529C8B060C1,
+                0x09AE26D8A7B0CA29,
+                0xAB9F356BB360A772,
+                0xB68834A25F19F6E9,
+                0x79B8D9894C5734E2,
+                0xC6847E7C8FFD265F,
+            ],
+            [
+                0x10C4BCB06A5111E6,
+                0x57CB50955B6A2516,
+                0xEF53C87798B6995F,
+                0xAB38E15BBD8D0197,
+                0xA51C6106EFF73C93,
+                0x83D7F0E2270A7134,
+                0x0923FD330397FCE5,
+                0xF9DE54EDFE58FB45,
+            ],
+            [
+                0x07D44833ACCD1A94,
+                0xAAD3C9E945E2F9F3,
+                0xABF4C879B876AA37,
+                0xF29C69A21B301619,
+                0x2DDCE959111C788B,
+                0x7CEDB48F8AC1729B,
+                0x93F3BA9A02B659BE,
+                0xF20A87FF17933CBE,
+            ],
+            [
+                0x8E96EBE93180CFE6,
+                0x94CAA12873937079,
+                0x05F613D9380D4189,
+                0xBCAB40C1DC79F38A,
+                0x0AD8907B7C61D19E,
+                0x88534E189D103910,
+                0x2DB2FAABA160AB8F,
+                0xA070E7506B06F15C,
+            ],
+            [
+                0x6FB1FCDAFFEF87A9,
+                0xE735CF25337A090D,
+                0x172C6EDCEFEF1825,
+                0x76957EA49EF0542D,
+                0x819BF4CD250F7C49,
+                0xD6FF23E4AD00C4D4,
+                0xE79673C1EC358FF0,
+                0xAC9C048144337938,
+            ],
+            [
+                0x4C5387FF258B3AF4,
+                0xEDB68FAEC2CB1AA3,
+                0x02A624E67B4E1DA4,
+                0x5C44797A38E08AF2,
+                0x36546A70E9411B4B,
+                0x47C17B24D2FD9675,
+                0x101957AAA020CA26,
+                0x47A1619D4779F122,
+            ],
+            [
+                0xF84B8BCDC92D9A3C,
+                0x951D7D2C74B3066B,
+                0x7AC287C06EDDD9B2,
+                0x4C38FC476608D38F,
+                0x224D793B19CB4BCD,
+                0x835A255899BF1A41,
+                0x4AD250E9F62DB4AB,
+                0xD9B44F4B58781096,
+            ],
+            [
+                0xABBAF99A8EB5C6B8,
+                0xFB568E900D3A9F56,
+                0x11EDF63D23C5DF11,
+                0xA9C3011D3FA7C5A8,
+                0xAEDD3CF11AFFF725,
+                0xABCA472B5F1EDD6B,
+                0x0600B6BB5D879804,
+                0xDB4DE007F22191A0,
+            ],
+            [
+                0xD76CC9EFF0CE9392,
+                0xF5E0A772B59BA49A,
+                0x7D1AE1ED0C1261B5,
+                0x79224A33B5EA4F4A,
+                0x6DD825D80C40EA60,
+                0x47FC8E747E51C953,
+                0x695C05F72888BF98,
+                0x1A012428440B9015,
+            ],
+            [
+                0xD754DD61F9B772BF,
+                0xC4A2FCF4C0F9D4EB,
+                0x461167CDF67A24A2,
+                0x434748490EBCB9D4,
+                0x274DD9CDCA5781DE,
+                0x36BAC63BA9A85209,
+                0x30324DAFDA36B70F,
+                0x337570DB4FE6DAB3,
+            ],
+            [
+                0xF46CBDD57C551546,
+                0x8E02507E676DA3E3,
+                0xD826245A8C15406D,
+                0xDFB38A5B71113B72,
+                0x5EA38454C95B16B5,
+                0x28C054FB87ABF3E1,
+                0xAA2724C0BA1A8096,
+                0xECA83EC980304F2F,
+            ],
+            [
+                0x6AA76EC294EB3303,
+                0x42D4CDB2A8032E3B,
+                0x7999EDF75DCD8735,
+                0xB422BFFE696CCDCC,
+                0x8F721461FD7CCDFE,
+                0x148E1A5814FDE253,
+                0x4DC941F4375EF8FF,
+                0x27B2A9E0EB5B49CF,
+            ],
+            [
+                0xCEA592EF9343EBE1,
+                0xF7D38B5FA7698903,
+                0x6CCBF352203FEAB6,
+                0x830F3095FCCDA9C5,
+                0xDBEEF4B81B81C8F4,
+                0x6D7EB9BCEECA5CF9,
+                0xC58ABB0FBE436C69,
+                0xE4B97E6DB2041A4B,
+            ],
+            [
+                0x7E40FC772978AF14,
+                0xCDDA4BBAE28354A1,
+                0xE4F993B832C32613,
+                0xD3608093C68A4B35,
+                0x9A3B60E01BEE3699,
+                0x03BEF248F3288713,
+                0x70B9294318F3E9B4,
+                0x8D2ABB913B8610DE,
+            ],
+            [
+                0x37F209128E7D8B2C,
+                0x81D2AB375BD874BC,
+                0xA716A1B7373F7408,
+                0x0CEE97BEC4706540,
+                0xA40C5FD9CDBC1512,
+                0x73CAF6C8918409E7,
+                0x45E11BCEDF0BBAA1,
+                0x612C612BFF6E6605,
+            ],
+            [
+                0xF8ECB14A12D0F649,
+                0xDA683CD7C01BA1AC,
+                0xA2203F7510E124C1,
+                0x7F83E52E162F3C78,
+                0x77D2BB73456ACADB,
+                0x37FC34FC840BBA6F,
+                0x3076BC7D4C6EBC1F,
+                0x4F514123632B5FA9,
+            ],
+            [
+                0x44D789DED935E884,
+                0xF8291591E09FEC9F,
+                0xD9CED2CF32A2E4B7,
+                0x95F70E1EB604904A,
+                0xDE438FE43C14F6AB,
+                0x4C8D23E4FAFCF8D8,
+                0xC716910A3067EB86,
+                0x3D6B7915315095D3,
+            ],
+            [
+                0x3170FDBADAB92095,
+                0x8F1963933FC5650B,
+                0x72F94F00ABECFEAB,
+                0x6E3AE826C6AAB4CE,
+                0xA677A2BF31068258,
+                0x9660CDC4F363AF10,
+                0xD81A15A152379EF1,
+                0x5D7D285E1080A3F9,
+            ],
+            [
+                0xDAD5DDFF9A2249B3,
+                0x6F9721D926103FAE,
+                0x1418CBB83FFA349A,
+                0xE71A30AD48C012B2,
+                0xBE76376C63751132,
+                0x3496467ACA713AE6,
+                0x8D7EC01369F991A3,
+                0xD8C73A88B96B154E,
+            ],
+            [
+                0x8B5D9C74AEB4833A,
+                0xF914FB3F867B912F,
+                0xB894EA034936B1DC,
+                0x8A16D21BE51C4F5B,
+                0x31FF048ED582D98E,
+                0xB95AB2F4DC65B820,
+                0x04082B9170561AF7,
+                0xA215610A5DC836FA,
+            ],
+            [
+                0xB2ADE592C092FAAC,
+                0x7A1E683BCBF13294,
+                0xC7A4DBF86858C096,
+                0x3A49940F97BFF316,
+                0xCAE5C06B82C46703,
+                0xC7F413A0F951E2BD,
+                0x6665E7BB10EB5916,
+                0x86F84A5A94EDE319,
+            ],
+            [
+                0x4EA199D8FAA79CA3,
+                0xDFA26E5BF1981704,
+                0x0F5E081D37FA4E01,
+                0x9CB632F89CD675CD,
+                0x4A09DB89D48C0304,
+                0x88142742EA3C7672,
+                0xAC4F149E6D2E9BDB,
+                0x6D9E1C23F8B1C6C6,
+            ],
+            [
+                0xD58BE47B92DEC0E9,
+                0x8E57573645E34328,
+                0x4CC094CCB5FB5126,
+                0x5F1D66AF6FB40E3C,
+                0x2BA15509132D3B00,
+                0x0D6545646120E567,
+                0x3CF680C45C223666,
+                0x96B28E32930179DA,
+            ],
+            [
+                0x5900C45853AC7990,
+                0x61881E3E8B7FF169,
+                0x4DE5F835DF2230FF,
+                0x4427A9E7932F73FF,
+                0x9B641BAD379A8C8D,
+                0xDF271E5BF98F4E5C,
+                0xDFDA16DB830FF5EE,
+                0x371C7E7CFB89C0E9,
+            ],
+            [
+                0x4410A8576247A250,
+                0x6AD2DA12B45AC0D9,
+                0x18DFC72AAC85EECC,
+                0x06FC8BB2A0EF25C8,
+                0xEB287619C85E6118,
+                0x19553ECA67F25A2C,
+                0x3B9557F1DCEC5BAA,
+                0x7BAD9E8B710D1079,
+            ],
+            [
+                0x34F365D66BD22B28,
+                0xE6E124B9F10F835D,
+                0x0573C38ABF2B24DC,
+                0xD32E6AF10A0125AE,
+                0x383590ACEA979519,
+                0x8376ED7A39E28205,
+                0xF0B7F184DCBDA435,
+                0x062A203390E31794,
+            ],
+            [
+                0xA2AFFD7E41918760,
+                0x7F90FC1BD0819C86,
+                0x5033C08E5A969533,
+                0x2707AF5C6D039590,
+                0x57BBD5980F17DF9C,
+                0xD3FE6E61D763268A,
+                0x9E0A0AE40F335A3B,
+                0x43CF4EB0A99613C5,
+            ],
+            [
+                0xD4D2A397CE1A7C2E,
+                0x3DF7CE7CC3212DAD,
+                0x0880F0D5D356C75A,
+                0xA8AFC44DD03B1346,
+                0x79263B46C13A29E0,
+                0x11071B3C0ED58E7A,
+                0xED46DC9F538406BF,
+                0x2C94974F2B94843D,
+            ],
+            [
+                0xE246E13C39AB5D5E,
+                0xAC1018489D955B20,
+                0x8601B558771852B8,
+                0x110BD4C06DB40173,
+                0x738FC8A18CCA0EBB,
+                0x6673E09BE0EA76E5,
+                0x024BC7A0C7527877,
+                0x45E6B4652E2EC34E,
+            ],
+            [
+                0xD1ED26A1A375CDC8,
+                0xAABC4E896A617CB8,
+                0x0A9C9E8E57D753C6,
+                0xA3774A75FEB4C30E,
+                0x30B816C01C93E49E,
+                0xF405BABC06D2408C,
+                0xCC0CE6B4CE788ABC,
+                0x75E7922D0447956C,
+            ],
+            [
+                0xD07C1676A698BC95,
+                0x5F9AEA4840E2D860,
+                0xD5FC10D58BDF6F02,
+                0xF190A2AD4BC2EEA7,
+                0x0C24D11F51726931,
+                0xDB646899A16B6512,
+                0x7BC10670047B1DD8,
+                0x2413A5ABCD45F092,
+            ],
+            [
+                0x4E66892190CFD923,
+                0xF10162440365EC8E,
+                0x158ACA5A6A2280AE,
+                0x0D60ED11C0224166,
+                0x7CD2E9A71B9D7488,
+                0x450D7289706AB2A3,
+                0x88FAE34EC9A0D7DC,
+                0x96FF9103575A97DA,
+            ],
+            [
+                0x77990FAC6046C446,
+                0xB174B5FB30C76676,
+                0xE352CE3EB56CF82A,
+                0xC6039B6873A9A082,
+                0xE3F80F3AE333148A,
+                0xB853BA24BA3539B9,
+                0xE8863E52ECCB0C74,
+                0x309B4CC1092CC245,
+            ],
+            [
+                0xBC2B70BEE8388D9F,
+                0xE48D92AE22216DCE,
+                0xF15F3BF3E2C15D8F,
+                0x1DD964D4812D8B24,
+                0xD56AF02FB4665E4C,
+                0x98002200595BD9A3,
+                0x049246D50BB8FA12,
+                0x1B542DF485B579B9,
+            ],
+            [
+                0x2347409ADFA8E497,
+                0x36015C2211D62498,
+                0xE9F141F32EB82690,
+                0x1F839912D0449FB9,
+                0x4E4DCFFF2D02D97C,
+                0xF8A03AB4C0F625C9,
+                0x0605F575795DAC5C,
+                0x4746C9BEA0DDA6B1,
+            ],
+            [
+                0xCA5BB519ECE7481B,
+                0xFD496155E55CA945,
+                0xF753B9DBB1515F81,
+                0x50549E8BAC0F70E7,
+                0x8614FB0271E21C60,
+                0x60C72947EB0F0070,
+                0xA6511C10AEE742B6,
+                0x48FB48F2CACCB43E,
+            ],
+        ];
+
+        let mut rng = Xorshift128Plus::new_with_seed(12345);
+        for expected_row in EXPECTED.iter() {
+            let mut row = [0; Xorshift128Plus::N];
+            rng.fill(&mut row);
+            for (&actual, &expected) in row.iter().zip(expected_row) {
+                assert_eq!(actual, expected);
+            }
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/.cargo-checksum.json b/third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/.cargo-checksum.json
new file mode 100644
index 0000000..697c9ce
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{}}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/.cargo_vcs_info.json
new file mode 100644
index 0000000..f23045d
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+  "git": {
+    "sha1": "e3d3eeb3b30c9a50e0c3646046648ae708154099"
+  },
+  "path_in_vcs": "jxl_macros"
+}
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/Cargo.lock b/third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/Cargo.lock
new file mode 100644
index 0000000..1244f8c
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/Cargo.lock
@@ -0,0 +1,70 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "jxl_macros"
+version = "0.1.4"
+dependencies = [
+ "proc-macro-error2",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "proc-macro-error-attr2"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+]
+
+[[package]]
+name = "proc-macro-error2"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
+dependencies = [
+ "proc-macro-error-attr2",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.103"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.110"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/Cargo.toml
new file mode 100644
index 0000000..8e2691c
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/Cargo.toml
@@ -0,0 +1,63 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2024"
+name = "jxl_macros"
+version = "0.1.4"
+authors = ["Luca Versari <veluca93@gmail.com>"]
+build = false
+autolib = false
+autobins = false
+autoexamples = false
+autotests = false
+autobenches = false
+description = "High performance Rust implementation of a JPEG XL decoder - supporting macros"
+readme = "README.md"
+keywords = [
+    "jpeg-xl",
+    "decoder",
+]
+categories = ["multimedia::images"]
+license = "BSD-3-Clause"
+repository = "https://github.com/libjxl/jxl-rs"
+resolver = "2"
+
+[features]
+test = []
+
+[lib]
+name = "jxl_macros"
+path = "src/lib.rs"
+proc-macro = true
+
+[dependencies.proc-macro-error2]
+version = "2.0.1"
+
+[dependencies.proc-macro2]
+version = "1.0"
+
+[dependencies.quote]
+version = "1.0"
+
+[dependencies.syn]
+version = "2.0.90"
+features = [
+    "extra-traits",
+    "full",
+]
+
+[lints.clippy]
+missing_safety_doc = "deny"
+undocumented_unsafe_blocks = "deny"
+
+[lints.rust]
+unsafe_op_in_unsafe_fn = "deny"
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/Cargo.toml.orig
new file mode 100644
index 0000000..019abac
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/Cargo.toml.orig
@@ -0,0 +1,26 @@
+[package]
+name = "jxl_macros"
+description = "High performance Rust implementation of a JPEG XL decoder - supporting macros"
+version = "0.1.4"
+readme = "../README.md"
+keywords = ["jpeg-xl", "decoder"]
+categories = ["multimedia::images"]
+authors = ["Luca Versari <veluca93@gmail.com>"]
+repository = "https://github.com/libjxl/jxl-rs"
+edition = "2024"
+license = "BSD-3-Clause"
+
+[lib]
+proc-macro = true
+
+[dependencies]
+proc-macro-error2 = "2.0.1"
+proc-macro2 = "1.0"
+quote = "1.0"
+syn = { version = "2.0.90", features = ["extra-traits", "full"] }
+
+[lints]
+workspace = true
+
+[features]
+test = []
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/LICENSE b/third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/LICENSE
new file mode 100644
index 0000000..c66034b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) the JPEG XL Project Authors.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/README.md b/third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/README.md
new file mode 100644
index 0000000..b6bf14a
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/README.md
@@ -0,0 +1,9 @@
+# JPEG XL in Rust
+
+This is a work-in-progress reimplementation of a JPEG XL decoder in Rust, aiming to be conforming, safe, and fast.
+
+We strive to decode all conformant JPEG XL bitstreams correctly. If you find an image that can be decoded with the reference 
+implementation `djxl` (from [`libjxl`](https://github.com/libjxl/libjxl)) but is decoded incorrectly or not at all by `jxl-rs`, 
+please report it by [opening an issue](https://github.com/libjxl/jxl-rs/issues/new).
+
+For more information, including contributing instructions, refer to the [libjxl repository](https://github.com/libjxl/libjxl).
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/src/lib.rs
new file mode 100644
index 0000000..6a918ee
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/src/lib.rs
@@ -0,0 +1,755 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+use proc_macro_error2::{abort, proc_macro_error};
+use proc_macro2::TokenStream as TokenStream2;
+use quote::quote;
+use syn::{DeriveInput, Meta, parse_macro_input};
+
+fn get_bits(expr_call: &syn::ExprCall) -> syn::Expr {
+    if let syn::Expr::Path(ep) = &*expr_call.func {
+        if !ep.path.is_ident("Bits") {
+            abort!(
+                expr_call,
+                "Unexpected function name in coder: {}",
+                ep.path.get_ident().unwrap()
+            );
+        }
+        if expr_call.args.len() != 1 {
+            abort!(
+                expr_call,
+                "Unexpected number of arguments for Bits() in coder: {}",
+                expr_call.args.len()
+            );
+        }
+        return expr_call.args[0].clone();
+    }
+    abort!(expr_call, "Unexpected function call in coder");
+}
+
+fn parse_single_coder(input: &syn::Expr, extra_lit: Option<&syn::ExprLit>) -> TokenStream2 {
+    match &input {
+        syn::Expr::Lit(lit) => match extra_lit {
+            None => quote! {U32::Val(#lit)},
+            Some(elit) => quote! {U32::Val(#lit + #elit)},
+        },
+        syn::Expr::Call(expr_call) => {
+            let bits = get_bits(expr_call);
+            match extra_lit {
+                None => quote! {U32::Bits(#bits)},
+                Some(elit) => quote! {U32::BitsOffset{n: #bits, off: #elit}},
+            }
+        }
+        syn::Expr::Binary(syn::ExprBinary {
+            attrs: _,
+            left,
+            op: syn::BinOp::Add(_),
+            right,
+        }) => {
+            let (left, right) = if let syn::Expr::Lit(_) = **left {
+                (right, left)
+            } else {
+                (left, right)
+            };
+            match (&**left, &**right) {
+                (syn::Expr::Call(expr_call), syn::Expr::Lit(lit)) => {
+                    let bits = get_bits(expr_call);
+                    match extra_lit {
+                        None => quote! {U32::BitsOffset{n: #bits, off: #lit}},
+                        Some(elit) => quote! {U32::BitsOffset{n: #bits, off: #lit + #elit}},
+                    }
+                }
+                _ => abort!(
+                    input,
+                    "Unexpected expression in coder, must be Bits(a) + b, Bits(a), or b"
+                ),
+            }
+        }
+        _ => abort!(
+            input,
+            "Unexpected expression in coder, must be Bits(a) + b, Bits(a), or b"
+        ),
+    }
+}
+
+fn parse_coder(input: &syn::Expr) -> TokenStream2 {
+    let parse_u2s = |expr_call: &syn::ExprCall, lit: Option<&syn::ExprLit>| {
+        if let syn::Expr::Path(ep) = &*expr_call.func {
+            if !ep.path.is_ident("u2S") {
+                let coder = parse_single_coder(input, None);
+                return quote! {U32Coder::Direct(#coder)};
+            }
+            if expr_call.args.len() != 4 {
+                abort!(
+                    input,
+                    "Unexpected number of arguments for U32() in coder: {}",
+                    expr_call.args.len()
+                );
+            }
+            let args = vec![
+                parse_single_coder(&expr_call.args[0], lit),
+                parse_single_coder(&expr_call.args[1], lit),
+                parse_single_coder(&expr_call.args[2], lit),
+                parse_single_coder(&expr_call.args[3], lit),
+            ];
+            return quote! {U32Coder::Select(#(#args),*)};
+        }
+        abort!(input, "Unexpected function call in coder");
+    };
+
+    match &input {
+        syn::Expr::Call(expr_call) => parse_u2s(expr_call, None),
+        syn::Expr::Binary(syn::ExprBinary {
+            attrs: _,
+            left,
+            op: syn::BinOp::Add(_),
+            right,
+        }) => {
+            let (left, right) = if let syn::Expr::Lit(_) = **left {
+                (right, left)
+            } else {
+                (left, right)
+            };
+            match (&**left, &**right) {
+                (syn::Expr::Call(expr_call), syn::Expr::Lit(lit)) => {
+                    parse_u2s(expr_call, Some(lit))
+                }
+                _ => abort!(
+                    input,
+                    "Unexpected expression in coder, must be (u2S|Bits)(a) + b, (u2S|Bits)(a), or b"
+                ),
+            }
+        }
+        _ => parse_single_coder(input, None),
+    }
+}
+
+fn parse_size_coder(mut input: syn::Expr) -> TokenStream2 {
+    match input {
+        syn::Expr::Call(syn::ExprCall {
+            ref func,
+            ref mut args,
+            ..
+        }) => {
+            if args.len() != 1 {
+                abort!(input, "Expected 1 argument in sized_coder inner call");
+            }
+
+            match &**func {
+                syn::Expr::Path(expr_path) if expr_path.path.is_ident("implicit") => {
+                    let arg = args.first().unwrap().clone();
+                    parse_coder(&arg)
+                }
+                syn::Expr::Path(expr_path) if expr_path.path.is_ident("explicit") => {
+                    quote! { U32Coder::Direct(U32::Val(#args)) }
+                }
+                _ => abort!(
+                    input,
+                    "Unexpected expression in size_coder, must be 'implicit()' or 'explicit()'"
+                ),
+            }
+        }
+        _ => abort!(
+            input,
+            "Unexpected expression in size_coder, must be 'implicit()' or 'explicit()'"
+        ),
+    }
+}
+
+fn prettify_condition(cond: &syn::Expr) -> String {
+    (quote! {#cond})
+        .to_string()
+        .replace(" . ", ".")
+        .replace("! ", "!")
+        .replace(" :: ", "::")
+}
+
+#[derive(Debug)]
+struct Condition {
+    expr: Option<syn::Expr>,
+    has_all_default: bool,
+    pretty: String,
+}
+
+impl Condition {
+    fn get_expr(&self, all_default_field: &Option<syn::Ident>) -> Option<TokenStream2> {
+        if self.has_all_default {
+            let all_default = all_default_field.as_ref().unwrap();
+            match &self.expr {
+                Some(expr) => Some(quote! { !#all_default && (#expr) }),
+                None => Some(quote! { !#all_default }),
+            }
+        } else {
+            self.expr.as_ref().map(|expr| quote! {#expr})
+        }
+    }
+    fn get_pretty(&self, all_default_field: &Option<syn::Ident>) -> String {
+        if self.has_all_default {
+            let all_default = all_default_field.as_ref().unwrap();
+            let all_default = "!".to_owned() + &quote! {#all_default}.to_string();
+            match &self.expr {
+                Some(_) => all_default + " && (" + &self.pretty + ")",
+                None => all_default,
+            }
+        } else {
+            self.pretty.clone()
+        }
+    }
+}
+
+#[derive(Debug, Clone)]
+struct U32 {
+    coder: TokenStream2,
+}
+
+#[derive(Debug)]
+#[allow(clippy::large_enum_variant)]
+enum Coder {
+    WithoutConfig,
+    U32(U32),
+    Select(Condition, U32, U32),
+    Vector(U32, Box<Coder>),
+}
+
+impl Coder {
+    fn ty(&self) -> TokenStream2 {
+        match self {
+            Coder::WithoutConfig => quote! {()},
+            Coder::U32(..) => quote! {U32Coder},
+            Coder::Select(..) => quote! {SelectCoder<U32Coder>},
+            Coder::Vector(_, value_coder) => {
+                let value_coder_ty = value_coder.ty();
+                quote! {VectorCoder<#value_coder_ty>}
+            }
+        }
+    }
+
+    fn config(&self, all_default_field: &Option<syn::Ident>) -> TokenStream2 {
+        match self {
+            Coder::WithoutConfig => quote! { () },
+            Coder::U32(U32 { coder }) => quote! { #coder },
+            Coder::Select(condition, U32 { coder: coder_true }, U32 { coder: coder_false }) => {
+                let cnd = condition.get_expr(all_default_field).unwrap();
+                quote! {
+                    SelectCoder{use_true: #cnd, coder_true: #coder_true, coder_false: #coder_false}
+                }
+            }
+            Coder::Vector(U32 { coder }, value_coder) => {
+                let value_coder = value_coder.config(all_default_field);
+                quote! {VectorCoder{size_coder: #coder, value_coder: #value_coder}}
+            }
+        }
+    }
+}
+
+#[derive(Debug)]
+enum FieldKind {
+    Unconditional(Coder),
+    Conditional(Condition, Coder),
+    Defaulted(Condition, Coder),
+}
+
+#[derive(Debug)]
+struct Field {
+    name: proc_macro2::Ident,
+    kind: FieldKind,
+    ty: syn::Type,
+    default: Option<TokenStream2>,
+    default_element: Option<TokenStream2>,
+    nonserialized_inits: Vec<TokenStream2>,
+}
+
+impl Field {
+    fn parse(f: &syn::Field, num: usize, all_default_field: &mut Option<syn::Ident>) -> Field {
+        let mut condition = None;
+        let mut default = None;
+        let mut coder = None;
+
+        let mut select_coder = None;
+        let mut coder_true = None;
+        let mut coder_false = None;
+
+        let mut is_all_default = false;
+
+        let mut size_coder = None;
+
+        let mut nonserialized = vec![];
+
+        let mut default_element = None;
+
+        // Parse attributes.
+        for a in &f.attrs {
+            match a.path().get_ident().map(syn::Ident::to_string).as_deref() {
+                Some("coder") => {
+                    if coder.is_some() {
+                        abort!(f, "Repeated coder");
+                    }
+                    let coder_ast = a.parse_args::<syn::Expr>().unwrap();
+                    coder = Some(Coder::U32(U32 {
+                        coder: parse_coder(&coder_ast),
+                    }));
+                }
+                Some("default") => {
+                    if default.is_some() {
+                        abort!(f, "Repeated default");
+                    }
+                    let default_expr = a.parse_args::<syn::Expr>().unwrap();
+                    default = Some(quote! {#default_expr});
+                }
+                Some("default_element") => {
+                    if default_element.is_some() {
+                        abort!(f, "Repeated default_element")
+                    }
+                    let default_element_expr = a.parse_args::<syn::Expr>().unwrap();
+                    default_element = Some(quote! { #default_element_expr })
+                }
+                Some("condition") => {
+                    if condition.is_some() {
+                        abort!(f, "Repeated condition");
+                    }
+                    let condition_ast = a.parse_args::<syn::Expr>().unwrap();
+                    let pretty_cond = prettify_condition(&condition_ast);
+                    condition = Some(Condition {
+                        expr: Some(condition_ast),
+                        has_all_default: all_default_field.is_some(),
+                        pretty: pretty_cond,
+                    });
+                }
+                Some("all_default") => {
+                    if num != 0 {
+                        abort!(f, "all_default is not the first field");
+                    }
+                    if default.is_some() {
+                        abort!(f, "all_default has an implicit default");
+                    }
+                    is_all_default = true;
+                    default = Some(quote! { true });
+                }
+                Some("select_coder") => {
+                    if select_coder.is_some() {
+                        abort!(f, "Repeated select_coder");
+                    }
+                    let condition_ast = a.parse_args::<syn::Expr>().unwrap();
+                    let pretty_cond = prettify_condition(&condition_ast);
+                    select_coder = Some(Condition {
+                        expr: Some(condition_ast),
+                        has_all_default: false,
+                        pretty: pretty_cond,
+                    });
+                }
+                Some("coder_false") => {
+                    if coder_false.is_some() {
+                        abort!(f, "Repeated coder_false");
+                    }
+                    let coder_ast = a.parse_args::<syn::Expr>().unwrap();
+                    coder_false = Some(U32 {
+                        coder: parse_coder(&coder_ast),
+                    });
+                }
+                Some("coder_true") => {
+                    if coder_true.is_some() {
+                        abort!(f, "Repeated coder_true");
+                    }
+                    let coder_ast = a.parse_args::<syn::Expr>().unwrap();
+                    coder_true = Some(U32 {
+                        coder: parse_coder(&coder_ast),
+                    });
+                }
+                Some("size_coder") => {
+                    if size_coder.is_some() {
+                        abort!(f, "Repeated size_coder");
+                    }
+                    let coder_ast = a.parse_args::<syn::Expr>().unwrap();
+                    size_coder = Some(U32 {
+                        coder: parse_size_coder(coder_ast),
+                    });
+                }
+                Some("nonserialized") => {
+                    let Meta::List(ns) = &a.meta else {
+                        abort!(a, "Invalid attribute");
+                    };
+                    let stream = &ns.tokens;
+                    nonserialized.push(quote! {#stream});
+                }
+                _ => {}
+            }
+        }
+
+        if default.is_some() && default_element.is_some() {
+            abort!(f, "default is incompatible with default_element");
+        }
+
+        if let Some(select_coder) = select_coder {
+            if coder_true.is_none() || coder_false.is_none() {
+                abort!(
+                    f,
+                    "Invalid field, select_coder is set but coder_true or coder_false are not"
+                )
+            }
+            if coder.is_some() {
+                abort!(f, "Invalid field, select_coder and coder are both present")
+            }
+            coder = Some(Coder::Select(
+                select_coder,
+                coder_true.unwrap(),
+                coder_false.unwrap(),
+            ))
+        }
+
+        let condition = if condition.is_some() || all_default_field.is_none() {
+            condition
+        } else {
+            Some(Condition {
+                expr: None,
+                has_all_default: true,
+                pretty: String::new(),
+            })
+        };
+
+        // Assume nested field if no coder.
+        let mut coder = coder.unwrap_or_else(|| Coder::WithoutConfig);
+
+        if let Some(c) = size_coder {
+            if default.is_none() {
+                default = Some(quote! { Vec::new() });
+            }
+
+            coder = Coder::Vector(c, Box::new(coder))
+        }
+
+        let ident = f.ident.as_ref().unwrap();
+
+        let kind = match (condition, default.is_some()) {
+            (None, _) => FieldKind::Unconditional(coder),
+            (Some(cond), false) => FieldKind::Conditional(cond, coder),
+            (Some(cond), true) => FieldKind::Defaulted(cond, coder),
+        };
+        if is_all_default {
+            *all_default_field = Some(f.ident.as_ref().unwrap().clone());
+        }
+        Field {
+            name: ident.clone(),
+            kind,
+            ty: f.ty.clone(),
+            default,
+            default_element,
+            nonserialized_inits: nonserialized,
+        }
+    }
+
+    // Produces reading code (possibly with tracing).
+    fn read_fun(&self, all_default_field: &Option<syn::Ident>) -> TokenStream2 {
+        let ident = &self.name;
+        let ty = &self.ty;
+        let nonserialized_inits = &self.nonserialized_inits;
+        match &self.kind {
+            FieldKind::Unconditional(coder) => {
+                let cfg_ty = coder.ty();
+                let cfg = coder.config(all_default_field);
+                let trc = quote! {
+                    crate::util::tracing_wrappers::trace!("Setting {} to {:?}. total_bits_read: {}, peek: {:08b}", stringify!(#ident), #ident, br.total_bits_read(), br.peek(8));
+                };
+                quote! {
+                    let #ident = {
+                        let cfg = #cfg;
+                        type NS = <#ty as UnconditionalCoder<#cfg_ty>>::Nonserialized;
+                        let nonserialized = NS { #(#nonserialized_inits),* };
+                        <#ty>::read_unconditional(&cfg, br, &nonserialized)?
+                    };
+                    #trc
+                }
+            }
+            FieldKind::Conditional(condition, coder) => {
+                let cfg_ty = coder.ty();
+                let cfg = coder.config(all_default_field);
+                let cnd = condition.get_expr(all_default_field).unwrap();
+                let pretty_cnd = condition.get_pretty(all_default_field);
+                let trc = quote! {
+                    crate::util::tracing_wrappers::trace!("{} is {}, setting {} to {:?}. total_bits_read: {}, peek {:08b}", #pretty_cnd, #cnd, stringify!(#ident), #ident, br.total_bits_read(), br.peek(8));
+                };
+                quote! {
+                    let #ident = {
+                        let cond = #cnd;
+                        let cfg = #cfg;
+                        type NS = <#ty as ConditionalCoder<#cfg_ty>>::Nonserialized;
+                        let nonserialized = NS { #(#nonserialized_inits),* };
+                        <#ty>::read_conditional(&cfg, cond, br, &nonserialized)?
+                    };
+                    #trc
+                }
+            }
+            FieldKind::Defaulted(condition, coder) => {
+                let cfg_ty = coder.ty();
+                let cfg = coder.config(all_default_field);
+                let cnd = condition.get_expr(all_default_field).unwrap();
+                let pretty_cnd = condition.get_pretty(all_default_field);
+                let default = &self.default;
+                let trc = quote! {
+                    crate::util::tracing_wrappers::trace!("{} is {}, setting {} to {:?}. total_bits_read: {}, peek {:08b}", #pretty_cnd, #cnd, stringify!(#ident), #ident, br.total_bits_read(), br.peek(8));
+                };
+
+                let (read_fn, default) = if let Some(def) = &self.default_element {
+                    (quote! { read_defaulted_element }, Some(def))
+                } else {
+                    (quote! { read_defaulted }, default.as_ref())
+                };
+
+                quote! {
+                    let #ident = {
+                        let cond = #cnd;
+                        let cfg = #cfg;
+                        type NS = <#ty as DefaultedCoder<#cfg_ty>>::Nonserialized;
+                        let field_nonserialized = NS { #(#nonserialized_inits),* };
+                        let default = #default;
+                        <#ty>::#read_fn(&cfg, cond, default, br, &field_nonserialized)?
+                    };
+                    #trc
+                }
+            }
+        }
+    }
+
+    // Produces default code.
+    fn default_code(&self) -> TokenStream2 {
+        let ident = &self.name;
+        let ty = &self.ty;
+        let nonserialized_inits = &self.nonserialized_inits;
+        let default = &self.default;
+        match &self.kind {
+            FieldKind::Defaulted(_, coder) => {
+                let cfg_ty = coder.ty();
+                let default = &self.default;
+
+                quote! {
+                    let #ident = {
+                        type NS = <#ty as DefaultedCoder<#cfg_ty>>::Nonserialized;
+                        let field_nonserialized = NS { #(#nonserialized_inits),* };
+                        #default
+                    };
+                }
+            }
+            _ => quote! { let #ident = #default; },
+        }
+    }
+}
+
+fn derive_struct(input: &DeriveInput) -> TokenStream2 {
+    let name = &input.ident;
+
+    let validate = input.attrs.iter().any(|a| a.path().is_ident("validate"));
+    let nonserialized: Vec<_> = input
+        .attrs
+        .iter()
+        .filter_map(|a| {
+            if a.path().is_ident("nonserialized") {
+                Some(a.parse_args::<syn::Expr>().unwrap())
+            } else {
+                None
+            }
+        })
+        .collect();
+    if nonserialized.len() > 1 {
+        abort!(input, "repeated nonserialized");
+    }
+    let nonserialized = if nonserialized.is_empty() {
+        quote! {Empty}
+    } else {
+        let v = &nonserialized[0];
+        quote! {#v}
+    };
+
+    let data = if let syn::Data::Struct(struct_data) = &input.data {
+        struct_data
+    } else {
+        abort!(input, "derive_struct didn't get a struct");
+    };
+
+    let fields = if let syn::Fields::Named(syn::FieldsNamed {
+        brace_token: _,
+        named,
+    }) = &data.fields
+    {
+        named
+    } else {
+        abort!(data.fields, "only named fields are supported (for now?)");
+    };
+
+    let mut all_default_field = None;
+
+    let fields: Vec<_> = fields
+        .iter()
+        .enumerate()
+        .map(|(n, f)| Field::parse(f, n, &mut all_default_field))
+        .collect();
+    let fields_read = fields.iter().map(|x| x.read_fun(&all_default_field));
+    let fields_names = fields.iter().map(|x| &x.name);
+
+    let impl_default = if fields.iter().all(|x| x.default.is_some()) {
+        let field_init = fields.iter().map(Field::default_code);
+        let struct_init = fields.iter().map(|f| {
+            let ident = &f.name;
+            quote! { #ident }
+        });
+        quote! {
+            impl #name {
+                pub fn default(nonserialized: &#nonserialized) -> #name {
+                    #(#field_init)*
+                    #name {
+                        #(#struct_init),*
+                    }
+                }
+            }
+
+        }
+    } else {
+        quote! {}
+    };
+
+    let impl_validate = if validate {
+        quote! { return_value.check(nonserialized)?; }
+    } else {
+        quote! {}
+    };
+
+    let align = match input.attrs.iter().any(|a| a.path().is_ident("aligned")) {
+        true => quote! { br.jump_to_byte_boundary()?; },
+        false => quote! {},
+    };
+
+    quote! {
+        #impl_default
+        impl crate::headers::encodings::UnconditionalCoder<()> for #name {
+            type Nonserialized = #nonserialized;
+            #[cold]
+            #[inline(never)]
+            fn read_unconditional(_: &(), br: &mut BitReader, nonserialized: &Self::Nonserialized) -> Result<#name, Error> {
+                use crate::headers::encodings::UnconditionalCoder;
+                use crate::headers::encodings::ConditionalCoder;
+                use crate::headers::encodings::DefaultedCoder;
+                use crate::headers::encodings::DefaultedElementCoder;
+                #align
+                #(#fields_read)*
+                let return_value = #name {
+                    #(#fields_names),*
+                };
+                #impl_validate
+                Ok(return_value)
+            }
+        }
+    }
+}
+
+fn derive_enum(input: &DeriveInput) -> TokenStream2 {
+    let name = &input.ident;
+    quote! {
+        impl crate::headers::encodings::UnconditionalCoder<U32Coder> for #name {
+            type Nonserialized = Empty;
+            fn read_unconditional(config: &U32Coder, br: &mut BitReader, _: &Empty) -> Result<#name, Error> {
+                use num_traits::FromPrimitive;
+                let u = u32::read_unconditional(config, br, &Empty{})?;
+                if let Some(e) =  #name::from_u32(u) {
+                    Ok(e)
+                } else {
+                    Err(Error::InvalidEnum(u, stringify!(#name).to_string()))
+                }
+            }
+        }
+        impl crate::headers::encodings::UnconditionalCoder<()> for #name {
+            type Nonserialized = Empty;
+            fn read_unconditional(config: &(), br: &mut BitReader, nonserialized: &Empty) -> Result<#name, Error> {
+                #name::read_unconditional(
+                    &U32Coder::Select(
+                        U32::Val(0), U32::Val(1),
+                        U32::BitsOffset{n: 4, off: 2},
+                        U32::BitsOffset{n: 6, off: 18}), br, nonserialized)
+            }
+        }
+    }
+}
+
+#[proc_macro_error]
+#[proc_macro_derive(
+    UnconditionalCoder,
+    attributes(
+        coder,
+        condition,
+        default,
+        default_element,
+        all_default,
+        select_coder,
+        coder_true,
+        coder_false,
+        validate,
+        size_coder,
+        nonserialized,
+        aligned,
+    )
+)]
+pub fn derive_jxl_headers(input: TokenStream) -> TokenStream {
+    let input = parse_macro_input!(input as DeriveInput);
+
+    match &input.data {
+        syn::Data::Struct(_) => derive_struct(&input).into(),
+        syn::Data::Enum(_) => derive_enum(&input).into(),
+        _ => abort!(input, "Only implemented for struct"),
+    }
+}
+
+#[proc_macro_attribute]
+pub fn noop(_attr: TokenStream, item: TokenStream) -> TokenStream {
+    item
+}
+
+#[cfg(feature = "test")]
+#[proc_macro]
+pub fn for_each_test_file(input: TokenStream) -> TokenStream {
+    use std::{fs, path::Path};
+    use syn::Ident;
+
+    let fn_name = parse_macro_input!(input as Ident);
+    let root_test_dir = Path::new(env!("CARGO_MANIFEST_DIR"))
+        .join("..")
+        .join("jxl")
+        .join("resources")
+        .join("test");
+    let conformance_test_dir = root_test_dir.join("conformance_test_images");
+
+    let mut tests = vec![];
+
+    for test_dir in [root_test_dir, conformance_test_dir] {
+        for entry in fs::read_dir(&test_dir).unwrap() {
+            let entry = entry.unwrap();
+            let path = entry.path();
+            if path.extension().is_some_and(|ext| ext == "jxl") {
+                let pathname = path.to_string_lossy();
+                let relative_path = path
+                    .strip_prefix(&test_dir)
+                    .unwrap()
+                    .to_string_lossy()
+                    .replace('/', "_slash_");
+                let test_name = format!(
+                    "{}_{}",
+                    fn_name,
+                    relative_path.strip_suffix(".jxl").unwrap()
+                );
+                let test_name = Ident::new(&test_name, fn_name.span());
+                tests.push(quote! {
+                    #[test]
+                    fn #test_name() {
+                        #fn_name(&Path::new(#pathname)).unwrap()
+                    }
+                });
+            }
+        }
+    }
+
+    quote! {
+        #(#tests)*
+    }
+    .into()
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/.cargo-checksum.json b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/.cargo-checksum.json
new file mode 100644
index 0000000..697c9ce
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{}}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/.cargo_vcs_info.json
new file mode 100644
index 0000000..a148977
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+  "git": {
+    "sha1": "e3d3eeb3b30c9a50e0c3646046648ae708154099"
+  },
+  "path_in_vcs": "jxl_simd"
+}
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/Cargo.lock b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/Cargo.lock
new file mode 100644
index 0000000..60ccdbc
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/Cargo.lock
@@ -0,0 +1,32 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "arbitrary"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
+
+[[package]]
+name = "arbtest"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a3be567977128c0f71ad1462d9624ccda712193d124e944252f0c5789a06d46"
+dependencies = [
+ "arbitrary",
+]
+
+[[package]]
+name = "jxl_simd"
+version = "0.1.4"
+dependencies = [
+ "arbtest",
+ "paste",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/Cargo.toml
new file mode 100644
index 0000000..1075406
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/Cargo.toml
@@ -0,0 +1,63 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2024"
+name = "jxl_simd"
+version = "0.1.4"
+authors = ["Luca Versari <veluca93@gmail.com>"]
+build = false
+autolib = false
+autobins = false
+autoexamples = false
+autotests = false
+autobenches = false
+description = "High performance Rust implementation of a JPEG XL decoder - SIMD support code"
+readme = "README.md"
+keywords = [
+    "jpeg-xl",
+    "simd",
+]
+categories = ["multimedia::images"]
+license = "BSD-3-Clause"
+repository = "https://github.com/libjxl/jxl-rs"
+resolver = "2"
+
+[features]
+all-simd = [
+    "sse42",
+    "avx",
+    "avx512",
+    "neon",
+]
+avx = ["sse42"]
+avx512 = ["avx"]
+neon = []
+sse42 = []
+
+[lib]
+name = "jxl_simd"
+path = "src/lib.rs"
+
+[dependencies]
+
+[dev-dependencies.arbtest]
+version = "0.3.2"
+
+[dev-dependencies.paste]
+version = "1.0.15"
+
+[lints.clippy]
+missing_safety_doc = "deny"
+undocumented_unsafe_blocks = "deny"
+
+[lints.rust]
+unsafe_op_in_unsafe_fn = "deny"
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/Cargo.toml.orig
new file mode 100644
index 0000000..314193d
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/Cargo.toml.orig
@@ -0,0 +1,27 @@
+[package]
+name = "jxl_simd"
+description = "High performance Rust implementation of a JPEG XL decoder - SIMD support code"
+version = "0.1.4"
+readme = "../README.md"
+keywords = ["jpeg-xl", "simd"]
+categories = ["multimedia::images"]
+authors = ["Luca Versari <veluca93@gmail.com>"]
+repository = "https://github.com/libjxl/jxl-rs"
+edition = "2024"
+license = "BSD-3-Clause"
+
+[dependencies]
+
+[dev-dependencies]
+arbtest = "0.3.2"
+paste = "1.0.15"
+
+[features]
+all-simd = ["sse42", "avx", "avx512", "neon"]
+sse42 = []
+avx = ["sse42"]
+avx512 = ["avx"]
+neon = []
+
+[lints]
+workspace = true
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/LICENSE b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/LICENSE
new file mode 100644
index 0000000..c66034b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) the JPEG XL Project Authors.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/README.md b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/README.md
new file mode 100644
index 0000000..b6bf14a
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/README.md
@@ -0,0 +1,9 @@
+# JPEG XL in Rust
+
+This is a work-in-progress reimplementation of a JPEG XL decoder in Rust, aiming to be conforming, safe, and fast.
+
+We strive to decode all conformant JPEG XL bitstreams correctly. If you find an image that can be decoded with the reference 
+implementation `djxl` (from [`libjxl`](https://github.com/libjxl/libjxl)) but is decoded incorrectly or not at all by `jxl-rs`, 
+please report it by [opening an issue](https://github.com/libjxl/jxl-rs/issues/new).
+
+For more information, including contributing instructions, refer to the [libjxl repository](https://github.com/libjxl/libjxl).
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/aarch64/mod.rs b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/aarch64/mod.rs
new file mode 100644
index 0000000..0371f83
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/aarch64/mod.rs
@@ -0,0 +1,126 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(unsafe_code)]
+#![allow(clippy::identity_op)]
+
+#[cfg(feature = "neon")]
+pub(super) mod neon;
+
+#[macro_export]
+macro_rules! simd_function {
+    (
+        $dname:ident,
+        $descr:ident: $descr_ty:ident,
+        $(#[$($attr:meta)*])*
+        $pub:vis fn $name:ident($($arg:ident: $ty:ty),* $(,)?) $(-> $ret:ty )? $body: block
+    ) => {
+        #[inline(always)]
+        $(#[$($attr)*])*
+        $pub fn $name<$descr_ty: $crate::SimdDescriptor>($descr: $descr_ty, $($arg: $ty),*) $(-> $ret)? $body
+        #[allow(unsafe_code)]
+        $(#[$($attr)*])*
+        $pub fn $dname($($arg: $ty),*) $(-> $ret)? {
+            #[allow(unused)]
+            use $crate::SimdDescriptor;
+            $crate::simd_function_body_neon!($name($($arg: $ty),*) $(-> $ret)?; ($($arg),*));
+            $name($crate::ScalarDescriptor::new().unwrap(), $($arg),*)
+        }
+    };
+}
+
+#[cfg(feature = "neon")]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! simd_function_body_neon {
+    ($name:ident($($arg:ident: $ty:ty),* $(,)?) $(-> $ret:ty )?; ($($val:expr),* $(,)?)) => {
+        if cfg!(target_feature = "neon") {
+            // SAFETY: we just checked for neon.
+            let d = unsafe { $crate::NeonDescriptor::new_unchecked() };
+            return $name(d, $($val),*);
+        } else if let Some(d) = $crate::NeonDescriptor::new() {
+            #[target_feature(enable = "neon")]
+            fn neon(d: $crate::NeonDescriptor, $($arg: $ty),*) $(-> $ret)? {
+                $name(d, $($val),*)
+            }
+            // SAFETY: we just checked for neon.
+            return unsafe { neon(d, $($arg),*) };
+        }
+    };
+}
+
+#[cfg(not(feature = "neon"))]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! simd_function_body_neon {
+    ($($ignore:tt)*) => {};
+}
+
+#[macro_export]
+macro_rules! test_all_instruction_sets {
+    (
+        $name:ident
+    ) => {
+        paste::paste! {
+            #[test]
+            fn [<$name _scalar>]() {
+                use $crate::SimdDescriptor;
+                $name($crate::ScalarDescriptor::new().unwrap())
+            }
+        }
+
+        $crate::test_neon!($name);
+    };
+}
+
+#[cfg(feature = "neon")]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! test_neon {
+    ($name:ident) => {
+        paste::paste! {
+            #[allow(unsafe_code)]
+            #[test]
+            fn [<$name _neon>]() {
+                use $crate::SimdDescriptor;
+                let Some(d) = $crate::NeonDescriptor::new() else { return; };
+                #[target_feature(enable = "neon")]
+                fn inner(d: $crate::NeonDescriptor) {
+                    $name(d)
+                }
+                // SAFETY: we just checked for neon.
+                return unsafe { inner(d) };
+
+            }
+        }
+    };
+}
+
+#[cfg(not(feature = "neon"))]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! test_neon {
+    ($name:ident) => {};
+}
+
+#[macro_export]
+macro_rules! bench_all_instruction_sets {
+    (
+        $name:ident,
+        $criterion:ident
+    ) => {
+        use $crate::SimdDescriptor;
+        // `simd_function_body_*` does early return; wrap it with an immediately-invoked closure
+        (|| $crate::simd_function_body_neon!(
+            $name($criterion: &mut ::criterion::BenchmarkGroup<'_, impl ::criterion::measurement::Measurement>);
+            ($criterion, "neon")
+        ))();
+        $name(
+            $crate::ScalarDescriptor::new().unwrap(),
+            $criterion,
+            "scalar",
+        );
+    };
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/aarch64/neon.rs b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/aarch64/neon.rs
new file mode 100644
index 0000000..21e8458
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/aarch64/neon.rs
@@ -0,0 +1,577 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::arch::aarch64::*;
+use std::ops::{
+    Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
+    Mul, MulAssign, Neg, Sub, SubAssign,
+};
+
+use crate::U32SimdVec;
+
+use super::super::{F32SimdVec, I32SimdVec, SimdDescriptor, SimdMask};
+
+// Safety invariant: this type is only ever constructed if neon is available.
+#[derive(Clone, Copy, Debug)]
+pub struct NeonDescriptor(());
+
+impl NeonDescriptor {
+    /// # Safety
+    /// The caller must guarantee that the "neon" target feature is available.
+    pub unsafe fn new_unchecked() -> Self {
+        Self(())
+    }
+}
+
+impl SimdDescriptor for NeonDescriptor {
+    type F32Vec = F32VecNeon;
+
+    type I32Vec = I32VecNeon;
+
+    type U32Vec = U32VecNeon;
+
+    type Mask = MaskNeon;
+
+    type Descriptor256 = Self;
+    type Descriptor128 = Self;
+
+    fn new() -> Option<Self> {
+        if std::arch::is_aarch64_feature_detected!("neon") {
+            // SAFETY: we just checked neon.
+            Some(unsafe { Self::new_unchecked() })
+        } else {
+            None
+        }
+    }
+
+    fn maybe_downgrade_256bit(self) -> Self {
+        self
+    }
+
+    fn maybe_downgrade_128bit(self) -> Self {
+        self
+    }
+
+    fn call<R>(self, f: impl FnOnce(Self) -> R) -> R {
+        #[target_feature(enable = "neon")]
+        #[inline(never)]
+        unsafe fn inner<R>(d: NeonDescriptor, f: impl FnOnce(NeonDescriptor) -> R) -> R {
+            f(d)
+        }
+        // SAFETY: the safety invariant on `self` guarantees neon.
+        unsafe { inner(self, f) }
+    }
+}
+
+// TODO: retire this macro once we have #[unsafe(target_feature)].
+macro_rules! fn_neon {
+    {} => {};
+    {$(
+        fn $name:ident($this:ident: $self_ty:ty $(, $arg:ident: $ty:ty)* $(,)?) $(-> $ret:ty )?
+        $body: block
+    )*} => {$(
+        #[inline(always)]
+        fn $name(self: $self_ty, $($arg: $ty),*) $(-> $ret)? {
+            #[target_feature(enable = "neon")]
+            #[inline]
+            fn inner($this: $self_ty, $($arg: $ty),*) $(-> $ret)? {
+                $body
+            }
+            // SAFETY: `self.1` is constructed iff neon is available.
+            unsafe { inner(self, $($arg),*) }
+        }
+    )*};
+}
+
+#[derive(Clone, Copy, Debug)]
+#[repr(transparent)]
+pub struct F32VecNeon(float32x4_t, NeonDescriptor);
+
+impl F32SimdVec for F32VecNeon {
+    type Descriptor = NeonDescriptor;
+
+    const LEN: usize = 4;
+
+    #[inline(always)]
+    fn splat(d: Self::Descriptor, v: f32) -> Self {
+        // SAFETY: We know neon is available from the safety invariant on `d`.
+        Self(unsafe { vdupq_n_f32(v) }, d)
+    }
+
+    #[inline(always)]
+    fn zero(d: Self::Descriptor) -> Self {
+        // SAFETY: We know neon is available from the safety invariant on `d`.
+        Self(unsafe { vdupq_n_f32(0.0) }, d)
+    }
+
+    #[inline(always)]
+    fn load(d: Self::Descriptor, mem: &[f32]) -> Self {
+        assert!(mem.len() >= Self::LEN);
+        // SAFETY: we just checked that `mem` has enough space. Moreover, we know neon is available
+        // from the safety invariant on `d`.
+        Self(unsafe { vld1q_f32(mem.as_ptr()) }, d)
+    }
+
+    #[inline(always)]
+    fn store(&self, mem: &mut [f32]) {
+        assert!(mem.len() >= Self::LEN);
+        // SAFETY: we just checked that `mem` has enough space. Moreover, we know neon is available
+        // from the safety invariant on `d`.
+        unsafe { vst1q_f32(mem.as_mut_ptr(), self.0) }
+    }
+
+    #[inline(always)]
+    fn transpose_square(d: NeonDescriptor, data: &mut [[f32; 4]], stride: usize) {
+        #[target_feature(enable = "neon")]
+        #[inline]
+        fn transpose4x4f32(d: NeonDescriptor, data: &mut [[f32; 4]], stride: usize) {
+            assert!(data.len() > 3 * stride);
+
+            let p0 = F32VecNeon::load_array(d, &data[0]).0;
+            let p1 = F32VecNeon::load_array(d, &data[1 * stride]).0;
+            let p2 = F32VecNeon::load_array(d, &data[2 * stride]).0;
+            let p3 = F32VecNeon::load_array(d, &data[3 * stride]).0;
+
+            // Stage 1: Transpose within each of 2x2 blocks
+            let tr0 = vreinterpretq_f64_f32(vtrn1q_f32(p0, p1));
+            let tr1 = vreinterpretq_f64_f32(vtrn2q_f32(p0, p1));
+            let tr2 = vreinterpretq_f64_f32(vtrn1q_f32(p2, p3));
+            let tr3 = vreinterpretq_f64_f32(vtrn2q_f32(p2, p3));
+
+            // Stage 2: Transpose 2x2 grid of 2x2 blocks
+            let p0 = vreinterpretq_f32_f64(vzip1q_f64(tr0, tr2));
+            let p1 = vreinterpretq_f32_f64(vzip1q_f64(tr1, tr3));
+            let p2 = vreinterpretq_f32_f64(vzip2q_f64(tr0, tr2));
+            let p3 = vreinterpretq_f32_f64(vzip2q_f64(tr1, tr3));
+
+            F32VecNeon(p0, d).store_array(&mut data[0]);
+            F32VecNeon(p1, d).store_array(&mut data[1 * stride]);
+            F32VecNeon(p2, d).store_array(&mut data[2 * stride]);
+            F32VecNeon(p3, d).store_array(&mut data[3 * stride]);
+        }
+
+        /// Potentially faster variant of `transpose4x4f32` where `stride == 1`.
+        #[target_feature(enable = "neon")]
+        #[inline]
+        fn transpose4x4f32_contiguous(d: NeonDescriptor, data: &mut [[f32; 4]]) {
+            assert!(data.len() > 3);
+
+            // Transposed load
+            // SAFETY: input is verified to be large enough for this pointer.
+            let float32x4x4_t(p0, p1, p2, p3) = unsafe { vld4q_f32(data.as_ptr().cast()) };
+
+            F32VecNeon(p0, d).store_array(&mut data[0]);
+            F32VecNeon(p1, d).store_array(&mut data[1]);
+            F32VecNeon(p2, d).store_array(&mut data[2]);
+            F32VecNeon(p3, d).store_array(&mut data[3]);
+        }
+
+        if stride == 1 {
+            // SAFETY: the safety invariant on `d` guarantees neon
+            unsafe {
+                transpose4x4f32_contiguous(d, data);
+            }
+        } else {
+            // SAFETY: the safety invariant on `d` guarantees neon
+            unsafe {
+                transpose4x4f32(d, data, stride);
+            }
+        }
+    }
+
+    crate::impl_f32_array_interface!();
+
+    fn_neon! {
+        fn mul_add(this: F32VecNeon, mul: F32VecNeon, add: F32VecNeon) -> F32VecNeon {
+            F32VecNeon(vfmaq_f32(add.0, this.0, mul.0), this.1)
+        }
+
+        fn neg_mul_add(this: F32VecNeon, mul: F32VecNeon, add: F32VecNeon) -> F32VecNeon {
+            F32VecNeon(vfmsq_f32(add.0, this.0, mul.0), this.1)
+        }
+
+        fn abs(this: F32VecNeon) -> F32VecNeon {
+            F32VecNeon(vabsq_f32(this.0), this.1)
+        }
+
+        fn floor(this: F32VecNeon) -> F32VecNeon {
+            F32VecNeon(vrndmq_f32(this.0), this.1)
+        }
+
+        fn sqrt(this: F32VecNeon) -> F32VecNeon {
+            F32VecNeon(vsqrtq_f32(this.0), this.1)
+        }
+
+        fn neg(this: F32VecNeon) -> F32VecNeon {
+            F32VecNeon(vnegq_f32(this.0), this.1)
+        }
+
+        fn copysign(this: F32VecNeon, sign: F32VecNeon) -> F32VecNeon {
+            F32VecNeon(
+                vbslq_f32(vdupq_n_u32(0x8000_0000), sign.0, this.0),
+                this.1,
+            )
+        }
+
+        fn max(this: F32VecNeon, other: F32VecNeon) -> F32VecNeon {
+            F32VecNeon(vmaxq_f32(this.0, other.0), this.1)
+        }
+
+        fn gt(this: F32VecNeon, other: F32VecNeon) -> MaskNeon {
+            MaskNeon(vcgtq_f32(this.0, other.0), this.1)
+        }
+
+        fn as_i32(this: F32VecNeon) -> I32VecNeon {
+            I32VecNeon(vcvtq_s32_f32(this.0), this.1)
+        }
+
+        fn bitcast_to_i32(this: F32VecNeon) -> I32VecNeon {
+            I32VecNeon(vreinterpretq_s32_f32(this.0), this.1)
+        }
+    }
+}
+
+impl Add<F32VecNeon> for F32VecNeon {
+    type Output = Self;
+    fn_neon! {
+        fn add(this: F32VecNeon, rhs: F32VecNeon) -> F32VecNeon {
+            F32VecNeon(vaddq_f32(this.0, rhs.0), this.1)
+        }
+    }
+}
+
+impl Sub<F32VecNeon> for F32VecNeon {
+    type Output = Self;
+    fn_neon! {
+        fn sub(this: F32VecNeon, rhs: F32VecNeon) -> F32VecNeon {
+            F32VecNeon(vsubq_f32(this.0, rhs.0), this.1)
+        }
+    }
+}
+
+impl Mul<F32VecNeon> for F32VecNeon {
+    type Output = Self;
+    fn_neon! {
+        fn mul(this: F32VecNeon, rhs: F32VecNeon) -> F32VecNeon {
+            F32VecNeon(vmulq_f32(this.0, rhs.0), this.1)
+        }
+    }
+}
+
+impl Div<F32VecNeon> for F32VecNeon {
+    type Output = Self;
+    fn_neon! {
+        fn div(this: F32VecNeon, rhs: F32VecNeon) -> F32VecNeon {
+            F32VecNeon(vdivq_f32(this.0, rhs.0), this.1)
+        }
+    }
+}
+
+impl AddAssign<F32VecNeon> for F32VecNeon {
+    fn_neon! {
+        fn add_assign(this: &mut F32VecNeon, rhs: F32VecNeon) {
+            this.0 = vaddq_f32(this.0, rhs.0);
+        }
+    }
+}
+
+impl SubAssign<F32VecNeon> for F32VecNeon {
+    fn_neon! {
+        fn sub_assign(this: &mut F32VecNeon, rhs: F32VecNeon) {
+            this.0 = vsubq_f32(this.0, rhs.0);
+        }
+    }
+}
+
+impl MulAssign<F32VecNeon> for F32VecNeon {
+    fn_neon! {
+        fn mul_assign(this: &mut F32VecNeon, rhs: F32VecNeon) {
+            this.0 = vmulq_f32(this.0, rhs.0);
+        }
+    }
+}
+
+impl DivAssign<F32VecNeon> for F32VecNeon {
+    fn_neon! {
+        fn div_assign(this: &mut F32VecNeon, rhs: F32VecNeon) {
+            this.0 = vdivq_f32(this.0, rhs.0);
+        }
+    }
+}
+
+#[derive(Clone, Copy, Debug)]
+#[repr(transparent)]
+pub struct I32VecNeon(int32x4_t, NeonDescriptor);
+
+impl I32SimdVec for I32VecNeon {
+    type Descriptor = NeonDescriptor;
+
+    const LEN: usize = 4;
+
+    #[inline(always)]
+    fn splat(d: Self::Descriptor, v: i32) -> Self {
+        // SAFETY: We know neon is available from the safety invariant on `d`.
+        Self(unsafe { vdupq_n_s32(v) }, d)
+    }
+
+    #[inline(always)]
+    fn load(d: Self::Descriptor, mem: &[i32]) -> Self {
+        assert!(mem.len() >= Self::LEN);
+        // SAFETY: we just checked that `mem` has enough space. Moreover, we know neon is available
+        // from the safety invariant on `d`.
+        Self(unsafe { vld1q_s32(mem.as_ptr()) }, d)
+    }
+
+    #[inline(always)]
+    fn store(&self, mem: &mut [i32]) {
+        assert!(mem.len() >= Self::LEN);
+        // SAFETY: we just checked that `mem` has enough space. Moreover, we know neon is available
+        // from the safety invariant on `d`.
+        unsafe { vst1q_s32(mem.as_mut_ptr(), self.0) }
+    }
+
+    fn_neon! {
+        fn abs(this: I32VecNeon) -> I32VecNeon {
+            I32VecNeon(vabsq_s32(this.0), this.1)
+        }
+
+        fn as_f32(this: I32VecNeon) -> F32VecNeon {
+            F32VecNeon(vcvtq_f32_s32(this.0), this.1)
+        }
+
+        fn bitcast_to_f32(this: I32VecNeon) -> F32VecNeon {
+            F32VecNeon(vreinterpretq_f32_s32(this.0), this.1)
+        }
+
+        fn bitcast_to_u32(this: I32VecNeon) -> U32VecNeon {
+            U32VecNeon(vreinterpretq_u32_s32(this.0), this.1)
+        }
+
+        fn gt(this: I32VecNeon, other: I32VecNeon) -> MaskNeon {
+            MaskNeon(vcgtq_s32(this.0, other.0), this.1)
+        }
+
+        fn lt_zero(this: I32VecNeon) -> MaskNeon {
+            MaskNeon(vcltzq_s32(this.0), this.1)
+        }
+
+        fn eq(this: I32VecNeon, other: I32VecNeon) -> MaskNeon {
+            MaskNeon(vceqq_s32(this.0, other.0), this.1)
+        }
+
+        fn eq_zero(this: I32VecNeon) -> MaskNeon {
+            MaskNeon(vceqzq_s32(this.0), this.1)
+        }
+
+        fn mul_wide_take_high(this: I32VecNeon, rhs: I32VecNeon) -> I32VecNeon {
+            let l = vmull_s32(vget_low_s32(this.0), vget_low_s32(rhs.0));
+            let l = vreinterpretq_s32_s64(l);
+            let h = vmull_high_s32(this.0, rhs.0);
+            let h = vreinterpretq_s32_s64(h);
+            I32VecNeon(vuzp2q_s32(l, h), this.1)
+        }
+    }
+
+    #[inline(always)]
+    fn shl<const AMOUNT_U: u32, const AMOUNT_I: i32>(self) -> Self {
+        // SAFETY: We know neon is available from the safety invariant on `self.1`.
+        unsafe { Self(vshlq_n_s32::<AMOUNT_I>(self.0), self.1) }
+    }
+
+    #[inline(always)]
+    fn shr<const AMOUNT_U: u32, const AMOUNT_I: i32>(self) -> Self {
+        // SAFETY: We know neon is available from the safety invariant on `self.1`.
+        unsafe { Self(vshrq_n_s32::<AMOUNT_I>(self.0), self.1) }
+    }
+}
+
+impl Add<I32VecNeon> for I32VecNeon {
+    type Output = I32VecNeon;
+    fn_neon! {
+        fn add(this: I32VecNeon, rhs: I32VecNeon) -> I32VecNeon {
+            I32VecNeon(vaddq_s32(this.0, rhs.0), this.1)
+        }
+    }
+}
+
+impl Sub<I32VecNeon> for I32VecNeon {
+    type Output = I32VecNeon;
+    fn_neon! {
+        fn sub(this: I32VecNeon, rhs: I32VecNeon) -> I32VecNeon {
+            I32VecNeon(vsubq_s32(this.0, rhs.0), this.1)
+        }
+    }
+}
+
+impl Mul<I32VecNeon> for I32VecNeon {
+    type Output = I32VecNeon;
+    fn_neon! {
+        fn mul(this: I32VecNeon, rhs: I32VecNeon) -> I32VecNeon {
+            I32VecNeon(vmulq_s32(this.0, rhs.0), this.1)
+        }
+    }
+}
+
+impl Neg for I32VecNeon {
+    type Output = I32VecNeon;
+    fn_neon! {
+        fn neg(this: I32VecNeon) -> I32VecNeon {
+            I32VecNeon(vnegq_s32(this.0), this.1)
+        }
+    }
+}
+
+impl BitAnd<I32VecNeon> for I32VecNeon {
+    type Output = I32VecNeon;
+    fn_neon! {
+        fn bitand(this: I32VecNeon, rhs: I32VecNeon) -> I32VecNeon {
+            I32VecNeon(vandq_s32(this.0, rhs.0), this.1)
+        }
+    }
+}
+
+impl BitOr<I32VecNeon> for I32VecNeon {
+    type Output = I32VecNeon;
+    fn_neon! {
+        fn bitor(this: I32VecNeon, rhs: I32VecNeon) -> I32VecNeon {
+            I32VecNeon(vorrq_s32(this.0, rhs.0), this.1)
+        }
+    }
+}
+
+impl BitXor<I32VecNeon> for I32VecNeon {
+    type Output = I32VecNeon;
+    fn_neon! {
+        fn bitxor(this: I32VecNeon, rhs: I32VecNeon) -> I32VecNeon {
+            I32VecNeon(veorq_s32(this.0, rhs.0), this.1)
+        }
+    }
+}
+
+impl AddAssign<I32VecNeon> for I32VecNeon {
+    fn_neon! {
+        fn add_assign(this: &mut I32VecNeon, rhs: I32VecNeon) {
+            this.0 = vaddq_s32(this.0, rhs.0)
+        }
+    }
+}
+
+impl SubAssign<I32VecNeon> for I32VecNeon {
+    fn_neon! {
+        fn sub_assign(this: &mut I32VecNeon, rhs: I32VecNeon) {
+            this.0 = vsubq_s32(this.0, rhs.0)
+        }
+    }
+}
+
+impl MulAssign<I32VecNeon> for I32VecNeon {
+    fn_neon! {
+        fn mul_assign(this: &mut I32VecNeon, rhs: I32VecNeon) {
+            this.0 = vmulq_s32(this.0, rhs.0)
+        }
+    }
+}
+
+impl BitAndAssign<I32VecNeon> for I32VecNeon {
+    fn_neon! {
+        fn bitand_assign(this: &mut I32VecNeon, rhs: I32VecNeon) {
+            this.0 = vandq_s32(this.0, rhs.0);
+        }
+    }
+}
+
+impl BitOrAssign<I32VecNeon> for I32VecNeon {
+    fn_neon! {
+        fn bitor_assign(this: &mut I32VecNeon, rhs: I32VecNeon) {
+            this.0 = vorrq_s32(this.0, rhs.0);
+        }
+    }
+}
+
+impl BitXorAssign<I32VecNeon> for I32VecNeon {
+    fn_neon! {
+        fn bitxor_assign(this: &mut I32VecNeon, rhs: I32VecNeon) {
+            this.0 = veorq_s32(this.0, rhs.0);
+        }
+    }
+}
+
+#[derive(Clone, Copy, Debug)]
+#[repr(transparent)]
+pub struct U32VecNeon(uint32x4_t, NeonDescriptor);
+
+impl U32SimdVec for U32VecNeon {
+    type Descriptor = NeonDescriptor;
+
+    const LEN: usize = 4;
+
+    fn_neon! {
+        fn bitcast_to_i32(this: U32VecNeon) -> I32VecNeon {
+            I32VecNeon(vreinterpretq_s32_u32(this.0), this.1)
+        }
+    }
+
+    #[inline(always)]
+    fn shr<const AMOUNT_U: u32, const AMOUNT_I: i32>(self) -> Self {
+        // SAFETY: We know neon is available from the safety invariant on `self.1`.
+        unsafe { Self(vshrq_n_u32::<AMOUNT_I>(self.0), self.1) }
+    }
+}
+
+#[derive(Clone, Copy, Debug)]
+#[repr(transparent)]
+pub struct MaskNeon(uint32x4_t, NeonDescriptor);
+
+impl SimdMask for MaskNeon {
+    type Descriptor = NeonDescriptor;
+
+    fn_neon! {
+        fn if_then_else_f32(
+            this: MaskNeon,
+            if_true: F32VecNeon,
+            if_false: F32VecNeon,
+        ) -> F32VecNeon {
+            F32VecNeon(vbslq_f32(this.0, if_true.0, if_false.0), this.1)
+        }
+
+        fn if_then_else_i32(
+            this: MaskNeon,
+            if_true: I32VecNeon,
+            if_false: I32VecNeon,
+        ) -> I32VecNeon {
+            I32VecNeon(vbslq_s32(this.0, if_true.0, if_false.0), this.1)
+        }
+
+        fn maskz_i32(this: MaskNeon, v: I32VecNeon) -> I32VecNeon {
+            I32VecNeon(vbicq_s32(v.0, vreinterpretq_s32_u32(this.0)), this.1)
+        }
+
+        fn andnot(this: MaskNeon, rhs: MaskNeon) -> MaskNeon {
+            MaskNeon(vbicq_u32(rhs.0, this.0), this.1)
+        }
+
+        fn all(this: MaskNeon) -> bool {
+            vminvq_u32(this.0) == u32::MAX
+        }
+    }
+}
+
+impl BitAnd<MaskNeon> for MaskNeon {
+    type Output = MaskNeon;
+    fn_neon! {
+        fn bitand(this: MaskNeon, rhs: MaskNeon) -> MaskNeon {
+            MaskNeon(vandq_u32(this.0, rhs.0), this.1)
+        }
+    }
+}
+
+impl BitOr<MaskNeon> for MaskNeon {
+    type Output = MaskNeon;
+    fn_neon! {
+        fn bitor(this: MaskNeon, rhs: MaskNeon) -> MaskNeon {
+            MaskNeon(vorrq_u32(this.0, rhs.0), this.1)
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/lib.rs
new file mode 100644
index 0000000..558e12c
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/lib.rs
@@ -0,0 +1,565 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use std::{
+    fmt::Debug,
+    ops::{
+        Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div,
+        DivAssign, Mul, MulAssign, Neg, Sub, SubAssign,
+    },
+};
+
+#[cfg(target_arch = "x86_64")]
+mod x86_64;
+
+#[cfg(target_arch = "aarch64")]
+mod aarch64;
+
+mod scalar;
+
+#[cfg(all(target_arch = "x86_64", feature = "avx"))]
+pub use x86_64::avx::AvxDescriptor;
+#[cfg(all(target_arch = "x86_64", feature = "avx512"))]
+pub use x86_64::avx512::Avx512Descriptor;
+#[cfg(all(target_arch = "x86_64", feature = "sse42"))]
+pub use x86_64::sse42::Sse42Descriptor;
+
+#[cfg(all(target_arch = "aarch64", feature = "neon"))]
+pub use aarch64::neon::NeonDescriptor;
+
+pub use scalar::ScalarDescriptor;
+
+pub trait SimdDescriptor: Sized + Copy + Debug + Send + Sync {
+    type F32Vec: F32SimdVec<Descriptor = Self>;
+
+    type I32Vec: I32SimdVec<Descriptor = Self>;
+
+    type U32Vec: U32SimdVec<Descriptor = Self>;
+
+    type Mask: SimdMask<Descriptor = Self>;
+
+    type Descriptor256: SimdDescriptor<Descriptor256 = Self::Descriptor256>;
+    type Descriptor128: SimdDescriptor<Descriptor128 = Self::Descriptor128>;
+
+    fn new() -> Option<Self>;
+
+    /// Returns a vector descriptor suitable for operations on vectors of length 256 (Self if the
+    /// current vector type is suitable). Note that it might still be beneficial to use `Self` for
+    /// .call(), as the compiler could make use of features from more advanced instruction sets.
+    fn maybe_downgrade_256bit(self) -> Self::Descriptor256;
+
+    /// Same as Self::maybe_downgrade_256bit, but for 128 bits.
+    fn maybe_downgrade_128bit(self) -> Self::Descriptor128;
+
+    /// Calls the given closure within a target feature context.
+    /// This enables establishing an unbroken chain of inline functions from the feature-annotated
+    /// gateway up to the closure, allowing SIMD intrinsics to be used safely.
+    fn call<R>(self, f: impl FnOnce(Self) -> R) -> R;
+}
+
+pub trait F32SimdVec:
+    Sized
+    + Copy
+    + Debug
+    + Send
+    + Sync
+    + Add<Self, Output = Self>
+    + Mul<Self, Output = Self>
+    + Sub<Self, Output = Self>
+    + Div<Self, Output = Self>
+    + AddAssign<Self>
+    + MulAssign<Self>
+    + SubAssign<Self>
+    + DivAssign<Self>
+{
+    type Descriptor: SimdDescriptor;
+
+    const LEN: usize;
+
+    /// An array of f32 of length Self::LEN.
+    type UnderlyingArray: Copy + Default + Debug;
+
+    /// Converts v to an array of v.
+    fn splat(d: Self::Descriptor, v: f32) -> Self;
+
+    fn zero(d: Self::Descriptor) -> Self;
+
+    fn mul_add(self, mul: Self, add: Self) -> Self;
+
+    /// Computes `add - self * mul`, equivalent to `self * (-mul) + add`.
+    /// Uses fused multiply-add with negation when available (FMA3 fnmadd).
+    fn neg_mul_add(self, mul: Self, add: Self) -> Self;
+
+    // Requires `mem.len() >= Self::LEN` or it will panic.
+    fn load(d: Self::Descriptor, mem: &[f32]) -> Self;
+
+    fn load_array(d: Self::Descriptor, mem: &Self::UnderlyingArray) -> Self;
+
+    // Requires `mem.len() >= Self::LEN` or it will panic.
+    fn store(&self, mem: &mut [f32]);
+
+    fn store_array(&self, mem: &mut Self::UnderlyingArray);
+
+    fn abs(self) -> Self;
+
+    fn floor(self) -> Self;
+
+    fn sqrt(self) -> Self;
+
+    /// Negates all elements. Currently unused but kept for API completeness.
+    #[allow(dead_code)]
+    fn neg(self) -> Self;
+
+    fn copysign(self, sign: Self) -> Self;
+
+    fn max(self, other: Self) -> Self;
+
+    fn gt(self, other: Self) -> <<Self as F32SimdVec>::Descriptor as SimdDescriptor>::Mask;
+
+    fn as_i32(self) -> <<Self as F32SimdVec>::Descriptor as SimdDescriptor>::I32Vec;
+
+    fn bitcast_to_i32(self) -> <<Self as F32SimdVec>::Descriptor as SimdDescriptor>::I32Vec;
+
+    /// Converts a slice of f32 into a slice of Self::UnderlyingArray. If slice.len() is not a
+    /// multiple of `Self::LEN` this will panic.
+    fn make_array_slice(slice: &[f32]) -> &[Self::UnderlyingArray];
+
+    /// Converts a mut slice of f32 into a slice of Self::UnderlyingArray. If slice.len() is not a
+    /// multiple of `Self::LEN` this will panic.
+    fn make_array_slice_mut(slice: &mut [f32]) -> &mut [Self::UnderlyingArray];
+
+    /// Transposes the Self::LEN x Self::LEN matrix formed by array elements
+    /// `data[stride * i]` for i = 0..Self::LEN.
+    fn transpose_square(d: Self::Descriptor, data: &mut [Self::UnderlyingArray], stride: usize);
+}
+
+pub trait I32SimdVec:
+    Sized
+    + Copy
+    + Debug
+    + Send
+    + Sync
+    + Add<Self, Output = Self>
+    + Mul<Self, Output = Self>
+    + Sub<Self, Output = Self>
+    + Neg<Output = Self>
+    + BitAnd<Self, Output = Self>
+    + BitOr<Self, Output = Self>
+    + BitXor<Self, Output = Self>
+    + AddAssign<Self>
+    + MulAssign<Self>
+    + SubAssign<Self>
+    + BitAndAssign<Self>
+    + BitOrAssign<Self>
+    + BitXorAssign<Self>
+{
+    type Descriptor: SimdDescriptor;
+
+    #[allow(dead_code)]
+    const LEN: usize;
+
+    /// Converts v to an array of v.
+    fn splat(d: Self::Descriptor, v: i32) -> Self;
+
+    // Requires `mem.len() >= Self::LEN` or it will panic.
+    fn load(d: Self::Descriptor, mem: &[i32]) -> Self;
+
+    // Requires `mem.len() >= Self::LEN` or it will panic.
+    fn store(&self, mem: &mut [i32]);
+
+    fn abs(self) -> Self;
+
+    fn as_f32(self) -> <<Self as I32SimdVec>::Descriptor as SimdDescriptor>::F32Vec;
+
+    fn bitcast_to_f32(self) -> <<Self as I32SimdVec>::Descriptor as SimdDescriptor>::F32Vec;
+
+    fn bitcast_to_u32(self) -> <<Self as I32SimdVec>::Descriptor as SimdDescriptor>::U32Vec;
+
+    fn gt(self, other: Self) -> <<Self as I32SimdVec>::Descriptor as SimdDescriptor>::Mask;
+
+    fn lt_zero(self) -> <<Self as I32SimdVec>::Descriptor as SimdDescriptor>::Mask;
+
+    fn eq(self, other: Self) -> <<Self as I32SimdVec>::Descriptor as SimdDescriptor>::Mask;
+
+    fn eq_zero(self) -> <<Self as I32SimdVec>::Descriptor as SimdDescriptor>::Mask;
+
+    fn shl<const AMOUNT_U: u32, const AMOUNT_I: i32>(self) -> Self;
+
+    fn shr<const AMOUNT_U: u32, const AMOUNT_I: i32>(self) -> Self;
+
+    fn mul_wide_take_high(self, rhs: Self) -> Self;
+}
+
+pub trait U32SimdVec: Sized + Copy + Debug + Send + Sync {
+    type Descriptor: SimdDescriptor;
+
+    #[allow(dead_code)]
+    const LEN: usize;
+
+    fn bitcast_to_i32(self) -> <<Self as U32SimdVec>::Descriptor as SimdDescriptor>::I32Vec;
+
+    fn shr<const AMOUNT_U: u32, const AMOUNT_I: i32>(self) -> Self;
+}
+
+#[macro_export]
+macro_rules! shl {
+    ($val: expr, $amount: literal) => {
+        $val.shl::<{ $amount as u32 }, { $amount as i32 }>()
+    };
+}
+
+#[macro_export]
+macro_rules! shr {
+    ($val: expr, $amount: literal) => {
+        $val.shr::<{ $amount as u32 }, { $amount as i32 }>()
+    };
+}
+
+pub trait SimdMask:
+    Sized + Copy + Debug + Send + Sync + BitAnd<Self, Output = Self> + BitOr<Self, Output = Self>
+{
+    type Descriptor: SimdDescriptor;
+
+    fn if_then_else_f32(
+        self,
+        if_true: <<Self as SimdMask>::Descriptor as SimdDescriptor>::F32Vec,
+        if_false: <<Self as SimdMask>::Descriptor as SimdDescriptor>::F32Vec,
+    ) -> <<Self as SimdMask>::Descriptor as SimdDescriptor>::F32Vec;
+
+    fn if_then_else_i32(
+        self,
+        if_true: <<Self as SimdMask>::Descriptor as SimdDescriptor>::I32Vec,
+        if_false: <<Self as SimdMask>::Descriptor as SimdDescriptor>::I32Vec,
+    ) -> <<Self as SimdMask>::Descriptor as SimdDescriptor>::I32Vec;
+
+    fn maskz_i32(
+        self,
+        v: <<Self as SimdMask>::Descriptor as SimdDescriptor>::I32Vec,
+    ) -> <<Self as SimdMask>::Descriptor as SimdDescriptor>::I32Vec;
+
+    fn all(self) -> bool;
+
+    // !self & rhs
+    fn andnot(self, rhs: Self) -> Self;
+}
+
+macro_rules! impl_f32_array_interface {
+    () => {
+        type UnderlyingArray = [f32; Self::LEN];
+
+        #[inline(always)]
+        fn make_array_slice(slice: &[f32]) -> &[Self::UnderlyingArray] {
+            let (ret, rem) = slice.as_chunks();
+            assert!(rem.is_empty());
+            ret
+        }
+
+        #[inline(always)]
+        fn make_array_slice_mut(slice: &mut [f32]) -> &mut [Self::UnderlyingArray] {
+            let (ret, rem) = slice.as_chunks_mut();
+            assert!(rem.is_empty());
+            ret
+        }
+
+        #[inline(always)]
+        fn load_array(d: Self::Descriptor, mem: &Self::UnderlyingArray) -> Self {
+            Self::load(d, mem)
+        }
+
+        #[inline(always)]
+        fn store_array(&self, mem: &mut Self::UnderlyingArray) {
+            self.store(mem);
+        }
+    };
+}
+
+pub(crate) use impl_f32_array_interface;
+
+#[cfg(test)]
+mod test {
+    use arbtest::arbitrary::Unstructured;
+
+    use crate::{F32SimdVec, ScalarDescriptor, SimdDescriptor, test_all_instruction_sets};
+
+    enum Distribution {
+        Floats,
+        NonZeroFloats,
+    }
+
+    fn arb_vec<D: SimdDescriptor>(_: D, u: &mut Unstructured, dist: Distribution) -> Vec<f32> {
+        let mut res = vec![0.0; D::F32Vec::LEN];
+        for v in res.iter_mut() {
+            match dist {
+                Distribution::Floats => {
+                    *v = u.arbitrary::<i32>().unwrap() as f32
+                        / (1.0 + u.arbitrary::<u32>().unwrap() as f32)
+                }
+                Distribution::NonZeroFloats => {
+                    let sign = if u.arbitrary::<bool>().unwrap() {
+                        1.0
+                    } else {
+                        -1.0
+                    };
+                    *v = sign * (1.0 + u.arbitrary::<u32>().unwrap() as f32)
+                        / (1.0 + u.arbitrary::<u32>().unwrap() as f32);
+                }
+            }
+        }
+        res
+    }
+
+    fn compare_scalar_simd(scalar: f32, simd: f32, max_abs: f32, max_rel: f32) {
+        let abs = (simd - scalar).abs();
+        let max = simd.abs().max(scalar.abs());
+        let rel = abs / max;
+        assert!(
+            abs < max_abs || rel < max_rel,
+            "simd {simd}, scalar {scalar}, abs {abs:?} rel {rel:?}",
+        );
+    }
+
+    macro_rules! test_instruction {
+        ($name:ident, |$a:ident: $a_dist:ident| $block:expr) => {
+            fn $name<D: SimdDescriptor>(d: D) {
+                fn compute<D: SimdDescriptor>(d: D, a: &[f32]) -> Vec<f32> {
+                    let closure = |$a: D::F32Vec| $block;
+                    let mut res = vec![0f32; a.len()];
+                    for idx in (0..a.len()).step_by(D::F32Vec::LEN) {
+                        closure(D::F32Vec::load(d, &a[idx..])).store(&mut res[idx..]);
+                    }
+                    res
+                }
+                arbtest::arbtest(|u| {
+                    let a = arb_vec(d, u, Distribution::$a_dist);
+                    let scalar_res = compute(ScalarDescriptor::new().unwrap(), &a);
+                    let simd_res = compute(d, &a);
+                    for (scalar, simd) in scalar_res.iter().zip(simd_res.iter()) {
+                        compare_scalar_simd(*scalar, *simd, 1e-6, 1e-6);
+                    }
+                    Ok(())
+                })
+                .size_min(64);
+            }
+            test_all_instruction_sets!($name);
+        };
+        ($name:ident, |$a:ident: $a_dist:ident, $b:ident: $b_dist:ident| $block:expr) => {
+            fn $name<D: SimdDescriptor>(d: D) {
+                fn compute<D: SimdDescriptor>(d: D, a: &[f32], b: &[f32]) -> Vec<f32> {
+                    let closure = |$a: D::F32Vec, $b: D::F32Vec| $block;
+                    let mut res = vec![0f32; a.len()];
+                    for idx in (0..a.len()).step_by(D::F32Vec::LEN) {
+                        closure(D::F32Vec::load(d, &a[idx..]), D::F32Vec::load(d, &b[idx..]))
+                            .store(&mut res[idx..]);
+                    }
+                    res
+                }
+                arbtest::arbtest(|u| {
+                    let a = arb_vec(d, u, Distribution::$a_dist);
+                    let b = arb_vec(d, u, Distribution::$b_dist);
+                    let scalar_res = compute(ScalarDescriptor::new().unwrap(), &a, &b);
+                    let simd_res = compute(d, &a, &b);
+                    for (scalar, simd) in scalar_res.iter().zip(simd_res.iter()) {
+                        compare_scalar_simd(*scalar, *simd, 1e-6, 1e-6);
+                    }
+                    Ok(())
+                })
+                .size_min(128);
+            }
+            test_all_instruction_sets!($name);
+        };
+        ($name:ident, |$a:ident: $a_dist:ident, $b:ident: $b_dist:ident, $c:ident: $c_dist:ident| $block:expr) => {
+            fn $name<D: SimdDescriptor>(d: D) {
+                fn compute<D: SimdDescriptor>(d: D, a: &[f32], b: &[f32], c: &[f32]) -> Vec<f32> {
+                    let closure = |$a: D::F32Vec, $b: D::F32Vec, $c: D::F32Vec| $block;
+                    let mut res = vec![0f32; a.len()];
+                    for idx in (0..a.len()).step_by(D::F32Vec::LEN) {
+                        closure(
+                            D::F32Vec::load(d, &a[idx..]),
+                            D::F32Vec::load(d, &b[idx..]),
+                            D::F32Vec::load(d, &c[idx..]),
+                        )
+                        .store(&mut res[idx..]);
+                    }
+                    res
+                }
+                arbtest::arbtest(|u| {
+                    let a = arb_vec(d, u, Distribution::$a_dist);
+                    let b = arb_vec(d, u, Distribution::$b_dist);
+                    let c = arb_vec(d, u, Distribution::$c_dist);
+                    let scalar_res = compute(ScalarDescriptor::new().unwrap(), &a, &b, &c);
+                    let simd_res = compute(d, &a, &b, &c);
+                    for (scalar, simd) in scalar_res.iter().zip(simd_res.iter()) {
+                        // Less strict requirements because of fma.
+                        compare_scalar_simd(*scalar, *simd, 2e-5, 2e-5);
+                    }
+                    Ok(())
+                })
+                .size_min(172);
+            }
+            test_all_instruction_sets!($name);
+        };
+    }
+
+    test_instruction!(add, |a: Floats, b: Floats| { a + b });
+    test_instruction!(mul, |a: Floats, b: Floats| { a * b });
+    test_instruction!(sub, |a: Floats, b: Floats| { a - b });
+    test_instruction!(div, |a: Floats, b: NonZeroFloats| { a / b });
+
+    test_instruction!(add_assign, |a: Floats, b: Floats| {
+        let mut res = a;
+        res += b;
+        res
+    });
+    test_instruction!(mul_assign, |a: Floats, b: Floats| {
+        let mut res = a;
+        res *= b;
+        res
+    });
+    test_instruction!(sub_assign, |a: Floats, b: Floats| {
+        let mut res = a;
+        res -= b;
+        res
+    });
+    test_instruction!(div_assign, |a: Floats, b: NonZeroFloats| {
+        let mut res = a;
+        res /= b;
+        res
+    });
+
+    test_instruction!(mul_add, |a: Floats, b: Floats, c: Floats| {
+        a.mul_add(b, c)
+    });
+
+    test_instruction!(neg_mul_add, |a: Floats, b: Floats, c: Floats| {
+        a.neg_mul_add(b, c)
+    });
+
+    // Validate that neg_mul_add computes c - a * b correctly
+    fn test_neg_mul_add_correctness<D: SimdDescriptor>(d: D) {
+        let a_vals = [
+            2.0, 3.0, 4.0, 5.0, 1.5, 2.5, 3.5, 4.5, 2.5, 3.5, 4.5, 5.5, 1.0, 2.0, 3.0, 4.0,
+        ];
+        let b_vals = [
+            1.0, 2.0, 3.0, 4.0, 0.5, 1.5, 2.5, 3.5, 1.5, 2.5, 3.5, 4.5, 0.25, 0.75, 1.25, 1.75,
+        ];
+        let c_vals = [
+            10.0, 20.0, 30.0, 40.0, 5.0, 15.0, 25.0, 35.0, 12.0, 22.0, 32.0, 42.0, 6.0, 16.0, 26.0,
+            36.0,
+        ];
+
+        let a = D::F32Vec::load(d, &a_vals[..D::F32Vec::LEN]);
+        let b = D::F32Vec::load(d, &b_vals[..D::F32Vec::LEN]);
+        let c = D::F32Vec::load(d, &c_vals[..D::F32Vec::LEN]);
+
+        let result = a.neg_mul_add(b, c);
+        let expected = c - a * b;
+
+        let mut result_vals = [0.0; 16];
+        let mut expected_vals = [0.0; 16];
+        result.store(&mut result_vals[..D::F32Vec::LEN]);
+        expected.store(&mut expected_vals[..D::F32Vec::LEN]);
+
+        for i in 0..D::F32Vec::LEN {
+            assert!(
+                (result_vals[i] - expected_vals[i]).abs() < 1e-5,
+                "neg_mul_add correctness failed at index {}: got {}, expected {}",
+                i,
+                result_vals[i],
+                expected_vals[i]
+            );
+        }
+    }
+
+    test_all_instruction_sets!(test_neg_mul_add_correctness);
+
+    test_instruction!(abs, |a: Floats| { a.abs() });
+    test_instruction!(max, |a: Floats, b: Floats| { a.max(b) });
+
+    // Test that the call method works, compiles, and can capture arguments
+    fn test_call<D: SimdDescriptor>(d: D) {
+        // Test basic call functionality
+        let result = d.call(|_d| 42);
+        assert_eq!(result, 42);
+
+        // Test with capturing variables
+        let multiplier = 3.0f32;
+        let addend = 5.0f32;
+
+        // Test SIMD operations inside call with captures
+        let input = vec![1.0f32; D::F32Vec::LEN * 4];
+        let mut output = vec![0.0f32; D::F32Vec::LEN * 4];
+
+        d.call(|d| {
+            let mult_vec = D::F32Vec::splat(d, multiplier);
+            let add_vec = D::F32Vec::splat(d, addend);
+
+            for idx in (0..input.len()).step_by(D::F32Vec::LEN) {
+                let vec = D::F32Vec::load(d, &input[idx..]);
+                let result = vec * mult_vec + add_vec;
+                result.store(&mut output[idx..]);
+            }
+        });
+
+        // Verify results
+        for &val in &output {
+            assert_eq!(val, 1.0 * multiplier + addend);
+        }
+    }
+    test_all_instruction_sets!(test_call);
+
+    fn test_neg<D: SimdDescriptor>(d: D) {
+        // Test negation operation with enough elements for any SIMD size
+        let len = D::F32Vec::LEN * 2; // Ensure we have at least 2 full vectors
+        let input: Vec<f32> = (0..len)
+            .map(|i| if i % 2 == 0 { i as f32 } else { -(i as f32) })
+            .collect();
+        let expected: Vec<f32> = (0..len)
+            .map(|i| if i % 2 == 0 { -(i as f32) } else { i as f32 })
+            .collect();
+        let mut output = vec![0.0f32; input.len()];
+
+        for idx in (0..input.len()).step_by(D::F32Vec::LEN) {
+            let vec = D::F32Vec::load(d, &input[idx..]);
+            let negated = vec.neg();
+            negated.store(&mut output[idx..]);
+        }
+
+        for (i, (&out, &exp)) in output.iter().zip(expected.iter()).enumerate() {
+            assert_eq!(
+                out, exp,
+                "Mismatch at index {}: expected {}, got {}",
+                i, exp, out
+            );
+        }
+    }
+    test_all_instruction_sets!(test_neg);
+
+    fn test_transpose_square<D: SimdDescriptor>(d: D) {
+        // Test square matrix transpose
+        let len = D::F32Vec::LEN;
+        // Input: sequential values 0..
+        let mut input = vec![0.0f32; len * len];
+        for (i, val) in input.iter_mut().enumerate() {
+            *val = i as f32;
+        }
+
+        let mut output = input.clone();
+        D::F32Vec::transpose_square(d, D::F32Vec::make_array_slice_mut(&mut output), 1);
+
+        // Verify transpose: output[i*len+j] should equal input[j*len+i]
+        for i in 0..len {
+            for j in 0..len {
+                let expected = input[j * len + i];
+                let actual = output[i * len + j];
+                assert_eq!(
+                    actual, expected,
+                    "Mismatch at position ({}, {}): expected {}, got {}",
+                    i, j, expected, actual
+                );
+            }
+        }
+    }
+    test_all_instruction_sets!(test_transpose_square);
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/scalar.rs b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/scalar.rs
new file mode 100644
index 0000000..bc95433b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/scalar.rs
@@ -0,0 +1,298 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{U32SimdVec, impl_f32_array_interface};
+
+use super::{F32SimdVec, I32SimdVec, SimdDescriptor, SimdMask};
+
+#[derive(Clone, Copy, Debug)]
+pub struct ScalarDescriptor;
+
+impl SimdDescriptor for ScalarDescriptor {
+    type F32Vec = f32;
+    type I32Vec = i32;
+    type U32Vec = u32;
+    type Mask = bool;
+
+    type Descriptor256 = Self;
+    type Descriptor128 = Self;
+
+    fn maybe_downgrade_256bit(self) -> Self::Descriptor256 {
+        self
+    }
+
+    fn maybe_downgrade_128bit(self) -> Self::Descriptor128 {
+        self
+    }
+
+    fn new() -> Option<Self> {
+        Some(Self)
+    }
+
+    fn call<R>(self, f: impl FnOnce(Self) -> R) -> R {
+        // No special features needed for scalar implementation
+        f(self)
+    }
+}
+
+impl F32SimdVec for f32 {
+    type Descriptor = ScalarDescriptor;
+
+    const LEN: usize = 1;
+
+    #[inline(always)]
+    fn load(_d: Self::Descriptor, mem: &[f32]) -> Self {
+        mem[0]
+    }
+
+    #[inline(always)]
+    fn store(&self, mem: &mut [f32]) {
+        mem[0] = *self;
+    }
+
+    #[inline(always)]
+    fn mul_add(self, mul: Self, add: Self) -> Self {
+        (self * mul) + add
+    }
+
+    #[inline(always)]
+    fn neg_mul_add(self, mul: Self, add: Self) -> Self {
+        -(self * mul) + add
+    }
+
+    #[inline(always)]
+    fn splat(_d: Self::Descriptor, v: f32) -> Self {
+        v
+    }
+
+    #[inline(always)]
+    fn zero(_d: Self::Descriptor) -> Self {
+        0.0
+    }
+
+    #[inline(always)]
+    fn abs(self) -> Self {
+        self.abs()
+    }
+
+    #[inline(always)]
+    fn floor(self) -> Self {
+        self.floor()
+    }
+
+    #[inline(always)]
+    fn sqrt(self) -> Self {
+        self.sqrt()
+    }
+
+    #[inline(always)]
+    fn neg(self) -> Self {
+        -self
+    }
+
+    #[inline(always)]
+    fn copysign(self, sign: Self) -> Self {
+        self.copysign(sign)
+    }
+
+    #[inline(always)]
+    fn max(self, other: Self) -> Self {
+        self.max(other)
+    }
+
+    #[inline(always)]
+    fn gt(self, other: Self) -> bool {
+        self > other
+    }
+
+    #[inline(always)]
+    fn as_i32(self) -> i32 {
+        self as i32
+    }
+
+    #[inline(always)]
+    fn bitcast_to_i32(self) -> i32 {
+        self.to_bits() as i32
+    }
+
+    impl_f32_array_interface!();
+
+    #[inline(always)]
+    fn transpose_square(_d: Self::Descriptor, _data: &mut [Self::UnderlyingArray], _stride: usize) {
+        // Nothing to do.
+    }
+}
+
+impl I32SimdVec for i32 {
+    type Descriptor = ScalarDescriptor;
+
+    const LEN: usize = 1;
+
+    #[inline(always)]
+    fn splat(_d: Self::Descriptor, v: i32) -> Self {
+        v
+    }
+
+    #[inline(always)]
+    fn load(_d: Self::Descriptor, mem: &[i32]) -> Self {
+        mem[0]
+    }
+
+    #[inline(always)]
+    fn store(&self, mem: &mut [i32]) {
+        mem[0] = *self;
+    }
+
+    #[inline(always)]
+    fn abs(self) -> Self {
+        self.abs()
+    }
+
+    #[inline(always)]
+    fn as_f32(self) -> f32 {
+        self as f32
+    }
+
+    #[inline(always)]
+    fn bitcast_to_f32(self) -> f32 {
+        f32::from_bits(self as u32)
+    }
+
+    #[inline(always)]
+    fn bitcast_to_u32(self) -> u32 {
+        self as u32
+    }
+
+    #[inline(always)]
+    fn gt(self, other: Self) -> bool {
+        self > other
+    }
+
+    #[inline(always)]
+    fn lt_zero(self) -> bool {
+        self < 0
+    }
+
+    #[inline(always)]
+    fn eq(self, other: Self) -> bool {
+        self == other
+    }
+
+    #[inline(always)]
+    fn eq_zero(self) -> bool {
+        self == 0
+    }
+
+    #[inline(always)]
+    fn shl<const AMOUNT_U: u32, const AMOUNT_I: i32>(self) -> Self {
+        self << AMOUNT_U
+    }
+
+    #[inline(always)]
+    fn shr<const AMOUNT_U: u32, const AMOUNT_I: i32>(self) -> Self {
+        self >> AMOUNT_U
+    }
+
+    #[inline(always)]
+    fn mul_wide_take_high(self, rhs: Self) -> Self {
+        ((self as i64 * rhs as i64) >> 32) as i32
+    }
+}
+
+impl U32SimdVec for u32 {
+    type Descriptor = ScalarDescriptor;
+
+    const LEN: usize = 1;
+
+    #[inline(always)]
+    fn bitcast_to_i32(self) -> i32 {
+        self as i32
+    }
+
+    #[inline(always)]
+    fn shr<const AMOUNT_U: u32, const AMOUNT_I: i32>(self) -> Self {
+        self >> AMOUNT_U
+    }
+}
+
+impl SimdMask for bool {
+    type Descriptor = ScalarDescriptor;
+
+    #[inline(always)]
+    fn if_then_else_f32(self, if_true: f32, if_false: f32) -> f32 {
+        if self { if_true } else { if_false }
+    }
+
+    #[inline(always)]
+    fn if_then_else_i32(self, if_true: i32, if_false: i32) -> i32 {
+        if self { if_true } else { if_false }
+    }
+
+    #[inline(always)]
+    fn maskz_i32(self, v: i32) -> i32 {
+        if self { 0 } else { v }
+    }
+
+    #[inline(always)]
+    fn all(self) -> bool {
+        self
+    }
+
+    #[inline(always)]
+    fn andnot(self, rhs: Self) -> Self {
+        (!self) & rhs
+    }
+}
+
+#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
+#[macro_export]
+macro_rules! simd_function {
+    (
+        $dname:ident,
+        $descr:ident: $descr_ty:ident,
+        $(#[$($attr:meta)*])*
+        $pub:vis fn $name:ident($($arg:ident: $ty:ty),* $(,)?) $(-> $ret:ty )? $body: block
+    ) => {
+        $(#[$($attr)*])*
+        $pub fn $name<$descr_ty: $crate::SimdDescriptor>($descr: $descr_ty, $($arg: $ty),*) $(-> $ret)? $body
+        $(#[$($attr)*])*
+        $pub fn $dname($($arg: $ty),*) $(-> $ret)? {
+            use $crate::SimdDescriptor;
+            $name($crate::ScalarDescriptor::new().unwrap(), $($arg),*)
+        }
+    };
+}
+
+#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
+#[macro_export]
+macro_rules! test_all_instruction_sets {
+    (
+        $name:ident
+    ) => {
+        paste::paste! {
+            #[test]
+            fn [<$name _scalar>]() {
+                use $crate::SimdDescriptor;
+                $name($crate::ScalarDescriptor::new().unwrap())
+            }
+        }
+    };
+}
+
+#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
+#[macro_export]
+macro_rules! bench_all_instruction_sets {
+    (
+        $name:ident,
+        $criterion:ident
+    ) => {
+        use $crate::SimdDescriptor;
+        $name(
+            $crate::ScalarDescriptor::new().unwrap(),
+            $criterion,
+            "scalar",
+        );
+    };
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/x86_64/avx.rs b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/x86_64/avx.rs
new file mode 100644
index 0000000..a58c1b9f
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/x86_64/avx.rs
@@ -0,0 +1,571 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{U32SimdVec, impl_f32_array_interface, x86_64::sse42::Sse42Descriptor};
+
+use super::super::{F32SimdVec, I32SimdVec, SimdDescriptor, SimdMask};
+use std::{
+    arch::x86_64::*,
+    ops::{
+        Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div,
+        DivAssign, Mul, MulAssign, Neg, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
+    },
+};
+
+// Safety invariant: this type is only ever constructed if avx2 and fma are available.
+#[derive(Clone, Copy, Debug)]
+pub struct AvxDescriptor(());
+
+impl AvxDescriptor {
+    /// # Safety
+    /// The caller must guarantee that the "avx2" and "fma" target features are available.
+    pub unsafe fn new_unchecked() -> Self {
+        Self(())
+    }
+
+    pub fn as_sse42(&self) -> Sse42Descriptor {
+        // SAFETY: the safety invariant on `self` guarantees avx is available, which implies
+        // sse42.
+        unsafe { Sse42Descriptor::new_unchecked() }
+    }
+}
+
+impl SimdDescriptor for AvxDescriptor {
+    type F32Vec = F32VecAvx;
+    type I32Vec = I32VecAvx;
+    type U32Vec = U32VecAvx;
+    type Mask = MaskAvx;
+
+    type Descriptor256 = Self;
+    type Descriptor128 = Sse42Descriptor;
+
+    fn maybe_downgrade_256bit(self) -> Self::Descriptor256 {
+        self
+    }
+
+    fn maybe_downgrade_128bit(self) -> Self::Descriptor128 {
+        self.as_sse42()
+    }
+
+    fn new() -> Option<Self> {
+        if is_x86_feature_detected!("avx2") && is_x86_feature_detected!("fma") {
+            // SAFETY: we just checked avx2 and fma.
+            Some(unsafe { Self::new_unchecked() })
+        } else {
+            None
+        }
+    }
+
+    fn call<R>(self, f: impl FnOnce(Self) -> R) -> R {
+        #[target_feature(enable = "avx2,fma")]
+        #[inline(never)]
+        unsafe fn inner<R>(d: AvxDescriptor, f: impl FnOnce(AvxDescriptor) -> R) -> R {
+            f(d)
+        }
+        // SAFETY: the safety invariant on `self` guarantees avx2 and fma.
+        unsafe { inner(self, f) }
+    }
+}
+
+// TODO(veluca): retire this macro once we have #[unsafe(target_feature)].
+macro_rules! fn_avx {
+    (
+        $this:ident: $self_ty:ty,
+        fn $name:ident($($arg:ident: $ty:ty),* $(,)?) $(-> $ret:ty )? $body: block) => {
+        #[inline(always)]
+        fn $name(self: $self_ty, $($arg: $ty),*) $(-> $ret)? {
+            #[target_feature(enable = "fma,avx2")]
+            #[inline]
+            fn inner($this: $self_ty, $($arg: $ty),*) $(-> $ret)? {
+                $body
+            }
+            // SAFETY: `self.1` is constructed iff avx2 and fma are available.
+            unsafe { inner(self, $($arg),*) }
+        }
+    };
+}
+
+#[derive(Clone, Copy, Debug)]
+#[repr(transparent)]
+pub struct F32VecAvx(__m256, AvxDescriptor);
+
+#[derive(Clone, Copy, Debug)]
+#[repr(transparent)]
+pub struct MaskAvx(__m256, AvxDescriptor);
+
+impl F32SimdVec for F32VecAvx {
+    type Descriptor = AvxDescriptor;
+
+    const LEN: usize = 8;
+
+    #[inline(always)]
+    fn load(d: Self::Descriptor, mem: &[f32]) -> Self {
+        assert!(mem.len() >= Self::LEN);
+        // SAFETY: we just checked that `mem` has enough space. Moreover, we know avx is available
+        // from the safety invariant on `d`.
+        Self(unsafe { _mm256_loadu_ps(mem.as_ptr()) }, d)
+    }
+
+    #[inline(always)]
+    fn store(&self, mem: &mut [f32]) {
+        assert!(mem.len() >= Self::LEN);
+        // SAFETY: we just checked that `mem` has enough space. Moreover, we know avx is available
+        // from the safety invariant on `self.1`.
+        unsafe { _mm256_storeu_ps(mem.as_mut_ptr(), self.0) }
+    }
+
+    fn_avx!(this: F32VecAvx, fn mul_add(mul: F32VecAvx, add: F32VecAvx) -> F32VecAvx {
+        F32VecAvx(_mm256_fmadd_ps(this.0, mul.0, add.0), this.1)
+    });
+
+    fn_avx!(this: F32VecAvx, fn neg_mul_add(mul: F32VecAvx, add: F32VecAvx) -> F32VecAvx {
+        F32VecAvx(_mm256_fnmadd_ps(this.0, mul.0, add.0), this.1)
+    });
+
+    #[inline(always)]
+    fn splat(d: Self::Descriptor, v: f32) -> Self {
+        // SAFETY: We know avx is available from the safety invariant on `d`.
+        unsafe { Self(_mm256_set1_ps(v), d) }
+    }
+
+    #[inline(always)]
+    fn zero(d: Self::Descriptor) -> Self {
+        // SAFETY: We know avx is available from the safety invariant on `d`.
+        unsafe { Self(_mm256_setzero_ps(), d) }
+    }
+
+    fn_avx!(this: F32VecAvx, fn abs() -> F32VecAvx {
+        F32VecAvx(_mm256_andnot_ps(_mm256_set1_ps(-0.0), this.0), this.1)
+    });
+
+    fn_avx!(this: F32VecAvx, fn floor() -> F32VecAvx {
+        F32VecAvx(_mm256_floor_ps(this.0), this.1)
+    });
+
+    fn_avx!(this: F32VecAvx, fn sqrt() -> F32VecAvx {
+        F32VecAvx(_mm256_sqrt_ps(this.0), this.1)
+    });
+
+    fn_avx!(this: F32VecAvx, fn neg() -> F32VecAvx {
+        F32VecAvx(_mm256_xor_ps(_mm256_set1_ps(-0.0), this.0), this.1)
+    });
+
+    fn_avx!(this: F32VecAvx, fn copysign(sign: F32VecAvx) -> F32VecAvx {
+        let sign_mask = _mm256_castsi256_ps(_mm256_set1_epi32(i32::MIN));
+        F32VecAvx(
+            _mm256_or_ps(
+                _mm256_andnot_ps(sign_mask, this.0),
+                _mm256_and_ps(sign_mask, sign.0),
+            ),
+            this.1,
+        )
+    });
+
+    fn_avx!(this: F32VecAvx, fn max(other: F32VecAvx) -> F32VecAvx {
+        F32VecAvx(_mm256_max_ps(this.0, other.0), this.1)
+    });
+
+    fn_avx!(this: F32VecAvx, fn gt(other: F32VecAvx) -> MaskAvx {
+        MaskAvx(_mm256_cmp_ps::<{_CMP_GT_OQ}>(this.0, other.0), this.1)
+    });
+
+    fn_avx!(this: F32VecAvx, fn as_i32() -> I32VecAvx {
+        I32VecAvx(_mm256_cvtps_epi32(this.0), this.1)
+    });
+
+    fn_avx!(this: F32VecAvx, fn bitcast_to_i32() -> I32VecAvx {
+        I32VecAvx(_mm256_castps_si256(this.0), this.1)
+    });
+
+    impl_f32_array_interface!();
+
+    #[inline(always)]
+    fn transpose_square(d: Self::Descriptor, data: &mut [Self::UnderlyingArray], stride: usize) {
+        #[target_feature(enable = "avx2")]
+        #[inline]
+        fn unpacklo_pd(a: __m256, b: __m256) -> __m256 {
+            _mm256_castpd_ps(_mm256_unpacklo_pd(_mm256_castps_pd(a), _mm256_castps_pd(b)))
+        }
+
+        #[target_feature(enable = "avx2")]
+        #[inline]
+        fn unpackhi_pd(a: __m256, b: __m256) -> __m256 {
+            _mm256_castpd_ps(_mm256_unpackhi_pd(_mm256_castps_pd(a), _mm256_castps_pd(b)))
+        }
+
+        #[target_feature(enable = "avx2")]
+        #[inline]
+        fn transpose8x8f32(d: AvxDescriptor, data: &mut [[f32; 8]], stride: usize) {
+            assert!(data.len() > stride * 7);
+
+            let r0 = F32VecAvx::load_array(d, &data[0]).0;
+            let r1 = F32VecAvx::load_array(d, &data[1 * stride]).0;
+            let r2 = F32VecAvx::load_array(d, &data[2 * stride]).0;
+            let r3 = F32VecAvx::load_array(d, &data[3 * stride]).0;
+            let r4 = F32VecAvx::load_array(d, &data[4 * stride]).0;
+            let r5 = F32VecAvx::load_array(d, &data[5 * stride]).0;
+            let r6 = F32VecAvx::load_array(d, &data[6 * stride]).0;
+            let r7 = F32VecAvx::load_array(d, &data[7 * stride]).0;
+
+            // Stage 1: Unpack low/high pairs
+            let t0 = _mm256_unpacklo_ps(r0, r1);
+            let t1 = _mm256_unpackhi_ps(r0, r1);
+            let t2 = _mm256_unpacklo_ps(r2, r3);
+            let t3 = _mm256_unpackhi_ps(r2, r3);
+            let t4 = _mm256_unpacklo_ps(r4, r5);
+            let t5 = _mm256_unpackhi_ps(r4, r5);
+            let t6 = _mm256_unpacklo_ps(r6, r7);
+            let t7 = _mm256_unpackhi_ps(r6, r7);
+
+            // Stage 2: Shuffle to group 32-bit elements
+            let s0 = unpacklo_pd(t0, t2);
+            let s1 = unpackhi_pd(t0, t2);
+            let s2 = unpacklo_pd(t1, t3);
+            let s3 = unpackhi_pd(t1, t3);
+            let s4 = unpacklo_pd(t4, t6);
+            let s5 = unpackhi_pd(t4, t6);
+            let s6 = unpacklo_pd(t5, t7);
+            let s7 = unpackhi_pd(t5, t7);
+
+            // Stage 3: 128-bit permute to finalize transpose
+            let c0 = _mm256_permute2f128_ps::<0x20>(s0, s4);
+            let c1 = _mm256_permute2f128_ps::<0x20>(s1, s5);
+            let c2 = _mm256_permute2f128_ps::<0x20>(s2, s6);
+            let c3 = _mm256_permute2f128_ps::<0x20>(s3, s7);
+            let c4 = _mm256_permute2f128_ps::<0x31>(s0, s4);
+            let c5 = _mm256_permute2f128_ps::<0x31>(s1, s5);
+            let c6 = _mm256_permute2f128_ps::<0x31>(s2, s6);
+            let c7 = _mm256_permute2f128_ps::<0x31>(s3, s7);
+
+            F32VecAvx(c0, d).store_array(&mut data[0]);
+            F32VecAvx(c1, d).store_array(&mut data[1 * stride]);
+            F32VecAvx(c2, d).store_array(&mut data[2 * stride]);
+            F32VecAvx(c3, d).store_array(&mut data[3 * stride]);
+            F32VecAvx(c4, d).store_array(&mut data[4 * stride]);
+            F32VecAvx(c5, d).store_array(&mut data[5 * stride]);
+            F32VecAvx(c6, d).store_array(&mut data[6 * stride]);
+            F32VecAvx(c7, d).store_array(&mut data[7 * stride]);
+        }
+        // SAFETY: the safety invariant on `d` guarantees avx2
+        unsafe {
+            transpose8x8f32(d, data, stride);
+        }
+    }
+}
+
+impl Add<F32VecAvx> for F32VecAvx {
+    type Output = F32VecAvx;
+    fn_avx!(this: F32VecAvx, fn add(rhs: F32VecAvx) -> F32VecAvx {
+        F32VecAvx(_mm256_add_ps(this.0, rhs.0), this.1)
+    });
+}
+
+impl Sub<F32VecAvx> for F32VecAvx {
+    type Output = F32VecAvx;
+    fn_avx!(this: F32VecAvx, fn sub(rhs: F32VecAvx) -> F32VecAvx {
+        F32VecAvx(_mm256_sub_ps(this.0, rhs.0), this.1)
+    });
+}
+
+impl Mul<F32VecAvx> for F32VecAvx {
+    type Output = F32VecAvx;
+    fn_avx!(this: F32VecAvx, fn mul(rhs: F32VecAvx) -> F32VecAvx {
+        F32VecAvx(_mm256_mul_ps(this.0, rhs.0), this.1)
+    });
+}
+
+impl Div<F32VecAvx> for F32VecAvx {
+    type Output = F32VecAvx;
+    fn_avx!(this: F32VecAvx, fn div(rhs: F32VecAvx) -> F32VecAvx {
+        F32VecAvx(_mm256_div_ps(this.0, rhs.0), this.1)
+    });
+}
+
+impl AddAssign<F32VecAvx> for F32VecAvx {
+    fn_avx!(this: &mut F32VecAvx, fn add_assign(rhs: F32VecAvx) {
+        this.0 = _mm256_add_ps(this.0, rhs.0)
+    });
+}
+
+impl SubAssign<F32VecAvx> for F32VecAvx {
+    fn_avx!(this: &mut F32VecAvx, fn sub_assign(rhs: F32VecAvx) {
+        this.0 = _mm256_sub_ps(this.0, rhs.0)
+    });
+}
+
+impl MulAssign<F32VecAvx> for F32VecAvx {
+    fn_avx!(this: &mut F32VecAvx, fn mul_assign(rhs: F32VecAvx) {
+        this.0 = _mm256_mul_ps(this.0, rhs.0)
+    });
+}
+
+impl DivAssign<F32VecAvx> for F32VecAvx {
+    fn_avx!(this: &mut F32VecAvx, fn div_assign(rhs: F32VecAvx) {
+        this.0 = _mm256_div_ps(this.0, rhs.0)
+    });
+}
+
+#[derive(Clone, Copy, Debug)]
+#[repr(transparent)]
+pub struct I32VecAvx(__m256i, AvxDescriptor);
+
+impl I32SimdVec for I32VecAvx {
+    type Descriptor = AvxDescriptor;
+
+    const LEN: usize = 8;
+
+    #[inline(always)]
+    fn load(d: Self::Descriptor, mem: &[i32]) -> Self {
+        assert!(mem.len() >= Self::LEN);
+        // SAFETY: we just checked that `mem` has enough space. Moreover, we know avx is available
+        // from the safety invariant on `d`.
+        Self(unsafe { _mm256_loadu_si256(mem.as_ptr() as *const _) }, d)
+    }
+
+    #[inline(always)]
+    fn store(&self, mem: &mut [i32]) {
+        assert!(mem.len() >= Self::LEN);
+        // SAFETY: we just checked that `mem` has enough space. Moreover, we know avx is available
+        // from the safety invariant on `self.1`.
+        unsafe { _mm256_storeu_si256(mem.as_mut_ptr().cast(), self.0) }
+    }
+
+    #[inline(always)]
+    fn splat(d: Self::Descriptor, v: i32) -> Self {
+        // SAFETY: We know avx is available from the safety invariant on `d`.
+        unsafe { Self(_mm256_set1_epi32(v), d) }
+    }
+
+    fn_avx!(this: I32VecAvx, fn as_f32() -> F32VecAvx {
+        F32VecAvx(_mm256_cvtepi32_ps(this.0), this.1)
+    });
+
+    fn_avx!(this: I32VecAvx, fn bitcast_to_f32() -> F32VecAvx {
+        F32VecAvx(_mm256_castsi256_ps(this.0), this.1)
+    });
+
+    #[inline(always)]
+    fn bitcast_to_u32(self) -> U32VecAvx {
+        U32VecAvx(self.0, self.1)
+    }
+
+    fn_avx!(this: I32VecAvx, fn abs() -> I32VecAvx {
+        I32VecAvx(
+            _mm256_abs_epi32(this.0),
+            this.1)
+    });
+
+    fn_avx!(this: I32VecAvx, fn gt(rhs: I32VecAvx) -> MaskAvx {
+        MaskAvx(
+            _mm256_castsi256_ps(_mm256_cmpgt_epi32(this.0, rhs.0)),
+            this.1,
+        )
+    });
+
+    fn_avx!(this: I32VecAvx, fn lt_zero() -> MaskAvx {
+        I32VecAvx(_mm256_setzero_si256(), this.1).gt(this)
+    });
+
+    fn_avx!(this: I32VecAvx, fn eq(rhs: I32VecAvx) -> MaskAvx {
+        MaskAvx(
+            _mm256_castsi256_ps(_mm256_cmpeq_epi32(this.0, rhs.0)),
+            this.1,
+        )
+    });
+
+    fn_avx!(this: I32VecAvx, fn eq_zero() -> MaskAvx {
+        this.eq(I32VecAvx(_mm256_setzero_si256(), this.1))
+    });
+
+    #[inline(always)]
+    fn shl<const AMOUNT_U: u32, const AMOUNT_I: i32>(self) -> Self {
+        // SAFETY: We know avx2 is available from the safety invariant on `d`.
+        unsafe { I32VecAvx(_mm256_slli_epi32::<AMOUNT_I>(self.0), self.1) }
+    }
+
+    #[inline(always)]
+    fn shr<const AMOUNT_U: u32, const AMOUNT_I: i32>(self) -> Self {
+        // SAFETY: We know avx2 is available from the safety invariant on `d`.
+        unsafe { I32VecAvx(_mm256_srai_epi32::<AMOUNT_I>(self.0), self.1) }
+    }
+
+    fn_avx!(this: I32VecAvx, fn mul_wide_take_high(rhs: I32VecAvx) -> I32VecAvx {
+        let l = _mm256_mul_epi32(this.0, rhs.0);
+        let h = _mm256_mul_epi32(_mm256_srli_epi64::<32>(this.0), _mm256_srli_epi64::<32>(rhs.0));
+        let p0 = _mm256_unpacklo_epi32(l, h);
+        let p1 = _mm256_unpackhi_epi32(l, h);
+        I32VecAvx(_mm256_unpackhi_epi64(p0, p1), this.1)
+    });
+}
+
+impl Add<I32VecAvx> for I32VecAvx {
+    type Output = I32VecAvx;
+    fn_avx!(this: I32VecAvx, fn add(rhs: I32VecAvx) -> I32VecAvx {
+        I32VecAvx(_mm256_add_epi32(this.0, rhs.0), this.1)
+    });
+}
+
+impl Sub<I32VecAvx> for I32VecAvx {
+    type Output = I32VecAvx;
+    fn_avx!(this: I32VecAvx, fn sub(rhs: I32VecAvx) -> I32VecAvx {
+        I32VecAvx(_mm256_sub_epi32(this.0, rhs.0), this.1)
+    });
+}
+
+impl Mul<I32VecAvx> for I32VecAvx {
+    type Output = I32VecAvx;
+    fn_avx!(this: I32VecAvx, fn mul(rhs: I32VecAvx) -> I32VecAvx {
+        I32VecAvx(_mm256_mul_epi32(this.0, rhs.0), this.1)
+    });
+}
+
+impl Shl<I32VecAvx> for I32VecAvx {
+    type Output = I32VecAvx;
+    fn_avx!(this: I32VecAvx, fn shl(rhs: I32VecAvx) -> I32VecAvx {
+        I32VecAvx(_mm256_sllv_epi32(this.0, rhs.0), this.1)
+    });
+}
+
+impl Shr<I32VecAvx> for I32VecAvx {
+    type Output = I32VecAvx;
+    fn_avx!(this: I32VecAvx, fn shr(rhs: I32VecAvx) -> I32VecAvx {
+        I32VecAvx(_mm256_srav_epi32(this.0, rhs.0), this.1)
+    });
+}
+
+impl Neg for I32VecAvx {
+    type Output = I32VecAvx;
+    fn_avx!(this: I32VecAvx, fn neg() -> I32VecAvx {
+        I32VecAvx(_mm256_setzero_si256(), this.1) - this
+    });
+}
+
+impl BitAnd<I32VecAvx> for I32VecAvx {
+    type Output = I32VecAvx;
+    fn_avx!(this: I32VecAvx, fn bitand(rhs: I32VecAvx) -> I32VecAvx {
+        I32VecAvx(_mm256_and_si256(this.0, rhs.0), this.1)
+    });
+}
+
+impl BitOr<I32VecAvx> for I32VecAvx {
+    type Output = I32VecAvx;
+    fn_avx!(this: I32VecAvx, fn bitor(rhs: I32VecAvx) -> I32VecAvx {
+        I32VecAvx(_mm256_or_si256(this.0, rhs.0), this.1)
+    });
+}
+
+impl BitXor<I32VecAvx> for I32VecAvx {
+    type Output = I32VecAvx;
+    fn_avx!(this: I32VecAvx, fn bitxor(rhs: I32VecAvx) -> I32VecAvx {
+        I32VecAvx(_mm256_xor_si256(this.0, rhs.0), this.1)
+    });
+}
+
+impl AddAssign<I32VecAvx> for I32VecAvx {
+    fn_avx!(this: &mut I32VecAvx, fn add_assign(rhs: I32VecAvx) {
+        this.0 = _mm256_add_epi32(this.0, rhs.0)
+    });
+}
+
+impl SubAssign<I32VecAvx> for I32VecAvx {
+    fn_avx!(this: &mut I32VecAvx, fn sub_assign(rhs: I32VecAvx) {
+        this.0 = _mm256_sub_epi32(this.0, rhs.0)
+    });
+}
+
+impl MulAssign<I32VecAvx> for I32VecAvx {
+    fn_avx!(this: &mut I32VecAvx, fn mul_assign(rhs: I32VecAvx) {
+        this.0 = _mm256_mul_epi32(this.0, rhs.0)
+    });
+}
+
+impl ShlAssign<I32VecAvx> for I32VecAvx {
+    fn_avx!(this: &mut I32VecAvx, fn shl_assign(rhs: I32VecAvx) {
+        this.0 = _mm256_sllv_epi32(this.0, rhs.0)
+    });
+}
+
+impl ShrAssign<I32VecAvx> for I32VecAvx {
+    fn_avx!(this: &mut I32VecAvx, fn shr_assign(rhs: I32VecAvx) {
+        this.0 = _mm256_srav_epi32(this.0, rhs.0)
+    });
+}
+
+impl BitAndAssign<I32VecAvx> for I32VecAvx {
+    fn_avx!(this: &mut I32VecAvx, fn bitand_assign(rhs: I32VecAvx) {
+        this.0 = _mm256_and_si256(this.0, rhs.0)
+    });
+}
+
+impl BitOrAssign<I32VecAvx> for I32VecAvx {
+    fn_avx!(this: &mut I32VecAvx, fn bitor_assign(rhs: I32VecAvx) {
+        this.0 = _mm256_or_si256(this.0, rhs.0)
+    });
+}
+
+impl BitXorAssign<I32VecAvx> for I32VecAvx {
+    fn_avx!(this: &mut I32VecAvx, fn bitxor_assign(rhs: I32VecAvx) {
+        this.0 = _mm256_xor_si256(this.0, rhs.0)
+    });
+}
+
+#[derive(Clone, Copy, Debug)]
+#[repr(transparent)]
+pub struct U32VecAvx(__m256i, AvxDescriptor);
+
+impl U32SimdVec for U32VecAvx {
+    type Descriptor = AvxDescriptor;
+
+    const LEN: usize = 8;
+
+    #[inline(always)]
+    fn bitcast_to_i32(self) -> I32VecAvx {
+        I32VecAvx(self.0, self.1)
+    }
+
+    #[inline(always)]
+    fn shr<const AMOUNT_U: u32, const AMOUNT_I: i32>(self) -> Self {
+        // SAFETY: We know avx2 is available from the safety invariant on `self.1`.
+        unsafe { Self(_mm256_srli_epi32::<AMOUNT_I>(self.0), self.1) }
+    }
+}
+
+impl SimdMask for MaskAvx {
+    type Descriptor = AvxDescriptor;
+
+    fn_avx!(this: MaskAvx, fn if_then_else_f32(if_true: F32VecAvx, if_false: F32VecAvx) -> F32VecAvx {
+        F32VecAvx(_mm256_blendv_ps(if_false.0, if_true.0, this.0), this.1)
+    });
+
+    fn_avx!(this: MaskAvx, fn if_then_else_i32(if_true: I32VecAvx, if_false: I32VecAvx) -> I32VecAvx {
+        I32VecAvx(_mm256_blendv_epi8(if_false.0, if_true.0, _mm256_castps_si256(this.0)), this.1)
+    });
+
+    fn_avx!(this: MaskAvx, fn maskz_i32(v: I32VecAvx) -> I32VecAvx {
+        I32VecAvx(_mm256_andnot_si256(_mm256_castps_si256(this.0), v.0), this.1)
+    });
+
+    fn_avx!(this: MaskAvx, fn all() -> bool {
+        _mm256_movemask_ps(this.0) == 0b11111111
+    });
+
+    fn_avx!(this: MaskAvx, fn andnot(rhs: MaskAvx) -> MaskAvx {
+        MaskAvx(_mm256_andnot_ps(this.0, rhs.0), this.1)
+    });
+}
+
+impl BitAnd<MaskAvx> for MaskAvx {
+    type Output = MaskAvx;
+    fn_avx!(this: MaskAvx, fn bitand(rhs: MaskAvx) -> MaskAvx {
+        MaskAvx(_mm256_and_ps(this.0, rhs.0), this.1)
+    });
+}
+
+impl BitOr<MaskAvx> for MaskAvx {
+    type Output = MaskAvx;
+    fn_avx!(this: MaskAvx, fn bitor(rhs: MaskAvx) -> MaskAvx {
+        MaskAvx(_mm256_or_ps(this.0, rhs.0), this.1)
+    });
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/x86_64/avx512.rs b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/x86_64/avx512.rs
new file mode 100644
index 0000000..3a3ee2c
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/x86_64/avx512.rs
@@ -0,0 +1,654 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use super::super::{AvxDescriptor, F32SimdVec, I32SimdVec, SimdDescriptor, SimdMask};
+use crate::{Sse42Descriptor, U32SimdVec, impl_f32_array_interface};
+use std::{
+    arch::x86_64::*,
+    ops::{
+        Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div,
+        DivAssign, Mul, MulAssign, Neg, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
+    },
+};
+
+// Safety invariant: this type is only ever constructed if avx512f is available.
+#[derive(Clone, Copy, Debug)]
+pub struct Avx512Descriptor(());
+
+#[allow(unused)]
+impl Avx512Descriptor {
+    /// # Safety
+    /// The caller must guarantee that the "avx512f" target feature is available.
+    pub unsafe fn new_unchecked() -> Self {
+        Self(())
+    }
+    pub fn as_avx(&self) -> AvxDescriptor {
+        // SAFETY: the safety invariant on `self` guarantees avx512f is available, which implies
+        // avx2 and fma.
+        unsafe { AvxDescriptor::new_unchecked() }
+    }
+}
+
+impl SimdDescriptor for Avx512Descriptor {
+    type F32Vec = F32VecAvx512;
+    type I32Vec = I32VecAvx512;
+    type U32Vec = U32VecAvx512;
+    type Mask = MaskAvx512;
+
+    type Descriptor256 = AvxDescriptor;
+    type Descriptor128 = Sse42Descriptor;
+
+    fn maybe_downgrade_256bit(self) -> Self::Descriptor256 {
+        self.as_avx()
+    }
+
+    fn maybe_downgrade_128bit(self) -> Self::Descriptor128 {
+        self.as_avx().as_sse42()
+    }
+
+    fn new() -> Option<Self> {
+        if is_x86_feature_detected!("avx512f") {
+            // SAFETY: we just checked avx512f.
+            Some(Self(()))
+        } else {
+            None
+        }
+    }
+
+    fn call<R>(self, f: impl FnOnce(Self) -> R) -> R {
+        #[target_feature(enable = "avx512f")]
+        #[inline(never)]
+        unsafe fn inner<R>(d: Avx512Descriptor, f: impl FnOnce(Avx512Descriptor) -> R) -> R {
+            f(d)
+        }
+        // SAFETY: the safety invariant on `self` guarantees avx512f.
+        unsafe { inner(self, f) }
+    }
+}
+
+// TODO(veluca): retire this macro once we have #[unsafe(target_feature)].
+macro_rules! fn_avx {
+    (
+        $this:ident: $self_ty:ty,
+        fn $name:ident($($arg:ident: $ty:ty),* $(,)?) $(-> $ret:ty )? $body: block) => {
+        #[inline(always)]
+        fn $name(self: $self_ty, $($arg: $ty),*) $(-> $ret)? {
+            #[target_feature(enable = "avx512f")]
+            #[inline]
+            fn inner($this: $self_ty, $($arg: $ty),*) $(-> $ret)? {
+                $body
+            }
+            // SAFETY: `self.1` is constructed iff avx512f is available.
+            unsafe { inner(self, $($arg),*) }
+        }
+    };
+}
+
+#[derive(Clone, Copy, Debug)]
+#[repr(transparent)]
+pub struct F32VecAvx512(__m512, Avx512Descriptor);
+
+#[derive(Clone, Copy, Debug)]
+#[repr(transparent)]
+pub struct MaskAvx512(__mmask16, Avx512Descriptor);
+
+impl F32SimdVec for F32VecAvx512 {
+    type Descriptor = Avx512Descriptor;
+
+    const LEN: usize = 16;
+
+    #[inline(always)]
+    fn load(d: Self::Descriptor, mem: &[f32]) -> Self {
+        assert!(mem.len() >= Self::LEN);
+        // SAFETY: we just checked that `mem` has enough space. Moreover, we know avx512f is available
+        // from the safety invariant on `d`.
+        Self(unsafe { _mm512_loadu_ps(mem.as_ptr()) }, d)
+    }
+
+    #[inline(always)]
+    fn store(&self, mem: &mut [f32]) {
+        assert!(mem.len() >= Self::LEN);
+        // SAFETY: we just checked that `mem` has enough space. Moreover, we know avx512f is available
+        // from the safety invariant on `self.1`.
+        unsafe { _mm512_storeu_ps(mem.as_mut_ptr(), self.0) }
+    }
+
+    fn_avx!(this: F32VecAvx512, fn mul_add(mul: F32VecAvx512, add: F32VecAvx512) -> F32VecAvx512 {
+        F32VecAvx512(_mm512_fmadd_ps(this.0, mul.0, add.0), this.1)
+    });
+
+    fn_avx!(this: F32VecAvx512, fn neg_mul_add(mul: F32VecAvx512, add: F32VecAvx512) -> F32VecAvx512 {
+        F32VecAvx512(_mm512_fnmadd_ps(this.0, mul.0, add.0), this.1)
+    });
+
+    #[inline(always)]
+    fn splat(d: Self::Descriptor, v: f32) -> Self {
+        // SAFETY: We know avx512f is available from the safety invariant on `d`.
+        unsafe { Self(_mm512_set1_ps(v), d) }
+    }
+
+    #[inline(always)]
+    fn zero(d: Self::Descriptor) -> Self {
+        // SAFETY: We know avx512f is available from the safety invariant on `d`.
+        unsafe { Self(_mm512_setzero_ps(), d) }
+    }
+
+    fn_avx!(this: F32VecAvx512, fn abs() -> F32VecAvx512 {
+        F32VecAvx512(_mm512_abs_ps(this.0), this.1)
+    });
+
+    fn_avx!(this: F32VecAvx512, fn floor() -> F32VecAvx512 {
+        F32VecAvx512(_mm512_roundscale_ps::<{ _MM_FROUND_FLOOR }>(this.0), this.1)
+    });
+
+    fn_avx!(this: F32VecAvx512, fn sqrt() -> F32VecAvx512 {
+        F32VecAvx512(_mm512_sqrt_ps(this.0), this.1)
+    });
+
+    fn_avx!(this: F32VecAvx512, fn neg() -> F32VecAvx512 {
+        F32VecAvx512(
+            _mm512_castsi512_ps(_mm512_xor_si512(
+                _mm512_set1_epi32(i32::MIN),
+                _mm512_castps_si512(this.0),
+            )),
+            this.1,
+        )
+    });
+
+    fn_avx!(this: F32VecAvx512, fn copysign(sign: F32VecAvx512) -> F32VecAvx512 {
+        let sign_mask = _mm512_set1_epi32(i32::MIN);
+        F32VecAvx512(
+            _mm512_castsi512_ps(_mm512_or_si512(
+                _mm512_andnot_si512(sign_mask, _mm512_castps_si512(this.0)),
+                _mm512_and_si512(sign_mask, _mm512_castps_si512(sign.0)),
+            )),
+            this.1,
+        )
+    });
+
+    fn_avx!(this: F32VecAvx512, fn max(other: F32VecAvx512) -> F32VecAvx512 {
+        F32VecAvx512(_mm512_max_ps(this.0, other.0), this.1)
+    });
+
+    fn_avx!(this: F32VecAvx512, fn gt(other: F32VecAvx512) -> MaskAvx512 {
+        MaskAvx512(_mm512_cmp_ps_mask::<{_CMP_GT_OQ}>(this.0, other.0), this.1)
+    });
+
+    fn_avx!(this: F32VecAvx512, fn as_i32() -> I32VecAvx512 {
+        I32VecAvx512(_mm512_cvtps_epi32(this.0), this.1)
+    });
+
+    fn_avx!(this: F32VecAvx512, fn bitcast_to_i32() -> I32VecAvx512 {
+        I32VecAvx512(_mm512_castps_si512(this.0), this.1)
+    });
+
+    impl_f32_array_interface!();
+
+    #[inline(always)]
+    fn transpose_square(d: Self::Descriptor, data: &mut [Self::UnderlyingArray], stride: usize) {
+        #[target_feature(enable = "avx512f")]
+        #[inline]
+        fn transpose16x16f32(d: Avx512Descriptor, data: &mut [[f32; 16]], stride: usize) {
+            assert!(data.len() > stride * 15);
+
+            let r0 = F32VecAvx512::load_array(d, &data[0]).0;
+            let r1 = F32VecAvx512::load_array(d, &data[1 * stride]).0;
+            let r2 = F32VecAvx512::load_array(d, &data[2 * stride]).0;
+            let r3 = F32VecAvx512::load_array(d, &data[3 * stride]).0;
+            let r4 = F32VecAvx512::load_array(d, &data[4 * stride]).0;
+            let r5 = F32VecAvx512::load_array(d, &data[5 * stride]).0;
+            let r6 = F32VecAvx512::load_array(d, &data[6 * stride]).0;
+            let r7 = F32VecAvx512::load_array(d, &data[7 * stride]).0;
+            let r8 = F32VecAvx512::load_array(d, &data[8 * stride]).0;
+            let r9 = F32VecAvx512::load_array(d, &data[9 * stride]).0;
+            let r10 = F32VecAvx512::load_array(d, &data[10 * stride]).0;
+            let r11 = F32VecAvx512::load_array(d, &data[11 * stride]).0;
+            let r12 = F32VecAvx512::load_array(d, &data[12 * stride]).0;
+            let r13 = F32VecAvx512::load_array(d, &data[13 * stride]).0;
+            let r14 = F32VecAvx512::load_array(d, &data[14 * stride]).0;
+            let r15 = F32VecAvx512::load_array(d, &data[15 * stride]).0;
+
+            // Stage 1: Unpack low/high pairs
+            let t0 = _mm512_unpacklo_ps(r0, r1);
+            let t1 = _mm512_unpackhi_ps(r0, r1);
+            let t2 = _mm512_unpacklo_ps(r2, r3);
+            let t3 = _mm512_unpackhi_ps(r2, r3);
+            let t4 = _mm512_unpacklo_ps(r4, r5);
+            let t5 = _mm512_unpackhi_ps(r4, r5);
+            let t6 = _mm512_unpacklo_ps(r6, r7);
+            let t7 = _mm512_unpackhi_ps(r6, r7);
+            let t8 = _mm512_unpacklo_ps(r8, r9);
+            let t9 = _mm512_unpackhi_ps(r8, r9);
+            let t10 = _mm512_unpacklo_ps(r10, r11);
+            let t11 = _mm512_unpackhi_ps(r10, r11);
+            let t12 = _mm512_unpacklo_ps(r12, r13);
+            let t13 = _mm512_unpackhi_ps(r12, r13);
+            let t14 = _mm512_unpacklo_ps(r14, r15);
+            let t15 = _mm512_unpackhi_ps(r14, r15);
+
+            // Cast to 64 bits.
+            let t0 = _mm512_castps_pd(t0);
+            let t1 = _mm512_castps_pd(t1);
+            let t2 = _mm512_castps_pd(t2);
+            let t3 = _mm512_castps_pd(t3);
+            let t4 = _mm512_castps_pd(t4);
+            let t5 = _mm512_castps_pd(t5);
+            let t6 = _mm512_castps_pd(t6);
+            let t7 = _mm512_castps_pd(t7);
+            let t8 = _mm512_castps_pd(t8);
+            let t9 = _mm512_castps_pd(t9);
+            let t10 = _mm512_castps_pd(t10);
+            let t11 = _mm512_castps_pd(t11);
+            let t12 = _mm512_castps_pd(t12);
+            let t13 = _mm512_castps_pd(t13);
+            let t14 = _mm512_castps_pd(t14);
+            let t15 = _mm512_castps_pd(t15);
+
+            // Stage 2: Shuffle to group 32-bit elements
+            let s0 = _mm512_unpacklo_pd(t0, t2);
+            let s1 = _mm512_unpackhi_pd(t0, t2);
+            let s2 = _mm512_unpacklo_pd(t1, t3);
+            let s3 = _mm512_unpackhi_pd(t1, t3);
+            let s4 = _mm512_unpacklo_pd(t4, t6);
+            let s5 = _mm512_unpackhi_pd(t4, t6);
+            let s6 = _mm512_unpacklo_pd(t5, t7);
+            let s7 = _mm512_unpackhi_pd(t5, t7);
+            let s8 = _mm512_unpacklo_pd(t8, t10);
+            let s9 = _mm512_unpackhi_pd(t8, t10);
+            let s10 = _mm512_unpacklo_pd(t9, t11);
+            let s11 = _mm512_unpackhi_pd(t9, t11);
+            let s12 = _mm512_unpacklo_pd(t12, t14);
+            let s13 = _mm512_unpackhi_pd(t12, t14);
+            let s14 = _mm512_unpacklo_pd(t13, t15);
+            let s15 = _mm512_unpackhi_pd(t13, t15);
+
+            // Stage 3: 128-bit permute
+            let idx_hi = _mm512_setr_epi64(0, 1, 8, 9, 4, 5, 12, 13);
+            let idx_lo = _mm512_add_epi64(idx_hi, _mm512_set1_epi64(2));
+
+            let c0 = _mm512_permutex2var_pd(s0, idx_hi, s4);
+            let c1 = _mm512_permutex2var_pd(s1, idx_hi, s5);
+            let c2 = _mm512_permutex2var_pd(s2, idx_hi, s6);
+            let c3 = _mm512_permutex2var_pd(s3, idx_hi, s7);
+            let c4 = _mm512_permutex2var_pd(s0, idx_lo, s4);
+            let c5 = _mm512_permutex2var_pd(s1, idx_lo, s5);
+            let c6 = _mm512_permutex2var_pd(s2, idx_lo, s6);
+            let c7 = _mm512_permutex2var_pd(s3, idx_lo, s7);
+            let c8 = _mm512_permutex2var_pd(s8, idx_hi, s12);
+            let c9 = _mm512_permutex2var_pd(s9, idx_hi, s13);
+            let c10 = _mm512_permutex2var_pd(s10, idx_hi, s14);
+            let c11 = _mm512_permutex2var_pd(s11, idx_hi, s15);
+            let c12 = _mm512_permutex2var_pd(s8, idx_lo, s12);
+            let c13 = _mm512_permutex2var_pd(s9, idx_lo, s13);
+            let c14 = _mm512_permutex2var_pd(s10, idx_lo, s14);
+            let c15 = _mm512_permutex2var_pd(s11, idx_lo, s15);
+
+            // Stage 4: 256-bit permute
+            let idx_hi = _mm512_setr_epi64(0, 1, 2, 3, 8, 9, 10, 11);
+            let idx_lo = _mm512_add_epi64(idx_hi, _mm512_set1_epi64(4));
+
+            let o0 = _mm512_permutex2var_pd(c0, idx_hi, c8);
+            let o1 = _mm512_permutex2var_pd(c1, idx_hi, c9);
+            let o2 = _mm512_permutex2var_pd(c2, idx_hi, c10);
+            let o3 = _mm512_permutex2var_pd(c3, idx_hi, c11);
+            let o4 = _mm512_permutex2var_pd(c4, idx_hi, c12);
+            let o5 = _mm512_permutex2var_pd(c5, idx_hi, c13);
+            let o6 = _mm512_permutex2var_pd(c6, idx_hi, c14);
+            let o7 = _mm512_permutex2var_pd(c7, idx_hi, c15);
+            let o8 = _mm512_permutex2var_pd(c0, idx_lo, c8);
+            let o9 = _mm512_permutex2var_pd(c1, idx_lo, c9);
+            let o10 = _mm512_permutex2var_pd(c2, idx_lo, c10);
+            let o11 = _mm512_permutex2var_pd(c3, idx_lo, c11);
+            let o12 = _mm512_permutex2var_pd(c4, idx_lo, c12);
+            let o13 = _mm512_permutex2var_pd(c5, idx_lo, c13);
+            let o14 = _mm512_permutex2var_pd(c6, idx_lo, c14);
+            let o15 = _mm512_permutex2var_pd(c7, idx_lo, c15);
+
+            let o0 = _mm512_castpd_ps(o0);
+            let o1 = _mm512_castpd_ps(o1);
+            let o2 = _mm512_castpd_ps(o2);
+            let o3 = _mm512_castpd_ps(o3);
+            let o4 = _mm512_castpd_ps(o4);
+            let o5 = _mm512_castpd_ps(o5);
+            let o6 = _mm512_castpd_ps(o6);
+            let o7 = _mm512_castpd_ps(o7);
+            let o8 = _mm512_castpd_ps(o8);
+            let o9 = _mm512_castpd_ps(o9);
+            let o10 = _mm512_castpd_ps(o10);
+            let o11 = _mm512_castpd_ps(o11);
+            let o12 = _mm512_castpd_ps(o12);
+            let o13 = _mm512_castpd_ps(o13);
+            let o14 = _mm512_castpd_ps(o14);
+            let o15 = _mm512_castpd_ps(o15);
+
+            F32VecAvx512(o0, d).store_array(&mut data[0]);
+            F32VecAvx512(o1, d).store_array(&mut data[1 * stride]);
+            F32VecAvx512(o2, d).store_array(&mut data[2 * stride]);
+            F32VecAvx512(o3, d).store_array(&mut data[3 * stride]);
+            F32VecAvx512(o4, d).store_array(&mut data[4 * stride]);
+            F32VecAvx512(o5, d).store_array(&mut data[5 * stride]);
+            F32VecAvx512(o6, d).store_array(&mut data[6 * stride]);
+            F32VecAvx512(o7, d).store_array(&mut data[7 * stride]);
+            F32VecAvx512(o8, d).store_array(&mut data[8 * stride]);
+            F32VecAvx512(o9, d).store_array(&mut data[9 * stride]);
+            F32VecAvx512(o10, d).store_array(&mut data[10 * stride]);
+            F32VecAvx512(o11, d).store_array(&mut data[11 * stride]);
+            F32VecAvx512(o12, d).store_array(&mut data[12 * stride]);
+            F32VecAvx512(o13, d).store_array(&mut data[13 * stride]);
+            F32VecAvx512(o14, d).store_array(&mut data[14 * stride]);
+            F32VecAvx512(o15, d).store_array(&mut data[15 * stride]);
+        }
+        // SAFETY: the safety invariant on `d` guarantees avx512f
+        unsafe {
+            transpose16x16f32(d, data, stride);
+        }
+    }
+}
+
+impl Add<F32VecAvx512> for F32VecAvx512 {
+    type Output = F32VecAvx512;
+    fn_avx!(this: F32VecAvx512, fn add(rhs: F32VecAvx512) -> F32VecAvx512 {
+        F32VecAvx512(_mm512_add_ps(this.0, rhs.0), this.1)
+    });
+}
+
+impl Sub<F32VecAvx512> for F32VecAvx512 {
+    type Output = F32VecAvx512;
+    fn_avx!(this: F32VecAvx512, fn sub(rhs: F32VecAvx512) -> F32VecAvx512 {
+        F32VecAvx512(_mm512_sub_ps(this.0, rhs.0), this.1)
+    });
+}
+
+impl Mul<F32VecAvx512> for F32VecAvx512 {
+    type Output = F32VecAvx512;
+    fn_avx!(this: F32VecAvx512, fn mul(rhs: F32VecAvx512) -> F32VecAvx512 {
+        F32VecAvx512(_mm512_mul_ps(this.0, rhs.0), this.1)
+    });
+}
+
+impl Div<F32VecAvx512> for F32VecAvx512 {
+    type Output = F32VecAvx512;
+    fn_avx!(this: F32VecAvx512, fn div(rhs: F32VecAvx512) -> F32VecAvx512 {
+        F32VecAvx512(_mm512_div_ps(this.0, rhs.0), this.1)
+    });
+}
+
+impl AddAssign<F32VecAvx512> for F32VecAvx512 {
+    fn_avx!(this: &mut F32VecAvx512, fn add_assign(rhs: F32VecAvx512) {
+        this.0 = _mm512_add_ps(this.0, rhs.0)
+    });
+}
+
+impl SubAssign<F32VecAvx512> for F32VecAvx512 {
+    fn_avx!(this: &mut F32VecAvx512, fn sub_assign(rhs: F32VecAvx512) {
+        this.0 = _mm512_sub_ps(this.0, rhs.0)
+    });
+}
+
+impl MulAssign<F32VecAvx512> for F32VecAvx512 {
+    fn_avx!(this: &mut F32VecAvx512, fn mul_assign(rhs: F32VecAvx512) {
+        this.0 = _mm512_mul_ps(this.0, rhs.0)
+    });
+}
+
+impl DivAssign<F32VecAvx512> for F32VecAvx512 {
+    fn_avx!(this: &mut F32VecAvx512, fn div_assign(rhs: F32VecAvx512) {
+        this.0 = _mm512_div_ps(this.0, rhs.0)
+    });
+}
+
+#[derive(Clone, Copy, Debug)]
+#[repr(transparent)]
+pub struct I32VecAvx512(__m512i, Avx512Descriptor);
+
+impl I32SimdVec for I32VecAvx512 {
+    type Descriptor = Avx512Descriptor;
+
+    const LEN: usize = 16;
+
+    #[inline(always)]
+    fn load(d: Self::Descriptor, mem: &[i32]) -> Self {
+        assert!(mem.len() >= Self::LEN);
+        // SAFETY: we just checked that `mem` has enough space. Moreover, we know avx512f is available
+        // from the safety invariant on `d`.
+        Self(unsafe { _mm512_loadu_epi32(mem.as_ptr()) }, d)
+    }
+
+    #[inline(always)]
+    fn store(&self, mem: &mut [i32]) {
+        assert!(mem.len() >= Self::LEN);
+        // SAFETY: we just checked that `mem` has enough space. Moreover, we know avx512f is available
+        // from the safety invariant on `self.1`.
+        unsafe { _mm512_storeu_epi32(mem.as_mut_ptr(), self.0) }
+    }
+
+    #[inline(always)]
+    fn splat(d: Self::Descriptor, v: i32) -> Self {
+        // SAFETY: We know avx512f is available from the safety invariant on `d`.
+        unsafe { Self(_mm512_set1_epi32(v), d) }
+    }
+
+    fn_avx!(this: I32VecAvx512, fn as_f32() -> F32VecAvx512 {
+         F32VecAvx512(_mm512_cvtepi32_ps(this.0), this.1)
+    });
+
+    fn_avx!(this: I32VecAvx512, fn bitcast_to_f32() -> F32VecAvx512 {
+         F32VecAvx512(_mm512_castsi512_ps(this.0), this.1)
+    });
+
+    #[inline(always)]
+    fn bitcast_to_u32(self) -> U32VecAvx512 {
+        U32VecAvx512(self.0, self.1)
+    }
+
+    fn_avx!(this: I32VecAvx512, fn abs() -> I32VecAvx512 {
+        I32VecAvx512(_mm512_abs_epi32(this.0), this.1)
+    });
+
+    fn_avx!(this: I32VecAvx512, fn gt(rhs: I32VecAvx512) -> MaskAvx512 {
+        MaskAvx512(_mm512_cmpgt_epi32_mask(this.0, rhs.0), this.1)
+    });
+
+    fn_avx!(this: I32VecAvx512, fn lt_zero() -> MaskAvx512 {
+        I32VecAvx512(_mm512_setzero_epi32(), this.1).gt(this)
+    });
+
+    fn_avx!(this: I32VecAvx512, fn eq(rhs: I32VecAvx512) -> MaskAvx512 {
+        MaskAvx512(_mm512_cmpeq_epi32_mask(this.0, rhs.0), this.1)
+    });
+
+    fn_avx!(this: I32VecAvx512, fn eq_zero() -> MaskAvx512 {
+        I32VecAvx512(_mm512_setzero_epi32(), this.1).eq(this)
+    });
+
+    #[inline(always)]
+    fn shl<const AMOUNT_U: u32, const AMOUNT_I: i32>(self) -> Self {
+        // SAFETY: We know avx512f is available from the safety invariant on `d`.
+        unsafe { I32VecAvx512(_mm512_slli_epi32::<AMOUNT_U>(self.0), self.1) }
+    }
+
+    #[inline(always)]
+    fn shr<const AMOUNT_U: u32, const AMOUNT_I: i32>(self) -> Self {
+        // SAFETY: We know avx512f is available from the safety invariant on `d`.
+        unsafe { I32VecAvx512(_mm512_srai_epi32::<AMOUNT_U>(self.0), self.1) }
+    }
+
+    fn_avx!(this: I32VecAvx512, fn mul_wide_take_high(rhs: I32VecAvx512) -> I32VecAvx512 {
+        let l = _mm512_mul_epi32(this.0, rhs.0);
+        let h = _mm512_mul_epi32(_mm512_srli_epi64::<32>(this.0), _mm512_srli_epi64::<32>(rhs.0));
+        let idx = _mm512_setr_epi32(1, 17, 3, 19, 5, 21, 7, 23, 9, 25, 11, 27, 13, 29, 15, 31);
+        I32VecAvx512(_mm512_permutex2var_epi32(l, idx, h), this.1)
+    });
+}
+
+impl Add<I32VecAvx512> for I32VecAvx512 {
+    type Output = I32VecAvx512;
+    fn_avx!(this: I32VecAvx512, fn add(rhs: I32VecAvx512) -> I32VecAvx512 {
+        I32VecAvx512(_mm512_add_epi32(this.0, rhs.0), this.1)
+    });
+}
+
+impl Sub<I32VecAvx512> for I32VecAvx512 {
+    type Output = I32VecAvx512;
+    fn_avx!(this: I32VecAvx512, fn sub(rhs: I32VecAvx512) -> I32VecAvx512 {
+        I32VecAvx512(_mm512_sub_epi32(this.0, rhs.0), this.1)
+    });
+}
+
+impl Mul<I32VecAvx512> for I32VecAvx512 {
+    type Output = I32VecAvx512;
+    fn_avx!(this: I32VecAvx512, fn mul(rhs: I32VecAvx512) -> I32VecAvx512 {
+        I32VecAvx512(_mm512_mul_epi32(this.0, rhs.0), this.1)
+    });
+}
+
+impl Neg for I32VecAvx512 {
+    type Output = I32VecAvx512;
+    fn_avx!(this: I32VecAvx512, fn neg() -> I32VecAvx512 {
+        I32VecAvx512(_mm512_setzero_epi32(), this.1) - this
+    });
+}
+
+impl Shl<I32VecAvx512> for I32VecAvx512 {
+    type Output = I32VecAvx512;
+    fn_avx!(this: I32VecAvx512, fn shl(rhs: I32VecAvx512) -> I32VecAvx512 {
+        I32VecAvx512(_mm512_sllv_epi32(this.0, rhs.0), this.1)
+    });
+}
+
+impl Shr<I32VecAvx512> for I32VecAvx512 {
+    type Output = I32VecAvx512;
+    fn_avx!(this: I32VecAvx512, fn shr(rhs: I32VecAvx512) -> I32VecAvx512 {
+        I32VecAvx512(_mm512_srav_epi32(this.0, rhs.0), this.1)
+    });
+}
+
+impl BitAnd<I32VecAvx512> for I32VecAvx512 {
+    type Output = I32VecAvx512;
+    fn_avx!(this: I32VecAvx512, fn bitand(rhs: I32VecAvx512) -> I32VecAvx512 {
+        I32VecAvx512(_mm512_and_si512(this.0, rhs.0), this.1)
+    });
+}
+
+impl BitOr<I32VecAvx512> for I32VecAvx512 {
+    type Output = I32VecAvx512;
+    fn_avx!(this: I32VecAvx512, fn bitor(rhs: I32VecAvx512) -> I32VecAvx512 {
+        I32VecAvx512(_mm512_or_si512(this.0, rhs.0), this.1)
+    });
+}
+
+impl BitXor<I32VecAvx512> for I32VecAvx512 {
+    type Output = I32VecAvx512;
+    fn_avx!(this: I32VecAvx512, fn bitxor(rhs: I32VecAvx512) -> I32VecAvx512 {
+        I32VecAvx512(_mm512_xor_si512(this.0, rhs.0), this.1)
+    });
+}
+
+impl AddAssign<I32VecAvx512> for I32VecAvx512 {
+    fn_avx!(this: &mut I32VecAvx512, fn add_assign(rhs: I32VecAvx512) {
+        this.0 = _mm512_add_epi32(this.0, rhs.0)
+    });
+}
+
+impl SubAssign<I32VecAvx512> for I32VecAvx512 {
+    fn_avx!(this: &mut I32VecAvx512, fn sub_assign(rhs: I32VecAvx512) {
+        this.0 = _mm512_sub_epi32(this.0, rhs.0)
+    });
+}
+
+impl MulAssign<I32VecAvx512> for I32VecAvx512 {
+    fn_avx!(this: &mut I32VecAvx512, fn mul_assign(rhs: I32VecAvx512) {
+        this.0 = _mm512_mul_epi32(this.0, rhs.0)
+    });
+}
+
+impl ShlAssign<I32VecAvx512> for I32VecAvx512 {
+    fn_avx!(this: &mut I32VecAvx512, fn shl_assign(rhs: I32VecAvx512) {
+        this.0 = _mm512_sllv_epi32(this.0, rhs.0)
+    });
+}
+
+impl ShrAssign<I32VecAvx512> for I32VecAvx512 {
+    fn_avx!(this: &mut I32VecAvx512, fn shr_assign(rhs: I32VecAvx512) {
+        this.0 = _mm512_srav_epi32(this.0, rhs.0)
+    });
+}
+
+impl BitAndAssign<I32VecAvx512> for I32VecAvx512 {
+    fn_avx!(this: &mut I32VecAvx512, fn bitand_assign(rhs: I32VecAvx512) {
+        this.0 = _mm512_and_si512(this.0, rhs.0)
+    });
+}
+
+impl BitOrAssign<I32VecAvx512> for I32VecAvx512 {
+    fn_avx!(this: &mut I32VecAvx512, fn bitor_assign(rhs: I32VecAvx512) {
+        this.0 = _mm512_or_si512(this.0, rhs.0)
+    });
+}
+
+impl BitXorAssign<I32VecAvx512> for I32VecAvx512 {
+    fn_avx!(this: &mut I32VecAvx512, fn bitxor_assign(rhs: I32VecAvx512) {
+        this.0 = _mm512_xor_si512(this.0, rhs.0)
+    });
+}
+
+#[derive(Clone, Copy, Debug)]
+#[repr(transparent)]
+pub struct U32VecAvx512(__m512i, Avx512Descriptor);
+
+impl U32SimdVec for U32VecAvx512 {
+    type Descriptor = Avx512Descriptor;
+
+    const LEN: usize = 8;
+
+    #[inline(always)]
+    fn bitcast_to_i32(self) -> I32VecAvx512 {
+        I32VecAvx512(self.0, self.1)
+    }
+
+    #[inline(always)]
+    fn shr<const AMOUNT_U: u32, const AMOUNT_I: i32>(self) -> Self {
+        // SAFETY: We know avx512f is available from the safety invariant on `self.1`.
+        unsafe { Self(_mm512_srli_epi32::<AMOUNT_U>(self.0), self.1) }
+    }
+}
+
+impl SimdMask for MaskAvx512 {
+    type Descriptor = Avx512Descriptor;
+
+    fn_avx!(this: MaskAvx512, fn if_then_else_f32(if_true: F32VecAvx512, if_false: F32VecAvx512) -> F32VecAvx512 {
+        F32VecAvx512(_mm512_mask_blend_ps(this.0, if_false.0, if_true.0), this.1)
+    });
+
+    fn_avx!(this: MaskAvx512, fn if_then_else_i32(if_true: I32VecAvx512, if_false: I32VecAvx512) -> I32VecAvx512 {
+        I32VecAvx512(_mm512_mask_blend_epi32(this.0, if_false.0, if_true.0), this.1)
+    });
+
+    fn_avx!(this: MaskAvx512, fn maskz_i32(v: I32VecAvx512) -> I32VecAvx512 {
+        I32VecAvx512(_mm512_mask_set1_epi32(v.0, this.0, 0), this.1)
+    });
+
+    fn_avx!(this: MaskAvx512, fn all() -> bool {
+        this.0 == 0b1111111111111111
+    });
+
+    fn_avx!(this: MaskAvx512, fn andnot(rhs: MaskAvx512) -> MaskAvx512 {
+        MaskAvx512((!this.0) & rhs.0, this.1)
+    });
+}
+
+impl BitAnd<MaskAvx512> for MaskAvx512 {
+    type Output = MaskAvx512;
+    fn_avx!(this: MaskAvx512, fn bitand(rhs: MaskAvx512) -> MaskAvx512 {
+        MaskAvx512(this.0 & rhs.0, this.1)
+    });
+}
+
+impl BitOr<MaskAvx512> for MaskAvx512 {
+    type Output = MaskAvx512;
+    fn_avx!(this: MaskAvx512, fn bitor(rhs: MaskAvx512) -> MaskAvx512 {
+        MaskAvx512(this.0 | rhs.0, this.1)
+    });
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/x86_64/mod.rs b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/x86_64/mod.rs
new file mode 100644
index 0000000..939dd24a
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/x86_64/mod.rs
@@ -0,0 +1,260 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(unsafe_code)]
+#![allow(clippy::identity_op)]
+
+#[cfg(feature = "avx")]
+pub(super) mod avx;
+#[cfg(feature = "avx512")]
+pub(super) mod avx512;
+#[cfg(feature = "sse42")]
+pub(super) mod sse42;
+
+#[macro_export]
+macro_rules! simd_function {
+    (
+        $dname:ident,
+        $descr:ident: $descr_ty:ident,
+        $(#[$($attr:meta)*])*
+        $pub:vis fn $name:ident($($arg:ident: $ty:ty),* $(,)?) $(-> $ret:ty )? $body: block
+    ) => {
+        #[inline(always)]
+        $(#[$($attr)*])*
+        $pub fn $name<$descr_ty: $crate::SimdDescriptor>($descr: $descr_ty, $($arg: $ty),*) $(-> $ret)? $body
+        #[allow(unsafe_code)]
+        $(#[$($attr)*])*
+        $pub fn $dname($($arg: $ty),*) $(-> $ret)? {
+            #[allow(unused)]
+            use $crate::SimdDescriptor;
+            $crate::simd_function_body_avx512!($name($($arg: $ty),*) $(-> $ret)?; ($($arg),*));
+            $crate::simd_function_body_avx!($name($($arg: $ty),*) $(-> $ret)?; ($($arg),*));
+            $crate::simd_function_body_sse42!($name($($arg: $ty),*) $(-> $ret)?; ($($arg),*));
+            $name($crate::ScalarDescriptor::new().unwrap(), $($arg),*)
+        }
+    };
+}
+
+#[cfg(feature = "sse42")]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! simd_function_body_sse42 {
+    ($name:ident($($arg:ident: $ty:ty),* $(,)?) $(-> $ret:ty )?; ($($val:expr),* $(,)?)) => {
+        if cfg!(target_feature = "sse4.2") {
+            // SAFETY: we just checked for sse4.2.
+            let d = unsafe { $crate::Sse42Descriptor::new_unchecked() };
+            return $name(d, $($val),*);
+        } else if let Some(d) = $crate::Sse42Descriptor::new() {
+            #[target_feature(enable = "sse4.2")]
+            fn sse42(d: $crate::Sse42Descriptor, $($arg: $ty),*) $(-> $ret)? {
+                $name(d, $($val),*)
+            }
+            // SAFETY: we just checked for sse4.2.
+            return unsafe { sse42(d, $($arg),*) };
+        }
+    };
+}
+
+#[cfg(feature = "avx")]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! simd_function_body_avx {
+    ($name:ident($($arg:ident: $ty:ty),* $(,)?) $(-> $ret:ty )?; ($($val:expr),* $(,)?)) => {
+        if cfg!(all(target_feature = "avx2", target_feature = "fma")) {
+            // SAFETY: we just checked for avx2 and fma.
+            let d = unsafe { $crate::AvxDescriptor::new_unchecked() };
+            return $name(d, $($val),*);
+        } else if let Some(d) = $crate::AvxDescriptor::new() {
+            #[target_feature(enable = "avx2,fma")]
+            fn avx(d: $crate::AvxDescriptor, $($arg: $ty),*) $(-> $ret)? {
+                $name(d, $($val),*)
+            }
+            // SAFETY: we just checked for avx2 and fma.
+            return unsafe { avx(d, $($arg),*) };
+        }
+    };
+}
+
+#[cfg(feature = "avx512")]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! simd_function_body_avx512 {
+    ($name:ident($($arg:ident: $ty:ty),* $(,)?) $(-> $ret:ty )?; ($($val:expr),* $(,)?)) => {
+        if cfg!(target_feature = "avx512f") {
+            // SAFETY: we just checked for avx512f.
+            let d = unsafe { $crate::Avx512Descriptor::new_unchecked() };
+            return $name(d, $($val),*);
+        } else if let Some(d) = $crate::Avx512Descriptor::new() {
+            #[target_feature(enable = "avx512f")]
+            fn avx512(d: $crate::Avx512Descriptor, $($arg: $ty),*) $(-> $ret)? {
+                $name(d, $($val),*)
+            }
+            // SAFETY: we just checked for avx512f.
+            return unsafe { avx512(d, $($arg),*) };
+        }
+    };
+}
+
+#[cfg(not(feature = "sse42"))]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! simd_function_body_sse42 {
+    ($($ignore:tt)*) => {};
+}
+
+#[cfg(not(feature = "avx"))]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! simd_function_body_avx {
+    ($($ignore:tt)*) => {};
+}
+
+#[cfg(not(feature = "avx512"))]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! simd_function_body_avx512 {
+    ($($ignore:tt)*) => {};
+}
+
+#[macro_export]
+macro_rules! test_all_instruction_sets {
+    (
+        $name:ident
+    ) => {
+        paste::paste! {
+            #[test]
+            fn [<$name _scalar>]() {
+                use $crate::SimdDescriptor;
+                $name($crate::ScalarDescriptor::new().unwrap())
+            }
+        }
+
+        $crate::test_sse42!($name);
+        $crate::test_avx!($name);
+        $crate::test_avx512!($name);
+    };
+}
+
+#[cfg(feature = "sse42")]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! test_sse42 {
+    ($name:ident) => {
+        paste::paste! {
+            #[allow(unsafe_code)]
+            #[test]
+            fn [<$name _sse42>]() {
+                use $crate::SimdDescriptor;
+                let Some(d) = $crate::Sse42Descriptor::new() else { return; };
+                #[target_feature(enable = "sse4.2")]
+                fn inner(d: $crate::Sse42Descriptor) {
+                    $name(d)
+                }
+                // SAFETY: we just checked for sse4.2.
+                return unsafe { inner(d) };
+            }
+        }
+    };
+}
+
+#[cfg(feature = "avx")]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! test_avx {
+    ($name:ident) => {
+        paste::paste! {
+            #[allow(unsafe_code)]
+            #[test]
+            fn [<$name _avx>]() {
+                use $crate::SimdDescriptor;
+                let Some(d) = $crate::AvxDescriptor::new() else { return; };
+                #[target_feature(enable = "avx2,fma")]
+                fn inner(d: $crate::AvxDescriptor) {
+                    $name(d)
+                }
+                // SAFETY: we just checked for avx2 and fma.
+                return unsafe { inner(d) };
+            }
+        }
+    };
+}
+
+#[cfg(feature = "avx512")]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! test_avx512 {
+    ($name:ident) => {
+        paste::paste! {
+            #[allow(unsafe_code)]
+            #[test]
+            fn [<$name _avx512>]() {
+                use $crate::SimdDescriptor;
+                let Some(d) = $crate::Avx512Descriptor::new() else { return; };
+                #[target_feature(enable = "avx512f")]
+                fn inner(d: $crate::Avx512Descriptor) {
+                    $name(d)
+                }
+                // SAFETY: we just checked for avx512f.
+                return unsafe { inner(d) };
+            }
+        }
+    };
+}
+
+#[cfg(not(feature = "sse42"))]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! test_sse42 {
+    ($name:ident) => {};
+}
+
+#[cfg(not(feature = "avx"))]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! test_avx {
+    ($name:ident) => {};
+}
+
+#[cfg(not(feature = "avx512"))]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! test_avx512 {
+    ($name:ident) => {};
+}
+
+#[macro_export]
+macro_rules! bench_all_instruction_sets {
+    (
+        $name:ident,
+        $criterion:ident
+    ) => {
+        #[allow(unused)]
+        use $crate::SimdDescriptor;
+        // `simd_function_body_*` does early return; wrap it with an immediately-invoked closure
+        (|| {
+            $crate::simd_function_body_avx512!(
+                $name($criterion: &mut ::criterion::BenchmarkGroup<'_, impl ::criterion::measurement::Measurement>);
+                ($criterion, "avx512")
+            );
+        })();
+        (|| {
+            $crate::simd_function_body_avx!(
+                $name($criterion: &mut ::criterion::BenchmarkGroup<'_, impl ::criterion::measurement::Measurement>);
+                ($criterion, "avx")
+            );
+        })();
+        (|| {
+            $crate::simd_function_body_sse42!(
+                $name($criterion: &mut ::criterion::BenchmarkGroup<'_, impl ::criterion::measurement::Measurement>);
+                ($criterion, "sse42")
+            );
+        })();
+        $name(
+            $crate::ScalarDescriptor::new().unwrap(),
+            $criterion,
+            "scalar",
+        );
+    };
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/x86_64/sse42.rs b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/x86_64/sse42.rs
new file mode 100644
index 0000000..21d2cd3f
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/x86_64/sse42.rs
@@ -0,0 +1,512 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{U32SimdVec, impl_f32_array_interface};
+
+use super::super::{F32SimdVec, I32SimdVec, SimdDescriptor, SimdMask};
+use std::{
+    arch::x86_64::*,
+    ops::{
+        Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div,
+        DivAssign, Mul, MulAssign, Neg, Sub, SubAssign,
+    },
+};
+
+// Safety invariant: this type is only ever constructed if sse4.2 is available.
+#[derive(Clone, Copy, Debug)]
+pub struct Sse42Descriptor(());
+
+impl Sse42Descriptor {
+    /// # Safety
+    /// The caller must guarantee that the sse4.2 target feature is available.
+    pub unsafe fn new_unchecked() -> Self {
+        Self(())
+    }
+}
+
+impl SimdDescriptor for Sse42Descriptor {
+    type F32Vec = F32VecSse42;
+    type I32Vec = I32VecSse42;
+    type U32Vec = U32VecSse42;
+    type Mask = MaskSse42;
+
+    type Descriptor256 = Self;
+    type Descriptor128 = Self;
+
+    fn maybe_downgrade_256bit(self) -> Self::Descriptor256 {
+        self
+    }
+
+    fn maybe_downgrade_128bit(self) -> Self::Descriptor128 {
+        self
+    }
+
+    fn new() -> Option<Self> {
+        if is_x86_feature_detected!("sse4.2") {
+            // SAFETY: we just checked sse4.2.
+            Some(unsafe { Self::new_unchecked() })
+        } else {
+            None
+        }
+    }
+
+    fn call<R>(self, f: impl FnOnce(Self) -> R) -> R {
+        #[target_feature(enable = "sse4.2")]
+        #[inline(never)]
+        unsafe fn inner<R>(d: Sse42Descriptor, f: impl FnOnce(Sse42Descriptor) -> R) -> R {
+            f(d)
+        }
+        // SAFETY: the safety invariant on `self` guarantees sse4.2.
+        unsafe { inner(self, f) }
+    }
+}
+
+// TODO(veluca): retire this macro once we have #[unsafe(target_feature)].
+macro_rules! fn_sse42 {
+    (
+        $this:ident: $self_ty:ty,
+        fn $name:ident($($arg:ident: $ty:ty),* $(,)?) $(-> $ret:ty )? $body: block) => {
+        #[inline(always)]
+        fn $name(self: $self_ty, $($arg: $ty),*) $(-> $ret)? {
+            #[target_feature(enable = "sse4.2")]
+            #[inline]
+            fn inner($this: $self_ty, $($arg: $ty),*) $(-> $ret)? {
+                $body
+            }
+            // SAFETY: `self.1` is constructed iff sse42 are available.
+            unsafe { inner(self, $($arg),*) }
+        }
+    };
+}
+
+#[derive(Clone, Copy, Debug)]
+#[repr(transparent)]
+pub struct F32VecSse42(__m128, Sse42Descriptor);
+
+#[derive(Clone, Copy, Debug)]
+#[repr(transparent)]
+pub struct MaskSse42(__m128, Sse42Descriptor);
+
+impl F32SimdVec for F32VecSse42 {
+    type Descriptor = Sse42Descriptor;
+
+    const LEN: usize = 4;
+
+    #[inline(always)]
+    fn load(d: Self::Descriptor, mem: &[f32]) -> Self {
+        assert!(mem.len() >= Self::LEN);
+        // SAFETY: we just checked that `mem` has enough space. Moreover, we know sse4.2 is available
+        // from the safety invariant on `d`.
+        Self(unsafe { _mm_loadu_ps(mem.as_ptr()) }, d)
+    }
+
+    #[inline(always)]
+    fn store(&self, mem: &mut [f32]) {
+        assert!(mem.len() >= Self::LEN);
+        // SAFETY: we just checked that `mem` has enough space. Moreover, we know sse4.2 is available
+        // from the safety invariant on `self.1`.
+        unsafe { _mm_storeu_ps(mem.as_mut_ptr(), self.0) }
+    }
+
+    fn_sse42!(this: F32VecSse42, fn mul_add(mul: F32VecSse42, add: F32VecSse42) -> F32VecSse42 {
+        this * mul + add
+    });
+
+    fn_sse42!(this: F32VecSse42, fn neg_mul_add(mul: F32VecSse42, add: F32VecSse42) -> F32VecSse42 {
+        add - this * mul
+    });
+
+    #[inline(always)]
+    fn splat(d: Self::Descriptor, v: f32) -> Self {
+        // SAFETY: We know sse4.2 is available from the safety invariant on `d`.
+        unsafe { Self(_mm_set1_ps(v), d) }
+    }
+
+    #[inline(always)]
+    fn zero(d: Self::Descriptor) -> Self {
+        // SAFETY: We know sse4.2 is available from the safety invariant on `d`.
+        unsafe { Self(_mm_setzero_ps(), d) }
+    }
+
+    fn_sse42!(this: F32VecSse42, fn abs() -> F32VecSse42 {
+        F32VecSse42(
+            _mm_castsi128_ps(_mm_andnot_si128(
+                _mm_set1_epi32(i32::MIN),
+                _mm_castps_si128(this.0),
+            )),
+            this.1)
+    });
+
+    fn_sse42!(this: F32VecSse42, fn floor() -> F32VecSse42 {
+        F32VecSse42(_mm_floor_ps(this.0), this.1)
+    });
+
+    fn_sse42!(this: F32VecSse42, fn sqrt() -> F32VecSse42 {
+        F32VecSse42(_mm_sqrt_ps(this.0), this.1)
+    });
+
+    fn_sse42!(this: F32VecSse42, fn neg() -> F32VecSse42 {
+        F32VecSse42(
+            _mm_castsi128_ps(_mm_xor_si128(
+                _mm_set1_epi32(i32::MIN),
+                _mm_castps_si128(this.0),
+            )),
+            this.1)
+    });
+
+    fn_sse42!(this: F32VecSse42, fn copysign(sign: F32VecSse42) -> F32VecSse42 {
+        let sign_mask = _mm_castsi128_ps(_mm_set1_epi32(i32::MIN));
+        F32VecSse42(
+            _mm_or_ps(
+                _mm_andnot_ps(sign_mask, this.0),
+                _mm_and_ps(sign_mask, sign.0),
+            ),
+            this.1,
+        )
+    });
+
+    fn_sse42!(this: F32VecSse42, fn max(other: F32VecSse42) -> F32VecSse42 {
+        F32VecSse42(_mm_max_ps(this.0, other.0), this.1)
+    });
+
+    fn_sse42!(this: F32VecSse42, fn gt(other: F32VecSse42) -> MaskSse42 {
+        MaskSse42(_mm_cmpgt_ps(this.0, other.0), this.1)
+    });
+
+    fn_sse42!(this: F32VecSse42, fn as_i32() -> I32VecSse42 {
+        I32VecSse42(_mm_cvtps_epi32(this.0), this.1)
+    });
+
+    fn_sse42!(this: F32VecSse42, fn bitcast_to_i32() -> I32VecSse42 {
+        I32VecSse42(_mm_castps_si128(this.0), this.1)
+    });
+
+    impl_f32_array_interface!();
+
+    #[inline(always)]
+    fn transpose_square(d: Self::Descriptor, data: &mut [Self::UnderlyingArray], stride: usize) {
+        #[target_feature(enable = "sse4.2")]
+        #[inline]
+        fn transpose4x4f32(d: Sse42Descriptor, data: &mut [[f32; 4]], stride: usize) {
+            assert!(data.len() > stride * 3);
+
+            let p0 = F32VecSse42::load_array(d, &data[0]).0;
+            let p1 = F32VecSse42::load_array(d, &data[1 * stride]).0;
+            let p2 = F32VecSse42::load_array(d, &data[2 * stride]).0;
+            let p3 = F32VecSse42::load_array(d, &data[3 * stride]).0;
+
+            let q0 = _mm_unpacklo_ps(p0, p2);
+            let q1 = _mm_unpacklo_ps(p1, p3);
+            let q2 = _mm_unpackhi_ps(p0, p2);
+            let q3 = _mm_unpackhi_ps(p1, p3);
+
+            let r0 = _mm_unpacklo_ps(q0, q1);
+            let r1 = _mm_unpackhi_ps(q0, q1);
+            let r2 = _mm_unpacklo_ps(q2, q3);
+            let r3 = _mm_unpackhi_ps(q2, q3);
+
+            F32VecSse42(r0, d).store_array(&mut data[0]);
+            F32VecSse42(r1, d).store_array(&mut data[1 * stride]);
+            F32VecSse42(r2, d).store_array(&mut data[2 * stride]);
+            F32VecSse42(r3, d).store_array(&mut data[3 * stride]);
+        }
+
+        // SAFETY: the safety invariant on `d` guarantees sse42
+        unsafe {
+            transpose4x4f32(d, data, stride);
+        }
+    }
+}
+
+impl Add<F32VecSse42> for F32VecSse42 {
+    type Output = F32VecSse42;
+    fn_sse42!(this: F32VecSse42, fn add(rhs: F32VecSse42) -> F32VecSse42 {
+        F32VecSse42(_mm_add_ps(this.0, rhs.0), this.1)
+    });
+}
+
+impl Sub<F32VecSse42> for F32VecSse42 {
+    type Output = F32VecSse42;
+    fn_sse42!(this: F32VecSse42, fn sub(rhs: F32VecSse42) -> F32VecSse42 {
+        F32VecSse42(_mm_sub_ps(this.0, rhs.0), this.1)
+    });
+}
+
+impl Mul<F32VecSse42> for F32VecSse42 {
+    type Output = F32VecSse42;
+    fn_sse42!(this: F32VecSse42, fn mul(rhs: F32VecSse42) -> F32VecSse42 {
+        F32VecSse42(_mm_mul_ps(this.0, rhs.0), this.1)
+    });
+}
+
+impl Div<F32VecSse42> for F32VecSse42 {
+    type Output = F32VecSse42;
+    fn_sse42!(this: F32VecSse42, fn div(rhs: F32VecSse42) -> F32VecSse42 {
+        F32VecSse42(_mm_div_ps(this.0, rhs.0), this.1)
+    });
+}
+
+impl AddAssign<F32VecSse42> for F32VecSse42 {
+    fn_sse42!(this: &mut F32VecSse42, fn add_assign(rhs: F32VecSse42) {
+        this.0 = _mm_add_ps(this.0, rhs.0)
+    });
+}
+
+impl SubAssign<F32VecSse42> for F32VecSse42 {
+    fn_sse42!(this: &mut F32VecSse42, fn sub_assign(rhs: F32VecSse42) {
+        this.0 = _mm_sub_ps(this.0, rhs.0)
+    });
+}
+
+impl MulAssign<F32VecSse42> for F32VecSse42 {
+    fn_sse42!(this: &mut F32VecSse42, fn mul_assign(rhs: F32VecSse42) {
+        this.0 = _mm_mul_ps(this.0, rhs.0)
+    });
+}
+
+impl DivAssign<F32VecSse42> for F32VecSse42 {
+    fn_sse42!(this: &mut F32VecSse42, fn div_assign(rhs: F32VecSse42) {
+        this.0 = _mm_div_ps(this.0, rhs.0)
+    });
+}
+
+#[derive(Clone, Copy, Debug)]
+#[repr(transparent)]
+pub struct I32VecSse42(__m128i, Sse42Descriptor);
+
+impl I32SimdVec for I32VecSse42 {
+    type Descriptor = Sse42Descriptor;
+
+    const LEN: usize = 4;
+
+    #[inline(always)]
+    fn load(d: Self::Descriptor, mem: &[i32]) -> Self {
+        assert!(mem.len() >= Self::LEN);
+        // SAFETY: we just checked that `mem` has enough space. Moreover, we know sse4.2 is available
+        // from the safety invariant on `d`.
+        Self(unsafe { _mm_loadu_si128(mem.as_ptr() as *const _) }, d)
+    }
+
+    #[inline(always)]
+    fn store(&self, mem: &mut [i32]) {
+        assert!(mem.len() >= Self::LEN);
+        // SAFETY: we just checked that `mem` has enough space. Moreover, we know sse4.2 is available
+        // from the safety invariant on `self.1`.
+        unsafe { _mm_storeu_si128(mem.as_mut_ptr().cast(), self.0) }
+    }
+
+    #[inline(always)]
+    fn splat(d: Self::Descriptor, v: i32) -> Self {
+        // SAFETY: We know sse4.2 is available from the safety invariant on `d`.
+        unsafe { Self(_mm_set1_epi32(v), d) }
+    }
+
+    fn_sse42!(this: I32VecSse42, fn as_f32() -> F32VecSse42 {
+        F32VecSse42(_mm_cvtepi32_ps(this.0), this.1)
+    });
+
+    fn_sse42!(this: I32VecSse42, fn bitcast_to_f32() -> F32VecSse42 {
+        F32VecSse42(_mm_castsi128_ps(this.0), this.1)
+    });
+
+    #[inline(always)]
+    fn bitcast_to_u32(self) -> U32VecSse42 {
+        U32VecSse42(self.0, self.1)
+    }
+
+    fn_sse42!(this: I32VecSse42, fn abs() -> I32VecSse42 {
+        I32VecSse42(
+            _mm_abs_epi32(
+                this.0,
+            ),
+            this.1)
+    });
+
+    fn_sse42!(this: I32VecSse42, fn gt(rhs: I32VecSse42) -> MaskSse42 {
+        MaskSse42(
+            _mm_castsi128_ps(_mm_cmpgt_epi32(this.0, rhs.0)),
+            this.1,
+        )
+    });
+
+    fn_sse42!(this: I32VecSse42, fn lt_zero() -> MaskSse42 {
+        I32VecSse42(_mm_setzero_si128(), this.1).gt(this)
+    });
+
+    fn_sse42!(this: I32VecSse42, fn eq(rhs: I32VecSse42) -> MaskSse42 {
+        MaskSse42(
+            _mm_castsi128_ps(_mm_cmpeq_epi32(this.0, rhs.0)),
+            this.1,
+        )
+    });
+
+    fn_sse42!(this: I32VecSse42, fn eq_zero() -> MaskSse42 {
+        this.eq(I32VecSse42(_mm_setzero_si128(), this.1))
+    });
+
+    #[inline(always)]
+    fn shl<const AMOUNT_U: u32, const AMOUNT_I: i32>(self) -> Self {
+        // SAFETY: We know sse2 is available from the safety invariant on `d`.
+        unsafe { Self(_mm_slli_epi32::<AMOUNT_I>(self.0), self.1) }
+    }
+
+    #[inline(always)]
+    fn shr<const AMOUNT_U: u32, const AMOUNT_I: i32>(self) -> Self {
+        // SAFETY: We know sse2 is available from the safety invariant on `d`.
+        unsafe { Self(_mm_srai_epi32::<AMOUNT_I>(self.0), self.1) }
+    }
+
+    fn_sse42!(this: I32VecSse42, fn mul_wide_take_high(rhs: I32VecSse42) -> I32VecSse42 {
+        let l = _mm_mul_epi32(this.0, rhs.0);
+        let h = _mm_mul_epi32(_mm_srli_epi64::<32>(this.0), _mm_srli_epi64::<32>(rhs.0));
+        let p0 = _mm_unpacklo_epi32(l, h);
+        let p1 = _mm_unpackhi_epi32(l, h);
+        I32VecSse42(_mm_unpackhi_epi64(p0, p1), this.1)
+    });
+}
+
+impl Add<I32VecSse42> for I32VecSse42 {
+    type Output = I32VecSse42;
+    fn_sse42!(this: I32VecSse42, fn add(rhs: I32VecSse42) -> I32VecSse42 {
+        I32VecSse42(_mm_add_epi32(this.0, rhs.0), this.1)
+    });
+}
+
+impl Sub<I32VecSse42> for I32VecSse42 {
+    type Output = I32VecSse42;
+    fn_sse42!(this: I32VecSse42, fn sub(rhs: I32VecSse42) -> I32VecSse42 {
+        I32VecSse42(_mm_sub_epi32(this.0, rhs.0), this.1)
+    });
+}
+
+impl Mul<I32VecSse42> for I32VecSse42 {
+    type Output = I32VecSse42;
+    fn_sse42!(this: I32VecSse42, fn mul(rhs: I32VecSse42) -> I32VecSse42 {
+        I32VecSse42(_mm_mul_epi32(this.0, rhs.0), this.1)
+    });
+}
+
+impl Neg for I32VecSse42 {
+    type Output = I32VecSse42;
+    fn_sse42!(this: I32VecSse42, fn neg() -> I32VecSse42 {
+        I32VecSse42(_mm_setzero_si128(), this.1) - this
+    });
+}
+
+impl BitAnd<I32VecSse42> for I32VecSse42 {
+    type Output = I32VecSse42;
+    fn_sse42!(this: I32VecSse42, fn bitand(rhs: I32VecSse42) -> I32VecSse42 {
+        I32VecSse42(_mm_and_si128(this.0, rhs.0), this.1)
+    });
+}
+
+impl BitOr<I32VecSse42> for I32VecSse42 {
+    type Output = I32VecSse42;
+    fn_sse42!(this: I32VecSse42, fn bitor(rhs: I32VecSse42) -> I32VecSse42 {
+        I32VecSse42(_mm_or_si128(this.0, rhs.0), this.1)
+    });
+}
+
+impl BitXor<I32VecSse42> for I32VecSse42 {
+    type Output = I32VecSse42;
+    fn_sse42!(this: I32VecSse42, fn bitxor(rhs: I32VecSse42) -> I32VecSse42 {
+        I32VecSse42(_mm_xor_si128(this.0, rhs.0), this.1)
+    });
+}
+
+impl AddAssign<I32VecSse42> for I32VecSse42 {
+    fn_sse42!(this: &mut I32VecSse42, fn add_assign(rhs: I32VecSse42) {
+        this.0 = _mm_add_epi32(this.0, rhs.0)
+    });
+}
+
+impl SubAssign<I32VecSse42> for I32VecSse42 {
+    fn_sse42!(this: &mut I32VecSse42, fn sub_assign(rhs: I32VecSse42) {
+        this.0 = _mm_sub_epi32(this.0, rhs.0)
+    });
+}
+
+impl MulAssign<I32VecSse42> for I32VecSse42 {
+    fn_sse42!(this: &mut I32VecSse42, fn mul_assign(rhs: I32VecSse42) {
+        this.0 = _mm_mul_epi32(this.0, rhs.0)
+    });
+}
+
+impl BitAndAssign<I32VecSse42> for I32VecSse42 {
+    fn_sse42!(this: &mut I32VecSse42, fn bitand_assign(rhs: I32VecSse42) {
+        this.0 = _mm_and_si128(this.0, rhs.0)
+    });
+}
+
+impl BitOrAssign<I32VecSse42> for I32VecSse42 {
+    fn_sse42!(this: &mut I32VecSse42, fn bitor_assign(rhs: I32VecSse42) {
+        this.0 = _mm_or_si128(this.0, rhs.0)
+    });
+}
+
+impl BitXorAssign<I32VecSse42> for I32VecSse42 {
+    fn_sse42!(this: &mut I32VecSse42, fn bitxor_assign(rhs: I32VecSse42) {
+        this.0 = _mm_xor_si128(this.0, rhs.0)
+    });
+}
+
+#[derive(Clone, Copy, Debug)]
+#[repr(transparent)]
+pub struct U32VecSse42(__m128i, Sse42Descriptor);
+
+impl U32SimdVec for U32VecSse42 {
+    type Descriptor = Sse42Descriptor;
+
+    const LEN: usize = 4;
+
+    #[inline(always)]
+    fn bitcast_to_i32(self) -> I32VecSse42 {
+        I32VecSse42(self.0, self.1)
+    }
+
+    #[inline(always)]
+    fn shr<const AMOUNT_U: u32, const AMOUNT_I: i32>(self) -> Self {
+        // SAFETY: We know sse2 is available from the safety invariant on `self.1`.
+        unsafe { Self(_mm_srli_epi32::<AMOUNT_I>(self.0), self.1) }
+    }
+}
+
+impl SimdMask for MaskSse42 {
+    type Descriptor = Sse42Descriptor;
+
+    fn_sse42!(this: MaskSse42, fn if_then_else_f32(if_true: F32VecSse42, if_false: F32VecSse42) -> F32VecSse42 {
+        F32VecSse42(_mm_blendv_ps(if_false.0, if_true.0, this.0), this.1)
+    });
+
+    fn_sse42!(this: MaskSse42, fn if_then_else_i32(if_true: I32VecSse42, if_false: I32VecSse42) -> I32VecSse42 {
+        I32VecSse42(_mm_blendv_epi8(if_false.0, if_true.0, _mm_castps_si128(this.0)), this.1)
+    });
+
+    fn_sse42!(this: MaskSse42, fn maskz_i32(v: I32VecSse42) -> I32VecSse42 {
+        I32VecSse42(_mm_andnot_si128(_mm_castps_si128(this.0), v.0), this.1)
+    });
+
+    fn_sse42!(this: MaskSse42, fn all() -> bool {
+        _mm_movemask_ps(this.0) == 0b1111
+    });
+
+    fn_sse42!(this: MaskSse42, fn andnot(rhs: MaskSse42) -> MaskSse42 {
+        MaskSse42(_mm_andnot_ps(this.0, rhs.0), this.1)
+    });
+}
+
+impl BitAnd<MaskSse42> for MaskSse42 {
+    type Output = MaskSse42;
+    fn_sse42!(this: MaskSse42, fn bitand(rhs: MaskSse42) -> MaskSse42 {
+        MaskSse42(_mm_and_ps(this.0, rhs.0), this.1)
+    });
+}
+
+impl BitOr<MaskSse42> for MaskSse42 {
+    type Output = MaskSse42;
+    fn_sse42!(this: MaskSse42, fn bitor(rhs: MaskSse42) -> MaskSse42 {
+        MaskSse42(_mm_or_ps(this.0, rhs.0), this.1)
+    });
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/.cargo-checksum.json b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/.cargo-checksum.json
new file mode 100644
index 0000000..697c9ce
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{}}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/.cargo_vcs_info.json
new file mode 100644
index 0000000..147f8f2
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+  "git": {
+    "sha1": "e3d3eeb3b30c9a50e0c3646046648ae708154099"
+  },
+  "path_in_vcs": "jxl_transforms"
+}
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/Cargo.lock b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/Cargo.lock
new file mode 100644
index 0000000..c1d4794f
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/Cargo.lock
@@ -0,0 +1,848 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "anes"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
+
+[[package]]
+name = "anstream"
+version = "0.6.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
+dependencies = [
+ "anstyle",
+ "once_cell_polyfill",
+ "windows-sys",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
+
+[[package]]
+name = "bumpalo"
+version = "3.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
+
+[[package]]
+name = "cast"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "ciborium"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
+dependencies = [
+ "ciborium-io",
+ "ciborium-ll",
+ "serde",
+]
+
+[[package]]
+name = "ciborium-io"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
+
+[[package]]
+name = "ciborium-ll"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
+dependencies = [
+ "ciborium-io",
+ "half",
+]
+
+[[package]]
+name = "clap"
+version = "4.5.51"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5"
+dependencies = [
+ "clap_builder",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.51"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a"
+dependencies = [
+ "anstyle",
+ "clap_lex",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
+
+[[package]]
+name = "criterion"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1c047a62b0cc3e145fa84415a3191f628e980b194c2755aa12300a4e6cbd928"
+dependencies = [
+ "anes",
+ "cast",
+ "ciborium",
+ "clap",
+ "criterion-plot",
+ "itertools",
+ "num-traits",
+ "oorandom",
+ "plotters",
+ "rayon",
+ "regex",
+ "serde",
+ "serde_json",
+ "tinytemplate",
+ "walkdir",
+]
+
+[[package]]
+name = "criterion-plot"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b1bcc0dc7dfae599d84ad0b1a55f80cde8af3725da8313b528da95ef783e338"
+dependencies = [
+ "cast",
+ "itertools",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
+dependencies = [
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
+
+[[package]]
+name = "crunchy"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
+
+[[package]]
+name = "either"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
+
+[[package]]
+name = "env_filter"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2"
+dependencies = [
+ "log",
+]
+
+[[package]]
+name = "env_logger"
+version = "0.11.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "env_filter",
+ "log",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "wasip2",
+]
+
+[[package]]
+name = "half"
+version = "2.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
+dependencies = [
+ "cfg-if",
+ "crunchy",
+ "zerocopy",
+]
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
+
+[[package]]
+name = "itertools"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+
+[[package]]
+name = "js-sys"
+version = "0.3.82"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65"
+dependencies = [
+ "once_cell",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "jxl_simd"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb6db6beb1373c3fe4fbeac894a67ac03e9996d94b8e3bb6ecd9ec97727c50b9"
+
+[[package]]
+name = "jxl_transforms"
+version = "0.1.4"
+dependencies = [
+ "criterion",
+ "jxl_simd",
+ "paste",
+ "rand",
+ "rand_chacha",
+ "test-log",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
+[[package]]
+name = "libc"
+version = "0.2.177"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
+
+[[package]]
+name = "log"
+version = "0.4.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
+
+[[package]]
+name = "matchers"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
+dependencies = [
+ "regex-automata",
+]
+
+[[package]]
+name = "memchr"
+version = "2.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
+
+[[package]]
+name = "nu-ansi-term"
+version = "0.50.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+
+[[package]]
+name = "once_cell_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
+
+[[package]]
+name = "oorandom"
+version = "11.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
+
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
+
+[[package]]
+name = "plotters"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747"
+dependencies = [
+ "num-traits",
+ "plotters-backend",
+ "plotters-svg",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "plotters-backend"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a"
+
+[[package]]
+name = "plotters-svg"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670"
+dependencies = [
+ "plotters-backend",
+]
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.103"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "5.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
+
+[[package]]
+name = "rand"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
+dependencies = [
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rayon"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
+dependencies = [
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
+dependencies = [
+ "crossbeam-deque",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "regex"
+version = "1.12.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
+
+[[package]]
+name = "rustversion"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
+
+[[package]]
+name = "ryu"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.145"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+ "serde_core",
+]
+
+[[package]]
+name = "sharded-slab"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.110"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "test-log"
+version = "0.2.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e33b98a582ea0be1168eba097538ee8dd4bbe0f2b01b22ac92ea30054e5be7b"
+dependencies = [
+ "env_logger",
+ "test-log-macros",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "test-log-macros"
+version = "0.2.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "451b374529930d7601b1eef8d32bc79ae870b6079b069401709c2a8bf9e75f36"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "thread_local"
+version = "1.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "tinytemplate"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
+dependencies = [
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "tracing"
+version = "0.1.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
+dependencies = [
+ "pin-project-lite",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
+dependencies = [
+ "once_cell",
+ "valuable",
+]
+
+[[package]]
+name = "tracing-log"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
+dependencies = [
+ "log",
+ "once_cell",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-subscriber"
+version = "0.3.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5"
+dependencies = [
+ "matchers",
+ "nu-ansi-term",
+ "once_cell",
+ "regex-automata",
+ "sharded-slab",
+ "thread_local",
+ "tracing",
+ "tracing-core",
+ "tracing-log",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "valuable"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
+
+[[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
+name = "wasip2"
+version = "1.0.1+wasi-0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
+dependencies = [
+ "wit-bindgen",
+]
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.105"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "rustversion",
+ "wasm-bindgen-macro",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.105"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.105"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc"
+dependencies = [
+ "bumpalo",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.105"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.82"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "winapi-util"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "wit-bindgen"
+version = "0.46.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
+
+[[package]]
+name = "zerocopy"
+version = "0.8.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/Cargo.toml
new file mode 100644
index 0000000..59fa52c
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/Cargo.toml
@@ -0,0 +1,74 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2021"
+name = "jxl_transforms"
+version = "0.1.4"
+authors = ["Luca Versari <veluca93@gmail.com>"]
+build = false
+autolib = false
+autobins = false
+autoexamples = false
+autotests = false
+autobenches = false
+description = "High performance Rust implementation of a JPEG XL decoder - Transforms"
+readme = "README.md"
+keywords = [
+    "jpeg-xl",
+    "simd",
+    "dct",
+]
+categories = ["multimedia::images"]
+license = "BSD-3-Clause"
+repository = "https://github.com/libjxl/jxl-rs"
+
+[features]
+all-simd = ["jxl_simd/all-simd"]
+avx = ["jxl_simd/avx"]
+avx512 = ["jxl_simd/avx512"]
+neon = ["jxl_simd/neon"]
+sse42 = ["jxl_simd/sse42"]
+
+[lib]
+name = "jxl_transforms"
+path = "src/lib.rs"
+
+[[bench]]
+name = "dct"
+path = "benches/dct.rs"
+harness = false
+
+[dependencies.jxl_simd]
+version = "=0.1.4"
+
+[dev-dependencies.criterion]
+version = "0.7.0"
+features = ["html_reports"]
+
+[dev-dependencies.paste]
+version = "1.0.15"
+
+[dev-dependencies.rand]
+version = "0.9.2"
+
+[dev-dependencies.rand_chacha]
+version = "0.9.0"
+
+[dev-dependencies.test-log]
+version = "0.2.14"
+
+[lints.clippy]
+missing_safety_doc = "deny"
+undocumented_unsafe_blocks = "deny"
+
+[lints.rust]
+unsafe_op_in_unsafe_fn = "deny"
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/Cargo.toml.orig
new file mode 100644
index 0000000..4344912a
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/Cargo.toml.orig
@@ -0,0 +1,35 @@
+[package]
+name = "jxl_transforms"
+description = "High performance Rust implementation of a JPEG XL decoder - Transforms"
+version = "0.1.4"
+readme = "../README.md"
+keywords = ["jpeg-xl", "simd", "dct"]
+categories = ["multimedia::images"]
+authors = ["Luca Versari <veluca93@gmail.com>"]
+repository = "https://github.com/libjxl/jxl-rs"
+edition = "2021"
+license = "BSD-3-Clause"
+
+[dependencies]
+jxl_simd = { path = "../jxl_simd", version = "=0.1.4" }
+
+[dev-dependencies]
+criterion = { version = "0.7.0", features = ["html_reports"] }
+test-log = "0.2.14"
+paste = "1.0.15"
+rand = "0.9.2"
+rand_chacha = "0.9.0"
+
+[features]
+all-simd = ["jxl_simd/all-simd"]
+sse42 = ["jxl_simd/sse42"]
+avx = ["jxl_simd/avx"]
+avx512 = ["jxl_simd/avx512"]
+neon = ["jxl_simd/neon"]
+
+[[bench]]
+name = "dct"
+harness = false
+
+[lints]
+workspace = true
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/LICENSE b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/LICENSE
new file mode 100644
index 0000000..c66034b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) the JPEG XL Project Authors.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/README.md b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/README.md
new file mode 100644
index 0000000..b6bf14a
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/README.md
@@ -0,0 +1,9 @@
+# JPEG XL in Rust
+
+This is a work-in-progress reimplementation of a JPEG XL decoder in Rust, aiming to be conforming, safe, and fast.
+
+We strive to decode all conformant JPEG XL bitstreams correctly. If you find an image that can be decoded with the reference 
+implementation `djxl` (from [`libjxl`](https://github.com/libjxl/libjxl)) but is decoded incorrectly or not at all by `jxl-rs`, 
+please report it by [opening an issue](https://github.com/libjxl/jxl-rs/issues/new).
+
+For more information, including contributing instructions, refer to the [libjxl repository](https://github.com/libjxl/libjxl).
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/benches/dct.rs b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/benches/dct.rs
new file mode 100644
index 0000000..f8f1c0e89
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/benches/dct.rs
@@ -0,0 +1,120 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(clippy::identity_op)]
+
+use criterion::measurement::Measurement;
+use criterion::{criterion_group, criterion_main, BenchmarkGroup, BenchmarkId, Criterion};
+use jxl_simd::{bench_all_instruction_sets, SimdDescriptor};
+use jxl_transforms::transform_map::MAX_COEFF_AREA;
+use jxl_transforms::*;
+
+fn bench_idct2d<D: SimdDescriptor>(d: D, c: &mut BenchmarkGroup<'_, impl Measurement>, name: &str) {
+    let mut data = vec![1.0; MAX_COEFF_AREA];
+
+    macro_rules! run {
+        ($fun: ident, $name: literal, $sz: expr) => {
+            let id = BenchmarkId::new(name, format_args!("{}", $name));
+            c.bench_function(id, |b| {
+                b.iter(|| {
+                    d.call(
+                        #[inline(always)]
+                        |d| $fun(d, &mut data[..$sz]),
+                    );
+                })
+            });
+        };
+    }
+
+    run!(idct2d_2_2, "2x2", 2 * 2);
+    run!(idct2d_4_4, "4x4", 4 * 4);
+    run!(idct2d_4_8, "4x8", 4 * 8);
+    run!(idct2d_8_4, "8x4", 4 * 8);
+    run!(idct2d_8_8, "8x8", 8 * 8);
+    run!(idct2d_16_8, "16x8", 16 * 8);
+    run!(idct2d_8_16, "8x16", 8 * 16);
+    run!(idct2d_16_16, "16x16", 16 * 16);
+    run!(idct2d_32_8, "32x8", 32 * 8);
+    run!(idct2d_8_32, "8x32", 8 * 32);
+    run!(idct2d_32_16, "32x16", 32 * 16);
+    run!(idct2d_16_32, "16x32", 16 * 32);
+    run!(idct2d_32_32, "32x32", 32 * 32);
+    run!(idct2d_64_32, "64x32", 64 * 32);
+    run!(idct2d_32_64, "32x64", 32 * 64);
+    run!(idct2d_64_64, "64x64", 64 * 64);
+    run!(idct2d_128_64, "128x64", 128 * 64);
+    run!(idct2d_64_128, "64x128", 64 * 128);
+    run!(idct2d_128_128, "128x128", 128 * 128);
+    run!(idct2d_256_128, "256x128", 256 * 128);
+    run!(idct2d_128_256, "128x256", 128 * 256);
+    run!(idct2d_256_256, "256x256", 256 * 256);
+}
+
+fn bench_reinterpreting_dct<D: SimdDescriptor>(
+    d: D,
+    c: &mut BenchmarkGroup<'_, impl Measurement>,
+    name: &str,
+) {
+    let mut data = vec![1.0; MAX_COEFF_AREA];
+    let mut output = vec![0.0; MAX_COEFF_AREA];
+
+    macro_rules! run {
+        ($fun: ident, $name: literal, $sz: expr) => {
+            let id = BenchmarkId::new(name, format_args!("{}", $name));
+
+            c.bench_function(id, |b| {
+                b.iter(|| {
+                    d.call(
+                        #[inline(always)]
+                        |d| $fun(d, &mut data[..$sz], &mut output),
+                    )
+                })
+            });
+        };
+    }
+
+    run!(reinterpreting_dct2d_1_2, "1x2", 1 * 2);
+    run!(reinterpreting_dct2d_2_1, "2x1", 2 * 1);
+    run!(reinterpreting_dct2d_2_2, "2x2", 2 * 2);
+    run!(reinterpreting_dct2d_1_4, "1x4", 1 * 4);
+    run!(reinterpreting_dct2d_4_1, "4x1", 4 * 1);
+    run!(reinterpreting_dct2d_2_4, "2x4", 2 * 4);
+    run!(reinterpreting_dct2d_4_2, "4x2", 4 * 2);
+    run!(reinterpreting_dct2d_4_4, "4x4", 4 * 4);
+    run!(reinterpreting_dct2d_8_4, "8x4", 8 * 4);
+    run!(reinterpreting_dct2d_4_8, "4x8", 4 * 8);
+    run!(reinterpreting_dct2d_8_8, "8x8", 8 * 8);
+    run!(reinterpreting_dct2d_8_16, "8x16", 8 * 16);
+    run!(reinterpreting_dct2d_16_8, "16x8", 16 * 8);
+    run!(reinterpreting_dct2d_16_16, "16x16", 16 * 16);
+    run!(reinterpreting_dct2d_32_16, "32x16", 32 * 16);
+    run!(reinterpreting_dct2d_16_32, "16x32", 16 * 32);
+    run!(reinterpreting_dct2d_32_32, "32x32", 32 * 32);
+}
+
+fn idct_benches(c: &mut Criterion) {
+    let mut group = c.benchmark_group("idct2d");
+    let g = &mut group;
+
+    bench_all_instruction_sets!(bench_idct2d, g);
+
+    group.finish();
+}
+
+fn reinterpreting_dct_benches(c: &mut Criterion) {
+    let mut group = c.benchmark_group("reinterpreting_dct");
+    let g = &mut group;
+
+    bench_all_instruction_sets!(bench_reinterpreting_dct, g);
+
+    group.finish();
+}
+
+criterion_group!(
+    name = benches;
+    config = Criterion::default().sample_size(50);
+    targets = idct_benches, reinterpreting_dct_benches
+);
+criterion_main!(benches);
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/gen_idct.py b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/gen_idct.py
new file mode 100644
index 0000000..b3286f0
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/gen_idct.py
@@ -0,0 +1,286 @@
+#!/usr/bin/env python3
+# Copyright (c) the JPEG XL Project Authors. All rights reserved.
+#
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+import sys
+import math
+
+n = int(sys.argv[1])
+
+assert n > 1
+assert n <= 256
+assert n & (n - 1) == 0
+
+print(
+    """\
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+"""
+)
+
+print("#![allow(unused)]")
+print("#![allow(clippy::type_complexity)]")
+print("#![allow(clippy::erasing_op)]")
+print("#![allow(clippy::identity_op)]")
+
+print("use jxl_simd::{F32SimdVec, SimdDescriptor};")
+print("use crate::*;")
+
+print()
+
+variables = list(range(n))
+
+next_var = n
+
+
+def next():
+    global next_var
+    next_var += 1
+    return next_var - 1
+
+
+def wc_multiplier(i, N):
+    return 1.0 / (2 * math.cos((i + 0.5) * math.pi / N))
+
+
+def forward_even_odd(variables):
+    n = len(variables)
+    ret = [0] * len(variables)
+    for i in range(n // 2):
+        ret[i] = variables[2 * i]
+    for i in range(n // 2, n):
+        ret[i] = variables[2 * (i - n // 2) + 1]
+    return ret
+
+
+def b_transpose(variables):
+    n = len(variables)
+    ret = [0] * len(variables)
+    for i in range(1, n):
+        ret[i] = next()
+        print("let mut v%d = v%d + v%d;" % (ret[i], variables[i - 1], variables[i]))
+    ret[0] = next()
+    print(
+        "let mut v%d = v%d * D::F32Vec::splat(d, std::f32::consts::SQRT_2);"
+        % (ret[0], variables[0])
+    )
+    return ret
+
+
+def multiply_and_add(variables):
+    n = len(variables)
+    ret = [0] * len(variables)
+    for i in range(n // 2):
+        print("let mul = D::F32Vec::splat(d, %.16f);" % wc_multiplier(i, n))
+        ret[i] = next()
+        print(
+            "let mut v%d = v%d.mul_add(mul, v%d);"
+            % (ret[i], variables[n // 2 + i], variables[i])
+        )
+        ret[n - i - 1] = next()
+        print(
+            "let mut v%d = v%d.neg_mul_add(mul, v%d);"
+            % (ret[n - i - 1], variables[n // 2 + i], variables[i])
+        )
+    return ret
+
+
+def call_idct(variables):
+    n = len(variables)
+    print("(")
+    for i in variables:
+        print("v%d," % i)
+    print(") = idct_%d(d," % n)
+    for i in variables:
+        print("v%d," % i)
+    print(");")
+
+
+def d_call_idct(variables):
+    print("d.call(#[inline(always)] |_| {")
+    call_idct(variables)
+    print("});")
+
+
+def idct(variables):
+    n = len(variables)
+    ret = [0] * len(variables)
+    if n == 2:
+        ret[0] = next()
+        print("let mut v%d = v%d + v%d;" % (ret[0], variables[0], variables[1]))
+        ret[1] = next()
+        print("let mut v%d = v%d - v%d;" % (ret[1], variables[0], variables[1]))
+    else:
+        ret = forward_even_odd(variables)
+        first_half = ret[: n // 2]
+        second_half = ret[n // 2 :]
+        first_half = idct(first_half)
+        second_half = b_transpose(second_half)
+        second_half = idct(second_half)
+        ret = first_half + second_half
+        ret = multiply_and_add(ret)
+
+    return ret
+
+
+print("#[allow(clippy::too_many_arguments)]")
+print("#[allow(clippy::excessive_precision)]")
+print("#[inline(always)]")
+print("pub(super) fn idct_%d<D: SimdDescriptor>(d: D," % n)
+for v in variables:
+    print("mut v%d: D::F32Vec," % v)
+print(") -> (")
+for _ in range(n):
+    print("D::F32Vec,")
+print(") {")
+
+variables = idct(variables)
+
+print("(")
+
+for v in variables:
+    print("v%d," % v)
+
+print(")")
+
+print("}")
+
+
+print()
+print("#[inline(always)]")
+print(
+    "pub(super) fn do_idct_%d<D: SimdDescriptor>(d: D, data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray], stride: usize) {"
+    % n
+)
+
+print("assert!(data.len() > %d * stride);" % (n - 1))
+for i in range(n):
+    print("let mut v%d = D::F32Vec::load_array(d, &data[%d*stride]);" % (i, i))
+
+call_idct(list(range(n)))
+
+for i in range(n):
+    print("v%d.store_array(&mut data[%d*stride]);" % (i, i))
+
+print("}")
+
+# IDCT on one row of KxK blocks, where K is the vector length.
+print()
+print("#[inline(always)]")
+print(
+    "pub(super) fn do_idct_%d_rowblock<D: SimdDescriptor>(d: D, data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray]) {"
+    % n
+)
+
+print("assert!(data.len() >= %d);" % n)
+print("const { assert!(%dusize.is_multiple_of(D::F32Vec::LEN)) };" % n)
+print("let row_stride = %d / D::F32Vec::LEN;" % n)
+
+for i in range(n):
+    print(
+        "let mut v%d = D::F32Vec::load_array(d, &data[row_stride*(%d %% D::F32Vec::LEN) + (%d / D::F32Vec::LEN)]);"
+        % (i, i, i)
+    )
+
+call_idct(list(range(n)))
+
+for i in range(n):
+    print(
+        "v%d.store_array(&mut data[row_stride*(%d %% D::F32Vec::LEN) + (%d / D::F32Vec::LEN)]);"
+        % (i, i, i)
+    )
+
+print("}")
+
+
+# n-IDCT + partial transpose of a n x (n/2) matrix
+if n > 2:
+    print()
+    print("#[inline(always)]")
+    print(
+        "pub(super) fn do_idct_%d_trh<D: SimdDescriptor>(d: D, data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray]) {"
+        % n
+    )
+
+    print("let row_stride = %d / D::F32Vec::LEN;" % (n // 2))
+    print("assert!(data.len() > %d * row_stride);" % (n - 1))
+    print("const { assert!(%dusize.is_multiple_of(D::F32Vec::LEN)) };" % (n // 2))
+
+    indices = forward_even_odd(list(range(n)))
+
+    for i in range(n):
+        print(
+            "let mut v%d = D::F32Vec::load_array(d, &data[row_stride*%d]);"
+            % (i, indices[i])
+        )
+
+    call_idct(list(range(n)))
+
+    for i in range(n):
+        print("v%d.store_array(&mut data[row_stride*%d]);" % (i, i))
+
+    print("}")
+
+# 32-IDCT + partial transpose of a 32x8 matrix
+if n == 32:
+    print()
+    print("#[inline(always)]")
+    print(
+        "pub(super) fn do_idct_32_trq<D: SimdDescriptor>(d: D, data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray]) {"
+    )
+
+    print("let row_stride = 8 / D::F32Vec::LEN;")
+    print("assert!(data.len() > 31 * row_stride);")
+    print("const { assert!(8usize.is_multiple_of(D::F32Vec::LEN)) };")
+
+    indices = [
+        0,
+        4,
+        8,
+        12,
+        16,
+        20,
+        24,
+        28,
+        1,
+        5,
+        9,
+        13,
+        17,
+        21,
+        25,
+        29,
+        2,
+        6,
+        10,
+        14,
+        18,
+        22,
+        26,
+        30,
+        3,
+        7,
+        11,
+        15,
+        19,
+        23,
+        27,
+        31,
+    ]
+
+    for i in range(n):
+        print(
+            "let mut v%d = D::F32Vec::load_array(d, &data[row_stride*%d]);"
+            % (i, indices[i])
+        )
+
+    call_idct(list(range(32)))
+
+    for i in range(n):
+        print("v%d.store_array(&mut data[row_stride*%d]);" % (i, i))
+
+    print("}")
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/gen_idct2d.py b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/gen_idct2d.py
new file mode 100644
index 0000000..068d0b9
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/gen_idct2d.py
@@ -0,0 +1,165 @@
+#!/usr/bin/env python3
+# Copyright (c) the JPEG XL Project Authors. All rights reserved.
+#
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+HEADER = """\
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+"""
+
+SIZES = [
+    (2, 2),
+    (4, 4),
+    (4, 8),
+    (8, 4),
+    (8, 8),
+    (8, 16),
+    (8, 32),
+    (16, 8),
+    (16, 16),
+    (16, 32),
+    (32, 8),
+    (32, 16),
+    (32, 32),
+]
+
+print(HEADER)
+
+print("use jxl_simd::{SimdDescriptor, F32SimdVec};")
+print("use crate::*;")
+
+
+def maybe_wrap(n, call):
+    print("%s;" % call)
+
+
+def impl_r_less_c(ROWS, COLS):
+    print("let data = D::F32Vec::make_array_slice_mut(data);")
+    print("let column_chunks = %d / D::F32Vec::LEN;" % COLS)
+    print("let row_chunks = %d / D::F32Vec::LEN;" % ROWS)
+    # Step 1: do rowblock-DCTs on the first K rows, transposing KxK blocks first.
+    print("for i in 0..row_chunks {")
+    print("for j in 0..column_chunks {")
+    print(
+        "D::F32Vec::transpose_square(d, &mut data[i * %d + j..], column_chunks);" % COLS
+    )
+    print("}")
+    maybe_wrap(COLS, "do_idct_%d_rowblock(d, &mut data[i * %d..])" % (COLS, COLS))
+    print("}")
+    # Step 2: do column-DCTs on groups of K columns, transposing KxK blocks back.
+    print("for i in 0..column_chunks {")
+    print("for j in 0..row_chunks {")
+    print(
+        "D::F32Vec::transpose_square(d, &mut data[j * %d + i..], column_chunks);" % COLS
+    )
+    print("}")
+    maybe_wrap(ROWS, "do_idct_%d(d, &mut data[i..], column_chunks)" % ROWS)
+    print("}")
+
+
+def impl_square(N):
+    print("let data = D::F32Vec::make_array_slice_mut(data);")
+    print("let chunks = %d / D::F32Vec::LEN;" % N)
+    # Step 1: do column-DCTs on the first K columns.
+    print("for i in 0..chunks {")
+    maybe_wrap(N, "do_idct_%d(d, &mut data[i..], chunks)" % N)
+    print("}")
+    # Step 2: do column-DCTs on groups of K columns, transposing KxK blocks and
+    # swapping them in their final place as we do so.
+    print("for i in 0..chunks {")
+    print("D::F32Vec::transpose_square(d, &mut data[i * %d + i..], chunks);" % N)
+    print("for j in i+1..chunks {")
+    print("D::F32Vec::transpose_square(d, &mut data[j * %d + i..], chunks);" % N)
+    print("D::F32Vec::transpose_square(d, &mut data[i * %d + j..], chunks);" % N)
+    print("for k in 0..D::F32Vec::LEN {")
+    print("data.swap(i * %d + j + k * chunks, j * %d + i + k * chunks);" % (N, N))
+    print("}")
+    print("}")
+    maybe_wrap(N, "do_idct_%d(d, &mut data[i..], chunks)" % N)
+    print("}")
+
+
+def impl_r_greater_c(ROWS, COLS):
+    ratio = ROWS / COLS
+    print("let data = D::F32Vec::make_array_slice_mut(data);")
+    print("let column_chunks = %d / D::F32Vec::LEN;" % COLS)
+    print("let row_chunks = %d / D::F32Vec::LEN;" % ROWS)
+    # Note: input is transposed, so in the beginning it has ROWS *columns* and COLS *rows*.
+    # Step 1: do column-DCTs on columns.
+    print("for i in 0..row_chunks {")
+    maybe_wrap(COLS, "do_idct_%d(d, &mut data[i..], row_chunks)" % COLS)
+    print("}")
+    # Step 2: Incrementally transpose each square sub-block of the matrix, then do a column-IDCT which also completes the transpose.
+    print("for i in 0..column_chunks {")
+    print(
+        "let tr_block = |data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray], i, j, l| {"
+    )
+    print(
+        "D::F32Vec::transpose_square(d, &mut data[i * %d + j + l * column_chunks..], row_chunks)};"
+        % ROWS
+    )
+    print("(0..%d).for_each(|l| tr_block(data, i, i, l));" % ratio)
+    print("for j in i+1..column_chunks {")
+    print("(0..%d).for_each(|l| tr_block(data, i, j, l));" % ratio)
+    print("(0..%d).for_each(|l| tr_block(data, j, i, l));" % ratio)
+    print("for l in 0..%d {" % ratio)
+    print("for k in 0..D::F32Vec::LEN {")
+    print(
+        "data.swap(i * %d + j + k * row_chunks + l * column_chunks, j * %d + i + k * row_chunks + l * column_chunks);"
+        % (ROWS, ROWS)
+    )
+    print("}")
+    print("}")
+    print("}")
+    if ratio == 2:
+        maybe_wrap(ROWS, "do_idct_%d_trh(d, &mut data[i..])" % ROWS)
+    else:
+        maybe_wrap(ROWS, "do_idct_%d_trq(d, &mut data[i..])" % ROWS)
+    print("}")
+
+
+for ROWS, COLS in SIZES:
+    print()
+    SZ = ROWS * COLS
+    print("#[inline(always)]")
+    print(
+        "fn idct2d_%d_%d_impl<D: SimdDescriptor>(d: D, data: &mut[f32]) {"
+        % (ROWS, COLS)
+    )
+    print('assert_eq!(data.len(), %d, "Data length mismatch");' % SZ)
+    print("const { assert!(%dusize.is_multiple_of(D::F32Vec::LEN)) };" % ROWS)
+    print("const { assert!(%dusize.is_multiple_of(D::F32Vec::LEN)) };" % COLS)
+    if ROWS < COLS:
+        impl_r_less_c(ROWS, COLS)
+    elif ROWS == COLS:
+        impl_square(ROWS)
+    else:
+        impl_r_greater_c(ROWS, COLS)
+    print("}")
+
+# Wrappers to reduce SIMD size.
+for ROWS, COLS in SIZES:
+    print()
+    print("#[inline(always)]")
+    print("#[allow(unused_variables)]")
+    print(
+        "pub fn idct2d_%d_%d<D: SimdDescriptor>(d: D, data: &mut[f32]) {" % (ROWS, COLS)
+    )
+    if ROWS < 4 or COLS < 4:
+        descriptor = "jxl_simd::ScalarDescriptor"
+        print("let d = %s::new().unwrap();" % descriptor)
+    elif ROWS < 8 or COLS < 8:
+        descriptor = "D::Descriptor128"
+        print("let d = d.maybe_downgrade_128bit();")
+    elif ROWS < 16 or COLS < 16:
+        descriptor = "D::Descriptor256"
+        print("let d = d.maybe_downgrade_256bit();")
+    else:
+        descriptor = "D"
+
+    print("idct2d_%d_%d_impl(d, data)" % (ROWS, COLS))
+    print("}")
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/gen_reinterpreting_dct.py b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/gen_reinterpreting_dct.py
new file mode 100644
index 0000000..1636e87
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/gen_reinterpreting_dct.py
@@ -0,0 +1,227 @@
+#!/usr/bin/env python3
+# Copyright (c) the JPEG XL Project Authors. All rights reserved.
+#
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+import sys
+import math
+
+n = int(sys.argv[1])
+
+assert n > 1
+assert n <= 32
+assert n & (n - 1) == 0
+
+print(
+    """\
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+"""
+)
+
+print("#![allow(clippy::type_complexity)]")
+print("#![allow(clippy::erasing_op)]")
+print("#![allow(clippy::identity_op)]")
+
+print("use jxl_simd::{F32SimdVec, SimdDescriptor};")
+
+print()
+
+variables = list(range(n))
+
+next_var = n
+
+
+def next():
+    global next_var
+    next_var += 1
+    return next_var - 1
+
+
+def wc_multiplier(i, N):
+    return 1.0 / (2 * math.cos((i + 0.5) * math.pi / N))
+
+
+def resampling_scale(i, N):
+    return (
+        math.cos(i / (16 * N) * math.pi)
+        * math.cos(i / (8 * N) * math.pi)
+        * math.cos(i / (4 * N) * math.pi)
+        * N
+    )
+
+
+def inverse_even_odd(variables):
+    n = len(variables)
+    ret = [0] * len(variables)
+    for i in range(n // 2):
+        ret[2 * i] = variables[i]
+    for i in range(n // 2):
+        ret[2 * i + 1] = variables[n // 2 + i]
+    return ret
+
+
+def addsub_reverse(variables, op):
+    n = len(variables)
+    ret = [0] * (n // 2)
+    for i in range(n // 2):
+        ret[i] = next()
+        print(
+            "let v%d = v%d %s v%d;" % (ret[i], variables[i], op, variables[n - i - 1])
+        )
+    return ret
+
+
+def b(variables):
+    n = len(variables)
+    ret = [0] * len(variables)
+    ret[0] = next()
+    print(
+        "let v%d = v%d.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v%d);"
+        % (ret[0], variables[0], variables[1])
+    )
+    for i in range(1, n - 1):
+        ret[i] = next()
+        print("let v%d = v%d + v%d;" % (ret[i], variables[i], variables[i + 1]))
+    ret[n - 1] = variables[n - 1]
+    return ret
+
+
+def multiply(variables):
+    n = len(variables)
+    ret = [x for x in variables]
+    for i in range(n):
+        print("let mul = D::F32Vec::splat(d, %.16f);" % wc_multiplier(i, 2 * n))
+        ret[i] = next()
+        print("let v%d = v%d * mul;" % (ret[i], variables[i]))
+    return ret
+
+
+def call_reinterpreting_dct(variables):
+    n = len(variables)
+    print("(")
+    for i in variables:
+        print("v%d," % i)
+    print(") = reinterpreting_dct_%d(d," % n)
+    for i in variables:
+        print("v%d," % i)
+    print(");")
+
+
+def dct(variables):
+    n = len(variables)
+    ret = [0] * len(variables)
+    if n == 2:
+        ret[0] = next()
+        print("let v%d = v%d + v%d;" % (ret[0], variables[0], variables[1]))
+        ret[1] = next()
+        print("let v%d = v%d - v%d;" % (ret[1], variables[0], variables[1]))
+    else:
+        first_half = addsub_reverse(variables, "+")
+        first_half = dct(first_half)
+        second_half = addsub_reverse(variables, "-")
+        second_half = multiply(second_half)
+        second_half = dct(second_half)
+        second_half = b(second_half)
+        ret = first_half + second_half
+        ret = inverse_even_odd(ret)
+
+    return ret
+
+
+print("#[allow(clippy::too_many_arguments)]")
+print("#[allow(clippy::excessive_precision)]")
+print("#[inline(always)]")
+print("pub(super) fn reinterpreting_dct_%d<D: SimdDescriptor>(d: D," % n)
+for v in variables:
+    print("v%d: D::F32Vec," % v)
+print(") -> (")
+for _ in range(n):
+    print("D::F32Vec,")
+print(") {")
+
+variables = dct(variables)
+
+print("(")
+
+for i, v in enumerate(variables):
+    print("v%d * D::F32Vec::splat(d, %f)," % (v, 1.0 / resampling_scale(i, n)))
+
+print(")")
+
+print("}")
+
+
+print()
+print("#[inline(always)]")
+print(
+    "pub(super) fn do_reinterpreting_dct_%d<D: SimdDescriptor>(d: D, data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray], stride: usize) {"
+    % n
+)
+
+print("assert!(data.len() > %d * stride);" % (n - 1))
+for i in range(n):
+    print("let mut v%d = D::F32Vec::load_array(d, &data[%d*stride]);" % (i, i))
+
+call_reinterpreting_dct(list(range(n)))
+
+for i in range(n):
+    print("v%d.store_array(&mut data[%d*stride]);" % (i, i))
+
+print("}")
+
+if n > 2:
+    # DCT on one row of KxK blocks, where K is the vector length.
+    print()
+    print("#[inline(always)]")
+    print(
+        "pub(super) fn do_reinterpreting_dct_%d_rowblock<D: SimdDescriptor>(d: D, data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray]) {"
+        % n
+    )
+
+    print("assert!(data.len() >= %d);" % n)
+    print("const { assert!(%dusize.is_multiple_of(D::F32Vec::LEN)) };" % n)
+    print("let row_stride = %d / D::F32Vec::LEN;" % n)
+
+    for i in range(n):
+        print(
+            "let mut v%d = D::F32Vec::load_array(d, &data[row_stride*(%d %% D::F32Vec::LEN) + (%d / D::F32Vec::LEN)]);"
+            % (i, i, i)
+        )
+
+    call_reinterpreting_dct(list(range(n)))
+
+    for i in range(n):
+        print(
+            "v%d.store_array(&mut data[row_stride*(%d %% D::F32Vec::LEN) + (%d / D::F32Vec::LEN)]);"
+            % (i, i, i)
+        )
+
+    print("}")
+
+    # n-DCT + partial transpose of a n x (n/2) matrix
+    print()
+    print("#[inline(always)]")
+    print(
+        "pub(super) fn do_reinterpreting_dct_%d_trh<D: SimdDescriptor>(d: D, data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray]) {"
+        % n
+    )
+
+    print("let row_stride = %d / D::F32Vec::LEN;" % (n // 2))
+    print("assert!(data.len() > %d * row_stride);" % (n - 1))
+    print("const { assert!(%dusize.is_multiple_of(D::F32Vec::LEN)) };" % (n // 2))
+
+    for i in range(n):
+        print("let mut v%d = D::F32Vec::load_array(d, &data[row_stride*%d]);" % (i, i))
+
+    call_reinterpreting_dct(list(range(n)))
+
+    indices = inverse_even_odd(list(range(n)))
+
+    for i in range(n):
+        print("v%d.store_array(&mut data[row_stride*%d]);" % (indices[i], i))
+
+    print("}")
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/gen_reinterpreting_dct2d.py b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/gen_reinterpreting_dct2d.py
new file mode 100644
index 0000000..d3eefed
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/gen_reinterpreting_dct2d.py
@@ -0,0 +1,180 @@
+#!/usr/bin/env python3
+# Copyright (c) the JPEG XL Project Authors. All rights reserved.
+#
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+HEADER = """\
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+"""
+
+SIZES = [
+    (1, 2),
+    (2, 1),
+    (1, 4),
+    (4, 1),
+    (2, 2),
+    (2, 4),
+    (4, 2),
+    (4, 4),
+    (4, 8),
+    (8, 4),
+    (8, 8),
+    (8, 16),
+    (16, 8),
+    (16, 16),
+    (16, 32),
+    (32, 16),
+    (32, 32),
+]
+
+print(HEADER)
+
+print("use jxl_simd::{SimdDescriptor, F32SimdVec};")
+print("use crate::*;")
+
+
+def impl_r_less_c(ROWS, COLS):
+    print("let data = D::F32Vec::make_array_slice_mut(data);")
+    print("let column_chunks = %d / D::F32Vec::LEN;" % COLS)
+    print("let row_chunks = %d / D::F32Vec::LEN;" % ROWS)
+    # Step 1: do rowblock-DCTs on the first K rows, transposing KxK blocks first.
+    print("for i in 0..row_chunks {")
+    print("for j in 0..column_chunks {")
+    print(
+        "D::F32Vec::transpose_square(d, &mut data[i * %d + j..], column_chunks);" % COLS
+    )
+    print("}")
+    print("do_reinterpreting_dct_%d_rowblock(d, &mut data[i * %d..]);" % (COLS, COLS))
+    print("}")
+    # Step 2: do column-DCTs on groups of K columns, transposing KxK blocks back.
+    print("for i in 0..column_chunks {")
+    print("for j in 0..row_chunks {")
+    print(
+        "D::F32Vec::transpose_square(d, &mut data[j * %d + i..], column_chunks);" % COLS
+    )
+    print("}")
+    print("do_reinterpreting_dct_%d(d, &mut data[i..], column_chunks)" % ROWS)
+    print("}")
+
+
+def impl_square(N):
+    print("let data = D::F32Vec::make_array_slice_mut(data);")
+    print("let chunks = %d / D::F32Vec::LEN;" % N)
+    # Step 1: do column-DCTs on the first K columns.
+    print("for i in 0..chunks {")
+    print("do_reinterpreting_dct_%d(d, &mut data[i..], chunks);" % N)
+    print("}")
+    # Step 2: do column-DCTs on groups of K columns, transposing KxK blocks and
+    # swapping them in their final place as we do so.
+    print("for i in 0..chunks {")
+    print("D::F32Vec::transpose_square(d, &mut data[i * %d + i..], chunks);" % N)
+    print("for j in i+1..chunks {")
+    print("D::F32Vec::transpose_square(d, &mut data[j * %d + i..], chunks);" % N)
+    print("D::F32Vec::transpose_square(d, &mut data[i * %d + j..], chunks);" % N)
+    print("for k in 0..D::F32Vec::LEN {")
+    print("data.swap(i * %d + j + k * chunks, j * %d + i + k * chunks);" % (N, N))
+    print("}")
+    print("}")
+    print("do_reinterpreting_dct_%d(d, &mut data[i..], chunks);" % N)
+    print("}")
+
+
+def impl_r_greater_c(ROWS, COLS):
+    ratio = ROWS / COLS
+    print("let data = D::F32Vec::make_array_slice_mut(data);")
+    print("let column_chunks = %d / D::F32Vec::LEN;" % COLS)
+    print("let row_chunks = %d / D::F32Vec::LEN;" % ROWS)
+    # Step 1: do column-DCTs on columns, which does the first part of the full matrix transpose.
+    print("for i in 0..column_chunks {")
+    print("do_reinterpreting_dct_%d_trh(d, &mut data[i..]);" % ROWS)
+    print("}")
+    # Step 2: Incrementally transpose each square sub-block of the matrix, then do a column-IDCT.
+    print("for l in 0..%d {" % ratio)
+    print("for i in 0..column_chunks {")
+    print(
+        "let tr_block = |data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray], i, j, l| {"
+    )
+    print(
+        "D::F32Vec::transpose_square(d, &mut data[i * %d + j + l * column_chunks..], row_chunks)};"
+        % ROWS
+    )
+    print("tr_block(data, i, i, l);")
+    print("for j in i+1..column_chunks {")
+    print("tr_block(data, i, j, l);")
+    print("tr_block(data, j, i, l);")
+    print("for k in 0..D::F32Vec::LEN {")
+    print(
+        "data.swap(i * %d + j + k * row_chunks + l * column_chunks, j * %d + i + k * row_chunks + l * column_chunks);"
+        % (ROWS, ROWS)
+    )
+    print("}")
+    print("}")
+    print(
+        "do_reinterpreting_dct_%d(d, &mut data[i + l * column_chunks..], row_chunks);"
+        % COLS
+    )
+    print("}")
+    print("}")
+
+
+for ROWS, COLS in SIZES:
+    print()
+    SZ = ROWS * COLS
+    L = min(ROWS, COLS)
+    S = max(ROWS, COLS)
+    print("#[inline(always)]")
+    print(
+        "fn reinterpreting_dct2d_%d_%d_impl<D: SimdDescriptor>(d: D, data: &mut[f32], output: &mut[f32]) {"
+        % (ROWS, COLS)
+    )
+    print('assert_eq!(data.len(), %d, "Data length mismatch");' % SZ)
+    print("assert!(output.len() > %d);" % ((L - 1) * S * 8 + S - 1))
+
+    print("const { assert!(%dusize.is_multiple_of(D::F32Vec::LEN)) };" % ROWS)
+    print("const { assert!(%dusize.is_multiple_of(D::F32Vec::LEN)) };" % COLS)
+    print("{")
+    if ROWS == 1 or COLS == 1:
+        print("let data = D::F32Vec::make_array_slice_mut(data);")
+        print("do_reinterpreting_dct_%d(d, data, 1);" % S)
+    elif ROWS < COLS:
+        impl_r_less_c(ROWS, COLS)
+    elif ROWS == COLS:
+        impl_square(ROWS)
+    else:
+        impl_r_greater_c(ROWS, COLS)
+    print("}")
+
+    print("for y in 0..%d {" % L)
+    print("for x in 0..%d {" % S)
+    print("output[y * %d + x] = data[y * %d + x];" % (S * 8, S))
+    print("}")
+    print("}")
+    print("}")
+
+# Wrappers to reduce SIMD size.
+for ROWS, COLS in SIZES:
+    print()
+    print("#[inline(always)]")
+    print("#[allow(unused_variables)]")
+    print(
+        "pub fn reinterpreting_dct2d_%d_%d<D: SimdDescriptor>(d: D, data: &mut[f32], output: &mut[f32]) {"
+        % (ROWS, COLS)
+    )
+    if ROWS < 4 or COLS < 4:
+        descriptor = "jxl_simd::ScalarDescriptor"
+        print("let d = %s::new().unwrap();" % descriptor)
+    elif ROWS < 8 or COLS < 8:
+        descriptor = "D::Descriptor128"
+        print("let d = d.maybe_downgrade_128bit();")
+    elif ROWS < 16 or COLS < 16:
+        descriptor = "D::Descriptor256"
+        print("let d = d.maybe_downgrade_256bit();")
+    else:
+        descriptor = "D"
+
+    print("reinterpreting_dct2d_%d_%d_impl(d, data, output)" % (ROWS, COLS))
+    print("}")
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/implementation_details.md b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/implementation_details.md
new file mode 100644
index 0000000..ac02a77
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/implementation_details.md
@@ -0,0 +1,71 @@
+# Implementation details of 2d-IDCT and reinterpreting-DCT
+
+First of all, note that we only need to generate Nx2N, NxN, 2NxN transforms for
+most sizes. The one exception are 8x32/32x8 IDCTs and 1x4/4x1
+reinterpreting-DCTs.
+
+The 4x1/1x4 reinterpreting-DCTs are very small and don't need special
+considerations.
+
+Large transforms use the same implementation strategy, but avoid increasing code
+size by using size-generic code.
+
+## Code generation
+Code is generated with python scripts. The following bash snippet
+generates the relevant files:
+
+```bash
+for i in 2 4 8 16 32
+do
+    python3 gen_idct.py $i > src/idct$i.rs
+done 
+for i in 2 4 8 16 32
+do
+    python3 gen_reinterpreting_dct.py $i > src/reinterpreting_dct$i.rs
+done 
+python3 gen_idct2d.py > src/idct2d.rs
+python3 gen_reinterpreting_dct2d.py > src/reinterpreting_dct2d.rs
+cargo fmt
+```
+
+## SIMD type selection
+
+The compiler generates suboptimal code when mixing different vector sizes. 
+
+Thus, as a first step we "downgrade" to the largest vector size that divides
+both sizes of the transform.
+
+## DCT/IDCT Implementation
+Both the DCT and the IDCT use the same recursive algorithm used in libjxl to
+compute a vector worth of DCTs/IDCTs.
+
+## 2d transforms
+The code is written to minimize transposition cost while still ensuring we load
+full vectors at a time. We don't use any additional memory to store transposes.
+
+Let K be vector length (which divides both sides of the DCT as per above).
+
+### N x 2N transforms and 8x32 IDCT
+For those transforms, the final output should be the same shape as the input.
+Thus, we logically need to transpose, DCT, transpose and DCT. However, we can
+instead first do a set of row-DCTs on K rows, transposing every KxK
+sub-matrix in place in advance, then do a column-DCT on the first K columns,
+and finally transpose the KxK sub-matrices in the columns again.
+
+### N x N transforms
+Square transforms are easy: we can do column-DCTs, then swap KxK blocks between
+lower and upper triangular part of the block-matrix, going K columns by K columns
+and transposing during the swap, and do a column-DCT after each group of columns
+is complete.
+
+### 2N x N IDCTs and 32x8 IDCT
+For these transforms, we have a special implementation of 1D-IDCT that does part
+of the transpose.
+In particular, we transpose NxN blocks as in the square case. We are then left
+with doing the row-DCT and interleaving blocks so that they go from stacked
+horizontally to stacked vertically. Since that can be done by just reshuffling
+individual columns of vectors, we merge that operation with the DCT.
+
+### 2N x N DCTs
+This is basically the same as the IDCTs, but in reverse order. Thus, the
+"special" DCT applies a different permutation.
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct16.rs b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct16.rs
new file mode 100644
index 0000000..90e51d9
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct16.rs
@@ -0,0 +1,355 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(unused)]
+#![allow(clippy::type_complexity)]
+#![allow(clippy::erasing_op)]
+#![allow(clippy::identity_op)]
+use crate::*;
+use jxl_simd::{F32SimdVec, SimdDescriptor};
+
+#[allow(clippy::too_many_arguments)]
+#[allow(clippy::excessive_precision)]
+#[inline(always)]
+pub(super) fn idct_16<D: SimdDescriptor>(
+    d: D,
+    mut v0: D::F32Vec,
+    mut v1: D::F32Vec,
+    mut v2: D::F32Vec,
+    mut v3: D::F32Vec,
+    mut v4: D::F32Vec,
+    mut v5: D::F32Vec,
+    mut v6: D::F32Vec,
+    mut v7: D::F32Vec,
+    mut v8: D::F32Vec,
+    mut v9: D::F32Vec,
+    mut v10: D::F32Vec,
+    mut v11: D::F32Vec,
+    mut v12: D::F32Vec,
+    mut v13: D::F32Vec,
+    mut v14: D::F32Vec,
+    mut v15: D::F32Vec,
+) -> (
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+) {
+    let mut v16 = v0 + v8;
+    let mut v17 = v0 - v8;
+    let mut v18 = v4 + v12;
+    let mut v19 = v4 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v20 = v19 + v18;
+    let mut v21 = v19 - v18;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let mut v22 = v20.mul_add(mul, v16);
+    let mut v23 = v20.neg_mul_add(mul, v16);
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let mut v24 = v21.mul_add(mul, v17);
+    let mut v25 = v21.neg_mul_add(mul, v17);
+    let mut v26 = v2 + v6;
+    let mut v27 = v6 + v10;
+    let mut v28 = v10 + v14;
+    let mut v29 = v2 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v30 = v29 + v27;
+    let mut v31 = v29 - v27;
+    let mut v32 = v26 + v28;
+    let mut v33 = v26 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v34 = v33 + v32;
+    let mut v35 = v33 - v32;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let mut v36 = v34.mul_add(mul, v30);
+    let mut v37 = v34.neg_mul_add(mul, v30);
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let mut v38 = v35.mul_add(mul, v31);
+    let mut v39 = v35.neg_mul_add(mul, v31);
+    let mul = D::F32Vec::splat(d, 0.5097955791041592);
+    let mut v40 = v36.mul_add(mul, v22);
+    let mut v41 = v36.neg_mul_add(mul, v22);
+    let mul = D::F32Vec::splat(d, 0.6013448869350453);
+    let mut v42 = v38.mul_add(mul, v24);
+    let mut v43 = v38.neg_mul_add(mul, v24);
+    let mul = D::F32Vec::splat(d, 0.8999762231364156);
+    let mut v44 = v39.mul_add(mul, v25);
+    let mut v45 = v39.neg_mul_add(mul, v25);
+    let mul = D::F32Vec::splat(d, 2.5629154477415055);
+    let mut v46 = v37.mul_add(mul, v23);
+    let mut v47 = v37.neg_mul_add(mul, v23);
+    let mut v48 = v1 + v3;
+    let mut v49 = v3 + v5;
+    let mut v50 = v5 + v7;
+    let mut v51 = v7 + v9;
+    let mut v52 = v9 + v11;
+    let mut v53 = v11 + v13;
+    let mut v54 = v13 + v15;
+    let mut v55 = v1 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v56 = v55 + v51;
+    let mut v57 = v55 - v51;
+    let mut v58 = v49 + v53;
+    let mut v59 = v49 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v60 = v59 + v58;
+    let mut v61 = v59 - v58;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let mut v62 = v60.mul_add(mul, v56);
+    let mut v63 = v60.neg_mul_add(mul, v56);
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let mut v64 = v61.mul_add(mul, v57);
+    let mut v65 = v61.neg_mul_add(mul, v57);
+    let mut v66 = v48 + v50;
+    let mut v67 = v50 + v52;
+    let mut v68 = v52 + v54;
+    let mut v69 = v48 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v70 = v69 + v67;
+    let mut v71 = v69 - v67;
+    let mut v72 = v66 + v68;
+    let mut v73 = v66 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v74 = v73 + v72;
+    let mut v75 = v73 - v72;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let mut v76 = v74.mul_add(mul, v70);
+    let mut v77 = v74.neg_mul_add(mul, v70);
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let mut v78 = v75.mul_add(mul, v71);
+    let mut v79 = v75.neg_mul_add(mul, v71);
+    let mul = D::F32Vec::splat(d, 0.5097955791041592);
+    let mut v80 = v76.mul_add(mul, v62);
+    let mut v81 = v76.neg_mul_add(mul, v62);
+    let mul = D::F32Vec::splat(d, 0.6013448869350453);
+    let mut v82 = v78.mul_add(mul, v64);
+    let mut v83 = v78.neg_mul_add(mul, v64);
+    let mul = D::F32Vec::splat(d, 0.8999762231364156);
+    let mut v84 = v79.mul_add(mul, v65);
+    let mut v85 = v79.neg_mul_add(mul, v65);
+    let mul = D::F32Vec::splat(d, 2.5629154477415055);
+    let mut v86 = v77.mul_add(mul, v63);
+    let mut v87 = v77.neg_mul_add(mul, v63);
+    let mul = D::F32Vec::splat(d, 0.5024192861881557);
+    let mut v88 = v80.mul_add(mul, v40);
+    let mut v89 = v80.neg_mul_add(mul, v40);
+    let mul = D::F32Vec::splat(d, 0.5224986149396889);
+    let mut v90 = v82.mul_add(mul, v42);
+    let mut v91 = v82.neg_mul_add(mul, v42);
+    let mul = D::F32Vec::splat(d, 0.5669440348163577);
+    let mut v92 = v84.mul_add(mul, v44);
+    let mut v93 = v84.neg_mul_add(mul, v44);
+    let mul = D::F32Vec::splat(d, 0.6468217833599901);
+    let mut v94 = v86.mul_add(mul, v46);
+    let mut v95 = v86.neg_mul_add(mul, v46);
+    let mul = D::F32Vec::splat(d, 0.7881546234512502);
+    let mut v96 = v87.mul_add(mul, v47);
+    let mut v97 = v87.neg_mul_add(mul, v47);
+    let mul = D::F32Vec::splat(d, 1.0606776859903471);
+    let mut v98 = v85.mul_add(mul, v45);
+    let mut v99 = v85.neg_mul_add(mul, v45);
+    let mul = D::F32Vec::splat(d, 1.7224470982383342);
+    let mut v100 = v83.mul_add(mul, v43);
+    let mut v101 = v83.neg_mul_add(mul, v43);
+    let mul = D::F32Vec::splat(d, 5.1011486186891553);
+    let mut v102 = v81.mul_add(mul, v41);
+    let mut v103 = v81.neg_mul_add(mul, v41);
+    (
+        v88, v90, v92, v94, v96, v98, v100, v102, v103, v101, v99, v97, v95, v93, v91, v89,
+    )
+}
+
+#[inline(always)]
+pub(super) fn do_idct_16<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+    stride: usize,
+) {
+    assert!(data.len() > 15 * stride);
+    let mut v0 = D::F32Vec::load_array(d, &data[0 * stride]);
+    let mut v1 = D::F32Vec::load_array(d, &data[1 * stride]);
+    let mut v2 = D::F32Vec::load_array(d, &data[2 * stride]);
+    let mut v3 = D::F32Vec::load_array(d, &data[3 * stride]);
+    let mut v4 = D::F32Vec::load_array(d, &data[4 * stride]);
+    let mut v5 = D::F32Vec::load_array(d, &data[5 * stride]);
+    let mut v6 = D::F32Vec::load_array(d, &data[6 * stride]);
+    let mut v7 = D::F32Vec::load_array(d, &data[7 * stride]);
+    let mut v8 = D::F32Vec::load_array(d, &data[8 * stride]);
+    let mut v9 = D::F32Vec::load_array(d, &data[9 * stride]);
+    let mut v10 = D::F32Vec::load_array(d, &data[10 * stride]);
+    let mut v11 = D::F32Vec::load_array(d, &data[11 * stride]);
+    let mut v12 = D::F32Vec::load_array(d, &data[12 * stride]);
+    let mut v13 = D::F32Vec::load_array(d, &data[13 * stride]);
+    let mut v14 = D::F32Vec::load_array(d, &data[14 * stride]);
+    let mut v15 = D::F32Vec::load_array(d, &data[15 * stride]);
+    (
+        v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+    ) = idct_16(
+        d, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+    );
+    v0.store_array(&mut data[0 * stride]);
+    v1.store_array(&mut data[1 * stride]);
+    v2.store_array(&mut data[2 * stride]);
+    v3.store_array(&mut data[3 * stride]);
+    v4.store_array(&mut data[4 * stride]);
+    v5.store_array(&mut data[5 * stride]);
+    v6.store_array(&mut data[6 * stride]);
+    v7.store_array(&mut data[7 * stride]);
+    v8.store_array(&mut data[8 * stride]);
+    v9.store_array(&mut data[9 * stride]);
+    v10.store_array(&mut data[10 * stride]);
+    v11.store_array(&mut data[11 * stride]);
+    v12.store_array(&mut data[12 * stride]);
+    v13.store_array(&mut data[13 * stride]);
+    v14.store_array(&mut data[14 * stride]);
+    v15.store_array(&mut data[15 * stride]);
+}
+
+#[inline(always)]
+pub(super) fn do_idct_16_rowblock<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+) {
+    assert!(data.len() >= 16);
+    const { assert!(16usize.is_multiple_of(D::F32Vec::LEN)) };
+    let row_stride = 16 / D::F32Vec::LEN;
+    let mut v0 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (0 % D::F32Vec::LEN) + (0 / D::F32Vec::LEN)],
+    );
+    let mut v1 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (1 % D::F32Vec::LEN) + (1 / D::F32Vec::LEN)],
+    );
+    let mut v2 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (2 % D::F32Vec::LEN) + (2 / D::F32Vec::LEN)],
+    );
+    let mut v3 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (3 % D::F32Vec::LEN) + (3 / D::F32Vec::LEN)],
+    );
+    let mut v4 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (4 % D::F32Vec::LEN) + (4 / D::F32Vec::LEN)],
+    );
+    let mut v5 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (5 % D::F32Vec::LEN) + (5 / D::F32Vec::LEN)],
+    );
+    let mut v6 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (6 % D::F32Vec::LEN) + (6 / D::F32Vec::LEN)],
+    );
+    let mut v7 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (7 % D::F32Vec::LEN) + (7 / D::F32Vec::LEN)],
+    );
+    let mut v8 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (8 % D::F32Vec::LEN) + (8 / D::F32Vec::LEN)],
+    );
+    let mut v9 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (9 % D::F32Vec::LEN) + (9 / D::F32Vec::LEN)],
+    );
+    let mut v10 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (10 % D::F32Vec::LEN) + (10 / D::F32Vec::LEN)],
+    );
+    let mut v11 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (11 % D::F32Vec::LEN) + (11 / D::F32Vec::LEN)],
+    );
+    let mut v12 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (12 % D::F32Vec::LEN) + (12 / D::F32Vec::LEN)],
+    );
+    let mut v13 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (13 % D::F32Vec::LEN) + (13 / D::F32Vec::LEN)],
+    );
+    let mut v14 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (14 % D::F32Vec::LEN) + (14 / D::F32Vec::LEN)],
+    );
+    let mut v15 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (15 % D::F32Vec::LEN) + (15 / D::F32Vec::LEN)],
+    );
+    (
+        v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+    ) = idct_16(
+        d, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+    );
+    v0.store_array(&mut data[row_stride * (0 % D::F32Vec::LEN) + (0 / D::F32Vec::LEN)]);
+    v1.store_array(&mut data[row_stride * (1 % D::F32Vec::LEN) + (1 / D::F32Vec::LEN)]);
+    v2.store_array(&mut data[row_stride * (2 % D::F32Vec::LEN) + (2 / D::F32Vec::LEN)]);
+    v3.store_array(&mut data[row_stride * (3 % D::F32Vec::LEN) + (3 / D::F32Vec::LEN)]);
+    v4.store_array(&mut data[row_stride * (4 % D::F32Vec::LEN) + (4 / D::F32Vec::LEN)]);
+    v5.store_array(&mut data[row_stride * (5 % D::F32Vec::LEN) + (5 / D::F32Vec::LEN)]);
+    v6.store_array(&mut data[row_stride * (6 % D::F32Vec::LEN) + (6 / D::F32Vec::LEN)]);
+    v7.store_array(&mut data[row_stride * (7 % D::F32Vec::LEN) + (7 / D::F32Vec::LEN)]);
+    v8.store_array(&mut data[row_stride * (8 % D::F32Vec::LEN) + (8 / D::F32Vec::LEN)]);
+    v9.store_array(&mut data[row_stride * (9 % D::F32Vec::LEN) + (9 / D::F32Vec::LEN)]);
+    v10.store_array(&mut data[row_stride * (10 % D::F32Vec::LEN) + (10 / D::F32Vec::LEN)]);
+    v11.store_array(&mut data[row_stride * (11 % D::F32Vec::LEN) + (11 / D::F32Vec::LEN)]);
+    v12.store_array(&mut data[row_stride * (12 % D::F32Vec::LEN) + (12 / D::F32Vec::LEN)]);
+    v13.store_array(&mut data[row_stride * (13 % D::F32Vec::LEN) + (13 / D::F32Vec::LEN)]);
+    v14.store_array(&mut data[row_stride * (14 % D::F32Vec::LEN) + (14 / D::F32Vec::LEN)]);
+    v15.store_array(&mut data[row_stride * (15 % D::F32Vec::LEN) + (15 / D::F32Vec::LEN)]);
+}
+
+#[inline(always)]
+pub(super) fn do_idct_16_trh<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+) {
+    let row_stride = 8 / D::F32Vec::LEN;
+    assert!(data.len() > 15 * row_stride);
+    const { assert!(8usize.is_multiple_of(D::F32Vec::LEN)) };
+    let mut v0 = D::F32Vec::load_array(d, &data[row_stride * 0]);
+    let mut v1 = D::F32Vec::load_array(d, &data[row_stride * 2]);
+    let mut v2 = D::F32Vec::load_array(d, &data[row_stride * 4]);
+    let mut v3 = D::F32Vec::load_array(d, &data[row_stride * 6]);
+    let mut v4 = D::F32Vec::load_array(d, &data[row_stride * 8]);
+    let mut v5 = D::F32Vec::load_array(d, &data[row_stride * 10]);
+    let mut v6 = D::F32Vec::load_array(d, &data[row_stride * 12]);
+    let mut v7 = D::F32Vec::load_array(d, &data[row_stride * 14]);
+    let mut v8 = D::F32Vec::load_array(d, &data[row_stride * 1]);
+    let mut v9 = D::F32Vec::load_array(d, &data[row_stride * 3]);
+    let mut v10 = D::F32Vec::load_array(d, &data[row_stride * 5]);
+    let mut v11 = D::F32Vec::load_array(d, &data[row_stride * 7]);
+    let mut v12 = D::F32Vec::load_array(d, &data[row_stride * 9]);
+    let mut v13 = D::F32Vec::load_array(d, &data[row_stride * 11]);
+    let mut v14 = D::F32Vec::load_array(d, &data[row_stride * 13]);
+    let mut v15 = D::F32Vec::load_array(d, &data[row_stride * 15]);
+    (
+        v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+    ) = idct_16(
+        d, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+    );
+    v0.store_array(&mut data[row_stride * 0]);
+    v1.store_array(&mut data[row_stride * 1]);
+    v2.store_array(&mut data[row_stride * 2]);
+    v3.store_array(&mut data[row_stride * 3]);
+    v4.store_array(&mut data[row_stride * 4]);
+    v5.store_array(&mut data[row_stride * 5]);
+    v6.store_array(&mut data[row_stride * 6]);
+    v7.store_array(&mut data[row_stride * 7]);
+    v8.store_array(&mut data[row_stride * 8]);
+    v9.store_array(&mut data[row_stride * 9]);
+    v10.store_array(&mut data[row_stride * 10]);
+    v11.store_array(&mut data[row_stride * 11]);
+    v12.store_array(&mut data[row_stride * 12]);
+    v13.store_array(&mut data[row_stride * 13]);
+    v14.store_array(&mut data[row_stride * 14]);
+    v15.store_array(&mut data[row_stride * 15]);
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct2.rs b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct2.rs
new file mode 100644
index 0000000..4605606
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct2.rs
@@ -0,0 +1,59 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(unused)]
+#![allow(clippy::type_complexity)]
+#![allow(clippy::erasing_op)]
+#![allow(clippy::identity_op)]
+use crate::*;
+use jxl_simd::{F32SimdVec, SimdDescriptor};
+
+#[allow(clippy::too_many_arguments)]
+#[allow(clippy::excessive_precision)]
+#[inline(always)]
+pub(super) fn idct_2<D: SimdDescriptor>(
+    d: D,
+    mut v0: D::F32Vec,
+    mut v1: D::F32Vec,
+) -> (D::F32Vec, D::F32Vec) {
+    let mut v2 = v0 + v1;
+    let mut v3 = v0 - v1;
+    (v2, v3)
+}
+
+#[inline(always)]
+pub(super) fn do_idct_2<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+    stride: usize,
+) {
+    assert!(data.len() > 1 * stride);
+    let mut v0 = D::F32Vec::load_array(d, &data[0 * stride]);
+    let mut v1 = D::F32Vec::load_array(d, &data[1 * stride]);
+    (v0, v1) = idct_2(d, v0, v1);
+    v0.store_array(&mut data[0 * stride]);
+    v1.store_array(&mut data[1 * stride]);
+}
+
+#[inline(always)]
+pub(super) fn do_idct_2_rowblock<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+) {
+    assert!(data.len() >= 2);
+    const { assert!(2usize.is_multiple_of(D::F32Vec::LEN)) };
+    let row_stride = 2 / D::F32Vec::LEN;
+    let mut v0 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (0 % D::F32Vec::LEN) + (0 / D::F32Vec::LEN)],
+    );
+    let mut v1 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (1 % D::F32Vec::LEN) + (1 / D::F32Vec::LEN)],
+    );
+    (v0, v1) = idct_2(d, v0, v1);
+    v0.store_array(&mut data[row_stride * (0 % D::F32Vec::LEN) + (0 / D::F32Vec::LEN)]);
+    v1.store_array(&mut data[row_stride * (1 % D::F32Vec::LEN) + (1 / D::F32Vec::LEN)]);
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct2d.rs b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct2d.rs
new file mode 100644
index 0000000..ae744e7
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct2d.rs
@@ -0,0 +1,425 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::*;
+use jxl_simd::{F32SimdVec, SimdDescriptor};
+
+#[inline(always)]
+fn idct2d_2_2_impl<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    assert_eq!(data.len(), 4, "Data length mismatch");
+    const { assert!(2usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(2usize.is_multiple_of(D::F32Vec::LEN)) };
+    let data = D::F32Vec::make_array_slice_mut(data);
+    let chunks = 2 / D::F32Vec::LEN;
+    for i in 0..chunks {
+        do_idct_2(d, &mut data[i..], chunks);
+    }
+    for i in 0..chunks {
+        D::F32Vec::transpose_square(d, &mut data[i * 2 + i..], chunks);
+        for j in i + 1..chunks {
+            D::F32Vec::transpose_square(d, &mut data[j * 2 + i..], chunks);
+            D::F32Vec::transpose_square(d, &mut data[i * 2 + j..], chunks);
+            for k in 0..D::F32Vec::LEN {
+                data.swap(i * 2 + j + k * chunks, j * 2 + i + k * chunks);
+            }
+        }
+        do_idct_2(d, &mut data[i..], chunks);
+    }
+}
+
+#[inline(always)]
+fn idct2d_4_4_impl<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    assert_eq!(data.len(), 16, "Data length mismatch");
+    const { assert!(4usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(4usize.is_multiple_of(D::F32Vec::LEN)) };
+    let data = D::F32Vec::make_array_slice_mut(data);
+    let chunks = 4 / D::F32Vec::LEN;
+    for i in 0..chunks {
+        do_idct_4(d, &mut data[i..], chunks);
+    }
+    for i in 0..chunks {
+        D::F32Vec::transpose_square(d, &mut data[i * 4 + i..], chunks);
+        for j in i + 1..chunks {
+            D::F32Vec::transpose_square(d, &mut data[j * 4 + i..], chunks);
+            D::F32Vec::transpose_square(d, &mut data[i * 4 + j..], chunks);
+            for k in 0..D::F32Vec::LEN {
+                data.swap(i * 4 + j + k * chunks, j * 4 + i + k * chunks);
+            }
+        }
+        do_idct_4(d, &mut data[i..], chunks);
+    }
+}
+
+#[inline(always)]
+fn idct2d_4_8_impl<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    assert_eq!(data.len(), 32, "Data length mismatch");
+    const { assert!(4usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(8usize.is_multiple_of(D::F32Vec::LEN)) };
+    let data = D::F32Vec::make_array_slice_mut(data);
+    let column_chunks = 8 / D::F32Vec::LEN;
+    let row_chunks = 4 / D::F32Vec::LEN;
+    for i in 0..row_chunks {
+        for j in 0..column_chunks {
+            D::F32Vec::transpose_square(d, &mut data[i * 8 + j..], column_chunks);
+        }
+        do_idct_8_rowblock(d, &mut data[i * 8..]);
+    }
+    for i in 0..column_chunks {
+        for j in 0..row_chunks {
+            D::F32Vec::transpose_square(d, &mut data[j * 8 + i..], column_chunks);
+        }
+        do_idct_4(d, &mut data[i..], column_chunks);
+    }
+}
+
+#[inline(always)]
+fn idct2d_8_4_impl<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    assert_eq!(data.len(), 32, "Data length mismatch");
+    const { assert!(8usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(4usize.is_multiple_of(D::F32Vec::LEN)) };
+    let data = D::F32Vec::make_array_slice_mut(data);
+    let column_chunks = 4 / D::F32Vec::LEN;
+    let row_chunks = 8 / D::F32Vec::LEN;
+    for i in 0..row_chunks {
+        do_idct_4(d, &mut data[i..], row_chunks);
+    }
+    for i in 0..column_chunks {
+        let tr_block = |data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray], i, j, l| {
+            D::F32Vec::transpose_square(d, &mut data[i * 8 + j + l * column_chunks..], row_chunks)
+        };
+        (0..2).for_each(|l| tr_block(data, i, i, l));
+        for j in i + 1..column_chunks {
+            (0..2).for_each(|l| tr_block(data, i, j, l));
+            (0..2).for_each(|l| tr_block(data, j, i, l));
+            for l in 0..2 {
+                for k in 0..D::F32Vec::LEN {
+                    data.swap(
+                        i * 8 + j + k * row_chunks + l * column_chunks,
+                        j * 8 + i + k * row_chunks + l * column_chunks,
+                    );
+                }
+            }
+        }
+        do_idct_8_trh(d, &mut data[i..]);
+    }
+}
+
+#[inline(always)]
+fn idct2d_8_8_impl<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    assert_eq!(data.len(), 64, "Data length mismatch");
+    const { assert!(8usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(8usize.is_multiple_of(D::F32Vec::LEN)) };
+    let data = D::F32Vec::make_array_slice_mut(data);
+    let chunks = 8 / D::F32Vec::LEN;
+    for i in 0..chunks {
+        do_idct_8(d, &mut data[i..], chunks);
+    }
+    for i in 0..chunks {
+        D::F32Vec::transpose_square(d, &mut data[i * 8 + i..], chunks);
+        for j in i + 1..chunks {
+            D::F32Vec::transpose_square(d, &mut data[j * 8 + i..], chunks);
+            D::F32Vec::transpose_square(d, &mut data[i * 8 + j..], chunks);
+            for k in 0..D::F32Vec::LEN {
+                data.swap(i * 8 + j + k * chunks, j * 8 + i + k * chunks);
+            }
+        }
+        do_idct_8(d, &mut data[i..], chunks);
+    }
+}
+
+#[inline(always)]
+fn idct2d_8_16_impl<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    assert_eq!(data.len(), 128, "Data length mismatch");
+    const { assert!(8usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(16usize.is_multiple_of(D::F32Vec::LEN)) };
+    let data = D::F32Vec::make_array_slice_mut(data);
+    let column_chunks = 16 / D::F32Vec::LEN;
+    let row_chunks = 8 / D::F32Vec::LEN;
+    for i in 0..row_chunks {
+        for j in 0..column_chunks {
+            D::F32Vec::transpose_square(d, &mut data[i * 16 + j..], column_chunks);
+        }
+        do_idct_16_rowblock(d, &mut data[i * 16..]);
+    }
+    for i in 0..column_chunks {
+        for j in 0..row_chunks {
+            D::F32Vec::transpose_square(d, &mut data[j * 16 + i..], column_chunks);
+        }
+        do_idct_8(d, &mut data[i..], column_chunks);
+    }
+}
+
+#[inline(always)]
+fn idct2d_8_32_impl<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    assert_eq!(data.len(), 256, "Data length mismatch");
+    const { assert!(8usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(32usize.is_multiple_of(D::F32Vec::LEN)) };
+    let data = D::F32Vec::make_array_slice_mut(data);
+    let column_chunks = 32 / D::F32Vec::LEN;
+    let row_chunks = 8 / D::F32Vec::LEN;
+    for i in 0..row_chunks {
+        for j in 0..column_chunks {
+            D::F32Vec::transpose_square(d, &mut data[i * 32 + j..], column_chunks);
+        }
+        do_idct_32_rowblock(d, &mut data[i * 32..]);
+    }
+    for i in 0..column_chunks {
+        for j in 0..row_chunks {
+            D::F32Vec::transpose_square(d, &mut data[j * 32 + i..], column_chunks);
+        }
+        do_idct_8(d, &mut data[i..], column_chunks);
+    }
+}
+
+#[inline(always)]
+fn idct2d_16_8_impl<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    assert_eq!(data.len(), 128, "Data length mismatch");
+    const { assert!(16usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(8usize.is_multiple_of(D::F32Vec::LEN)) };
+    let data = D::F32Vec::make_array_slice_mut(data);
+    let column_chunks = 8 / D::F32Vec::LEN;
+    let row_chunks = 16 / D::F32Vec::LEN;
+    for i in 0..row_chunks {
+        do_idct_8(d, &mut data[i..], row_chunks);
+    }
+    for i in 0..column_chunks {
+        let tr_block = |data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray], i, j, l| {
+            D::F32Vec::transpose_square(d, &mut data[i * 16 + j + l * column_chunks..], row_chunks)
+        };
+        (0..2).for_each(|l| tr_block(data, i, i, l));
+        for j in i + 1..column_chunks {
+            (0..2).for_each(|l| tr_block(data, i, j, l));
+            (0..2).for_each(|l| tr_block(data, j, i, l));
+            for l in 0..2 {
+                for k in 0..D::F32Vec::LEN {
+                    data.swap(
+                        i * 16 + j + k * row_chunks + l * column_chunks,
+                        j * 16 + i + k * row_chunks + l * column_chunks,
+                    );
+                }
+            }
+        }
+        do_idct_16_trh(d, &mut data[i..]);
+    }
+}
+
+#[inline(always)]
+fn idct2d_16_16_impl<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    assert_eq!(data.len(), 256, "Data length mismatch");
+    const { assert!(16usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(16usize.is_multiple_of(D::F32Vec::LEN)) };
+    let data = D::F32Vec::make_array_slice_mut(data);
+    let chunks = 16 / D::F32Vec::LEN;
+    for i in 0..chunks {
+        do_idct_16(d, &mut data[i..], chunks);
+    }
+    for i in 0..chunks {
+        D::F32Vec::transpose_square(d, &mut data[i * 16 + i..], chunks);
+        for j in i + 1..chunks {
+            D::F32Vec::transpose_square(d, &mut data[j * 16 + i..], chunks);
+            D::F32Vec::transpose_square(d, &mut data[i * 16 + j..], chunks);
+            for k in 0..D::F32Vec::LEN {
+                data.swap(i * 16 + j + k * chunks, j * 16 + i + k * chunks);
+            }
+        }
+        do_idct_16(d, &mut data[i..], chunks);
+    }
+}
+
+#[inline(always)]
+fn idct2d_16_32_impl<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    assert_eq!(data.len(), 512, "Data length mismatch");
+    const { assert!(16usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(32usize.is_multiple_of(D::F32Vec::LEN)) };
+    let data = D::F32Vec::make_array_slice_mut(data);
+    let column_chunks = 32 / D::F32Vec::LEN;
+    let row_chunks = 16 / D::F32Vec::LEN;
+    for i in 0..row_chunks {
+        for j in 0..column_chunks {
+            D::F32Vec::transpose_square(d, &mut data[i * 32 + j..], column_chunks);
+        }
+        do_idct_32_rowblock(d, &mut data[i * 32..]);
+    }
+    for i in 0..column_chunks {
+        for j in 0..row_chunks {
+            D::F32Vec::transpose_square(d, &mut data[j * 32 + i..], column_chunks);
+        }
+        do_idct_16(d, &mut data[i..], column_chunks);
+    }
+}
+
+#[inline(always)]
+fn idct2d_32_8_impl<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    assert_eq!(data.len(), 256, "Data length mismatch");
+    const { assert!(32usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(8usize.is_multiple_of(D::F32Vec::LEN)) };
+    let data = D::F32Vec::make_array_slice_mut(data);
+    let column_chunks = 8 / D::F32Vec::LEN;
+    let row_chunks = 32 / D::F32Vec::LEN;
+    for i in 0..row_chunks {
+        do_idct_8(d, &mut data[i..], row_chunks);
+    }
+    for i in 0..column_chunks {
+        let tr_block = |data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray], i, j, l| {
+            D::F32Vec::transpose_square(d, &mut data[i * 32 + j + l * column_chunks..], row_chunks)
+        };
+        (0..4).for_each(|l| tr_block(data, i, i, l));
+        for j in i + 1..column_chunks {
+            (0..4).for_each(|l| tr_block(data, i, j, l));
+            (0..4).for_each(|l| tr_block(data, j, i, l));
+            for l in 0..4 {
+                for k in 0..D::F32Vec::LEN {
+                    data.swap(
+                        i * 32 + j + k * row_chunks + l * column_chunks,
+                        j * 32 + i + k * row_chunks + l * column_chunks,
+                    );
+                }
+            }
+        }
+        do_idct_32_trq(d, &mut data[i..]);
+    }
+}
+
+#[inline(always)]
+fn idct2d_32_16_impl<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    assert_eq!(data.len(), 512, "Data length mismatch");
+    const { assert!(32usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(16usize.is_multiple_of(D::F32Vec::LEN)) };
+    let data = D::F32Vec::make_array_slice_mut(data);
+    let column_chunks = 16 / D::F32Vec::LEN;
+    let row_chunks = 32 / D::F32Vec::LEN;
+    for i in 0..row_chunks {
+        do_idct_16(d, &mut data[i..], row_chunks);
+    }
+    for i in 0..column_chunks {
+        let tr_block = |data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray], i, j, l| {
+            D::F32Vec::transpose_square(d, &mut data[i * 32 + j + l * column_chunks..], row_chunks)
+        };
+        (0..2).for_each(|l| tr_block(data, i, i, l));
+        for j in i + 1..column_chunks {
+            (0..2).for_each(|l| tr_block(data, i, j, l));
+            (0..2).for_each(|l| tr_block(data, j, i, l));
+            for l in 0..2 {
+                for k in 0..D::F32Vec::LEN {
+                    data.swap(
+                        i * 32 + j + k * row_chunks + l * column_chunks,
+                        j * 32 + i + k * row_chunks + l * column_chunks,
+                    );
+                }
+            }
+        }
+        do_idct_32_trh(d, &mut data[i..]);
+    }
+}
+
+#[inline(always)]
+fn idct2d_32_32_impl<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    assert_eq!(data.len(), 1024, "Data length mismatch");
+    const { assert!(32usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(32usize.is_multiple_of(D::F32Vec::LEN)) };
+    let data = D::F32Vec::make_array_slice_mut(data);
+    let chunks = 32 / D::F32Vec::LEN;
+    for i in 0..chunks {
+        do_idct_32(d, &mut data[i..], chunks);
+    }
+    for i in 0..chunks {
+        D::F32Vec::transpose_square(d, &mut data[i * 32 + i..], chunks);
+        for j in i + 1..chunks {
+            D::F32Vec::transpose_square(d, &mut data[j * 32 + i..], chunks);
+            D::F32Vec::transpose_square(d, &mut data[i * 32 + j..], chunks);
+            for k in 0..D::F32Vec::LEN {
+                data.swap(i * 32 + j + k * chunks, j * 32 + i + k * chunks);
+            }
+        }
+        do_idct_32(d, &mut data[i..], chunks);
+    }
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn idct2d_2_2<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    let d = jxl_simd::ScalarDescriptor::new().unwrap();
+    idct2d_2_2_impl(d, data)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn idct2d_4_4<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    let d = d.maybe_downgrade_128bit();
+    idct2d_4_4_impl(d, data)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn idct2d_4_8<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    let d = d.maybe_downgrade_128bit();
+    idct2d_4_8_impl(d, data)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn idct2d_8_4<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    let d = d.maybe_downgrade_128bit();
+    idct2d_8_4_impl(d, data)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn idct2d_8_8<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    let d = d.maybe_downgrade_256bit();
+    idct2d_8_8_impl(d, data)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn idct2d_8_16<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    let d = d.maybe_downgrade_256bit();
+    idct2d_8_16_impl(d, data)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn idct2d_8_32<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    let d = d.maybe_downgrade_256bit();
+    idct2d_8_32_impl(d, data)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn idct2d_16_8<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    let d = d.maybe_downgrade_256bit();
+    idct2d_16_8_impl(d, data)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn idct2d_16_16<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    idct2d_16_16_impl(d, data)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn idct2d_16_32<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    idct2d_16_32_impl(d, data)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn idct2d_32_8<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    let d = d.maybe_downgrade_256bit();
+    idct2d_32_8_impl(d, data)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn idct2d_32_16<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    idct2d_32_16_impl(d, data)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn idct2d_32_32<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+    idct2d_32_32_impl(d, data)
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct32.rs b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct32.rs
new file mode 100644
index 0000000..575920c
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct32.rs
@@ -0,0 +1,796 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(unused)]
+#![allow(clippy::type_complexity)]
+#![allow(clippy::erasing_op)]
+#![allow(clippy::identity_op)]
+use crate::*;
+use jxl_simd::{F32SimdVec, SimdDescriptor};
+
+#[allow(clippy::too_many_arguments)]
+#[allow(clippy::excessive_precision)]
+#[inline(always)]
+pub(super) fn idct_32<D: SimdDescriptor>(
+    d: D,
+    mut v0: D::F32Vec,
+    mut v1: D::F32Vec,
+    mut v2: D::F32Vec,
+    mut v3: D::F32Vec,
+    mut v4: D::F32Vec,
+    mut v5: D::F32Vec,
+    mut v6: D::F32Vec,
+    mut v7: D::F32Vec,
+    mut v8: D::F32Vec,
+    mut v9: D::F32Vec,
+    mut v10: D::F32Vec,
+    mut v11: D::F32Vec,
+    mut v12: D::F32Vec,
+    mut v13: D::F32Vec,
+    mut v14: D::F32Vec,
+    mut v15: D::F32Vec,
+    mut v16: D::F32Vec,
+    mut v17: D::F32Vec,
+    mut v18: D::F32Vec,
+    mut v19: D::F32Vec,
+    mut v20: D::F32Vec,
+    mut v21: D::F32Vec,
+    mut v22: D::F32Vec,
+    mut v23: D::F32Vec,
+    mut v24: D::F32Vec,
+    mut v25: D::F32Vec,
+    mut v26: D::F32Vec,
+    mut v27: D::F32Vec,
+    mut v28: D::F32Vec,
+    mut v29: D::F32Vec,
+    mut v30: D::F32Vec,
+    mut v31: D::F32Vec,
+) -> (
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+) {
+    let mut v32 = v0 + v16;
+    let mut v33 = v0 - v16;
+    let mut v34 = v8 + v24;
+    let mut v35 = v8 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v36 = v35 + v34;
+    let mut v37 = v35 - v34;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let mut v38 = v36.mul_add(mul, v32);
+    let mut v39 = v36.neg_mul_add(mul, v32);
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let mut v40 = v37.mul_add(mul, v33);
+    let mut v41 = v37.neg_mul_add(mul, v33);
+    let mut v42 = v4 + v12;
+    let mut v43 = v12 + v20;
+    let mut v44 = v20 + v28;
+    let mut v45 = v4 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v46 = v45 + v43;
+    let mut v47 = v45 - v43;
+    let mut v48 = v42 + v44;
+    let mut v49 = v42 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v50 = v49 + v48;
+    let mut v51 = v49 - v48;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let mut v52 = v50.mul_add(mul, v46);
+    let mut v53 = v50.neg_mul_add(mul, v46);
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let mut v54 = v51.mul_add(mul, v47);
+    let mut v55 = v51.neg_mul_add(mul, v47);
+    let mul = D::F32Vec::splat(d, 0.5097955791041592);
+    let mut v56 = v52.mul_add(mul, v38);
+    let mut v57 = v52.neg_mul_add(mul, v38);
+    let mul = D::F32Vec::splat(d, 0.6013448869350453);
+    let mut v58 = v54.mul_add(mul, v40);
+    let mut v59 = v54.neg_mul_add(mul, v40);
+    let mul = D::F32Vec::splat(d, 0.8999762231364156);
+    let mut v60 = v55.mul_add(mul, v41);
+    let mut v61 = v55.neg_mul_add(mul, v41);
+    let mul = D::F32Vec::splat(d, 2.5629154477415055);
+    let mut v62 = v53.mul_add(mul, v39);
+    let mut v63 = v53.neg_mul_add(mul, v39);
+    let mut v64 = v2 + v6;
+    let mut v65 = v6 + v10;
+    let mut v66 = v10 + v14;
+    let mut v67 = v14 + v18;
+    let mut v68 = v18 + v22;
+    let mut v69 = v22 + v26;
+    let mut v70 = v26 + v30;
+    let mut v71 = v2 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v72 = v71 + v67;
+    let mut v73 = v71 - v67;
+    let mut v74 = v65 + v69;
+    let mut v75 = v65 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v76 = v75 + v74;
+    let mut v77 = v75 - v74;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let mut v78 = v76.mul_add(mul, v72);
+    let mut v79 = v76.neg_mul_add(mul, v72);
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let mut v80 = v77.mul_add(mul, v73);
+    let mut v81 = v77.neg_mul_add(mul, v73);
+    let mut v82 = v64 + v66;
+    let mut v83 = v66 + v68;
+    let mut v84 = v68 + v70;
+    let mut v85 = v64 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v86 = v85 + v83;
+    let mut v87 = v85 - v83;
+    let mut v88 = v82 + v84;
+    let mut v89 = v82 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v90 = v89 + v88;
+    let mut v91 = v89 - v88;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let mut v92 = v90.mul_add(mul, v86);
+    let mut v93 = v90.neg_mul_add(mul, v86);
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let mut v94 = v91.mul_add(mul, v87);
+    let mut v95 = v91.neg_mul_add(mul, v87);
+    let mul = D::F32Vec::splat(d, 0.5097955791041592);
+    let mut v96 = v92.mul_add(mul, v78);
+    let mut v97 = v92.neg_mul_add(mul, v78);
+    let mul = D::F32Vec::splat(d, 0.6013448869350453);
+    let mut v98 = v94.mul_add(mul, v80);
+    let mut v99 = v94.neg_mul_add(mul, v80);
+    let mul = D::F32Vec::splat(d, 0.8999762231364156);
+    let mut v100 = v95.mul_add(mul, v81);
+    let mut v101 = v95.neg_mul_add(mul, v81);
+    let mul = D::F32Vec::splat(d, 2.5629154477415055);
+    let mut v102 = v93.mul_add(mul, v79);
+    let mut v103 = v93.neg_mul_add(mul, v79);
+    let mul = D::F32Vec::splat(d, 0.5024192861881557);
+    let mut v104 = v96.mul_add(mul, v56);
+    let mut v105 = v96.neg_mul_add(mul, v56);
+    let mul = D::F32Vec::splat(d, 0.5224986149396889);
+    let mut v106 = v98.mul_add(mul, v58);
+    let mut v107 = v98.neg_mul_add(mul, v58);
+    let mul = D::F32Vec::splat(d, 0.5669440348163577);
+    let mut v108 = v100.mul_add(mul, v60);
+    let mut v109 = v100.neg_mul_add(mul, v60);
+    let mul = D::F32Vec::splat(d, 0.6468217833599901);
+    let mut v110 = v102.mul_add(mul, v62);
+    let mut v111 = v102.neg_mul_add(mul, v62);
+    let mul = D::F32Vec::splat(d, 0.7881546234512502);
+    let mut v112 = v103.mul_add(mul, v63);
+    let mut v113 = v103.neg_mul_add(mul, v63);
+    let mul = D::F32Vec::splat(d, 1.0606776859903471);
+    let mut v114 = v101.mul_add(mul, v61);
+    let mut v115 = v101.neg_mul_add(mul, v61);
+    let mul = D::F32Vec::splat(d, 1.7224470982383342);
+    let mut v116 = v99.mul_add(mul, v59);
+    let mut v117 = v99.neg_mul_add(mul, v59);
+    let mul = D::F32Vec::splat(d, 5.1011486186891553);
+    let mut v118 = v97.mul_add(mul, v57);
+    let mut v119 = v97.neg_mul_add(mul, v57);
+    let mut v120 = v1 + v3;
+    let mut v121 = v3 + v5;
+    let mut v122 = v5 + v7;
+    let mut v123 = v7 + v9;
+    let mut v124 = v9 + v11;
+    let mut v125 = v11 + v13;
+    let mut v126 = v13 + v15;
+    let mut v127 = v15 + v17;
+    let mut v128 = v17 + v19;
+    let mut v129 = v19 + v21;
+    let mut v130 = v21 + v23;
+    let mut v131 = v23 + v25;
+    let mut v132 = v25 + v27;
+    let mut v133 = v27 + v29;
+    let mut v134 = v29 + v31;
+    let mut v135 = v1 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v136 = v135 + v127;
+    let mut v137 = v135 - v127;
+    let mut v138 = v123 + v131;
+    let mut v139 = v123 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v140 = v139 + v138;
+    let mut v141 = v139 - v138;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let mut v142 = v140.mul_add(mul, v136);
+    let mut v143 = v140.neg_mul_add(mul, v136);
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let mut v144 = v141.mul_add(mul, v137);
+    let mut v145 = v141.neg_mul_add(mul, v137);
+    let mut v146 = v121 + v125;
+    let mut v147 = v125 + v129;
+    let mut v148 = v129 + v133;
+    let mut v149 = v121 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v150 = v149 + v147;
+    let mut v151 = v149 - v147;
+    let mut v152 = v146 + v148;
+    let mut v153 = v146 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v154 = v153 + v152;
+    let mut v155 = v153 - v152;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let mut v156 = v154.mul_add(mul, v150);
+    let mut v157 = v154.neg_mul_add(mul, v150);
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let mut v158 = v155.mul_add(mul, v151);
+    let mut v159 = v155.neg_mul_add(mul, v151);
+    let mul = D::F32Vec::splat(d, 0.5097955791041592);
+    let mut v160 = v156.mul_add(mul, v142);
+    let mut v161 = v156.neg_mul_add(mul, v142);
+    let mul = D::F32Vec::splat(d, 0.6013448869350453);
+    let mut v162 = v158.mul_add(mul, v144);
+    let mut v163 = v158.neg_mul_add(mul, v144);
+    let mul = D::F32Vec::splat(d, 0.8999762231364156);
+    let mut v164 = v159.mul_add(mul, v145);
+    let mut v165 = v159.neg_mul_add(mul, v145);
+    let mul = D::F32Vec::splat(d, 2.5629154477415055);
+    let mut v166 = v157.mul_add(mul, v143);
+    let mut v167 = v157.neg_mul_add(mul, v143);
+    let mut v168 = v120 + v122;
+    let mut v169 = v122 + v124;
+    let mut v170 = v124 + v126;
+    let mut v171 = v126 + v128;
+    let mut v172 = v128 + v130;
+    let mut v173 = v130 + v132;
+    let mut v174 = v132 + v134;
+    let mut v175 = v120 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v176 = v175 + v171;
+    let mut v177 = v175 - v171;
+    let mut v178 = v169 + v173;
+    let mut v179 = v169 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v180 = v179 + v178;
+    let mut v181 = v179 - v178;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let mut v182 = v180.mul_add(mul, v176);
+    let mut v183 = v180.neg_mul_add(mul, v176);
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let mut v184 = v181.mul_add(mul, v177);
+    let mut v185 = v181.neg_mul_add(mul, v177);
+    let mut v186 = v168 + v170;
+    let mut v187 = v170 + v172;
+    let mut v188 = v172 + v174;
+    let mut v189 = v168 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v190 = v189 + v187;
+    let mut v191 = v189 - v187;
+    let mut v192 = v186 + v188;
+    let mut v193 = v186 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v194 = v193 + v192;
+    let mut v195 = v193 - v192;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let mut v196 = v194.mul_add(mul, v190);
+    let mut v197 = v194.neg_mul_add(mul, v190);
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let mut v198 = v195.mul_add(mul, v191);
+    let mut v199 = v195.neg_mul_add(mul, v191);
+    let mul = D::F32Vec::splat(d, 0.5097955791041592);
+    let mut v200 = v196.mul_add(mul, v182);
+    let mut v201 = v196.neg_mul_add(mul, v182);
+    let mul = D::F32Vec::splat(d, 0.6013448869350453);
+    let mut v202 = v198.mul_add(mul, v184);
+    let mut v203 = v198.neg_mul_add(mul, v184);
+    let mul = D::F32Vec::splat(d, 0.8999762231364156);
+    let mut v204 = v199.mul_add(mul, v185);
+    let mut v205 = v199.neg_mul_add(mul, v185);
+    let mul = D::F32Vec::splat(d, 2.5629154477415055);
+    let mut v206 = v197.mul_add(mul, v183);
+    let mut v207 = v197.neg_mul_add(mul, v183);
+    let mul = D::F32Vec::splat(d, 0.5024192861881557);
+    let mut v208 = v200.mul_add(mul, v160);
+    let mut v209 = v200.neg_mul_add(mul, v160);
+    let mul = D::F32Vec::splat(d, 0.5224986149396889);
+    let mut v210 = v202.mul_add(mul, v162);
+    let mut v211 = v202.neg_mul_add(mul, v162);
+    let mul = D::F32Vec::splat(d, 0.5669440348163577);
+    let mut v212 = v204.mul_add(mul, v164);
+    let mut v213 = v204.neg_mul_add(mul, v164);
+    let mul = D::F32Vec::splat(d, 0.6468217833599901);
+    let mut v214 = v206.mul_add(mul, v166);
+    let mut v215 = v206.neg_mul_add(mul, v166);
+    let mul = D::F32Vec::splat(d, 0.7881546234512502);
+    let mut v216 = v207.mul_add(mul, v167);
+    let mut v217 = v207.neg_mul_add(mul, v167);
+    let mul = D::F32Vec::splat(d, 1.0606776859903471);
+    let mut v218 = v205.mul_add(mul, v165);
+    let mut v219 = v205.neg_mul_add(mul, v165);
+    let mul = D::F32Vec::splat(d, 1.7224470982383342);
+    let mut v220 = v203.mul_add(mul, v163);
+    let mut v221 = v203.neg_mul_add(mul, v163);
+    let mul = D::F32Vec::splat(d, 5.1011486186891553);
+    let mut v222 = v201.mul_add(mul, v161);
+    let mut v223 = v201.neg_mul_add(mul, v161);
+    let mul = D::F32Vec::splat(d, 0.5006029982351963);
+    let mut v224 = v208.mul_add(mul, v104);
+    let mut v225 = v208.neg_mul_add(mul, v104);
+    let mul = D::F32Vec::splat(d, 0.5054709598975436);
+    let mut v226 = v210.mul_add(mul, v106);
+    let mut v227 = v210.neg_mul_add(mul, v106);
+    let mul = D::F32Vec::splat(d, 0.5154473099226246);
+    let mut v228 = v212.mul_add(mul, v108);
+    let mut v229 = v212.neg_mul_add(mul, v108);
+    let mul = D::F32Vec::splat(d, 0.5310425910897841);
+    let mut v230 = v214.mul_add(mul, v110);
+    let mut v231 = v214.neg_mul_add(mul, v110);
+    let mul = D::F32Vec::splat(d, 0.5531038960344445);
+    let mut v232 = v216.mul_add(mul, v112);
+    let mut v233 = v216.neg_mul_add(mul, v112);
+    let mul = D::F32Vec::splat(d, 0.5829349682061339);
+    let mut v234 = v218.mul_add(mul, v114);
+    let mut v235 = v218.neg_mul_add(mul, v114);
+    let mul = D::F32Vec::splat(d, 0.6225041230356648);
+    let mut v236 = v220.mul_add(mul, v116);
+    let mut v237 = v220.neg_mul_add(mul, v116);
+    let mul = D::F32Vec::splat(d, 0.6748083414550057);
+    let mut v238 = v222.mul_add(mul, v118);
+    let mut v239 = v222.neg_mul_add(mul, v118);
+    let mul = D::F32Vec::splat(d, 0.7445362710022986);
+    let mut v240 = v223.mul_add(mul, v119);
+    let mut v241 = v223.neg_mul_add(mul, v119);
+    let mul = D::F32Vec::splat(d, 0.8393496454155268);
+    let mut v242 = v221.mul_add(mul, v117);
+    let mut v243 = v221.neg_mul_add(mul, v117);
+    let mul = D::F32Vec::splat(d, 0.9725682378619608);
+    let mut v244 = v219.mul_add(mul, v115);
+    let mut v245 = v219.neg_mul_add(mul, v115);
+    let mul = D::F32Vec::splat(d, 1.1694399334328847);
+    let mut v246 = v217.mul_add(mul, v113);
+    let mut v247 = v217.neg_mul_add(mul, v113);
+    let mul = D::F32Vec::splat(d, 1.4841646163141662);
+    let mut v248 = v215.mul_add(mul, v111);
+    let mut v249 = v215.neg_mul_add(mul, v111);
+    let mul = D::F32Vec::splat(d, 2.0577810099534108);
+    let mut v250 = v213.mul_add(mul, v109);
+    let mut v251 = v213.neg_mul_add(mul, v109);
+    let mul = D::F32Vec::splat(d, 3.4076084184687190);
+    let mut v252 = v211.mul_add(mul, v107);
+    let mut v253 = v211.neg_mul_add(mul, v107);
+    let mul = D::F32Vec::splat(d, 10.1900081235480329);
+    let mut v254 = v209.mul_add(mul, v105);
+    let mut v255 = v209.neg_mul_add(mul, v105);
+    (
+        v224, v226, v228, v230, v232, v234, v236, v238, v240, v242, v244, v246, v248, v250, v252,
+        v254, v255, v253, v251, v249, v247, v245, v243, v241, v239, v237, v235, v233, v231, v229,
+        v227, v225,
+    )
+}
+
+#[inline(always)]
+pub(super) fn do_idct_32<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+    stride: usize,
+) {
+    assert!(data.len() > 31 * stride);
+    let mut v0 = D::F32Vec::load_array(d, &data[0 * stride]);
+    let mut v1 = D::F32Vec::load_array(d, &data[1 * stride]);
+    let mut v2 = D::F32Vec::load_array(d, &data[2 * stride]);
+    let mut v3 = D::F32Vec::load_array(d, &data[3 * stride]);
+    let mut v4 = D::F32Vec::load_array(d, &data[4 * stride]);
+    let mut v5 = D::F32Vec::load_array(d, &data[5 * stride]);
+    let mut v6 = D::F32Vec::load_array(d, &data[6 * stride]);
+    let mut v7 = D::F32Vec::load_array(d, &data[7 * stride]);
+    let mut v8 = D::F32Vec::load_array(d, &data[8 * stride]);
+    let mut v9 = D::F32Vec::load_array(d, &data[9 * stride]);
+    let mut v10 = D::F32Vec::load_array(d, &data[10 * stride]);
+    let mut v11 = D::F32Vec::load_array(d, &data[11 * stride]);
+    let mut v12 = D::F32Vec::load_array(d, &data[12 * stride]);
+    let mut v13 = D::F32Vec::load_array(d, &data[13 * stride]);
+    let mut v14 = D::F32Vec::load_array(d, &data[14 * stride]);
+    let mut v15 = D::F32Vec::load_array(d, &data[15 * stride]);
+    let mut v16 = D::F32Vec::load_array(d, &data[16 * stride]);
+    let mut v17 = D::F32Vec::load_array(d, &data[17 * stride]);
+    let mut v18 = D::F32Vec::load_array(d, &data[18 * stride]);
+    let mut v19 = D::F32Vec::load_array(d, &data[19 * stride]);
+    let mut v20 = D::F32Vec::load_array(d, &data[20 * stride]);
+    let mut v21 = D::F32Vec::load_array(d, &data[21 * stride]);
+    let mut v22 = D::F32Vec::load_array(d, &data[22 * stride]);
+    let mut v23 = D::F32Vec::load_array(d, &data[23 * stride]);
+    let mut v24 = D::F32Vec::load_array(d, &data[24 * stride]);
+    let mut v25 = D::F32Vec::load_array(d, &data[25 * stride]);
+    let mut v26 = D::F32Vec::load_array(d, &data[26 * stride]);
+    let mut v27 = D::F32Vec::load_array(d, &data[27 * stride]);
+    let mut v28 = D::F32Vec::load_array(d, &data[28 * stride]);
+    let mut v29 = D::F32Vec::load_array(d, &data[29 * stride]);
+    let mut v30 = D::F32Vec::load_array(d, &data[30 * stride]);
+    let mut v31 = D::F32Vec::load_array(d, &data[31 * stride]);
+    (
+        v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+        v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+    ) = idct_32(
+        d, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
+        v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+    );
+    v0.store_array(&mut data[0 * stride]);
+    v1.store_array(&mut data[1 * stride]);
+    v2.store_array(&mut data[2 * stride]);
+    v3.store_array(&mut data[3 * stride]);
+    v4.store_array(&mut data[4 * stride]);
+    v5.store_array(&mut data[5 * stride]);
+    v6.store_array(&mut data[6 * stride]);
+    v7.store_array(&mut data[7 * stride]);
+    v8.store_array(&mut data[8 * stride]);
+    v9.store_array(&mut data[9 * stride]);
+    v10.store_array(&mut data[10 * stride]);
+    v11.store_array(&mut data[11 * stride]);
+    v12.store_array(&mut data[12 * stride]);
+    v13.store_array(&mut data[13 * stride]);
+    v14.store_array(&mut data[14 * stride]);
+    v15.store_array(&mut data[15 * stride]);
+    v16.store_array(&mut data[16 * stride]);
+    v17.store_array(&mut data[17 * stride]);
+    v18.store_array(&mut data[18 * stride]);
+    v19.store_array(&mut data[19 * stride]);
+    v20.store_array(&mut data[20 * stride]);
+    v21.store_array(&mut data[21 * stride]);
+    v22.store_array(&mut data[22 * stride]);
+    v23.store_array(&mut data[23 * stride]);
+    v24.store_array(&mut data[24 * stride]);
+    v25.store_array(&mut data[25 * stride]);
+    v26.store_array(&mut data[26 * stride]);
+    v27.store_array(&mut data[27 * stride]);
+    v28.store_array(&mut data[28 * stride]);
+    v29.store_array(&mut data[29 * stride]);
+    v30.store_array(&mut data[30 * stride]);
+    v31.store_array(&mut data[31 * stride]);
+}
+
+#[inline(always)]
+pub(super) fn do_idct_32_rowblock<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+) {
+    assert!(data.len() >= 32);
+    const { assert!(32usize.is_multiple_of(D::F32Vec::LEN)) };
+    let row_stride = 32 / D::F32Vec::LEN;
+    let mut v0 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (0 % D::F32Vec::LEN) + (0 / D::F32Vec::LEN)],
+    );
+    let mut v1 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (1 % D::F32Vec::LEN) + (1 / D::F32Vec::LEN)],
+    );
+    let mut v2 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (2 % D::F32Vec::LEN) + (2 / D::F32Vec::LEN)],
+    );
+    let mut v3 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (3 % D::F32Vec::LEN) + (3 / D::F32Vec::LEN)],
+    );
+    let mut v4 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (4 % D::F32Vec::LEN) + (4 / D::F32Vec::LEN)],
+    );
+    let mut v5 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (5 % D::F32Vec::LEN) + (5 / D::F32Vec::LEN)],
+    );
+    let mut v6 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (6 % D::F32Vec::LEN) + (6 / D::F32Vec::LEN)],
+    );
+    let mut v7 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (7 % D::F32Vec::LEN) + (7 / D::F32Vec::LEN)],
+    );
+    let mut v8 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (8 % D::F32Vec::LEN) + (8 / D::F32Vec::LEN)],
+    );
+    let mut v9 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (9 % D::F32Vec::LEN) + (9 / D::F32Vec::LEN)],
+    );
+    let mut v10 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (10 % D::F32Vec::LEN) + (10 / D::F32Vec::LEN)],
+    );
+    let mut v11 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (11 % D::F32Vec::LEN) + (11 / D::F32Vec::LEN)],
+    );
+    let mut v12 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (12 % D::F32Vec::LEN) + (12 / D::F32Vec::LEN)],
+    );
+    let mut v13 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (13 % D::F32Vec::LEN) + (13 / D::F32Vec::LEN)],
+    );
+    let mut v14 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (14 % D::F32Vec::LEN) + (14 / D::F32Vec::LEN)],
+    );
+    let mut v15 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (15 % D::F32Vec::LEN) + (15 / D::F32Vec::LEN)],
+    );
+    let mut v16 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (16 % D::F32Vec::LEN) + (16 / D::F32Vec::LEN)],
+    );
+    let mut v17 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (17 % D::F32Vec::LEN) + (17 / D::F32Vec::LEN)],
+    );
+    let mut v18 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (18 % D::F32Vec::LEN) + (18 / D::F32Vec::LEN)],
+    );
+    let mut v19 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (19 % D::F32Vec::LEN) + (19 / D::F32Vec::LEN)],
+    );
+    let mut v20 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (20 % D::F32Vec::LEN) + (20 / D::F32Vec::LEN)],
+    );
+    let mut v21 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (21 % D::F32Vec::LEN) + (21 / D::F32Vec::LEN)],
+    );
+    let mut v22 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (22 % D::F32Vec::LEN) + (22 / D::F32Vec::LEN)],
+    );
+    let mut v23 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (23 % D::F32Vec::LEN) + (23 / D::F32Vec::LEN)],
+    );
+    let mut v24 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (24 % D::F32Vec::LEN) + (24 / D::F32Vec::LEN)],
+    );
+    let mut v25 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (25 % D::F32Vec::LEN) + (25 / D::F32Vec::LEN)],
+    );
+    let mut v26 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (26 % D::F32Vec::LEN) + (26 / D::F32Vec::LEN)],
+    );
+    let mut v27 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (27 % D::F32Vec::LEN) + (27 / D::F32Vec::LEN)],
+    );
+    let mut v28 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (28 % D::F32Vec::LEN) + (28 / D::F32Vec::LEN)],
+    );
+    let mut v29 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (29 % D::F32Vec::LEN) + (29 / D::F32Vec::LEN)],
+    );
+    let mut v30 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (30 % D::F32Vec::LEN) + (30 / D::F32Vec::LEN)],
+    );
+    let mut v31 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (31 % D::F32Vec::LEN) + (31 / D::F32Vec::LEN)],
+    );
+    (
+        v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+        v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+    ) = idct_32(
+        d, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
+        v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+    );
+    v0.store_array(&mut data[row_stride * (0 % D::F32Vec::LEN) + (0 / D::F32Vec::LEN)]);
+    v1.store_array(&mut data[row_stride * (1 % D::F32Vec::LEN) + (1 / D::F32Vec::LEN)]);
+    v2.store_array(&mut data[row_stride * (2 % D::F32Vec::LEN) + (2 / D::F32Vec::LEN)]);
+    v3.store_array(&mut data[row_stride * (3 % D::F32Vec::LEN) + (3 / D::F32Vec::LEN)]);
+    v4.store_array(&mut data[row_stride * (4 % D::F32Vec::LEN) + (4 / D::F32Vec::LEN)]);
+    v5.store_array(&mut data[row_stride * (5 % D::F32Vec::LEN) + (5 / D::F32Vec::LEN)]);
+    v6.store_array(&mut data[row_stride * (6 % D::F32Vec::LEN) + (6 / D::F32Vec::LEN)]);
+    v7.store_array(&mut data[row_stride * (7 % D::F32Vec::LEN) + (7 / D::F32Vec::LEN)]);
+    v8.store_array(&mut data[row_stride * (8 % D::F32Vec::LEN) + (8 / D::F32Vec::LEN)]);
+    v9.store_array(&mut data[row_stride * (9 % D::F32Vec::LEN) + (9 / D::F32Vec::LEN)]);
+    v10.store_array(&mut data[row_stride * (10 % D::F32Vec::LEN) + (10 / D::F32Vec::LEN)]);
+    v11.store_array(&mut data[row_stride * (11 % D::F32Vec::LEN) + (11 / D::F32Vec::LEN)]);
+    v12.store_array(&mut data[row_stride * (12 % D::F32Vec::LEN) + (12 / D::F32Vec::LEN)]);
+    v13.store_array(&mut data[row_stride * (13 % D::F32Vec::LEN) + (13 / D::F32Vec::LEN)]);
+    v14.store_array(&mut data[row_stride * (14 % D::F32Vec::LEN) + (14 / D::F32Vec::LEN)]);
+    v15.store_array(&mut data[row_stride * (15 % D::F32Vec::LEN) + (15 / D::F32Vec::LEN)]);
+    v16.store_array(&mut data[row_stride * (16 % D::F32Vec::LEN) + (16 / D::F32Vec::LEN)]);
+    v17.store_array(&mut data[row_stride * (17 % D::F32Vec::LEN) + (17 / D::F32Vec::LEN)]);
+    v18.store_array(&mut data[row_stride * (18 % D::F32Vec::LEN) + (18 / D::F32Vec::LEN)]);
+    v19.store_array(&mut data[row_stride * (19 % D::F32Vec::LEN) + (19 / D::F32Vec::LEN)]);
+    v20.store_array(&mut data[row_stride * (20 % D::F32Vec::LEN) + (20 / D::F32Vec::LEN)]);
+    v21.store_array(&mut data[row_stride * (21 % D::F32Vec::LEN) + (21 / D::F32Vec::LEN)]);
+    v22.store_array(&mut data[row_stride * (22 % D::F32Vec::LEN) + (22 / D::F32Vec::LEN)]);
+    v23.store_array(&mut data[row_stride * (23 % D::F32Vec::LEN) + (23 / D::F32Vec::LEN)]);
+    v24.store_array(&mut data[row_stride * (24 % D::F32Vec::LEN) + (24 / D::F32Vec::LEN)]);
+    v25.store_array(&mut data[row_stride * (25 % D::F32Vec::LEN) + (25 / D::F32Vec::LEN)]);
+    v26.store_array(&mut data[row_stride * (26 % D::F32Vec::LEN) + (26 / D::F32Vec::LEN)]);
+    v27.store_array(&mut data[row_stride * (27 % D::F32Vec::LEN) + (27 / D::F32Vec::LEN)]);
+    v28.store_array(&mut data[row_stride * (28 % D::F32Vec::LEN) + (28 / D::F32Vec::LEN)]);
+    v29.store_array(&mut data[row_stride * (29 % D::F32Vec::LEN) + (29 / D::F32Vec::LEN)]);
+    v30.store_array(&mut data[row_stride * (30 % D::F32Vec::LEN) + (30 / D::F32Vec::LEN)]);
+    v31.store_array(&mut data[row_stride * (31 % D::F32Vec::LEN) + (31 / D::F32Vec::LEN)]);
+}
+
+#[inline(always)]
+pub(super) fn do_idct_32_trh<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+) {
+    let row_stride = 16 / D::F32Vec::LEN;
+    assert!(data.len() > 31 * row_stride);
+    const { assert!(16usize.is_multiple_of(D::F32Vec::LEN)) };
+    let mut v0 = D::F32Vec::load_array(d, &data[row_stride * 0]);
+    let mut v1 = D::F32Vec::load_array(d, &data[row_stride * 2]);
+    let mut v2 = D::F32Vec::load_array(d, &data[row_stride * 4]);
+    let mut v3 = D::F32Vec::load_array(d, &data[row_stride * 6]);
+    let mut v4 = D::F32Vec::load_array(d, &data[row_stride * 8]);
+    let mut v5 = D::F32Vec::load_array(d, &data[row_stride * 10]);
+    let mut v6 = D::F32Vec::load_array(d, &data[row_stride * 12]);
+    let mut v7 = D::F32Vec::load_array(d, &data[row_stride * 14]);
+    let mut v8 = D::F32Vec::load_array(d, &data[row_stride * 16]);
+    let mut v9 = D::F32Vec::load_array(d, &data[row_stride * 18]);
+    let mut v10 = D::F32Vec::load_array(d, &data[row_stride * 20]);
+    let mut v11 = D::F32Vec::load_array(d, &data[row_stride * 22]);
+    let mut v12 = D::F32Vec::load_array(d, &data[row_stride * 24]);
+    let mut v13 = D::F32Vec::load_array(d, &data[row_stride * 26]);
+    let mut v14 = D::F32Vec::load_array(d, &data[row_stride * 28]);
+    let mut v15 = D::F32Vec::load_array(d, &data[row_stride * 30]);
+    let mut v16 = D::F32Vec::load_array(d, &data[row_stride * 1]);
+    let mut v17 = D::F32Vec::load_array(d, &data[row_stride * 3]);
+    let mut v18 = D::F32Vec::load_array(d, &data[row_stride * 5]);
+    let mut v19 = D::F32Vec::load_array(d, &data[row_stride * 7]);
+    let mut v20 = D::F32Vec::load_array(d, &data[row_stride * 9]);
+    let mut v21 = D::F32Vec::load_array(d, &data[row_stride * 11]);
+    let mut v22 = D::F32Vec::load_array(d, &data[row_stride * 13]);
+    let mut v23 = D::F32Vec::load_array(d, &data[row_stride * 15]);
+    let mut v24 = D::F32Vec::load_array(d, &data[row_stride * 17]);
+    let mut v25 = D::F32Vec::load_array(d, &data[row_stride * 19]);
+    let mut v26 = D::F32Vec::load_array(d, &data[row_stride * 21]);
+    let mut v27 = D::F32Vec::load_array(d, &data[row_stride * 23]);
+    let mut v28 = D::F32Vec::load_array(d, &data[row_stride * 25]);
+    let mut v29 = D::F32Vec::load_array(d, &data[row_stride * 27]);
+    let mut v30 = D::F32Vec::load_array(d, &data[row_stride * 29]);
+    let mut v31 = D::F32Vec::load_array(d, &data[row_stride * 31]);
+    (
+        v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+        v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+    ) = idct_32(
+        d, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
+        v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+    );
+    v0.store_array(&mut data[row_stride * 0]);
+    v1.store_array(&mut data[row_stride * 1]);
+    v2.store_array(&mut data[row_stride * 2]);
+    v3.store_array(&mut data[row_stride * 3]);
+    v4.store_array(&mut data[row_stride * 4]);
+    v5.store_array(&mut data[row_stride * 5]);
+    v6.store_array(&mut data[row_stride * 6]);
+    v7.store_array(&mut data[row_stride * 7]);
+    v8.store_array(&mut data[row_stride * 8]);
+    v9.store_array(&mut data[row_stride * 9]);
+    v10.store_array(&mut data[row_stride * 10]);
+    v11.store_array(&mut data[row_stride * 11]);
+    v12.store_array(&mut data[row_stride * 12]);
+    v13.store_array(&mut data[row_stride * 13]);
+    v14.store_array(&mut data[row_stride * 14]);
+    v15.store_array(&mut data[row_stride * 15]);
+    v16.store_array(&mut data[row_stride * 16]);
+    v17.store_array(&mut data[row_stride * 17]);
+    v18.store_array(&mut data[row_stride * 18]);
+    v19.store_array(&mut data[row_stride * 19]);
+    v20.store_array(&mut data[row_stride * 20]);
+    v21.store_array(&mut data[row_stride * 21]);
+    v22.store_array(&mut data[row_stride * 22]);
+    v23.store_array(&mut data[row_stride * 23]);
+    v24.store_array(&mut data[row_stride * 24]);
+    v25.store_array(&mut data[row_stride * 25]);
+    v26.store_array(&mut data[row_stride * 26]);
+    v27.store_array(&mut data[row_stride * 27]);
+    v28.store_array(&mut data[row_stride * 28]);
+    v29.store_array(&mut data[row_stride * 29]);
+    v30.store_array(&mut data[row_stride * 30]);
+    v31.store_array(&mut data[row_stride * 31]);
+}
+
+#[inline(always)]
+pub(super) fn do_idct_32_trq<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+) {
+    let row_stride = 8 / D::F32Vec::LEN;
+    assert!(data.len() > 31 * row_stride);
+    const { assert!(8usize.is_multiple_of(D::F32Vec::LEN)) };
+    let mut v0 = D::F32Vec::load_array(d, &data[row_stride * 0]);
+    let mut v1 = D::F32Vec::load_array(d, &data[row_stride * 4]);
+    let mut v2 = D::F32Vec::load_array(d, &data[row_stride * 8]);
+    let mut v3 = D::F32Vec::load_array(d, &data[row_stride * 12]);
+    let mut v4 = D::F32Vec::load_array(d, &data[row_stride * 16]);
+    let mut v5 = D::F32Vec::load_array(d, &data[row_stride * 20]);
+    let mut v6 = D::F32Vec::load_array(d, &data[row_stride * 24]);
+    let mut v7 = D::F32Vec::load_array(d, &data[row_stride * 28]);
+    let mut v8 = D::F32Vec::load_array(d, &data[row_stride * 1]);
+    let mut v9 = D::F32Vec::load_array(d, &data[row_stride * 5]);
+    let mut v10 = D::F32Vec::load_array(d, &data[row_stride * 9]);
+    let mut v11 = D::F32Vec::load_array(d, &data[row_stride * 13]);
+    let mut v12 = D::F32Vec::load_array(d, &data[row_stride * 17]);
+    let mut v13 = D::F32Vec::load_array(d, &data[row_stride * 21]);
+    let mut v14 = D::F32Vec::load_array(d, &data[row_stride * 25]);
+    let mut v15 = D::F32Vec::load_array(d, &data[row_stride * 29]);
+    let mut v16 = D::F32Vec::load_array(d, &data[row_stride * 2]);
+    let mut v17 = D::F32Vec::load_array(d, &data[row_stride * 6]);
+    let mut v18 = D::F32Vec::load_array(d, &data[row_stride * 10]);
+    let mut v19 = D::F32Vec::load_array(d, &data[row_stride * 14]);
+    let mut v20 = D::F32Vec::load_array(d, &data[row_stride * 18]);
+    let mut v21 = D::F32Vec::load_array(d, &data[row_stride * 22]);
+    let mut v22 = D::F32Vec::load_array(d, &data[row_stride * 26]);
+    let mut v23 = D::F32Vec::load_array(d, &data[row_stride * 30]);
+    let mut v24 = D::F32Vec::load_array(d, &data[row_stride * 3]);
+    let mut v25 = D::F32Vec::load_array(d, &data[row_stride * 7]);
+    let mut v26 = D::F32Vec::load_array(d, &data[row_stride * 11]);
+    let mut v27 = D::F32Vec::load_array(d, &data[row_stride * 15]);
+    let mut v28 = D::F32Vec::load_array(d, &data[row_stride * 19]);
+    let mut v29 = D::F32Vec::load_array(d, &data[row_stride * 23]);
+    let mut v30 = D::F32Vec::load_array(d, &data[row_stride * 27]);
+    let mut v31 = D::F32Vec::load_array(d, &data[row_stride * 31]);
+    (
+        v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+        v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+    ) = idct_32(
+        d, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
+        v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+    );
+    v0.store_array(&mut data[row_stride * 0]);
+    v1.store_array(&mut data[row_stride * 1]);
+    v2.store_array(&mut data[row_stride * 2]);
+    v3.store_array(&mut data[row_stride * 3]);
+    v4.store_array(&mut data[row_stride * 4]);
+    v5.store_array(&mut data[row_stride * 5]);
+    v6.store_array(&mut data[row_stride * 6]);
+    v7.store_array(&mut data[row_stride * 7]);
+    v8.store_array(&mut data[row_stride * 8]);
+    v9.store_array(&mut data[row_stride * 9]);
+    v10.store_array(&mut data[row_stride * 10]);
+    v11.store_array(&mut data[row_stride * 11]);
+    v12.store_array(&mut data[row_stride * 12]);
+    v13.store_array(&mut data[row_stride * 13]);
+    v14.store_array(&mut data[row_stride * 14]);
+    v15.store_array(&mut data[row_stride * 15]);
+    v16.store_array(&mut data[row_stride * 16]);
+    v17.store_array(&mut data[row_stride * 17]);
+    v18.store_array(&mut data[row_stride * 18]);
+    v19.store_array(&mut data[row_stride * 19]);
+    v20.store_array(&mut data[row_stride * 20]);
+    v21.store_array(&mut data[row_stride * 21]);
+    v22.store_array(&mut data[row_stride * 22]);
+    v23.store_array(&mut data[row_stride * 23]);
+    v24.store_array(&mut data[row_stride * 24]);
+    v25.store_array(&mut data[row_stride * 25]);
+    v26.store_array(&mut data[row_stride * 26]);
+    v27.store_array(&mut data[row_stride * 27]);
+    v28.store_array(&mut data[row_stride * 28]);
+    v29.store_array(&mut data[row_stride * 29]);
+    v30.store_array(&mut data[row_stride * 30]);
+    v31.store_array(&mut data[row_stride * 31]);
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct4.rs b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct4.rs
new file mode 100644
index 0000000..759a12c
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct4.rs
@@ -0,0 +1,104 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(unused)]
+#![allow(clippy::type_complexity)]
+#![allow(clippy::erasing_op)]
+#![allow(clippy::identity_op)]
+use crate::*;
+use jxl_simd::{F32SimdVec, SimdDescriptor};
+
+#[allow(clippy::too_many_arguments)]
+#[allow(clippy::excessive_precision)]
+#[inline(always)]
+pub(super) fn idct_4<D: SimdDescriptor>(
+    d: D,
+    mut v0: D::F32Vec,
+    mut v1: D::F32Vec,
+    mut v2: D::F32Vec,
+    mut v3: D::F32Vec,
+) -> (D::F32Vec, D::F32Vec, D::F32Vec, D::F32Vec) {
+    let mut v4 = v0 + v2;
+    let mut v5 = v0 - v2;
+    let mut v6 = v1 + v3;
+    let mut v7 = v1 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v8 = v7 + v6;
+    let mut v9 = v7 - v6;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let mut v10 = v8.mul_add(mul, v4);
+    let mut v11 = v8.neg_mul_add(mul, v4);
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let mut v12 = v9.mul_add(mul, v5);
+    let mut v13 = v9.neg_mul_add(mul, v5);
+    (v10, v12, v13, v11)
+}
+
+#[inline(always)]
+pub(super) fn do_idct_4<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+    stride: usize,
+) {
+    assert!(data.len() > 3 * stride);
+    let mut v0 = D::F32Vec::load_array(d, &data[0 * stride]);
+    let mut v1 = D::F32Vec::load_array(d, &data[1 * stride]);
+    let mut v2 = D::F32Vec::load_array(d, &data[2 * stride]);
+    let mut v3 = D::F32Vec::load_array(d, &data[3 * stride]);
+    (v0, v1, v2, v3) = idct_4(d, v0, v1, v2, v3);
+    v0.store_array(&mut data[0 * stride]);
+    v1.store_array(&mut data[1 * stride]);
+    v2.store_array(&mut data[2 * stride]);
+    v3.store_array(&mut data[3 * stride]);
+}
+
+#[inline(always)]
+pub(super) fn do_idct_4_rowblock<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+) {
+    assert!(data.len() >= 4);
+    const { assert!(4usize.is_multiple_of(D::F32Vec::LEN)) };
+    let row_stride = 4 / D::F32Vec::LEN;
+    let mut v0 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (0 % D::F32Vec::LEN) + (0 / D::F32Vec::LEN)],
+    );
+    let mut v1 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (1 % D::F32Vec::LEN) + (1 / D::F32Vec::LEN)],
+    );
+    let mut v2 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (2 % D::F32Vec::LEN) + (2 / D::F32Vec::LEN)],
+    );
+    let mut v3 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (3 % D::F32Vec::LEN) + (3 / D::F32Vec::LEN)],
+    );
+    (v0, v1, v2, v3) = idct_4(d, v0, v1, v2, v3);
+    v0.store_array(&mut data[row_stride * (0 % D::F32Vec::LEN) + (0 / D::F32Vec::LEN)]);
+    v1.store_array(&mut data[row_stride * (1 % D::F32Vec::LEN) + (1 / D::F32Vec::LEN)]);
+    v2.store_array(&mut data[row_stride * (2 % D::F32Vec::LEN) + (2 / D::F32Vec::LEN)]);
+    v3.store_array(&mut data[row_stride * (3 % D::F32Vec::LEN) + (3 / D::F32Vec::LEN)]);
+}
+
+#[inline(always)]
+pub(super) fn do_idct_4_trh<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+) {
+    let row_stride = 2 / D::F32Vec::LEN;
+    assert!(data.len() > 3 * row_stride);
+    const { assert!(2usize.is_multiple_of(D::F32Vec::LEN)) };
+    let mut v0 = D::F32Vec::load_array(d, &data[row_stride * 0]);
+    let mut v1 = D::F32Vec::load_array(d, &data[row_stride * 2]);
+    let mut v2 = D::F32Vec::load_array(d, &data[row_stride * 1]);
+    let mut v3 = D::F32Vec::load_array(d, &data[row_stride * 3]);
+    (v0, v1, v2, v3) = idct_4(d, v0, v1, v2, v3);
+    v0.store_array(&mut data[row_stride * 0]);
+    v1.store_array(&mut data[row_stride * 1]);
+    v2.store_array(&mut data[row_stride * 2]);
+    v3.store_array(&mut data[row_stride * 3]);
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct8.rs b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct8.rs
new file mode 100644
index 0000000..2001ec0
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct8.rs
@@ -0,0 +1,181 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(unused)]
+#![allow(clippy::type_complexity)]
+#![allow(clippy::erasing_op)]
+#![allow(clippy::identity_op)]
+use crate::*;
+use jxl_simd::{F32SimdVec, SimdDescriptor};
+
+#[allow(clippy::too_many_arguments)]
+#[allow(clippy::excessive_precision)]
+#[inline(always)]
+pub(super) fn idct_8<D: SimdDescriptor>(
+    d: D,
+    mut v0: D::F32Vec,
+    mut v1: D::F32Vec,
+    mut v2: D::F32Vec,
+    mut v3: D::F32Vec,
+    mut v4: D::F32Vec,
+    mut v5: D::F32Vec,
+    mut v6: D::F32Vec,
+    mut v7: D::F32Vec,
+) -> (
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+) {
+    let mut v8 = v0 + v4;
+    let mut v9 = v0 - v4;
+    let mut v10 = v2 + v6;
+    let mut v11 = v2 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v12 = v11 + v10;
+    let mut v13 = v11 - v10;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let mut v14 = v12.mul_add(mul, v8);
+    let mut v15 = v12.neg_mul_add(mul, v8);
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let mut v16 = v13.mul_add(mul, v9);
+    let mut v17 = v13.neg_mul_add(mul, v9);
+    let mut v18 = v1 + v3;
+    let mut v19 = v3 + v5;
+    let mut v20 = v5 + v7;
+    let mut v21 = v1 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v22 = v21 + v19;
+    let mut v23 = v21 - v19;
+    let mut v24 = v18 + v20;
+    let mut v25 = v18 * D::F32Vec::splat(d, std::f32::consts::SQRT_2);
+    let mut v26 = v25 + v24;
+    let mut v27 = v25 - v24;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let mut v28 = v26.mul_add(mul, v22);
+    let mut v29 = v26.neg_mul_add(mul, v22);
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let mut v30 = v27.mul_add(mul, v23);
+    let mut v31 = v27.neg_mul_add(mul, v23);
+    let mul = D::F32Vec::splat(d, 0.5097955791041592);
+    let mut v32 = v28.mul_add(mul, v14);
+    let mut v33 = v28.neg_mul_add(mul, v14);
+    let mul = D::F32Vec::splat(d, 0.6013448869350453);
+    let mut v34 = v30.mul_add(mul, v16);
+    let mut v35 = v30.neg_mul_add(mul, v16);
+    let mul = D::F32Vec::splat(d, 0.8999762231364156);
+    let mut v36 = v31.mul_add(mul, v17);
+    let mut v37 = v31.neg_mul_add(mul, v17);
+    let mul = D::F32Vec::splat(d, 2.5629154477415055);
+    let mut v38 = v29.mul_add(mul, v15);
+    let mut v39 = v29.neg_mul_add(mul, v15);
+    (v32, v34, v36, v38, v39, v37, v35, v33)
+}
+
+#[inline(always)]
+pub(super) fn do_idct_8<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+    stride: usize,
+) {
+    assert!(data.len() > 7 * stride);
+    let mut v0 = D::F32Vec::load_array(d, &data[0 * stride]);
+    let mut v1 = D::F32Vec::load_array(d, &data[1 * stride]);
+    let mut v2 = D::F32Vec::load_array(d, &data[2 * stride]);
+    let mut v3 = D::F32Vec::load_array(d, &data[3 * stride]);
+    let mut v4 = D::F32Vec::load_array(d, &data[4 * stride]);
+    let mut v5 = D::F32Vec::load_array(d, &data[5 * stride]);
+    let mut v6 = D::F32Vec::load_array(d, &data[6 * stride]);
+    let mut v7 = D::F32Vec::load_array(d, &data[7 * stride]);
+    (v0, v1, v2, v3, v4, v5, v6, v7) = idct_8(d, v0, v1, v2, v3, v4, v5, v6, v7);
+    v0.store_array(&mut data[0 * stride]);
+    v1.store_array(&mut data[1 * stride]);
+    v2.store_array(&mut data[2 * stride]);
+    v3.store_array(&mut data[3 * stride]);
+    v4.store_array(&mut data[4 * stride]);
+    v5.store_array(&mut data[5 * stride]);
+    v6.store_array(&mut data[6 * stride]);
+    v7.store_array(&mut data[7 * stride]);
+}
+
+#[inline(always)]
+pub(super) fn do_idct_8_rowblock<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+) {
+    assert!(data.len() >= 8);
+    const { assert!(8usize.is_multiple_of(D::F32Vec::LEN)) };
+    let row_stride = 8 / D::F32Vec::LEN;
+    let mut v0 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (0 % D::F32Vec::LEN) + (0 / D::F32Vec::LEN)],
+    );
+    let mut v1 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (1 % D::F32Vec::LEN) + (1 / D::F32Vec::LEN)],
+    );
+    let mut v2 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (2 % D::F32Vec::LEN) + (2 / D::F32Vec::LEN)],
+    );
+    let mut v3 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (3 % D::F32Vec::LEN) + (3 / D::F32Vec::LEN)],
+    );
+    let mut v4 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (4 % D::F32Vec::LEN) + (4 / D::F32Vec::LEN)],
+    );
+    let mut v5 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (5 % D::F32Vec::LEN) + (5 / D::F32Vec::LEN)],
+    );
+    let mut v6 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (6 % D::F32Vec::LEN) + (6 / D::F32Vec::LEN)],
+    );
+    let mut v7 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (7 % D::F32Vec::LEN) + (7 / D::F32Vec::LEN)],
+    );
+    (v0, v1, v2, v3, v4, v5, v6, v7) = idct_8(d, v0, v1, v2, v3, v4, v5, v6, v7);
+    v0.store_array(&mut data[row_stride * (0 % D::F32Vec::LEN) + (0 / D::F32Vec::LEN)]);
+    v1.store_array(&mut data[row_stride * (1 % D::F32Vec::LEN) + (1 / D::F32Vec::LEN)]);
+    v2.store_array(&mut data[row_stride * (2 % D::F32Vec::LEN) + (2 / D::F32Vec::LEN)]);
+    v3.store_array(&mut data[row_stride * (3 % D::F32Vec::LEN) + (3 / D::F32Vec::LEN)]);
+    v4.store_array(&mut data[row_stride * (4 % D::F32Vec::LEN) + (4 / D::F32Vec::LEN)]);
+    v5.store_array(&mut data[row_stride * (5 % D::F32Vec::LEN) + (5 / D::F32Vec::LEN)]);
+    v6.store_array(&mut data[row_stride * (6 % D::F32Vec::LEN) + (6 / D::F32Vec::LEN)]);
+    v7.store_array(&mut data[row_stride * (7 % D::F32Vec::LEN) + (7 / D::F32Vec::LEN)]);
+}
+
+#[inline(always)]
+pub(super) fn do_idct_8_trh<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+) {
+    let row_stride = 4 / D::F32Vec::LEN;
+    assert!(data.len() > 7 * row_stride);
+    const { assert!(4usize.is_multiple_of(D::F32Vec::LEN)) };
+    let mut v0 = D::F32Vec::load_array(d, &data[row_stride * 0]);
+    let mut v1 = D::F32Vec::load_array(d, &data[row_stride * 2]);
+    let mut v2 = D::F32Vec::load_array(d, &data[row_stride * 4]);
+    let mut v3 = D::F32Vec::load_array(d, &data[row_stride * 6]);
+    let mut v4 = D::F32Vec::load_array(d, &data[row_stride * 1]);
+    let mut v5 = D::F32Vec::load_array(d, &data[row_stride * 3]);
+    let mut v6 = D::F32Vec::load_array(d, &data[row_stride * 5]);
+    let mut v7 = D::F32Vec::load_array(d, &data[row_stride * 7]);
+    (v0, v1, v2, v3, v4, v5, v6, v7) = idct_8(d, v0, v1, v2, v3, v4, v5, v6, v7);
+    v0.store_array(&mut data[row_stride * 0]);
+    v1.store_array(&mut data[row_stride * 1]);
+    v2.store_array(&mut data[row_stride * 2]);
+    v3.store_array(&mut data[row_stride * 3]);
+    v4.store_array(&mut data[row_stride * 4]);
+    v5.store_array(&mut data[row_stride * 5]);
+    v6.store_array(&mut data[row_stride * 6]);
+    v7.store_array(&mut data[row_stride * 7]);
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct_large.rs b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct_large.rs
new file mode 100644
index 0000000..23e7dc86
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct_large.rs
@@ -0,0 +1,587 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains a generic implementation of large (>32x32) 2d IDCTs.
+// They are not implemented in the same way as smaller 2d IDCTs to reduce code size.
+
+use std::f32::consts::SQRT_2;
+
+use jxl_simd::F32SimdVec;
+use jxl_simd::SimdDescriptor;
+
+use crate::idct_32;
+
+const WC_WEIGHTS_64: [f32; 32] = [
+    0.500150636020651,
+    0.5013584524464084,
+    0.5037887256810443,
+    0.5074711720725553,
+    0.5124514794082247,
+    0.5187927131053328,
+    0.52657731515427,
+    0.535909816907992,
+    0.5469204379855088,
+    0.5597698129470802,
+    0.57465518403266,
+    0.5918185358574165,
+    0.6115573478825099,
+    0.6342389366884031,
+    0.6603198078137061,
+    0.6903721282002123,
+    0.7251205223771985,
+    0.7654941649730891,
+    0.8127020908144905,
+    0.8683447152233481,
+    0.9345835970364075,
+    1.0144082649970547,
+    1.1120716205797176,
+    1.233832737976571,
+    1.3892939586328277,
+    1.5939722833856311,
+    1.8746759800084078,
+    2.282050068005162,
+    2.924628428158216,
+    4.084611078129248,
+    6.796750711673633,
+    20.373878167231453,
+];
+
+const WC_WEIGHTS_128: [f32; 64] = [
+    0.5000376519155477,
+    0.5003390374428216,
+    0.5009427176380873,
+    0.5018505174842379,
+    0.5030651913013697,
+    0.5045904432216454,
+    0.5064309549285542,
+    0.5085924210498143,
+    0.5110815927066812,
+    0.5139063298475396,
+    0.5170756631334912,
+    0.5205998663018917,
+    0.524490540114724,
+    0.5287607092074876,
+    0.5334249333971333,
+    0.538499435291984,
+    0.5440022463817783,
+    0.549953374183236,
+    0.5563749934898856,
+    0.5632916653417023,
+    0.5707305880121454,
+    0.5787218851348208,
+    0.5872989370937893,
+    0.5964987630244563,
+    0.606362462272146,
+    0.6169357260050706,
+    0.6282694319707711,
+    0.6404203382416639,
+    0.6534518953751283,
+    0.6674352009263413,
+    0.6824501259764195,
+    0.6985866506472291,
+    0.7159464549705746,
+    0.7346448236478627,
+    0.7548129391165311,
+    0.776600658233963,
+    0.8001798956216941,
+    0.8257487738627852,
+    0.8535367510066064,
+    0.8838110045596234,
+    0.9168844461846523,
+    0.9531258743921193,
+    0.9929729612675466,
+    1.036949040910389,
+    1.0856850642580145,
+    1.1399486751015042,
+    1.2006832557294167,
+    1.2690611716991191,
+    1.346557628206286,
+    1.4350550884414341,
+    1.5369941008524954,
+    1.6555965242641195,
+    1.7952052190778898,
+    1.961817848571166,
+    2.163957818751979,
+    2.4141600002500763,
+    2.7316450287739396,
+    3.147462191781909,
+    3.7152427383269746,
+    4.5362909369693565,
+    5.827688377844654,
+    8.153848602466814,
+    13.58429025728446,
+    40.744688103351834,
+];
+
+const WC_WEIGHTS_256: [f32; 128] = [
+    0.5000094125358878,
+    0.500084723455784,
+    0.5002354020255269,
+    0.5004615618093246,
+    0.5007633734146156,
+    0.5011410648064231,
+    0.5015949217281668,
+    0.502125288230386,
+    0.5027325673091954,
+    0.5034172216566842,
+    0.5041797745258774,
+    0.5050208107132756,
+    0.5059409776624396,
+    0.5069409866925212,
+    0.5080216143561264,
+    0.509183703931388,
+    0.5104281670536573,
+    0.5117559854927805,
+    0.5131682130825206,
+    0.5146659778093218,
+    0.516250484068288,
+    0.5179230150949777,
+    0.5196849355823947,
+    0.5215376944933958,
+    0.5234828280796439,
+    0.52552196311921,
+    0.5276568203859896,
+    0.5298892183652453,
+    0.5322210772308335,
+    0.5346544231010253,
+    0.537191392591309,
+    0.5398342376841637,
+    0.5425853309375497,
+    0.545447171055775,
+    0.5484223888484947,
+    0.551513753605893,
+    0.554724179920619,
+    0.5580567349898085,
+    0.5615146464335654,
+    0.5651013106696203,
+    0.5688203018875696,
+    0.5726753816701664,
+    0.5766705093136241,
+    0.5808098529038624,
+    0.5850978012111273,
+    0.58953897647151,
+    0.5941382481306648,
+    0.5989007476325463,
+    0.6038318843443582,
+    0.6089373627182432,
+    0.614223200800649,
+    0.6196957502119484,
+    0.6253617177319102,
+    0.6312281886412079,
+    0.6373026519855411,
+    0.6435930279473415,
+    0.6501076975307724,
+    0.6568555347890955,
+    0.6638459418498757,
+    0.6710888870233562,
+    0.6785949463131795,
+    0.6863753486870501,
+    0.6944420255086364,
+    0.7028076645818034,
+    0.7114857693151208,
+    0.7204907235796304,
+    0.7298378629074134,
+    0.7395435527641373,
+    0.749625274727372,
+    0.7601017215162176,
+    0.7709929019493761,
+    0.7823202570613161,
+    0.7941067887834509,
+    0.8063772028037925,
+    0.8191580674598145,
+    0.83247799080191,
+    0.8463678182968619,
+    0.860860854031955,
+    0.8759931087426972,
+    0.8918035785352535,
+    0.9083345588266809,
+    0.9256319988042384,
+    0.9437459026371479,
+    0.962730784794803,
+    0.9826461881778968,
+    1.0035572754078206,
+    1.0255355056139732,
+    1.048659411496106,
+    1.0730154944316674,
+    1.0986992590905857,
+    1.1258164135986009,
+    1.1544842669978943,
+    1.184833362908442,
+    1.217009397314603,
+    1.2511754798461228,
+    1.287514812536712,
+    1.326233878832723,
+    1.3675662599582539,
+    1.411777227500661,
+    1.459169302866857,
+    1.5100890297227016,
+    1.5649352798258847,
+    1.6241695131835794,
+    1.6883285509131505,
+    1.7580406092704062,
+    1.8340456094306077,
+    1.9172211551275689,
+    2.0086161135167564,
+    2.1094945286246385,
+    2.22139377701127,
+    2.346202662531156,
+    2.486267909203593,
+    2.644541877144861,
+    2.824791402350551,
+    3.0318994541759925,
+    3.2723115884254845,
+    3.5547153325075804,
+    3.891107790700307,
+    4.298537526449054,
+    4.802076008665048,
+    5.440166215091329,
+    6.274908408039339,
+    7.413566756422303,
+    9.058751453879703,
+    11.644627325175037,
+    16.300023088031555,
+    27.163977662448232,
+    81.48784219222516,
+];
+
+#[inline(always)]
+fn idct_impl_inner<D: SimdDescriptor>(d: D, data: &mut [D::F32Vec], scratch: &mut [D::F32Vec]) {
+    let n = data.len();
+    assert!(scratch.len() >= n);
+
+    if n == 32 {
+        d.call(
+            #[inline(always)]
+            |_| {
+                (
+                    data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
+                    data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15],
+                    data[16], data[17], data[18], data[19], data[20], data[21], data[22], data[23],
+                    data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31],
+                ) = idct_32(
+                    d, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
+                    data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15],
+                    data[16], data[17], data[18], data[19], data[20], data[21], data[22], data[23],
+                    data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31],
+                )
+            },
+        );
+        return;
+    }
+
+    let wc_weights = match n {
+        64 => &WC_WEIGHTS_64[..],
+        128 => &WC_WEIGHTS_128[..],
+        256 => &WC_WEIGHTS_256[..],
+        _ => unreachable!("invalid large-dct size: {n}"),
+    };
+
+    assert_eq!(wc_weights.len(), n / 2);
+
+    let (first_half, second_half) = scratch[..n].split_at_mut(n / 2);
+    for i in 0..n / 2 {
+        first_half[i] = data[i * 2];
+        second_half[i] = data[2 * i + 1];
+    }
+
+    d.call(
+        #[inline(always)]
+        |_| idct_impl_inner(d, first_half, data),
+    );
+
+    for i in (1..n / 2).rev() {
+        second_half[i] = second_half[i] + second_half[i - 1];
+    }
+    second_half[0] *= D::F32Vec::splat(d, SQRT_2);
+
+    d.call(
+        #[inline(always)]
+        |_| idct_impl_inner(d, second_half, data),
+    );
+
+    for i in 0..n / 2 {
+        let mul = D::F32Vec::splat(d, wc_weights[i]);
+        data[i] = second_half[i].mul_add(mul, first_half[i]);
+        data[n - i - 1] = second_half[i].neg_mul_add(mul, first_half[i]);
+    }
+}
+
+#[inline(always)]
+fn do_idct<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+    stride: usize,
+    storage: &mut [D::F32Vec],
+    scratch: &mut [D::F32Vec],
+) {
+    let n = storage.len();
+    assert!((n - 1) * stride < data.len());
+    for i in 0..n {
+        storage[i] = D::F32Vec::load_array(d, &data[i * stride]);
+    }
+    d.call(
+        #[inline(always)]
+        |d| idct_impl_inner(d, storage, scratch),
+    );
+    for i in 0..n {
+        storage[i].store_array(&mut data[i * stride]);
+    }
+}
+
+#[inline(always)]
+fn do_idct_rowblock<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+    storage: &mut [D::F32Vec],
+    scratch: &mut [D::F32Vec],
+) {
+    let n = storage.len();
+    assert!(n.is_multiple_of(D::F32Vec::LEN));
+    assert!(data.len() >= n);
+
+    let row_stride = n / D::F32Vec::LEN;
+    for i in 0..n {
+        storage[i] = D::F32Vec::load_array(
+            d,
+            &data[row_stride * (i % D::F32Vec::LEN) + (i / D::F32Vec::LEN)],
+        );
+    }
+    d.call(
+        #[inline(always)]
+        |d| idct_impl_inner(d, storage, scratch),
+    );
+    for i in 0..n {
+        storage[i].store_array(&mut data[row_stride * (i % D::F32Vec::LEN) + (i / D::F32Vec::LEN)]);
+    }
+}
+
+#[inline(always)]
+fn do_idct_trh<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+    storage: &mut [D::F32Vec],
+    scratch: &mut [D::F32Vec],
+) {
+    let n = storage.len();
+    assert!(n.is_multiple_of(D::F32Vec::LEN));
+    assert!(data.len() >= n);
+
+    let row_stride = n / (2 * D::F32Vec::LEN);
+    for i in 0..n / 2 {
+        storage[i] = D::F32Vec::load_array(d, &data[row_stride * 2 * i]);
+        storage[i + n / 2] = D::F32Vec::load_array(d, &data[row_stride * (2 * i + 1)]);
+    }
+    d.call(
+        #[inline(always)]
+        |d| idct_impl_inner(d, storage, scratch),
+    );
+    for i in 0..n {
+        storage[i].store_array(&mut data[row_stride * i]);
+    }
+}
+
+#[inline(always)]
+fn idct2d_square<D: SimdDescriptor>(
+    d: D,
+    data: &mut [f32],
+    n: usize,
+    storage: &mut [D::F32Vec],
+    scratch: &mut [D::F32Vec],
+) {
+    let data = D::F32Vec::make_array_slice_mut(data);
+    let chunks = n / D::F32Vec::LEN;
+    // Step 1: do column-DCTs on the first K columns.
+    for i in 0..chunks {
+        d.call(
+            #[inline(always)]
+            |_| do_idct(d, &mut data[i..], chunks, &mut storage[..n], scratch),
+        );
+    }
+    // Step 2: do column-DCTs on groups of K columns, transposing KxK blocks and
+    // swapping them in their final place as we do so.
+    for i in 0..chunks {
+        D::F32Vec::transpose_square(d, &mut data[i * n + i..], chunks);
+        for j in i + 1..chunks {
+            D::F32Vec::transpose_square(d, &mut data[j * n + i..], chunks);
+            D::F32Vec::transpose_square(d, &mut data[i * n + j..], chunks);
+            for k in 0..D::F32Vec::LEN {
+                data.swap(i * n + j + k * chunks, j * n + i + k * chunks);
+            }
+        }
+        d.call(
+            #[inline(always)]
+            |_| do_idct(d, &mut data[i..], chunks, &mut storage[..n], scratch),
+        );
+    }
+}
+
+#[inline(always)]
+fn idct2d_wide<D: SimdDescriptor>(
+    d: D,
+    data: &mut [f32],
+    c: usize,
+    r: usize,
+    storage: &mut [D::F32Vec],
+    scratch: &mut [D::F32Vec],
+) {
+    assert!(r < c);
+    let data = D::F32Vec::make_array_slice_mut(data);
+    let column_chunks = c / D::F32Vec::LEN;
+    let row_chunks = r / D::F32Vec::LEN;
+    // Step 1: do rowblock-DCTs on the first K rows, transposing KxK blocks first.
+    for i in 0..row_chunks {
+        for j in 0..column_chunks {
+            D::F32Vec::transpose_square(d, &mut data[i * c + j..], column_chunks);
+        }
+        d.call(
+            #[inline(always)]
+            |_| do_idct_rowblock(d, &mut data[i * c..], &mut storage[..c], scratch),
+        );
+    }
+    // Step 2: do column-DCTs on groups of K columns, transposing KxK blocks back.
+    for i in 0..column_chunks {
+        for j in 0..row_chunks {
+            D::F32Vec::transpose_square(d, &mut data[j * c + i..], column_chunks);
+        }
+        d.call(
+            #[inline(always)]
+            |_| do_idct(d, &mut data[i..], column_chunks, &mut storage[..r], scratch),
+        );
+    }
+}
+
+#[inline(always)]
+fn idct2d_thin<D: SimdDescriptor>(
+    d: D,
+    data: &mut [f32],
+    c: usize,
+    r: usize,
+    storage: &mut [D::F32Vec],
+    scratch: &mut [D::F32Vec],
+) {
+    assert!(r > c);
+    let data = D::F32Vec::make_array_slice_mut(data);
+    let column_chunks = c / D::F32Vec::LEN;
+    let row_chunks = r / D::F32Vec::LEN;
+    // Note: input is transposed, so in the beginning it has ROWS *columns* and COLS *rows*.
+    // Step 1: do column-DCTs on columns.
+    for i in 0..row_chunks {
+        d.call(
+            #[inline(always)]
+            |_| do_idct(d, &mut data[i..], row_chunks, &mut storage[..c], scratch),
+        );
+    }
+    // Step 2: Incrementally transpose each square sub-block of the matrix, then do a column-IDCT which also completes the transpose.
+    for i in 0..column_chunks {
+        let tr_block = |data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray], i, j, l| {
+            D::F32Vec::transpose_square(d, &mut data[i * r + j + l * column_chunks..], row_chunks)
+        };
+
+        (0..2).for_each(|l| tr_block(data, i, i, l));
+        for j in i + 1..column_chunks {
+            (0..2).for_each(|l| tr_block(data, i, j, l));
+            (0..2).for_each(|l| tr_block(data, j, i, l));
+            for l in 0..2 {
+                for k in 0..D::F32Vec::LEN {
+                    data.swap(
+                        i * r + j + k * row_chunks + l * column_chunks,
+                        j * r + i + k * row_chunks + l * column_chunks,
+                    );
+                }
+            }
+        }
+        d.call(
+            #[inline(always)]
+            |_| do_idct_trh(d, &mut data[i..], &mut storage[..r], scratch),
+        );
+    }
+}
+
+macro_rules! make_idct2d {
+    ($name: ident, $h: literal, $w: literal) => {
+        pub fn $name<D: SimdDescriptor>(d: D, data: &mut [f32]) {
+            const L: usize = if $w < $h { $h } else { $w };
+            let mut storage = [D::F32Vec::zero(d); L];
+            let mut scratch = [D::F32Vec::zero(d); L];
+            if $w == $h {
+                return d.call(
+                    #[inline(always)]
+                    |_| idct2d_square(d, data, $w, &mut storage, &mut scratch),
+                );
+            }
+            if $w > $h {
+                return d.call(
+                    #[inline(always)]
+                    |_| idct2d_wide(d, data, $w, $h, &mut storage, &mut scratch),
+                );
+            }
+            return d.call(
+                #[inline(always)]
+                |_| idct2d_thin(d, data, $w, $h, &mut storage, &mut scratch),
+            );
+        }
+    };
+}
+
+make_idct2d!(idct2d_32_64, 32, 64);
+make_idct2d!(idct2d_64_32, 64, 32);
+make_idct2d!(idct2d_64_64, 64, 64);
+make_idct2d!(idct2d_64_128, 64, 128);
+make_idct2d!(idct2d_128_64, 128, 64);
+make_idct2d!(idct2d_128_128, 128, 128);
+make_idct2d!(idct2d_128_256, 128, 256);
+make_idct2d!(idct2d_256_128, 256, 128);
+make_idct2d!(idct2d_256_256, 256, 256);
+
+#[cfg(test)]
+#[inline(always)]
+pub fn do_idct_64<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+    stride: usize,
+) {
+    let mut storage = [D::F32Vec::zero(d); 64];
+    let mut scratch = [D::F32Vec::zero(d); 64];
+    d.call(
+        #[inline(always)]
+        |_| {
+            do_idct(d, data, stride, &mut storage, &mut scratch);
+        },
+    );
+}
+
+#[cfg(test)]
+#[inline(always)]
+pub fn do_idct_128<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+    stride: usize,
+) {
+    let mut storage = [D::F32Vec::zero(d); 128];
+    let mut scratch = [D::F32Vec::zero(d); 128];
+    d.call(
+        #[inline(always)]
+        |_| {
+            do_idct(d, data, stride, &mut storage, &mut scratch);
+        },
+    );
+}
+
+#[cfg(test)]
+#[inline(always)]
+pub fn do_idct_256<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+    stride: usize,
+) {
+    let mut storage = [D::F32Vec::zero(d); 256];
+    let mut scratch = [D::F32Vec::zero(d); 256];
+    d.call(
+        #[inline(always)]
+        |_| {
+            do_idct(d, data, stride, &mut storage, &mut scratch);
+        },
+    );
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/lib.rs
new file mode 100644
index 0000000..38849b9
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/lib.rs
@@ -0,0 +1,41 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+mod idct2d;
+mod reinterpreting_dct2d;
+pub mod transform;
+pub mod transform_map;
+
+mod idct16;
+mod idct2;
+mod idct32;
+mod idct4;
+mod idct8;
+mod idct_large;
+
+use idct16::*;
+use idct2::*;
+use idct32::*;
+use idct4::*;
+use idct8::*;
+
+mod reinterpreting_dct16;
+mod reinterpreting_dct2;
+mod reinterpreting_dct32;
+mod reinterpreting_dct4;
+mod reinterpreting_dct8;
+
+use reinterpreting_dct16::*;
+use reinterpreting_dct2::*;
+use reinterpreting_dct32::*;
+use reinterpreting_dct4::*;
+use reinterpreting_dct8::*;
+
+pub use idct2d::*;
+pub use idct_large::*;
+pub use reinterpreting_dct2d::*;
+
+#[cfg(test)]
+mod tests;
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/reinterpreting_dct16.rs b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/reinterpreting_dct16.rs
new file mode 100644
index 0000000..f3bc267e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/reinterpreting_dct16.rs
@@ -0,0 +1,385 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(clippy::type_complexity)]
+#![allow(clippy::erasing_op)]
+#![allow(clippy::identity_op)]
+use jxl_simd::{F32SimdVec, SimdDescriptor};
+
+#[allow(clippy::too_many_arguments)]
+#[allow(clippy::excessive_precision)]
+#[inline(always)]
+pub(super) fn reinterpreting_dct_16<D: SimdDescriptor>(
+    d: D,
+    v0: D::F32Vec,
+    v1: D::F32Vec,
+    v2: D::F32Vec,
+    v3: D::F32Vec,
+    v4: D::F32Vec,
+    v5: D::F32Vec,
+    v6: D::F32Vec,
+    v7: D::F32Vec,
+    v8: D::F32Vec,
+    v9: D::F32Vec,
+    v10: D::F32Vec,
+    v11: D::F32Vec,
+    v12: D::F32Vec,
+    v13: D::F32Vec,
+    v14: D::F32Vec,
+    v15: D::F32Vec,
+) -> (
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+) {
+    let v16 = v0 + v15;
+    let v17 = v1 + v14;
+    let v18 = v2 + v13;
+    let v19 = v3 + v12;
+    let v20 = v4 + v11;
+    let v21 = v5 + v10;
+    let v22 = v6 + v9;
+    let v23 = v7 + v8;
+    let v24 = v16 + v23;
+    let v25 = v17 + v22;
+    let v26 = v18 + v21;
+    let v27 = v19 + v20;
+    let v28 = v24 + v27;
+    let v29 = v25 + v26;
+    let v30 = v28 + v29;
+    let v31 = v28 - v29;
+    let v32 = v24 - v27;
+    let v33 = v25 - v26;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let v34 = v32 * mul;
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let v35 = v33 * mul;
+    let v36 = v34 + v35;
+    let v37 = v34 - v35;
+    let v38 = v36.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v37);
+    let v39 = v16 - v23;
+    let v40 = v17 - v22;
+    let v41 = v18 - v21;
+    let v42 = v19 - v20;
+    let mul = D::F32Vec::splat(d, 0.5097955791041592);
+    let v43 = v39 * mul;
+    let mul = D::F32Vec::splat(d, 0.6013448869350453);
+    let v44 = v40 * mul;
+    let mul = D::F32Vec::splat(d, 0.8999762231364156);
+    let v45 = v41 * mul;
+    let mul = D::F32Vec::splat(d, 2.5629154477415055);
+    let v46 = v42 * mul;
+    let v47 = v43 + v46;
+    let v48 = v44 + v45;
+    let v49 = v47 + v48;
+    let v50 = v47 - v48;
+    let v51 = v43 - v46;
+    let v52 = v44 - v45;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let v53 = v51 * mul;
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let v54 = v52 * mul;
+    let v55 = v53 + v54;
+    let v56 = v53 - v54;
+    let v57 = v55.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v56);
+    let v58 = v49.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v57);
+    let v59 = v57 + v50;
+    let v60 = v50 + v56;
+    let v61 = v0 - v15;
+    let v62 = v1 - v14;
+    let v63 = v2 - v13;
+    let v64 = v3 - v12;
+    let v65 = v4 - v11;
+    let v66 = v5 - v10;
+    let v67 = v6 - v9;
+    let v68 = v7 - v8;
+    let mul = D::F32Vec::splat(d, 0.5024192861881557);
+    let v69 = v61 * mul;
+    let mul = D::F32Vec::splat(d, 0.5224986149396889);
+    let v70 = v62 * mul;
+    let mul = D::F32Vec::splat(d, 0.5669440348163577);
+    let v71 = v63 * mul;
+    let mul = D::F32Vec::splat(d, 0.6468217833599901);
+    let v72 = v64 * mul;
+    let mul = D::F32Vec::splat(d, 0.7881546234512502);
+    let v73 = v65 * mul;
+    let mul = D::F32Vec::splat(d, 1.0606776859903471);
+    let v74 = v66 * mul;
+    let mul = D::F32Vec::splat(d, 1.7224470982383342);
+    let v75 = v67 * mul;
+    let mul = D::F32Vec::splat(d, 5.1011486186891553);
+    let v76 = v68 * mul;
+    let v77 = v69 + v76;
+    let v78 = v70 + v75;
+    let v79 = v71 + v74;
+    let v80 = v72 + v73;
+    let v81 = v77 + v80;
+    let v82 = v78 + v79;
+    let v83 = v81 + v82;
+    let v84 = v81 - v82;
+    let v85 = v77 - v80;
+    let v86 = v78 - v79;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let v87 = v85 * mul;
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let v88 = v86 * mul;
+    let v89 = v87 + v88;
+    let v90 = v87 - v88;
+    let v91 = v89.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v90);
+    let v92 = v69 - v76;
+    let v93 = v70 - v75;
+    let v94 = v71 - v74;
+    let v95 = v72 - v73;
+    let mul = D::F32Vec::splat(d, 0.5097955791041592);
+    let v96 = v92 * mul;
+    let mul = D::F32Vec::splat(d, 0.6013448869350453);
+    let v97 = v93 * mul;
+    let mul = D::F32Vec::splat(d, 0.8999762231364156);
+    let v98 = v94 * mul;
+    let mul = D::F32Vec::splat(d, 2.5629154477415055);
+    let v99 = v95 * mul;
+    let v100 = v96 + v99;
+    let v101 = v97 + v98;
+    let v102 = v100 + v101;
+    let v103 = v100 - v101;
+    let v104 = v96 - v99;
+    let v105 = v97 - v98;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let v106 = v104 * mul;
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let v107 = v105 * mul;
+    let v108 = v106 + v107;
+    let v109 = v106 - v107;
+    let v110 = v108.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v109);
+    let v111 = v102.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v110);
+    let v112 = v110 + v103;
+    let v113 = v103 + v109;
+    let v114 = v83.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v111);
+    let v115 = v111 + v91;
+    let v116 = v91 + v112;
+    let v117 = v112 + v84;
+    let v118 = v84 + v113;
+    let v119 = v113 + v90;
+    let v120 = v90 + v109;
+    (
+        v30 * D::F32Vec::splat(d, 0.062500),
+        v114 * D::F32Vec::splat(d, 0.062599),
+        v58 * D::F32Vec::splat(d, 0.062897),
+        v115 * D::F32Vec::splat(d, 0.063398),
+        v38 * D::F32Vec::splat(d, 0.064110),
+        v116 * D::F32Vec::splat(d, 0.065042),
+        v59 * D::F32Vec::splat(d, 0.066206),
+        v117 * D::F32Vec::splat(d, 0.067622),
+        v31 * D::F32Vec::splat(d, 0.069309),
+        v118 * D::F32Vec::splat(d, 0.071294),
+        v60 * D::F32Vec::splat(d, 0.073611),
+        v119 * D::F32Vec::splat(d, 0.076300),
+        v37 * D::F32Vec::splat(d, 0.079410),
+        v120 * D::F32Vec::splat(d, 0.083003),
+        v56 * D::F32Vec::splat(d, 0.087156),
+        v109 * D::F32Vec::splat(d, 0.091963),
+    )
+}
+
+#[inline(always)]
+pub(super) fn do_reinterpreting_dct_16<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+    stride: usize,
+) {
+    assert!(data.len() > 15 * stride);
+    let mut v0 = D::F32Vec::load_array(d, &data[0 * stride]);
+    let mut v1 = D::F32Vec::load_array(d, &data[1 * stride]);
+    let mut v2 = D::F32Vec::load_array(d, &data[2 * stride]);
+    let mut v3 = D::F32Vec::load_array(d, &data[3 * stride]);
+    let mut v4 = D::F32Vec::load_array(d, &data[4 * stride]);
+    let mut v5 = D::F32Vec::load_array(d, &data[5 * stride]);
+    let mut v6 = D::F32Vec::load_array(d, &data[6 * stride]);
+    let mut v7 = D::F32Vec::load_array(d, &data[7 * stride]);
+    let mut v8 = D::F32Vec::load_array(d, &data[8 * stride]);
+    let mut v9 = D::F32Vec::load_array(d, &data[9 * stride]);
+    let mut v10 = D::F32Vec::load_array(d, &data[10 * stride]);
+    let mut v11 = D::F32Vec::load_array(d, &data[11 * stride]);
+    let mut v12 = D::F32Vec::load_array(d, &data[12 * stride]);
+    let mut v13 = D::F32Vec::load_array(d, &data[13 * stride]);
+    let mut v14 = D::F32Vec::load_array(d, &data[14 * stride]);
+    let mut v15 = D::F32Vec::load_array(d, &data[15 * stride]);
+    (
+        v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+    ) = reinterpreting_dct_16(
+        d, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+    );
+    v0.store_array(&mut data[0 * stride]);
+    v1.store_array(&mut data[1 * stride]);
+    v2.store_array(&mut data[2 * stride]);
+    v3.store_array(&mut data[3 * stride]);
+    v4.store_array(&mut data[4 * stride]);
+    v5.store_array(&mut data[5 * stride]);
+    v6.store_array(&mut data[6 * stride]);
+    v7.store_array(&mut data[7 * stride]);
+    v8.store_array(&mut data[8 * stride]);
+    v9.store_array(&mut data[9 * stride]);
+    v10.store_array(&mut data[10 * stride]);
+    v11.store_array(&mut data[11 * stride]);
+    v12.store_array(&mut data[12 * stride]);
+    v13.store_array(&mut data[13 * stride]);
+    v14.store_array(&mut data[14 * stride]);
+    v15.store_array(&mut data[15 * stride]);
+}
+
+#[inline(always)]
+pub(super) fn do_reinterpreting_dct_16_rowblock<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+) {
+    assert!(data.len() >= 16);
+    const { assert!(16usize.is_multiple_of(D::F32Vec::LEN)) };
+    let row_stride = 16 / D::F32Vec::LEN;
+    let mut v0 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (0 % D::F32Vec::LEN) + (0 / D::F32Vec::LEN)],
+    );
+    let mut v1 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (1 % D::F32Vec::LEN) + (1 / D::F32Vec::LEN)],
+    );
+    let mut v2 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (2 % D::F32Vec::LEN) + (2 / D::F32Vec::LEN)],
+    );
+    let mut v3 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (3 % D::F32Vec::LEN) + (3 / D::F32Vec::LEN)],
+    );
+    let mut v4 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (4 % D::F32Vec::LEN) + (4 / D::F32Vec::LEN)],
+    );
+    let mut v5 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (5 % D::F32Vec::LEN) + (5 / D::F32Vec::LEN)],
+    );
+    let mut v6 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (6 % D::F32Vec::LEN) + (6 / D::F32Vec::LEN)],
+    );
+    let mut v7 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (7 % D::F32Vec::LEN) + (7 / D::F32Vec::LEN)],
+    );
+    let mut v8 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (8 % D::F32Vec::LEN) + (8 / D::F32Vec::LEN)],
+    );
+    let mut v9 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (9 % D::F32Vec::LEN) + (9 / D::F32Vec::LEN)],
+    );
+    let mut v10 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (10 % D::F32Vec::LEN) + (10 / D::F32Vec::LEN)],
+    );
+    let mut v11 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (11 % D::F32Vec::LEN) + (11 / D::F32Vec::LEN)],
+    );
+    let mut v12 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (12 % D::F32Vec::LEN) + (12 / D::F32Vec::LEN)],
+    );
+    let mut v13 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (13 % D::F32Vec::LEN) + (13 / D::F32Vec::LEN)],
+    );
+    let mut v14 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (14 % D::F32Vec::LEN) + (14 / D::F32Vec::LEN)],
+    );
+    let mut v15 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (15 % D::F32Vec::LEN) + (15 / D::F32Vec::LEN)],
+    );
+    (
+        v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+    ) = reinterpreting_dct_16(
+        d, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+    );
+    v0.store_array(&mut data[row_stride * (0 % D::F32Vec::LEN) + (0 / D::F32Vec::LEN)]);
+    v1.store_array(&mut data[row_stride * (1 % D::F32Vec::LEN) + (1 / D::F32Vec::LEN)]);
+    v2.store_array(&mut data[row_stride * (2 % D::F32Vec::LEN) + (2 / D::F32Vec::LEN)]);
+    v3.store_array(&mut data[row_stride * (3 % D::F32Vec::LEN) + (3 / D::F32Vec::LEN)]);
+    v4.store_array(&mut data[row_stride * (4 % D::F32Vec::LEN) + (4 / D::F32Vec::LEN)]);
+    v5.store_array(&mut data[row_stride * (5 % D::F32Vec::LEN) + (5 / D::F32Vec::LEN)]);
+    v6.store_array(&mut data[row_stride * (6 % D::F32Vec::LEN) + (6 / D::F32Vec::LEN)]);
+    v7.store_array(&mut data[row_stride * (7 % D::F32Vec::LEN) + (7 / D::F32Vec::LEN)]);
+    v8.store_array(&mut data[row_stride * (8 % D::F32Vec::LEN) + (8 / D::F32Vec::LEN)]);
+    v9.store_array(&mut data[row_stride * (9 % D::F32Vec::LEN) + (9 / D::F32Vec::LEN)]);
+    v10.store_array(&mut data[row_stride * (10 % D::F32Vec::LEN) + (10 / D::F32Vec::LEN)]);
+    v11.store_array(&mut data[row_stride * (11 % D::F32Vec::LEN) + (11 / D::F32Vec::LEN)]);
+    v12.store_array(&mut data[row_stride * (12 % D::F32Vec::LEN) + (12 / D::F32Vec::LEN)]);
+    v13.store_array(&mut data[row_stride * (13 % D::F32Vec::LEN) + (13 / D::F32Vec::LEN)]);
+    v14.store_array(&mut data[row_stride * (14 % D::F32Vec::LEN) + (14 / D::F32Vec::LEN)]);
+    v15.store_array(&mut data[row_stride * (15 % D::F32Vec::LEN) + (15 / D::F32Vec::LEN)]);
+}
+
+#[inline(always)]
+pub(super) fn do_reinterpreting_dct_16_trh<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+) {
+    let row_stride = 8 / D::F32Vec::LEN;
+    assert!(data.len() > 15 * row_stride);
+    const { assert!(8usize.is_multiple_of(D::F32Vec::LEN)) };
+    let mut v0 = D::F32Vec::load_array(d, &data[row_stride * 0]);
+    let mut v1 = D::F32Vec::load_array(d, &data[row_stride * 1]);
+    let mut v2 = D::F32Vec::load_array(d, &data[row_stride * 2]);
+    let mut v3 = D::F32Vec::load_array(d, &data[row_stride * 3]);
+    let mut v4 = D::F32Vec::load_array(d, &data[row_stride * 4]);
+    let mut v5 = D::F32Vec::load_array(d, &data[row_stride * 5]);
+    let mut v6 = D::F32Vec::load_array(d, &data[row_stride * 6]);
+    let mut v7 = D::F32Vec::load_array(d, &data[row_stride * 7]);
+    let mut v8 = D::F32Vec::load_array(d, &data[row_stride * 8]);
+    let mut v9 = D::F32Vec::load_array(d, &data[row_stride * 9]);
+    let mut v10 = D::F32Vec::load_array(d, &data[row_stride * 10]);
+    let mut v11 = D::F32Vec::load_array(d, &data[row_stride * 11]);
+    let mut v12 = D::F32Vec::load_array(d, &data[row_stride * 12]);
+    let mut v13 = D::F32Vec::load_array(d, &data[row_stride * 13]);
+    let mut v14 = D::F32Vec::load_array(d, &data[row_stride * 14]);
+    let mut v15 = D::F32Vec::load_array(d, &data[row_stride * 15]);
+    (
+        v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+    ) = reinterpreting_dct_16(
+        d, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+    );
+    v0.store_array(&mut data[row_stride * 0]);
+    v8.store_array(&mut data[row_stride * 1]);
+    v1.store_array(&mut data[row_stride * 2]);
+    v9.store_array(&mut data[row_stride * 3]);
+    v2.store_array(&mut data[row_stride * 4]);
+    v10.store_array(&mut data[row_stride * 5]);
+    v3.store_array(&mut data[row_stride * 6]);
+    v11.store_array(&mut data[row_stride * 7]);
+    v4.store_array(&mut data[row_stride * 8]);
+    v12.store_array(&mut data[row_stride * 9]);
+    v5.store_array(&mut data[row_stride * 10]);
+    v13.store_array(&mut data[row_stride * 11]);
+    v6.store_array(&mut data[row_stride * 12]);
+    v14.store_array(&mut data[row_stride * 13]);
+    v7.store_array(&mut data[row_stride * 14]);
+    v15.store_array(&mut data[row_stride * 15]);
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/reinterpreting_dct2.rs b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/reinterpreting_dct2.rs
new file mode 100644
index 0000000..f5caab0
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/reinterpreting_dct2.rs
@@ -0,0 +1,39 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(clippy::type_complexity)]
+#![allow(clippy::erasing_op)]
+#![allow(clippy::identity_op)]
+use jxl_simd::{F32SimdVec, SimdDescriptor};
+
+#[allow(clippy::too_many_arguments)]
+#[allow(clippy::excessive_precision)]
+#[inline(always)]
+pub(super) fn reinterpreting_dct_2<D: SimdDescriptor>(
+    d: D,
+    v0: D::F32Vec,
+    v1: D::F32Vec,
+) -> (D::F32Vec, D::F32Vec) {
+    let v2 = v0 + v1;
+    let v3 = v0 - v1;
+    (
+        v2 * D::F32Vec::splat(d, 0.500000),
+        v3 * D::F32Vec::splat(d, 0.554469),
+    )
+}
+
+#[inline(always)]
+pub(super) fn do_reinterpreting_dct_2<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+    stride: usize,
+) {
+    assert!(data.len() > 1 * stride);
+    let mut v0 = D::F32Vec::load_array(d, &data[0 * stride]);
+    let mut v1 = D::F32Vec::load_array(d, &data[1 * stride]);
+    (v0, v1) = reinterpreting_dct_2(d, v0, v1);
+    v0.store_array(&mut data[0 * stride]);
+    v1.store_array(&mut data[1 * stride]);
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/reinterpreting_dct2d.rs b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/reinterpreting_dct2d.rs
new file mode 100644
index 0000000..feefc7c
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/reinterpreting_dct2d.rs
@@ -0,0 +1,645 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::*;
+use jxl_simd::{F32SimdVec, SimdDescriptor};
+
+#[inline(always)]
+fn reinterpreting_dct2d_1_2_impl<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    assert_eq!(data.len(), 2, "Data length mismatch");
+    assert!(output.len() > 1);
+    const { assert!(1usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(2usize.is_multiple_of(D::F32Vec::LEN)) };
+    {
+        let data = D::F32Vec::make_array_slice_mut(data);
+        do_reinterpreting_dct_2(d, data, 1);
+    }
+    for y in 0..1 {
+        for x in 0..2 {
+            output[y * 16 + x] = data[y * 2 + x];
+        }
+    }
+}
+
+#[inline(always)]
+fn reinterpreting_dct2d_2_1_impl<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    assert_eq!(data.len(), 2, "Data length mismatch");
+    assert!(output.len() > 1);
+    const { assert!(2usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(1usize.is_multiple_of(D::F32Vec::LEN)) };
+    {
+        let data = D::F32Vec::make_array_slice_mut(data);
+        do_reinterpreting_dct_2(d, data, 1);
+    }
+    for y in 0..1 {
+        for x in 0..2 {
+            output[y * 16 + x] = data[y * 2 + x];
+        }
+    }
+}
+
+#[inline(always)]
+fn reinterpreting_dct2d_1_4_impl<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    assert_eq!(data.len(), 4, "Data length mismatch");
+    assert!(output.len() > 3);
+    const { assert!(1usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(4usize.is_multiple_of(D::F32Vec::LEN)) };
+    {
+        let data = D::F32Vec::make_array_slice_mut(data);
+        do_reinterpreting_dct_4(d, data, 1);
+    }
+    for y in 0..1 {
+        for x in 0..4 {
+            output[y * 32 + x] = data[y * 4 + x];
+        }
+    }
+}
+
+#[inline(always)]
+fn reinterpreting_dct2d_4_1_impl<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    assert_eq!(data.len(), 4, "Data length mismatch");
+    assert!(output.len() > 3);
+    const { assert!(4usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(1usize.is_multiple_of(D::F32Vec::LEN)) };
+    {
+        let data = D::F32Vec::make_array_slice_mut(data);
+        do_reinterpreting_dct_4(d, data, 1);
+    }
+    for y in 0..1 {
+        for x in 0..4 {
+            output[y * 32 + x] = data[y * 4 + x];
+        }
+    }
+}
+
+#[inline(always)]
+fn reinterpreting_dct2d_2_2_impl<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    assert_eq!(data.len(), 4, "Data length mismatch");
+    assert!(output.len() > 17);
+    const { assert!(2usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(2usize.is_multiple_of(D::F32Vec::LEN)) };
+    {
+        let data = D::F32Vec::make_array_slice_mut(data);
+        let chunks = 2 / D::F32Vec::LEN;
+        for i in 0..chunks {
+            do_reinterpreting_dct_2(d, &mut data[i..], chunks);
+        }
+        for i in 0..chunks {
+            D::F32Vec::transpose_square(d, &mut data[i * 2 + i..], chunks);
+            for j in i + 1..chunks {
+                D::F32Vec::transpose_square(d, &mut data[j * 2 + i..], chunks);
+                D::F32Vec::transpose_square(d, &mut data[i * 2 + j..], chunks);
+                for k in 0..D::F32Vec::LEN {
+                    data.swap(i * 2 + j + k * chunks, j * 2 + i + k * chunks);
+                }
+            }
+            do_reinterpreting_dct_2(d, &mut data[i..], chunks);
+        }
+    }
+    for y in 0..2 {
+        for x in 0..2 {
+            output[y * 16 + x] = data[y * 2 + x];
+        }
+    }
+}
+
+#[inline(always)]
+fn reinterpreting_dct2d_2_4_impl<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    assert_eq!(data.len(), 8, "Data length mismatch");
+    assert!(output.len() > 35);
+    const { assert!(2usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(4usize.is_multiple_of(D::F32Vec::LEN)) };
+    {
+        let data = D::F32Vec::make_array_slice_mut(data);
+        let column_chunks = 4 / D::F32Vec::LEN;
+        let row_chunks = 2 / D::F32Vec::LEN;
+        for i in 0..row_chunks {
+            for j in 0..column_chunks {
+                D::F32Vec::transpose_square(d, &mut data[i * 4 + j..], column_chunks);
+            }
+            do_reinterpreting_dct_4_rowblock(d, &mut data[i * 4..]);
+        }
+        for i in 0..column_chunks {
+            for j in 0..row_chunks {
+                D::F32Vec::transpose_square(d, &mut data[j * 4 + i..], column_chunks);
+            }
+            do_reinterpreting_dct_2(d, &mut data[i..], column_chunks)
+        }
+    }
+    for y in 0..2 {
+        for x in 0..4 {
+            output[y * 32 + x] = data[y * 4 + x];
+        }
+    }
+}
+
+#[inline(always)]
+fn reinterpreting_dct2d_4_2_impl<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    assert_eq!(data.len(), 8, "Data length mismatch");
+    assert!(output.len() > 35);
+    const { assert!(4usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(2usize.is_multiple_of(D::F32Vec::LEN)) };
+    {
+        let data = D::F32Vec::make_array_slice_mut(data);
+        let column_chunks = 2 / D::F32Vec::LEN;
+        let row_chunks = 4 / D::F32Vec::LEN;
+        for i in 0..column_chunks {
+            do_reinterpreting_dct_4_trh(d, &mut data[i..]);
+        }
+        for l in 0..2 {
+            for i in 0..column_chunks {
+                let tr_block =
+                    |data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray], i, j, l| {
+                        D::F32Vec::transpose_square(
+                            d,
+                            &mut data[i * 4 + j + l * column_chunks..],
+                            row_chunks,
+                        )
+                    };
+                tr_block(data, i, i, l);
+                for j in i + 1..column_chunks {
+                    tr_block(data, i, j, l);
+                    tr_block(data, j, i, l);
+                    for k in 0..D::F32Vec::LEN {
+                        data.swap(
+                            i * 4 + j + k * row_chunks + l * column_chunks,
+                            j * 4 + i + k * row_chunks + l * column_chunks,
+                        );
+                    }
+                }
+                do_reinterpreting_dct_2(d, &mut data[i + l * column_chunks..], row_chunks);
+            }
+        }
+    }
+    for y in 0..2 {
+        for x in 0..4 {
+            output[y * 32 + x] = data[y * 4 + x];
+        }
+    }
+}
+
+#[inline(always)]
+fn reinterpreting_dct2d_4_4_impl<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    assert_eq!(data.len(), 16, "Data length mismatch");
+    assert!(output.len() > 99);
+    const { assert!(4usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(4usize.is_multiple_of(D::F32Vec::LEN)) };
+    {
+        let data = D::F32Vec::make_array_slice_mut(data);
+        let chunks = 4 / D::F32Vec::LEN;
+        for i in 0..chunks {
+            do_reinterpreting_dct_4(d, &mut data[i..], chunks);
+        }
+        for i in 0..chunks {
+            D::F32Vec::transpose_square(d, &mut data[i * 4 + i..], chunks);
+            for j in i + 1..chunks {
+                D::F32Vec::transpose_square(d, &mut data[j * 4 + i..], chunks);
+                D::F32Vec::transpose_square(d, &mut data[i * 4 + j..], chunks);
+                for k in 0..D::F32Vec::LEN {
+                    data.swap(i * 4 + j + k * chunks, j * 4 + i + k * chunks);
+                }
+            }
+            do_reinterpreting_dct_4(d, &mut data[i..], chunks);
+        }
+    }
+    for y in 0..4 {
+        for x in 0..4 {
+            output[y * 32 + x] = data[y * 4 + x];
+        }
+    }
+}
+
+#[inline(always)]
+fn reinterpreting_dct2d_4_8_impl<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    assert_eq!(data.len(), 32, "Data length mismatch");
+    assert!(output.len() > 199);
+    const { assert!(4usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(8usize.is_multiple_of(D::F32Vec::LEN)) };
+    {
+        let data = D::F32Vec::make_array_slice_mut(data);
+        let column_chunks = 8 / D::F32Vec::LEN;
+        let row_chunks = 4 / D::F32Vec::LEN;
+        for i in 0..row_chunks {
+            for j in 0..column_chunks {
+                D::F32Vec::transpose_square(d, &mut data[i * 8 + j..], column_chunks);
+            }
+            do_reinterpreting_dct_8_rowblock(d, &mut data[i * 8..]);
+        }
+        for i in 0..column_chunks {
+            for j in 0..row_chunks {
+                D::F32Vec::transpose_square(d, &mut data[j * 8 + i..], column_chunks);
+            }
+            do_reinterpreting_dct_4(d, &mut data[i..], column_chunks)
+        }
+    }
+    for y in 0..4 {
+        for x in 0..8 {
+            output[y * 64 + x] = data[y * 8 + x];
+        }
+    }
+}
+
+#[inline(always)]
+fn reinterpreting_dct2d_8_4_impl<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    assert_eq!(data.len(), 32, "Data length mismatch");
+    assert!(output.len() > 199);
+    const { assert!(8usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(4usize.is_multiple_of(D::F32Vec::LEN)) };
+    {
+        let data = D::F32Vec::make_array_slice_mut(data);
+        let column_chunks = 4 / D::F32Vec::LEN;
+        let row_chunks = 8 / D::F32Vec::LEN;
+        for i in 0..column_chunks {
+            do_reinterpreting_dct_8_trh(d, &mut data[i..]);
+        }
+        for l in 0..2 {
+            for i in 0..column_chunks {
+                let tr_block =
+                    |data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray], i, j, l| {
+                        D::F32Vec::transpose_square(
+                            d,
+                            &mut data[i * 8 + j + l * column_chunks..],
+                            row_chunks,
+                        )
+                    };
+                tr_block(data, i, i, l);
+                for j in i + 1..column_chunks {
+                    tr_block(data, i, j, l);
+                    tr_block(data, j, i, l);
+                    for k in 0..D::F32Vec::LEN {
+                        data.swap(
+                            i * 8 + j + k * row_chunks + l * column_chunks,
+                            j * 8 + i + k * row_chunks + l * column_chunks,
+                        );
+                    }
+                }
+                do_reinterpreting_dct_4(d, &mut data[i + l * column_chunks..], row_chunks);
+            }
+        }
+    }
+    for y in 0..4 {
+        for x in 0..8 {
+            output[y * 64 + x] = data[y * 8 + x];
+        }
+    }
+}
+
+#[inline(always)]
+fn reinterpreting_dct2d_8_8_impl<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    assert_eq!(data.len(), 64, "Data length mismatch");
+    assert!(output.len() > 455);
+    const { assert!(8usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(8usize.is_multiple_of(D::F32Vec::LEN)) };
+    {
+        let data = D::F32Vec::make_array_slice_mut(data);
+        let chunks = 8 / D::F32Vec::LEN;
+        for i in 0..chunks {
+            do_reinterpreting_dct_8(d, &mut data[i..], chunks);
+        }
+        for i in 0..chunks {
+            D::F32Vec::transpose_square(d, &mut data[i * 8 + i..], chunks);
+            for j in i + 1..chunks {
+                D::F32Vec::transpose_square(d, &mut data[j * 8 + i..], chunks);
+                D::F32Vec::transpose_square(d, &mut data[i * 8 + j..], chunks);
+                for k in 0..D::F32Vec::LEN {
+                    data.swap(i * 8 + j + k * chunks, j * 8 + i + k * chunks);
+                }
+            }
+            do_reinterpreting_dct_8(d, &mut data[i..], chunks);
+        }
+    }
+    for y in 0..8 {
+        for x in 0..8 {
+            output[y * 64 + x] = data[y * 8 + x];
+        }
+    }
+}
+
+#[inline(always)]
+fn reinterpreting_dct2d_8_16_impl<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    assert_eq!(data.len(), 128, "Data length mismatch");
+    assert!(output.len() > 911);
+    const { assert!(8usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(16usize.is_multiple_of(D::F32Vec::LEN)) };
+    {
+        let data = D::F32Vec::make_array_slice_mut(data);
+        let column_chunks = 16 / D::F32Vec::LEN;
+        let row_chunks = 8 / D::F32Vec::LEN;
+        for i in 0..row_chunks {
+            for j in 0..column_chunks {
+                D::F32Vec::transpose_square(d, &mut data[i * 16 + j..], column_chunks);
+            }
+            do_reinterpreting_dct_16_rowblock(d, &mut data[i * 16..]);
+        }
+        for i in 0..column_chunks {
+            for j in 0..row_chunks {
+                D::F32Vec::transpose_square(d, &mut data[j * 16 + i..], column_chunks);
+            }
+            do_reinterpreting_dct_8(d, &mut data[i..], column_chunks)
+        }
+    }
+    for y in 0..8 {
+        for x in 0..16 {
+            output[y * 128 + x] = data[y * 16 + x];
+        }
+    }
+}
+
+#[inline(always)]
+fn reinterpreting_dct2d_16_8_impl<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    assert_eq!(data.len(), 128, "Data length mismatch");
+    assert!(output.len() > 911);
+    const { assert!(16usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(8usize.is_multiple_of(D::F32Vec::LEN)) };
+    {
+        let data = D::F32Vec::make_array_slice_mut(data);
+        let column_chunks = 8 / D::F32Vec::LEN;
+        let row_chunks = 16 / D::F32Vec::LEN;
+        for i in 0..column_chunks {
+            do_reinterpreting_dct_16_trh(d, &mut data[i..]);
+        }
+        for l in 0..2 {
+            for i in 0..column_chunks {
+                let tr_block =
+                    |data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray], i, j, l| {
+                        D::F32Vec::transpose_square(
+                            d,
+                            &mut data[i * 16 + j + l * column_chunks..],
+                            row_chunks,
+                        )
+                    };
+                tr_block(data, i, i, l);
+                for j in i + 1..column_chunks {
+                    tr_block(data, i, j, l);
+                    tr_block(data, j, i, l);
+                    for k in 0..D::F32Vec::LEN {
+                        data.swap(
+                            i * 16 + j + k * row_chunks + l * column_chunks,
+                            j * 16 + i + k * row_chunks + l * column_chunks,
+                        );
+                    }
+                }
+                do_reinterpreting_dct_8(d, &mut data[i + l * column_chunks..], row_chunks);
+            }
+        }
+    }
+    for y in 0..8 {
+        for x in 0..16 {
+            output[y * 128 + x] = data[y * 16 + x];
+        }
+    }
+}
+
+#[inline(always)]
+fn reinterpreting_dct2d_16_16_impl<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    assert_eq!(data.len(), 256, "Data length mismatch");
+    assert!(output.len() > 1935);
+    const { assert!(16usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(16usize.is_multiple_of(D::F32Vec::LEN)) };
+    {
+        let data = D::F32Vec::make_array_slice_mut(data);
+        let chunks = 16 / D::F32Vec::LEN;
+        for i in 0..chunks {
+            do_reinterpreting_dct_16(d, &mut data[i..], chunks);
+        }
+        for i in 0..chunks {
+            D::F32Vec::transpose_square(d, &mut data[i * 16 + i..], chunks);
+            for j in i + 1..chunks {
+                D::F32Vec::transpose_square(d, &mut data[j * 16 + i..], chunks);
+                D::F32Vec::transpose_square(d, &mut data[i * 16 + j..], chunks);
+                for k in 0..D::F32Vec::LEN {
+                    data.swap(i * 16 + j + k * chunks, j * 16 + i + k * chunks);
+                }
+            }
+            do_reinterpreting_dct_16(d, &mut data[i..], chunks);
+        }
+    }
+    for y in 0..16 {
+        for x in 0..16 {
+            output[y * 128 + x] = data[y * 16 + x];
+        }
+    }
+}
+
+#[inline(always)]
+fn reinterpreting_dct2d_16_32_impl<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    assert_eq!(data.len(), 512, "Data length mismatch");
+    assert!(output.len() > 3871);
+    const { assert!(16usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(32usize.is_multiple_of(D::F32Vec::LEN)) };
+    {
+        let data = D::F32Vec::make_array_slice_mut(data);
+        let column_chunks = 32 / D::F32Vec::LEN;
+        let row_chunks = 16 / D::F32Vec::LEN;
+        for i in 0..row_chunks {
+            for j in 0..column_chunks {
+                D::F32Vec::transpose_square(d, &mut data[i * 32 + j..], column_chunks);
+            }
+            do_reinterpreting_dct_32_rowblock(d, &mut data[i * 32..]);
+        }
+        for i in 0..column_chunks {
+            for j in 0..row_chunks {
+                D::F32Vec::transpose_square(d, &mut data[j * 32 + i..], column_chunks);
+            }
+            do_reinterpreting_dct_16(d, &mut data[i..], column_chunks)
+        }
+    }
+    for y in 0..16 {
+        for x in 0..32 {
+            output[y * 256 + x] = data[y * 32 + x];
+        }
+    }
+}
+
+#[inline(always)]
+fn reinterpreting_dct2d_32_16_impl<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    assert_eq!(data.len(), 512, "Data length mismatch");
+    assert!(output.len() > 3871);
+    const { assert!(32usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(16usize.is_multiple_of(D::F32Vec::LEN)) };
+    {
+        let data = D::F32Vec::make_array_slice_mut(data);
+        let column_chunks = 16 / D::F32Vec::LEN;
+        let row_chunks = 32 / D::F32Vec::LEN;
+        for i in 0..column_chunks {
+            do_reinterpreting_dct_32_trh(d, &mut data[i..]);
+        }
+        for l in 0..2 {
+            for i in 0..column_chunks {
+                let tr_block =
+                    |data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray], i, j, l| {
+                        D::F32Vec::transpose_square(
+                            d,
+                            &mut data[i * 32 + j + l * column_chunks..],
+                            row_chunks,
+                        )
+                    };
+                tr_block(data, i, i, l);
+                for j in i + 1..column_chunks {
+                    tr_block(data, i, j, l);
+                    tr_block(data, j, i, l);
+                    for k in 0..D::F32Vec::LEN {
+                        data.swap(
+                            i * 32 + j + k * row_chunks + l * column_chunks,
+                            j * 32 + i + k * row_chunks + l * column_chunks,
+                        );
+                    }
+                }
+                do_reinterpreting_dct_16(d, &mut data[i + l * column_chunks..], row_chunks);
+            }
+        }
+    }
+    for y in 0..16 {
+        for x in 0..32 {
+            output[y * 256 + x] = data[y * 32 + x];
+        }
+    }
+}
+
+#[inline(always)]
+fn reinterpreting_dct2d_32_32_impl<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    assert_eq!(data.len(), 1024, "Data length mismatch");
+    assert!(output.len() > 7967);
+    const { assert!(32usize.is_multiple_of(D::F32Vec::LEN)) };
+    const { assert!(32usize.is_multiple_of(D::F32Vec::LEN)) };
+    {
+        let data = D::F32Vec::make_array_slice_mut(data);
+        let chunks = 32 / D::F32Vec::LEN;
+        for i in 0..chunks {
+            do_reinterpreting_dct_32(d, &mut data[i..], chunks);
+        }
+        for i in 0..chunks {
+            D::F32Vec::transpose_square(d, &mut data[i * 32 + i..], chunks);
+            for j in i + 1..chunks {
+                D::F32Vec::transpose_square(d, &mut data[j * 32 + i..], chunks);
+                D::F32Vec::transpose_square(d, &mut data[i * 32 + j..], chunks);
+                for k in 0..D::F32Vec::LEN {
+                    data.swap(i * 32 + j + k * chunks, j * 32 + i + k * chunks);
+                }
+            }
+            do_reinterpreting_dct_32(d, &mut data[i..], chunks);
+        }
+    }
+    for y in 0..32 {
+        for x in 0..32 {
+            output[y * 256 + x] = data[y * 32 + x];
+        }
+    }
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn reinterpreting_dct2d_1_2<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    let d = jxl_simd::ScalarDescriptor::new().unwrap();
+    reinterpreting_dct2d_1_2_impl(d, data, output)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn reinterpreting_dct2d_2_1<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    let d = jxl_simd::ScalarDescriptor::new().unwrap();
+    reinterpreting_dct2d_2_1_impl(d, data, output)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn reinterpreting_dct2d_1_4<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    let d = jxl_simd::ScalarDescriptor::new().unwrap();
+    reinterpreting_dct2d_1_4_impl(d, data, output)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn reinterpreting_dct2d_4_1<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    let d = jxl_simd::ScalarDescriptor::new().unwrap();
+    reinterpreting_dct2d_4_1_impl(d, data, output)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn reinterpreting_dct2d_2_2<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    let d = jxl_simd::ScalarDescriptor::new().unwrap();
+    reinterpreting_dct2d_2_2_impl(d, data, output)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn reinterpreting_dct2d_2_4<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    let d = jxl_simd::ScalarDescriptor::new().unwrap();
+    reinterpreting_dct2d_2_4_impl(d, data, output)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn reinterpreting_dct2d_4_2<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    let d = jxl_simd::ScalarDescriptor::new().unwrap();
+    reinterpreting_dct2d_4_2_impl(d, data, output)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn reinterpreting_dct2d_4_4<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    let d = d.maybe_downgrade_128bit();
+    reinterpreting_dct2d_4_4_impl(d, data, output)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn reinterpreting_dct2d_4_8<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    let d = d.maybe_downgrade_128bit();
+    reinterpreting_dct2d_4_8_impl(d, data, output)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn reinterpreting_dct2d_8_4<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    let d = d.maybe_downgrade_128bit();
+    reinterpreting_dct2d_8_4_impl(d, data, output)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn reinterpreting_dct2d_8_8<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    let d = d.maybe_downgrade_256bit();
+    reinterpreting_dct2d_8_8_impl(d, data, output)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn reinterpreting_dct2d_8_16<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    let d = d.maybe_downgrade_256bit();
+    reinterpreting_dct2d_8_16_impl(d, data, output)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn reinterpreting_dct2d_16_8<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    let d = d.maybe_downgrade_256bit();
+    reinterpreting_dct2d_16_8_impl(d, data, output)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn reinterpreting_dct2d_16_16<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    reinterpreting_dct2d_16_16_impl(d, data, output)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn reinterpreting_dct2d_16_32<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    reinterpreting_dct2d_16_32_impl(d, data, output)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn reinterpreting_dct2d_32_16<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    reinterpreting_dct2d_32_16_impl(d, data, output)
+}
+
+#[inline(always)]
+#[allow(unused_variables)]
+pub fn reinterpreting_dct2d_32_32<D: SimdDescriptor>(d: D, data: &mut [f32], output: &mut [f32]) {
+    reinterpreting_dct2d_32_32_impl(d, data, output)
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/reinterpreting_dct32.rs b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/reinterpreting_dct32.rs
new file mode 100644
index 0000000..5e4388f
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/reinterpreting_dct32.rs
@@ -0,0 +1,791 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(clippy::type_complexity)]
+#![allow(clippy::erasing_op)]
+#![allow(clippy::identity_op)]
+use jxl_simd::{F32SimdVec, SimdDescriptor};
+
+#[allow(clippy::too_many_arguments)]
+#[allow(clippy::excessive_precision)]
+#[inline(always)]
+pub(super) fn reinterpreting_dct_32<D: SimdDescriptor>(
+    d: D,
+    v0: D::F32Vec,
+    v1: D::F32Vec,
+    v2: D::F32Vec,
+    v3: D::F32Vec,
+    v4: D::F32Vec,
+    v5: D::F32Vec,
+    v6: D::F32Vec,
+    v7: D::F32Vec,
+    v8: D::F32Vec,
+    v9: D::F32Vec,
+    v10: D::F32Vec,
+    v11: D::F32Vec,
+    v12: D::F32Vec,
+    v13: D::F32Vec,
+    v14: D::F32Vec,
+    v15: D::F32Vec,
+    v16: D::F32Vec,
+    v17: D::F32Vec,
+    v18: D::F32Vec,
+    v19: D::F32Vec,
+    v20: D::F32Vec,
+    v21: D::F32Vec,
+    v22: D::F32Vec,
+    v23: D::F32Vec,
+    v24: D::F32Vec,
+    v25: D::F32Vec,
+    v26: D::F32Vec,
+    v27: D::F32Vec,
+    v28: D::F32Vec,
+    v29: D::F32Vec,
+    v30: D::F32Vec,
+    v31: D::F32Vec,
+) -> (
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+) {
+    let v32 = v0 + v31;
+    let v33 = v1 + v30;
+    let v34 = v2 + v29;
+    let v35 = v3 + v28;
+    let v36 = v4 + v27;
+    let v37 = v5 + v26;
+    let v38 = v6 + v25;
+    let v39 = v7 + v24;
+    let v40 = v8 + v23;
+    let v41 = v9 + v22;
+    let v42 = v10 + v21;
+    let v43 = v11 + v20;
+    let v44 = v12 + v19;
+    let v45 = v13 + v18;
+    let v46 = v14 + v17;
+    let v47 = v15 + v16;
+    let v48 = v32 + v47;
+    let v49 = v33 + v46;
+    let v50 = v34 + v45;
+    let v51 = v35 + v44;
+    let v52 = v36 + v43;
+    let v53 = v37 + v42;
+    let v54 = v38 + v41;
+    let v55 = v39 + v40;
+    let v56 = v48 + v55;
+    let v57 = v49 + v54;
+    let v58 = v50 + v53;
+    let v59 = v51 + v52;
+    let v60 = v56 + v59;
+    let v61 = v57 + v58;
+    let v62 = v60 + v61;
+    let v63 = v60 - v61;
+    let v64 = v56 - v59;
+    let v65 = v57 - v58;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let v66 = v64 * mul;
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let v67 = v65 * mul;
+    let v68 = v66 + v67;
+    let v69 = v66 - v67;
+    let v70 = v68.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v69);
+    let v71 = v48 - v55;
+    let v72 = v49 - v54;
+    let v73 = v50 - v53;
+    let v74 = v51 - v52;
+    let mul = D::F32Vec::splat(d, 0.5097955791041592);
+    let v75 = v71 * mul;
+    let mul = D::F32Vec::splat(d, 0.6013448869350453);
+    let v76 = v72 * mul;
+    let mul = D::F32Vec::splat(d, 0.8999762231364156);
+    let v77 = v73 * mul;
+    let mul = D::F32Vec::splat(d, 2.5629154477415055);
+    let v78 = v74 * mul;
+    let v79 = v75 + v78;
+    let v80 = v76 + v77;
+    let v81 = v79 + v80;
+    let v82 = v79 - v80;
+    let v83 = v75 - v78;
+    let v84 = v76 - v77;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let v85 = v83 * mul;
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let v86 = v84 * mul;
+    let v87 = v85 + v86;
+    let v88 = v85 - v86;
+    let v89 = v87.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v88);
+    let v90 = v81.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v89);
+    let v91 = v89 + v82;
+    let v92 = v82 + v88;
+    let v93 = v32 - v47;
+    let v94 = v33 - v46;
+    let v95 = v34 - v45;
+    let v96 = v35 - v44;
+    let v97 = v36 - v43;
+    let v98 = v37 - v42;
+    let v99 = v38 - v41;
+    let v100 = v39 - v40;
+    let mul = D::F32Vec::splat(d, 0.5024192861881557);
+    let v101 = v93 * mul;
+    let mul = D::F32Vec::splat(d, 0.5224986149396889);
+    let v102 = v94 * mul;
+    let mul = D::F32Vec::splat(d, 0.5669440348163577);
+    let v103 = v95 * mul;
+    let mul = D::F32Vec::splat(d, 0.6468217833599901);
+    let v104 = v96 * mul;
+    let mul = D::F32Vec::splat(d, 0.7881546234512502);
+    let v105 = v97 * mul;
+    let mul = D::F32Vec::splat(d, 1.0606776859903471);
+    let v106 = v98 * mul;
+    let mul = D::F32Vec::splat(d, 1.7224470982383342);
+    let v107 = v99 * mul;
+    let mul = D::F32Vec::splat(d, 5.1011486186891553);
+    let v108 = v100 * mul;
+    let v109 = v101 + v108;
+    let v110 = v102 + v107;
+    let v111 = v103 + v106;
+    let v112 = v104 + v105;
+    let v113 = v109 + v112;
+    let v114 = v110 + v111;
+    let v115 = v113 + v114;
+    let v116 = v113 - v114;
+    let v117 = v109 - v112;
+    let v118 = v110 - v111;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let v119 = v117 * mul;
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let v120 = v118 * mul;
+    let v121 = v119 + v120;
+    let v122 = v119 - v120;
+    let v123 = v121.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v122);
+    let v124 = v101 - v108;
+    let v125 = v102 - v107;
+    let v126 = v103 - v106;
+    let v127 = v104 - v105;
+    let mul = D::F32Vec::splat(d, 0.5097955791041592);
+    let v128 = v124 * mul;
+    let mul = D::F32Vec::splat(d, 0.6013448869350453);
+    let v129 = v125 * mul;
+    let mul = D::F32Vec::splat(d, 0.8999762231364156);
+    let v130 = v126 * mul;
+    let mul = D::F32Vec::splat(d, 2.5629154477415055);
+    let v131 = v127 * mul;
+    let v132 = v128 + v131;
+    let v133 = v129 + v130;
+    let v134 = v132 + v133;
+    let v135 = v132 - v133;
+    let v136 = v128 - v131;
+    let v137 = v129 - v130;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let v138 = v136 * mul;
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let v139 = v137 * mul;
+    let v140 = v138 + v139;
+    let v141 = v138 - v139;
+    let v142 = v140.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v141);
+    let v143 = v134.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v142);
+    let v144 = v142 + v135;
+    let v145 = v135 + v141;
+    let v146 = v115.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v143);
+    let v147 = v143 + v123;
+    let v148 = v123 + v144;
+    let v149 = v144 + v116;
+    let v150 = v116 + v145;
+    let v151 = v145 + v122;
+    let v152 = v122 + v141;
+    let v153 = v0 - v31;
+    let v154 = v1 - v30;
+    let v155 = v2 - v29;
+    let v156 = v3 - v28;
+    let v157 = v4 - v27;
+    let v158 = v5 - v26;
+    let v159 = v6 - v25;
+    let v160 = v7 - v24;
+    let v161 = v8 - v23;
+    let v162 = v9 - v22;
+    let v163 = v10 - v21;
+    let v164 = v11 - v20;
+    let v165 = v12 - v19;
+    let v166 = v13 - v18;
+    let v167 = v14 - v17;
+    let v168 = v15 - v16;
+    let mul = D::F32Vec::splat(d, 0.5006029982351963);
+    let v169 = v153 * mul;
+    let mul = D::F32Vec::splat(d, 0.5054709598975436);
+    let v170 = v154 * mul;
+    let mul = D::F32Vec::splat(d, 0.5154473099226246);
+    let v171 = v155 * mul;
+    let mul = D::F32Vec::splat(d, 0.5310425910897841);
+    let v172 = v156 * mul;
+    let mul = D::F32Vec::splat(d, 0.5531038960344445);
+    let v173 = v157 * mul;
+    let mul = D::F32Vec::splat(d, 0.5829349682061339);
+    let v174 = v158 * mul;
+    let mul = D::F32Vec::splat(d, 0.6225041230356648);
+    let v175 = v159 * mul;
+    let mul = D::F32Vec::splat(d, 0.6748083414550057);
+    let v176 = v160 * mul;
+    let mul = D::F32Vec::splat(d, 0.7445362710022986);
+    let v177 = v161 * mul;
+    let mul = D::F32Vec::splat(d, 0.8393496454155268);
+    let v178 = v162 * mul;
+    let mul = D::F32Vec::splat(d, 0.9725682378619608);
+    let v179 = v163 * mul;
+    let mul = D::F32Vec::splat(d, 1.1694399334328847);
+    let v180 = v164 * mul;
+    let mul = D::F32Vec::splat(d, 1.4841646163141662);
+    let v181 = v165 * mul;
+    let mul = D::F32Vec::splat(d, 2.0577810099534108);
+    let v182 = v166 * mul;
+    let mul = D::F32Vec::splat(d, 3.4076084184687190);
+    let v183 = v167 * mul;
+    let mul = D::F32Vec::splat(d, 10.1900081235480329);
+    let v184 = v168 * mul;
+    let v185 = v169 + v184;
+    let v186 = v170 + v183;
+    let v187 = v171 + v182;
+    let v188 = v172 + v181;
+    let v189 = v173 + v180;
+    let v190 = v174 + v179;
+    let v191 = v175 + v178;
+    let v192 = v176 + v177;
+    let v193 = v185 + v192;
+    let v194 = v186 + v191;
+    let v195 = v187 + v190;
+    let v196 = v188 + v189;
+    let v197 = v193 + v196;
+    let v198 = v194 + v195;
+    let v199 = v197 + v198;
+    let v200 = v197 - v198;
+    let v201 = v193 - v196;
+    let v202 = v194 - v195;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let v203 = v201 * mul;
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let v204 = v202 * mul;
+    let v205 = v203 + v204;
+    let v206 = v203 - v204;
+    let v207 = v205.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v206);
+    let v208 = v185 - v192;
+    let v209 = v186 - v191;
+    let v210 = v187 - v190;
+    let v211 = v188 - v189;
+    let mul = D::F32Vec::splat(d, 0.5097955791041592);
+    let v212 = v208 * mul;
+    let mul = D::F32Vec::splat(d, 0.6013448869350453);
+    let v213 = v209 * mul;
+    let mul = D::F32Vec::splat(d, 0.8999762231364156);
+    let v214 = v210 * mul;
+    let mul = D::F32Vec::splat(d, 2.5629154477415055);
+    let v215 = v211 * mul;
+    let v216 = v212 + v215;
+    let v217 = v213 + v214;
+    let v218 = v216 + v217;
+    let v219 = v216 - v217;
+    let v220 = v212 - v215;
+    let v221 = v213 - v214;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let v222 = v220 * mul;
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let v223 = v221 * mul;
+    let v224 = v222 + v223;
+    let v225 = v222 - v223;
+    let v226 = v224.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v225);
+    let v227 = v218.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v226);
+    let v228 = v226 + v219;
+    let v229 = v219 + v225;
+    let v230 = v169 - v184;
+    let v231 = v170 - v183;
+    let v232 = v171 - v182;
+    let v233 = v172 - v181;
+    let v234 = v173 - v180;
+    let v235 = v174 - v179;
+    let v236 = v175 - v178;
+    let v237 = v176 - v177;
+    let mul = D::F32Vec::splat(d, 0.5024192861881557);
+    let v238 = v230 * mul;
+    let mul = D::F32Vec::splat(d, 0.5224986149396889);
+    let v239 = v231 * mul;
+    let mul = D::F32Vec::splat(d, 0.5669440348163577);
+    let v240 = v232 * mul;
+    let mul = D::F32Vec::splat(d, 0.6468217833599901);
+    let v241 = v233 * mul;
+    let mul = D::F32Vec::splat(d, 0.7881546234512502);
+    let v242 = v234 * mul;
+    let mul = D::F32Vec::splat(d, 1.0606776859903471);
+    let v243 = v235 * mul;
+    let mul = D::F32Vec::splat(d, 1.7224470982383342);
+    let v244 = v236 * mul;
+    let mul = D::F32Vec::splat(d, 5.1011486186891553);
+    let v245 = v237 * mul;
+    let v246 = v238 + v245;
+    let v247 = v239 + v244;
+    let v248 = v240 + v243;
+    let v249 = v241 + v242;
+    let v250 = v246 + v249;
+    let v251 = v247 + v248;
+    let v252 = v250 + v251;
+    let v253 = v250 - v251;
+    let v254 = v246 - v249;
+    let v255 = v247 - v248;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let v256 = v254 * mul;
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let v257 = v255 * mul;
+    let v258 = v256 + v257;
+    let v259 = v256 - v257;
+    let v260 = v258.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v259);
+    let v261 = v238 - v245;
+    let v262 = v239 - v244;
+    let v263 = v240 - v243;
+    let v264 = v241 - v242;
+    let mul = D::F32Vec::splat(d, 0.5097955791041592);
+    let v265 = v261 * mul;
+    let mul = D::F32Vec::splat(d, 0.6013448869350453);
+    let v266 = v262 * mul;
+    let mul = D::F32Vec::splat(d, 0.8999762231364156);
+    let v267 = v263 * mul;
+    let mul = D::F32Vec::splat(d, 2.5629154477415055);
+    let v268 = v264 * mul;
+    let v269 = v265 + v268;
+    let v270 = v266 + v267;
+    let v271 = v269 + v270;
+    let v272 = v269 - v270;
+    let v273 = v265 - v268;
+    let v274 = v266 - v267;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let v275 = v273 * mul;
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let v276 = v274 * mul;
+    let v277 = v275 + v276;
+    let v278 = v275 - v276;
+    let v279 = v277.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v278);
+    let v280 = v271.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v279);
+    let v281 = v279 + v272;
+    let v282 = v272 + v278;
+    let v283 = v252.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v280);
+    let v284 = v280 + v260;
+    let v285 = v260 + v281;
+    let v286 = v281 + v253;
+    let v287 = v253 + v282;
+    let v288 = v282 + v259;
+    let v289 = v259 + v278;
+    let v290 = v199.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v283);
+    let v291 = v283 + v227;
+    let v292 = v227 + v284;
+    let v293 = v284 + v207;
+    let v294 = v207 + v285;
+    let v295 = v285 + v228;
+    let v296 = v228 + v286;
+    let v297 = v286 + v200;
+    let v298 = v200 + v287;
+    let v299 = v287 + v229;
+    let v300 = v229 + v288;
+    let v301 = v288 + v206;
+    let v302 = v206 + v289;
+    let v303 = v289 + v225;
+    let v304 = v225 + v278;
+    (
+        v62 * D::F32Vec::splat(d, 0.031250),
+        v290 * D::F32Vec::splat(d, 0.031262),
+        v146 * D::F32Vec::splat(d, 0.031299),
+        v291 * D::F32Vec::splat(d, 0.031361),
+        v90 * D::F32Vec::splat(d, 0.031449),
+        v292 * D::F32Vec::splat(d, 0.031561),
+        v147 * D::F32Vec::splat(d, 0.031699),
+        v293 * D::F32Vec::splat(d, 0.031864),
+        v70 * D::F32Vec::splat(d, 0.032055),
+        v294 * D::F32Vec::splat(d, 0.032274),
+        v148 * D::F32Vec::splat(d, 0.032521),
+        v295 * D::F32Vec::splat(d, 0.032797),
+        v91 * D::F32Vec::splat(d, 0.033103),
+        v296 * D::F32Vec::splat(d, 0.033441),
+        v149 * D::F32Vec::splat(d, 0.033811),
+        v297 * D::F32Vec::splat(d, 0.034215),
+        v63 * D::F32Vec::splat(d, 0.034654),
+        v298 * D::F32Vec::splat(d, 0.035131),
+        v150 * D::F32Vec::splat(d, 0.035647),
+        v299 * D::F32Vec::splat(d, 0.036204),
+        v92 * D::F32Vec::splat(d, 0.036806),
+        v300 * D::F32Vec::splat(d, 0.037453),
+        v151 * D::F32Vec::splat(d, 0.038150),
+        v301 * D::F32Vec::splat(d, 0.038899),
+        v69 * D::F32Vec::splat(d, 0.039705),
+        v302 * D::F32Vec::splat(d, 0.040571),
+        v152 * D::F32Vec::splat(d, 0.041502),
+        v303 * D::F32Vec::splat(d, 0.042502),
+        v88 * D::F32Vec::splat(d, 0.043578),
+        v304 * D::F32Vec::splat(d, 0.044735),
+        v141 * D::F32Vec::splat(d, 0.045981),
+        v278 * D::F32Vec::splat(d, 0.047324),
+    )
+}
+
+#[inline(always)]
+pub(super) fn do_reinterpreting_dct_32<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+    stride: usize,
+) {
+    assert!(data.len() > 31 * stride);
+    let mut v0 = D::F32Vec::load_array(d, &data[0 * stride]);
+    let mut v1 = D::F32Vec::load_array(d, &data[1 * stride]);
+    let mut v2 = D::F32Vec::load_array(d, &data[2 * stride]);
+    let mut v3 = D::F32Vec::load_array(d, &data[3 * stride]);
+    let mut v4 = D::F32Vec::load_array(d, &data[4 * stride]);
+    let mut v5 = D::F32Vec::load_array(d, &data[5 * stride]);
+    let mut v6 = D::F32Vec::load_array(d, &data[6 * stride]);
+    let mut v7 = D::F32Vec::load_array(d, &data[7 * stride]);
+    let mut v8 = D::F32Vec::load_array(d, &data[8 * stride]);
+    let mut v9 = D::F32Vec::load_array(d, &data[9 * stride]);
+    let mut v10 = D::F32Vec::load_array(d, &data[10 * stride]);
+    let mut v11 = D::F32Vec::load_array(d, &data[11 * stride]);
+    let mut v12 = D::F32Vec::load_array(d, &data[12 * stride]);
+    let mut v13 = D::F32Vec::load_array(d, &data[13 * stride]);
+    let mut v14 = D::F32Vec::load_array(d, &data[14 * stride]);
+    let mut v15 = D::F32Vec::load_array(d, &data[15 * stride]);
+    let mut v16 = D::F32Vec::load_array(d, &data[16 * stride]);
+    let mut v17 = D::F32Vec::load_array(d, &data[17 * stride]);
+    let mut v18 = D::F32Vec::load_array(d, &data[18 * stride]);
+    let mut v19 = D::F32Vec::load_array(d, &data[19 * stride]);
+    let mut v20 = D::F32Vec::load_array(d, &data[20 * stride]);
+    let mut v21 = D::F32Vec::load_array(d, &data[21 * stride]);
+    let mut v22 = D::F32Vec::load_array(d, &data[22 * stride]);
+    let mut v23 = D::F32Vec::load_array(d, &data[23 * stride]);
+    let mut v24 = D::F32Vec::load_array(d, &data[24 * stride]);
+    let mut v25 = D::F32Vec::load_array(d, &data[25 * stride]);
+    let mut v26 = D::F32Vec::load_array(d, &data[26 * stride]);
+    let mut v27 = D::F32Vec::load_array(d, &data[27 * stride]);
+    let mut v28 = D::F32Vec::load_array(d, &data[28 * stride]);
+    let mut v29 = D::F32Vec::load_array(d, &data[29 * stride]);
+    let mut v30 = D::F32Vec::load_array(d, &data[30 * stride]);
+    let mut v31 = D::F32Vec::load_array(d, &data[31 * stride]);
+    (
+        v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+        v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+    ) = reinterpreting_dct_32(
+        d, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
+        v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+    );
+    v0.store_array(&mut data[0 * stride]);
+    v1.store_array(&mut data[1 * stride]);
+    v2.store_array(&mut data[2 * stride]);
+    v3.store_array(&mut data[3 * stride]);
+    v4.store_array(&mut data[4 * stride]);
+    v5.store_array(&mut data[5 * stride]);
+    v6.store_array(&mut data[6 * stride]);
+    v7.store_array(&mut data[7 * stride]);
+    v8.store_array(&mut data[8 * stride]);
+    v9.store_array(&mut data[9 * stride]);
+    v10.store_array(&mut data[10 * stride]);
+    v11.store_array(&mut data[11 * stride]);
+    v12.store_array(&mut data[12 * stride]);
+    v13.store_array(&mut data[13 * stride]);
+    v14.store_array(&mut data[14 * stride]);
+    v15.store_array(&mut data[15 * stride]);
+    v16.store_array(&mut data[16 * stride]);
+    v17.store_array(&mut data[17 * stride]);
+    v18.store_array(&mut data[18 * stride]);
+    v19.store_array(&mut data[19 * stride]);
+    v20.store_array(&mut data[20 * stride]);
+    v21.store_array(&mut data[21 * stride]);
+    v22.store_array(&mut data[22 * stride]);
+    v23.store_array(&mut data[23 * stride]);
+    v24.store_array(&mut data[24 * stride]);
+    v25.store_array(&mut data[25 * stride]);
+    v26.store_array(&mut data[26 * stride]);
+    v27.store_array(&mut data[27 * stride]);
+    v28.store_array(&mut data[28 * stride]);
+    v29.store_array(&mut data[29 * stride]);
+    v30.store_array(&mut data[30 * stride]);
+    v31.store_array(&mut data[31 * stride]);
+}
+
+#[inline(always)]
+pub(super) fn do_reinterpreting_dct_32_rowblock<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+) {
+    assert!(data.len() >= 32);
+    const { assert!(32usize.is_multiple_of(D::F32Vec::LEN)) };
+    let row_stride = 32 / D::F32Vec::LEN;
+    let mut v0 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (0 % D::F32Vec::LEN) + (0 / D::F32Vec::LEN)],
+    );
+    let mut v1 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (1 % D::F32Vec::LEN) + (1 / D::F32Vec::LEN)],
+    );
+    let mut v2 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (2 % D::F32Vec::LEN) + (2 / D::F32Vec::LEN)],
+    );
+    let mut v3 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (3 % D::F32Vec::LEN) + (3 / D::F32Vec::LEN)],
+    );
+    let mut v4 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (4 % D::F32Vec::LEN) + (4 / D::F32Vec::LEN)],
+    );
+    let mut v5 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (5 % D::F32Vec::LEN) + (5 / D::F32Vec::LEN)],
+    );
+    let mut v6 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (6 % D::F32Vec::LEN) + (6 / D::F32Vec::LEN)],
+    );
+    let mut v7 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (7 % D::F32Vec::LEN) + (7 / D::F32Vec::LEN)],
+    );
+    let mut v8 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (8 % D::F32Vec::LEN) + (8 / D::F32Vec::LEN)],
+    );
+    let mut v9 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (9 % D::F32Vec::LEN) + (9 / D::F32Vec::LEN)],
+    );
+    let mut v10 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (10 % D::F32Vec::LEN) + (10 / D::F32Vec::LEN)],
+    );
+    let mut v11 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (11 % D::F32Vec::LEN) + (11 / D::F32Vec::LEN)],
+    );
+    let mut v12 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (12 % D::F32Vec::LEN) + (12 / D::F32Vec::LEN)],
+    );
+    let mut v13 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (13 % D::F32Vec::LEN) + (13 / D::F32Vec::LEN)],
+    );
+    let mut v14 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (14 % D::F32Vec::LEN) + (14 / D::F32Vec::LEN)],
+    );
+    let mut v15 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (15 % D::F32Vec::LEN) + (15 / D::F32Vec::LEN)],
+    );
+    let mut v16 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (16 % D::F32Vec::LEN) + (16 / D::F32Vec::LEN)],
+    );
+    let mut v17 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (17 % D::F32Vec::LEN) + (17 / D::F32Vec::LEN)],
+    );
+    let mut v18 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (18 % D::F32Vec::LEN) + (18 / D::F32Vec::LEN)],
+    );
+    let mut v19 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (19 % D::F32Vec::LEN) + (19 / D::F32Vec::LEN)],
+    );
+    let mut v20 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (20 % D::F32Vec::LEN) + (20 / D::F32Vec::LEN)],
+    );
+    let mut v21 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (21 % D::F32Vec::LEN) + (21 / D::F32Vec::LEN)],
+    );
+    let mut v22 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (22 % D::F32Vec::LEN) + (22 / D::F32Vec::LEN)],
+    );
+    let mut v23 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (23 % D::F32Vec::LEN) + (23 / D::F32Vec::LEN)],
+    );
+    let mut v24 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (24 % D::F32Vec::LEN) + (24 / D::F32Vec::LEN)],
+    );
+    let mut v25 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (25 % D::F32Vec::LEN) + (25 / D::F32Vec::LEN)],
+    );
+    let mut v26 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (26 % D::F32Vec::LEN) + (26 / D::F32Vec::LEN)],
+    );
+    let mut v27 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (27 % D::F32Vec::LEN) + (27 / D::F32Vec::LEN)],
+    );
+    let mut v28 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (28 % D::F32Vec::LEN) + (28 / D::F32Vec::LEN)],
+    );
+    let mut v29 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (29 % D::F32Vec::LEN) + (29 / D::F32Vec::LEN)],
+    );
+    let mut v30 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (30 % D::F32Vec::LEN) + (30 / D::F32Vec::LEN)],
+    );
+    let mut v31 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (31 % D::F32Vec::LEN) + (31 / D::F32Vec::LEN)],
+    );
+    (
+        v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+        v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+    ) = reinterpreting_dct_32(
+        d, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
+        v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+    );
+    v0.store_array(&mut data[row_stride * (0 % D::F32Vec::LEN) + (0 / D::F32Vec::LEN)]);
+    v1.store_array(&mut data[row_stride * (1 % D::F32Vec::LEN) + (1 / D::F32Vec::LEN)]);
+    v2.store_array(&mut data[row_stride * (2 % D::F32Vec::LEN) + (2 / D::F32Vec::LEN)]);
+    v3.store_array(&mut data[row_stride * (3 % D::F32Vec::LEN) + (3 / D::F32Vec::LEN)]);
+    v4.store_array(&mut data[row_stride * (4 % D::F32Vec::LEN) + (4 / D::F32Vec::LEN)]);
+    v5.store_array(&mut data[row_stride * (5 % D::F32Vec::LEN) + (5 / D::F32Vec::LEN)]);
+    v6.store_array(&mut data[row_stride * (6 % D::F32Vec::LEN) + (6 / D::F32Vec::LEN)]);
+    v7.store_array(&mut data[row_stride * (7 % D::F32Vec::LEN) + (7 / D::F32Vec::LEN)]);
+    v8.store_array(&mut data[row_stride * (8 % D::F32Vec::LEN) + (8 / D::F32Vec::LEN)]);
+    v9.store_array(&mut data[row_stride * (9 % D::F32Vec::LEN) + (9 / D::F32Vec::LEN)]);
+    v10.store_array(&mut data[row_stride * (10 % D::F32Vec::LEN) + (10 / D::F32Vec::LEN)]);
+    v11.store_array(&mut data[row_stride * (11 % D::F32Vec::LEN) + (11 / D::F32Vec::LEN)]);
+    v12.store_array(&mut data[row_stride * (12 % D::F32Vec::LEN) + (12 / D::F32Vec::LEN)]);
+    v13.store_array(&mut data[row_stride * (13 % D::F32Vec::LEN) + (13 / D::F32Vec::LEN)]);
+    v14.store_array(&mut data[row_stride * (14 % D::F32Vec::LEN) + (14 / D::F32Vec::LEN)]);
+    v15.store_array(&mut data[row_stride * (15 % D::F32Vec::LEN) + (15 / D::F32Vec::LEN)]);
+    v16.store_array(&mut data[row_stride * (16 % D::F32Vec::LEN) + (16 / D::F32Vec::LEN)]);
+    v17.store_array(&mut data[row_stride * (17 % D::F32Vec::LEN) + (17 / D::F32Vec::LEN)]);
+    v18.store_array(&mut data[row_stride * (18 % D::F32Vec::LEN) + (18 / D::F32Vec::LEN)]);
+    v19.store_array(&mut data[row_stride * (19 % D::F32Vec::LEN) + (19 / D::F32Vec::LEN)]);
+    v20.store_array(&mut data[row_stride * (20 % D::F32Vec::LEN) + (20 / D::F32Vec::LEN)]);
+    v21.store_array(&mut data[row_stride * (21 % D::F32Vec::LEN) + (21 / D::F32Vec::LEN)]);
+    v22.store_array(&mut data[row_stride * (22 % D::F32Vec::LEN) + (22 / D::F32Vec::LEN)]);
+    v23.store_array(&mut data[row_stride * (23 % D::F32Vec::LEN) + (23 / D::F32Vec::LEN)]);
+    v24.store_array(&mut data[row_stride * (24 % D::F32Vec::LEN) + (24 / D::F32Vec::LEN)]);
+    v25.store_array(&mut data[row_stride * (25 % D::F32Vec::LEN) + (25 / D::F32Vec::LEN)]);
+    v26.store_array(&mut data[row_stride * (26 % D::F32Vec::LEN) + (26 / D::F32Vec::LEN)]);
+    v27.store_array(&mut data[row_stride * (27 % D::F32Vec::LEN) + (27 / D::F32Vec::LEN)]);
+    v28.store_array(&mut data[row_stride * (28 % D::F32Vec::LEN) + (28 / D::F32Vec::LEN)]);
+    v29.store_array(&mut data[row_stride * (29 % D::F32Vec::LEN) + (29 / D::F32Vec::LEN)]);
+    v30.store_array(&mut data[row_stride * (30 % D::F32Vec::LEN) + (30 / D::F32Vec::LEN)]);
+    v31.store_array(&mut data[row_stride * (31 % D::F32Vec::LEN) + (31 / D::F32Vec::LEN)]);
+}
+
+#[inline(always)]
+pub(super) fn do_reinterpreting_dct_32_trh<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+) {
+    let row_stride = 16 / D::F32Vec::LEN;
+    assert!(data.len() > 31 * row_stride);
+    const { assert!(16usize.is_multiple_of(D::F32Vec::LEN)) };
+    let mut v0 = D::F32Vec::load_array(d, &data[row_stride * 0]);
+    let mut v1 = D::F32Vec::load_array(d, &data[row_stride * 1]);
+    let mut v2 = D::F32Vec::load_array(d, &data[row_stride * 2]);
+    let mut v3 = D::F32Vec::load_array(d, &data[row_stride * 3]);
+    let mut v4 = D::F32Vec::load_array(d, &data[row_stride * 4]);
+    let mut v5 = D::F32Vec::load_array(d, &data[row_stride * 5]);
+    let mut v6 = D::F32Vec::load_array(d, &data[row_stride * 6]);
+    let mut v7 = D::F32Vec::load_array(d, &data[row_stride * 7]);
+    let mut v8 = D::F32Vec::load_array(d, &data[row_stride * 8]);
+    let mut v9 = D::F32Vec::load_array(d, &data[row_stride * 9]);
+    let mut v10 = D::F32Vec::load_array(d, &data[row_stride * 10]);
+    let mut v11 = D::F32Vec::load_array(d, &data[row_stride * 11]);
+    let mut v12 = D::F32Vec::load_array(d, &data[row_stride * 12]);
+    let mut v13 = D::F32Vec::load_array(d, &data[row_stride * 13]);
+    let mut v14 = D::F32Vec::load_array(d, &data[row_stride * 14]);
+    let mut v15 = D::F32Vec::load_array(d, &data[row_stride * 15]);
+    let mut v16 = D::F32Vec::load_array(d, &data[row_stride * 16]);
+    let mut v17 = D::F32Vec::load_array(d, &data[row_stride * 17]);
+    let mut v18 = D::F32Vec::load_array(d, &data[row_stride * 18]);
+    let mut v19 = D::F32Vec::load_array(d, &data[row_stride * 19]);
+    let mut v20 = D::F32Vec::load_array(d, &data[row_stride * 20]);
+    let mut v21 = D::F32Vec::load_array(d, &data[row_stride * 21]);
+    let mut v22 = D::F32Vec::load_array(d, &data[row_stride * 22]);
+    let mut v23 = D::F32Vec::load_array(d, &data[row_stride * 23]);
+    let mut v24 = D::F32Vec::load_array(d, &data[row_stride * 24]);
+    let mut v25 = D::F32Vec::load_array(d, &data[row_stride * 25]);
+    let mut v26 = D::F32Vec::load_array(d, &data[row_stride * 26]);
+    let mut v27 = D::F32Vec::load_array(d, &data[row_stride * 27]);
+    let mut v28 = D::F32Vec::load_array(d, &data[row_stride * 28]);
+    let mut v29 = D::F32Vec::load_array(d, &data[row_stride * 29]);
+    let mut v30 = D::F32Vec::load_array(d, &data[row_stride * 30]);
+    let mut v31 = D::F32Vec::load_array(d, &data[row_stride * 31]);
+    (
+        v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+        v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+    ) = reinterpreting_dct_32(
+        d, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
+        v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+    );
+    v0.store_array(&mut data[row_stride * 0]);
+    v16.store_array(&mut data[row_stride * 1]);
+    v1.store_array(&mut data[row_stride * 2]);
+    v17.store_array(&mut data[row_stride * 3]);
+    v2.store_array(&mut data[row_stride * 4]);
+    v18.store_array(&mut data[row_stride * 5]);
+    v3.store_array(&mut data[row_stride * 6]);
+    v19.store_array(&mut data[row_stride * 7]);
+    v4.store_array(&mut data[row_stride * 8]);
+    v20.store_array(&mut data[row_stride * 9]);
+    v5.store_array(&mut data[row_stride * 10]);
+    v21.store_array(&mut data[row_stride * 11]);
+    v6.store_array(&mut data[row_stride * 12]);
+    v22.store_array(&mut data[row_stride * 13]);
+    v7.store_array(&mut data[row_stride * 14]);
+    v23.store_array(&mut data[row_stride * 15]);
+    v8.store_array(&mut data[row_stride * 16]);
+    v24.store_array(&mut data[row_stride * 17]);
+    v9.store_array(&mut data[row_stride * 18]);
+    v25.store_array(&mut data[row_stride * 19]);
+    v10.store_array(&mut data[row_stride * 20]);
+    v26.store_array(&mut data[row_stride * 21]);
+    v11.store_array(&mut data[row_stride * 22]);
+    v27.store_array(&mut data[row_stride * 23]);
+    v12.store_array(&mut data[row_stride * 24]);
+    v28.store_array(&mut data[row_stride * 25]);
+    v13.store_array(&mut data[row_stride * 26]);
+    v29.store_array(&mut data[row_stride * 27]);
+    v14.store_array(&mut data[row_stride * 28]);
+    v30.store_array(&mut data[row_stride * 29]);
+    v15.store_array(&mut data[row_stride * 30]);
+    v31.store_array(&mut data[row_stride * 31]);
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/reinterpreting_dct4.rs b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/reinterpreting_dct4.rs
new file mode 100644
index 0000000..8e53070
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/reinterpreting_dct4.rs
@@ -0,0 +1,108 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(clippy::type_complexity)]
+#![allow(clippy::erasing_op)]
+#![allow(clippy::identity_op)]
+use jxl_simd::{F32SimdVec, SimdDescriptor};
+
+#[allow(clippy::too_many_arguments)]
+#[allow(clippy::excessive_precision)]
+#[inline(always)]
+pub(super) fn reinterpreting_dct_4<D: SimdDescriptor>(
+    d: D,
+    v0: D::F32Vec,
+    v1: D::F32Vec,
+    v2: D::F32Vec,
+    v3: D::F32Vec,
+) -> (D::F32Vec, D::F32Vec, D::F32Vec, D::F32Vec) {
+    let v4 = v0 + v3;
+    let v5 = v1 + v2;
+    let v6 = v4 + v5;
+    let v7 = v4 - v5;
+    let v8 = v0 - v3;
+    let v9 = v1 - v2;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let v10 = v8 * mul;
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let v11 = v9 * mul;
+    let v12 = v10 + v11;
+    let v13 = v10 - v11;
+    let v14 = v12.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v13);
+    (
+        v6 * D::F32Vec::splat(d, 0.250000),
+        v14 * D::F32Vec::splat(d, 0.256440),
+        v7 * D::F32Vec::splat(d, 0.277234),
+        v13 * D::F32Vec::splat(d, 0.317640),
+    )
+}
+
+#[inline(always)]
+pub(super) fn do_reinterpreting_dct_4<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+    stride: usize,
+) {
+    assert!(data.len() > 3 * stride);
+    let mut v0 = D::F32Vec::load_array(d, &data[0 * stride]);
+    let mut v1 = D::F32Vec::load_array(d, &data[1 * stride]);
+    let mut v2 = D::F32Vec::load_array(d, &data[2 * stride]);
+    let mut v3 = D::F32Vec::load_array(d, &data[3 * stride]);
+    (v0, v1, v2, v3) = reinterpreting_dct_4(d, v0, v1, v2, v3);
+    v0.store_array(&mut data[0 * stride]);
+    v1.store_array(&mut data[1 * stride]);
+    v2.store_array(&mut data[2 * stride]);
+    v3.store_array(&mut data[3 * stride]);
+}
+
+#[inline(always)]
+pub(super) fn do_reinterpreting_dct_4_rowblock<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+) {
+    assert!(data.len() >= 4);
+    const { assert!(4usize.is_multiple_of(D::F32Vec::LEN)) };
+    let row_stride = 4 / D::F32Vec::LEN;
+    let mut v0 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (0 % D::F32Vec::LEN) + (0 / D::F32Vec::LEN)],
+    );
+    let mut v1 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (1 % D::F32Vec::LEN) + (1 / D::F32Vec::LEN)],
+    );
+    let mut v2 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (2 % D::F32Vec::LEN) + (2 / D::F32Vec::LEN)],
+    );
+    let mut v3 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (3 % D::F32Vec::LEN) + (3 / D::F32Vec::LEN)],
+    );
+    (v0, v1, v2, v3) = reinterpreting_dct_4(d, v0, v1, v2, v3);
+    v0.store_array(&mut data[row_stride * (0 % D::F32Vec::LEN) + (0 / D::F32Vec::LEN)]);
+    v1.store_array(&mut data[row_stride * (1 % D::F32Vec::LEN) + (1 / D::F32Vec::LEN)]);
+    v2.store_array(&mut data[row_stride * (2 % D::F32Vec::LEN) + (2 / D::F32Vec::LEN)]);
+    v3.store_array(&mut data[row_stride * (3 % D::F32Vec::LEN) + (3 / D::F32Vec::LEN)]);
+}
+
+#[inline(always)]
+pub(super) fn do_reinterpreting_dct_4_trh<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+) {
+    let row_stride = 2 / D::F32Vec::LEN;
+    assert!(data.len() > 3 * row_stride);
+    const { assert!(2usize.is_multiple_of(D::F32Vec::LEN)) };
+    let mut v0 = D::F32Vec::load_array(d, &data[row_stride * 0]);
+    let mut v1 = D::F32Vec::load_array(d, &data[row_stride * 1]);
+    let mut v2 = D::F32Vec::load_array(d, &data[row_stride * 2]);
+    let mut v3 = D::F32Vec::load_array(d, &data[row_stride * 3]);
+    (v0, v1, v2, v3) = reinterpreting_dct_4(d, v0, v1, v2, v3);
+    v0.store_array(&mut data[row_stride * 0]);
+    v2.store_array(&mut data[row_stride * 1]);
+    v1.store_array(&mut data[row_stride * 2]);
+    v3.store_array(&mut data[row_stride * 3]);
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/reinterpreting_dct8.rs b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/reinterpreting_dct8.rs
new file mode 100644
index 0000000..842da31
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/reinterpreting_dct8.rs
@@ -0,0 +1,193 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#![allow(clippy::type_complexity)]
+#![allow(clippy::erasing_op)]
+#![allow(clippy::identity_op)]
+use jxl_simd::{F32SimdVec, SimdDescriptor};
+
+#[allow(clippy::too_many_arguments)]
+#[allow(clippy::excessive_precision)]
+#[inline(always)]
+pub(super) fn reinterpreting_dct_8<D: SimdDescriptor>(
+    d: D,
+    v0: D::F32Vec,
+    v1: D::F32Vec,
+    v2: D::F32Vec,
+    v3: D::F32Vec,
+    v4: D::F32Vec,
+    v5: D::F32Vec,
+    v6: D::F32Vec,
+    v7: D::F32Vec,
+) -> (
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+    D::F32Vec,
+) {
+    let v8 = v0 + v7;
+    let v9 = v1 + v6;
+    let v10 = v2 + v5;
+    let v11 = v3 + v4;
+    let v12 = v8 + v11;
+    let v13 = v9 + v10;
+    let v14 = v12 + v13;
+    let v15 = v12 - v13;
+    let v16 = v8 - v11;
+    let v17 = v9 - v10;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let v18 = v16 * mul;
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let v19 = v17 * mul;
+    let v20 = v18 + v19;
+    let v21 = v18 - v19;
+    let v22 = v20.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v21);
+    let v23 = v0 - v7;
+    let v24 = v1 - v6;
+    let v25 = v2 - v5;
+    let v26 = v3 - v4;
+    let mul = D::F32Vec::splat(d, 0.5097955791041592);
+    let v27 = v23 * mul;
+    let mul = D::F32Vec::splat(d, 0.6013448869350453);
+    let v28 = v24 * mul;
+    let mul = D::F32Vec::splat(d, 0.8999762231364156);
+    let v29 = v25 * mul;
+    let mul = D::F32Vec::splat(d, 2.5629154477415055);
+    let v30 = v26 * mul;
+    let v31 = v27 + v30;
+    let v32 = v28 + v29;
+    let v33 = v31 + v32;
+    let v34 = v31 - v32;
+    let v35 = v27 - v30;
+    let v36 = v28 - v29;
+    let mul = D::F32Vec::splat(d, 0.5411961001461970);
+    let v37 = v35 * mul;
+    let mul = D::F32Vec::splat(d, 1.3065629648763764);
+    let v38 = v36 * mul;
+    let v39 = v37 + v38;
+    let v40 = v37 - v38;
+    let v41 = v39.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v40);
+    let v42 = v33.mul_add(D::F32Vec::splat(d, std::f32::consts::SQRT_2), v41);
+    let v43 = v41 + v34;
+    let v44 = v34 + v40;
+    (
+        v14 * D::F32Vec::splat(d, 0.125000),
+        v42 * D::F32Vec::splat(d, 0.125794),
+        v22 * D::F32Vec::splat(d, 0.128220),
+        v43 * D::F32Vec::splat(d, 0.132413),
+        v15 * D::F32Vec::splat(d, 0.138617),
+        v44 * D::F32Vec::splat(d, 0.147222),
+        v21 * D::F32Vec::splat(d, 0.158820),
+        v40 * D::F32Vec::splat(d, 0.174311),
+    )
+}
+
+#[inline(always)]
+pub(super) fn do_reinterpreting_dct_8<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+    stride: usize,
+) {
+    assert!(data.len() > 7 * stride);
+    let mut v0 = D::F32Vec::load_array(d, &data[0 * stride]);
+    let mut v1 = D::F32Vec::load_array(d, &data[1 * stride]);
+    let mut v2 = D::F32Vec::load_array(d, &data[2 * stride]);
+    let mut v3 = D::F32Vec::load_array(d, &data[3 * stride]);
+    let mut v4 = D::F32Vec::load_array(d, &data[4 * stride]);
+    let mut v5 = D::F32Vec::load_array(d, &data[5 * stride]);
+    let mut v6 = D::F32Vec::load_array(d, &data[6 * stride]);
+    let mut v7 = D::F32Vec::load_array(d, &data[7 * stride]);
+    (v0, v1, v2, v3, v4, v5, v6, v7) = reinterpreting_dct_8(d, v0, v1, v2, v3, v4, v5, v6, v7);
+    v0.store_array(&mut data[0 * stride]);
+    v1.store_array(&mut data[1 * stride]);
+    v2.store_array(&mut data[2 * stride]);
+    v3.store_array(&mut data[3 * stride]);
+    v4.store_array(&mut data[4 * stride]);
+    v5.store_array(&mut data[5 * stride]);
+    v6.store_array(&mut data[6 * stride]);
+    v7.store_array(&mut data[7 * stride]);
+}
+
+#[inline(always)]
+pub(super) fn do_reinterpreting_dct_8_rowblock<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+) {
+    assert!(data.len() >= 8);
+    const { assert!(8usize.is_multiple_of(D::F32Vec::LEN)) };
+    let row_stride = 8 / D::F32Vec::LEN;
+    let mut v0 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (0 % D::F32Vec::LEN) + (0 / D::F32Vec::LEN)],
+    );
+    let mut v1 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (1 % D::F32Vec::LEN) + (1 / D::F32Vec::LEN)],
+    );
+    let mut v2 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (2 % D::F32Vec::LEN) + (2 / D::F32Vec::LEN)],
+    );
+    let mut v3 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (3 % D::F32Vec::LEN) + (3 / D::F32Vec::LEN)],
+    );
+    let mut v4 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (4 % D::F32Vec::LEN) + (4 / D::F32Vec::LEN)],
+    );
+    let mut v5 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (5 % D::F32Vec::LEN) + (5 / D::F32Vec::LEN)],
+    );
+    let mut v6 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (6 % D::F32Vec::LEN) + (6 / D::F32Vec::LEN)],
+    );
+    let mut v7 = D::F32Vec::load_array(
+        d,
+        &data[row_stride * (7 % D::F32Vec::LEN) + (7 / D::F32Vec::LEN)],
+    );
+    (v0, v1, v2, v3, v4, v5, v6, v7) = reinterpreting_dct_8(d, v0, v1, v2, v3, v4, v5, v6, v7);
+    v0.store_array(&mut data[row_stride * (0 % D::F32Vec::LEN) + (0 / D::F32Vec::LEN)]);
+    v1.store_array(&mut data[row_stride * (1 % D::F32Vec::LEN) + (1 / D::F32Vec::LEN)]);
+    v2.store_array(&mut data[row_stride * (2 % D::F32Vec::LEN) + (2 / D::F32Vec::LEN)]);
+    v3.store_array(&mut data[row_stride * (3 % D::F32Vec::LEN) + (3 / D::F32Vec::LEN)]);
+    v4.store_array(&mut data[row_stride * (4 % D::F32Vec::LEN) + (4 / D::F32Vec::LEN)]);
+    v5.store_array(&mut data[row_stride * (5 % D::F32Vec::LEN) + (5 / D::F32Vec::LEN)]);
+    v6.store_array(&mut data[row_stride * (6 % D::F32Vec::LEN) + (6 / D::F32Vec::LEN)]);
+    v7.store_array(&mut data[row_stride * (7 % D::F32Vec::LEN) + (7 / D::F32Vec::LEN)]);
+}
+
+#[inline(always)]
+pub(super) fn do_reinterpreting_dct_8_trh<D: SimdDescriptor>(
+    d: D,
+    data: &mut [<D::F32Vec as F32SimdVec>::UnderlyingArray],
+) {
+    let row_stride = 4 / D::F32Vec::LEN;
+    assert!(data.len() > 7 * row_stride);
+    const { assert!(4usize.is_multiple_of(D::F32Vec::LEN)) };
+    let mut v0 = D::F32Vec::load_array(d, &data[row_stride * 0]);
+    let mut v1 = D::F32Vec::load_array(d, &data[row_stride * 1]);
+    let mut v2 = D::F32Vec::load_array(d, &data[row_stride * 2]);
+    let mut v3 = D::F32Vec::load_array(d, &data[row_stride * 3]);
+    let mut v4 = D::F32Vec::load_array(d, &data[row_stride * 4]);
+    let mut v5 = D::F32Vec::load_array(d, &data[row_stride * 5]);
+    let mut v6 = D::F32Vec::load_array(d, &data[row_stride * 6]);
+    let mut v7 = D::F32Vec::load_array(d, &data[row_stride * 7]);
+    (v0, v1, v2, v3, v4, v5, v6, v7) = reinterpreting_dct_8(d, v0, v1, v2, v3, v4, v5, v6, v7);
+    v0.store_array(&mut data[row_stride * 0]);
+    v4.store_array(&mut data[row_stride * 1]);
+    v1.store_array(&mut data[row_stride * 2]);
+    v5.store_array(&mut data[row_stride * 3]);
+    v2.store_array(&mut data[row_stride * 4]);
+    v6.store_array(&mut data[row_stride * 5]);
+    v3.store_array(&mut data[row_stride * 6]);
+    v7.store_array(&mut data[row_stride * 7]);
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/tests.rs b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/tests.rs
new file mode 100644
index 0000000..bd139ff9
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/tests.rs
@@ -0,0 +1,494 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use super::*;
+use jxl_simd::{test_all_instruction_sets, ScalarDescriptor, SimdDescriptor};
+use rand::Rng;
+use rand::SeedableRng;
+use rand_chacha::ChaCha12Rng;
+use test_log::test;
+
+use std::f64::consts::FRAC_1_SQRT_2;
+use std::f64::consts::PI;
+use std::f64::consts::SQRT_2;
+
+#[inline(always)]
+fn alpha(u: usize) -> f64 {
+    if u == 0 {
+        FRAC_1_SQRT_2
+    } else {
+        1.0
+    }
+}
+
+pub fn dct1d(input_matrix: &[Vec<f64>]) -> Vec<Vec<f64>> {
+    let num_rows = input_matrix.len();
+
+    if num_rows == 0 {
+        return Vec::new();
+    }
+
+    let num_cols = input_matrix[0].len();
+
+    let mut output_matrix = vec![vec![0.0f64; num_cols]; num_rows];
+
+    let scale: f64 = SQRT_2;
+
+    // Precompute the DCT matrix (size: n_rows x n_rows)
+    let mut dct_coeff_matrix = vec![vec![0.0f64; num_rows]; num_rows];
+    for (u_freq, row) in dct_coeff_matrix.iter_mut().enumerate() {
+        let alpha_u_val = alpha(u_freq);
+        for (y_spatial, coeff) in row.iter_mut().enumerate() {
+            *coeff = alpha_u_val
+                * ((y_spatial as f64 + 0.5) * u_freq as f64 * PI / num_rows as f64).cos()
+                * scale;
+        }
+    }
+
+    // Perform the DCT calculation column by column
+    for x_col_idx in 0..num_cols {
+        for u_freq_idx in 0..num_rows {
+            let mut sum = 0.0;
+            for (y_spatial_idx, col) in input_matrix.iter().enumerate() {
+                // This access `input_matrix[y_spatial_idx][x_col_idx]` assumes the input_matrix
+                // is rectangular. If not, it might panic here.
+                sum += dct_coeff_matrix[u_freq_idx][y_spatial_idx] * col[x_col_idx];
+            }
+            output_matrix[u_freq_idx][x_col_idx] = sum;
+        }
+    }
+
+    output_matrix
+}
+
+pub fn idct1d(input_matrix: &[Vec<f64>]) -> Vec<Vec<f64>> {
+    let num_rows = input_matrix.len();
+
+    if num_rows == 0 {
+        return Vec::new();
+    }
+
+    let num_cols = input_matrix[0].len();
+
+    let mut output_matrix = vec![vec![0.0f64; num_cols]; num_rows];
+
+    let scale: f64 = SQRT_2;
+
+    // Precompute the DCT matrix (size: num_rows x num_rows)
+    let mut dct_coeff_matrix = vec![vec![0.0f64; num_rows]; num_rows];
+    for (u_freq, row) in dct_coeff_matrix.iter_mut().enumerate() {
+        let alpha_u_val = alpha(u_freq);
+        for (y_def_idx, coeff) in row.iter_mut().enumerate() {
+            *coeff = alpha_u_val
+                * ((y_def_idx as f64 + 0.5) * u_freq as f64 * PI / num_rows as f64).cos()
+                * scale;
+        }
+    }
+
+    // Perform the IDCT calculation column by column
+    for x_col_idx in 0..num_cols {
+        for (y_row_idx, row) in output_matrix.iter_mut().enumerate() {
+            let mut sum = 0.0;
+            for (u_freq_idx, col) in input_matrix.iter().enumerate() {
+                // This access input_coeffs_matrix[u_freq_idx][x_col_idx] assumes input_coeffs_matrix
+                // is rectangular. If not, it might panic here.
+                sum += dct_coeff_matrix[u_freq_idx][y_row_idx] * col[x_col_idx];
+            }
+            row[x_col_idx] = sum;
+        }
+    }
+
+    output_matrix
+}
+
+fn transpose_f64(matrix: &[Vec<f64>]) -> Vec<Vec<f64>> {
+    if matrix.is_empty() {
+        return Vec::new();
+    }
+    let num_rows = matrix.len();
+    let num_cols = matrix[0].len();
+    let mut transposed = vec![vec![0.0; num_rows]; num_cols];
+    for i in 0..num_rows {
+        for j in 0..num_cols {
+            transposed[j][i] = matrix[i][j];
+        }
+    }
+    transposed
+}
+
+pub fn slow_idct2d(input: &[Vec<f64>]) -> Vec<Vec<f64>> {
+    let rows = input.len();
+    let cols = input[0].len();
+    let idct1 = if rows < cols {
+        let transposed = transpose_f64(input);
+        idct1d(&transposed)
+    } else {
+        let input: Vec<_> = input.iter().flat_map(|x| x.iter()).copied().collect();
+        let input: Vec<_> = input.chunks_exact(rows).map(|x| x.to_vec()).collect();
+        idct1d(&input)
+    };
+    let transposed1 = transpose_f64(&idct1);
+    idct1d(&transposed1)
+}
+
+pub fn scales(n: usize) -> Vec<f64> {
+    (0..n)
+        .map(|i| {
+            (i as f64 / (16 * n) as f64 * PI).cos()
+                * (i as f64 / (8 * n) as f64 * PI).cos()
+                * (i as f64 / (4 * n) as f64 * PI).cos()
+                * n as f64
+        })
+        .collect()
+}
+
+pub fn slow_reinterpreting_dct2d(input: &[Vec<f64>]) -> Vec<Vec<f64>> {
+    let rows = input.len();
+    let cols = input[0].len();
+    let dct1 = dct1d(input);
+    let tdct1 = transpose_f64(&dct1);
+    let dct2 = dct1d(&tdct1);
+    let mut res = if rows < cols {
+        transpose_f64(&dct2)
+    } else {
+        dct2
+    };
+
+    let row_scales = scales(rows);
+    let col_scales = scales(cols);
+    if rows < cols {
+        for y in 0..rows {
+            for x in 0..cols {
+                res[y][x] /= row_scales[y] * col_scales[x];
+            }
+        }
+    } else {
+        for y in 0..cols {
+            for x in 0..rows {
+                res[y][x] /= row_scales[x] * col_scales[y];
+            }
+        }
+    }
+    res
+}
+
+#[track_caller]
+fn check_close(a: f64, b: f64, max_err: f64) {
+    let abs = (a - b).abs();
+    let rel = abs / a.abs().max(b.abs());
+    assert!(
+        abs < max_err || rel < max_err,
+        "a: {a} b: {b} abs diff: {abs:?} rel diff: {rel:?}"
+    );
+}
+
+macro_rules! test_reinterpreting_dct1d_eq_slow_n {
+    ($test_name:ident, $n_val:expr, $do_idct_fun:path, $tolerance:expr) => {
+        #[test]
+        fn $test_name() {
+            const N: usize = $n_val;
+
+            let input_matrix_for_ref = random_matrix(N, 1);
+
+            let output_matrix_slow: Vec<Vec<f64>> = dct1d(&input_matrix_for_ref);
+
+            let mut output: Vec<_> = input_matrix_for_ref.iter().map(|x| x[0] as f32).collect();
+            let d = ScalarDescriptor {};
+
+            let (output_chunks, remainder) = output.as_chunks_mut::<1>();
+            assert!(remainder.is_empty());
+            $do_idct_fun(d, output_chunks, 1);
+
+            let scales = scales(N);
+
+            for i in 0..N {
+                check_close(
+                    output[i] as f64,
+                    output_matrix_slow[i][0] / scales[i],
+                    $tolerance,
+                );
+            }
+        }
+    };
+}
+
+test_reinterpreting_dct1d_eq_slow_n!(
+    test_reinterpreting_dct1d_2_eq_slow,
+    2,
+    do_reinterpreting_dct_2,
+    1e-6
+);
+test_reinterpreting_dct1d_eq_slow_n!(
+    test_reinterpreting_dct1d_4_eq_slow,
+    4,
+    do_reinterpreting_dct_4,
+    1e-6
+);
+test_reinterpreting_dct1d_eq_slow_n!(
+    test_reinterpreting_dct1d_8_eq_slow,
+    8,
+    do_reinterpreting_dct_8,
+    1e-6
+);
+test_reinterpreting_dct1d_eq_slow_n!(
+    test_reinterpreting_dct1d_16_eq_slow,
+    16,
+    do_reinterpreting_dct_16,
+    5e-6
+);
+test_reinterpreting_dct1d_eq_slow_n!(
+    test_reinterpreting_dct1d_32_eq_slow,
+    32,
+    do_reinterpreting_dct_32,
+    5e-6
+);
+
+fn random_matrix(n: usize, m: usize) -> Vec<Vec<f64>> {
+    let mut rng = ChaCha12Rng::seed_from_u64(0);
+    let mut data = vec![vec![0.0; m]; n];
+
+    data.iter_mut()
+        .flat_map(|x| x.iter_mut())
+        .for_each(|x| *x = rng.random_range(-1.0..1.0));
+
+    data
+}
+
+macro_rules! test_idct1d_eq_slow_n {
+    ($test_name:ident, $n_val:expr, $do_idct_fun:path, $tolerance:expr) => {
+        #[test]
+        fn $test_name() {
+            const N: usize = $n_val;
+
+            let input_matrix_for_ref = random_matrix(N, 1);
+
+            let output_matrix_slow: Vec<Vec<f64>> = idct1d(&input_matrix_for_ref);
+
+            let mut output: Vec<_> = input_matrix_for_ref.iter().map(|x| x[0] as f32).collect();
+            let d = ScalarDescriptor {};
+
+            let (output_chunks, remainder) = output.as_chunks_mut::<1>();
+            assert!(remainder.is_empty());
+            $do_idct_fun(d, output_chunks, 1);
+
+            for i in 0..N {
+                check_close(output[i] as f64, output_matrix_slow[i][0], $tolerance);
+            }
+        }
+    };
+}
+
+test_idct1d_eq_slow_n!(test_idct1d_2_eq_slow, 2, do_idct_2, 1e-6);
+test_idct1d_eq_slow_n!(test_idct1d_4_eq_slow, 4, do_idct_4, 1e-6);
+test_idct1d_eq_slow_n!(test_idct1d_8_eq_slow, 8, do_idct_8, 1e-6);
+test_idct1d_eq_slow_n!(test_idct1d_16_eq_slow, 16, do_idct_16, 1e-6);
+test_idct1d_eq_slow_n!(test_idct1d_32_eq_slow, 32, do_idct_32, 5e-6);
+test_idct1d_eq_slow_n!(test_idct1d_64_eq_slow, 64, do_idct_64, 5e-6);
+test_idct1d_eq_slow_n!(test_idct1d_128_eq_slow, 128, do_idct_128, 5e-5);
+test_idct1d_eq_slow_n!(test_idct1d_256_eq_slow, 256, do_idct_256, 5e-5);
+
+macro_rules! test_idct2d_eq_slow {
+    ($test_name:ident, $rows:expr, $cols:expr, $fast_idct:ident, $tol:expr) => {
+        fn $test_name<D: SimdDescriptor>(d: D) {
+            const N: usize = $rows;
+            const M: usize = $cols;
+
+            let slow_input = random_matrix(N, M);
+
+            let slow_output = slow_idct2d(&slow_input);
+
+            let mut fast_input: Vec<_> = slow_input
+                .iter()
+                .flat_map(|x| x.iter())
+                .map(|x| *x as f32)
+                .collect();
+
+            $fast_idct(d, &mut fast_input);
+
+            for r in 0..N {
+                for c in 0..M {
+                    check_close(fast_input[r * M + c] as f64, slow_output[r][c], $tol);
+                }
+            }
+        }
+        test_all_instruction_sets!($test_name);
+    };
+}
+
+test_idct2d_eq_slow!(test_idct2d_2_2_eq_slow, 2, 2, idct2d_2_2, 1e-6);
+test_idct2d_eq_slow!(test_idct2d_4_4_eq_slow, 4, 4, idct2d_4_4, 1e-6);
+test_idct2d_eq_slow!(test_idct2d_4_8_eq_slow, 4, 8, idct2d_4_8, 1e-6);
+test_idct2d_eq_slow!(test_idct2d_8_4_eq_slow, 8, 4, idct2d_8_4, 1e-6);
+test_idct2d_eq_slow!(test_idct2d_8_8_eq_slow, 8, 8, idct2d_8_8, 5e-6);
+test_idct2d_eq_slow!(test_idct2d_16_8_eq_slow, 16, 8, idct2d_16_8, 5e-6);
+test_idct2d_eq_slow!(test_idct2d_8_16_eq_slow, 8, 16, idct2d_8_16, 5e-6);
+test_idct2d_eq_slow!(test_idct2d_16_16_eq_slow, 16, 16, idct2d_16_16, 1e-5);
+test_idct2d_eq_slow!(test_idct2d_32_8_eq_slow, 32, 8, idct2d_32_8, 5e-6);
+test_idct2d_eq_slow!(test_idct2d_8_32_eq_slow, 8, 32, idct2d_8_32, 5e-6);
+test_idct2d_eq_slow!(test_idct2d_32_16_eq_slow, 32, 16, idct2d_32_16, 1e-5);
+test_idct2d_eq_slow!(test_idct2d_16_32_eq_slow, 16, 32, idct2d_16_32, 1e-5);
+test_idct2d_eq_slow!(test_idct2d_32_32_eq_slow, 32, 32, idct2d_32_32, 5e-5);
+test_idct2d_eq_slow!(test_idct2d_64_32_eq_slow, 64, 32, idct2d_64_32, 1e-4);
+test_idct2d_eq_slow!(test_idct2d_32_64_eq_slow, 32, 64, idct2d_32_64, 1e-4);
+test_idct2d_eq_slow!(test_idct2d_64_64_eq_slow, 64, 64, idct2d_64_64, 1e-4);
+test_idct2d_eq_slow!(test_idct2d_128_64_eq_slow, 128, 64, idct2d_128_64, 5e-4);
+test_idct2d_eq_slow!(test_idct2d_64_128_eq_slow, 64, 128, idct2d_64_128, 5e-4);
+test_idct2d_eq_slow!(test_idct2d_128_128_eq_slow, 128, 128, idct2d_128_128, 5e-4);
+test_idct2d_eq_slow!(test_idct2d_256_128_eq_slow, 256, 128, idct2d_256_128, 1e-3);
+test_idct2d_eq_slow!(test_idct2d_128_256_eq_slow, 128, 256, idct2d_128_256, 1e-3);
+test_idct2d_eq_slow!(test_idct2d_256_256_eq_slow, 256, 256, idct2d_256_256, 5e-3);
+
+macro_rules! test_reinterpreting_dct_eq_slow {
+    ($test_name:ident, $fun: ident, $rows:expr, $cols:expr, $tol:expr) => {
+        fn $test_name<D: SimdDescriptor>(d: D) {
+            const N: usize = $rows;
+            const M: usize = $cols;
+
+            let slow_input = random_matrix(N, M);
+
+            let slow_output = slow_reinterpreting_dct2d(&slow_input);
+
+            let mut fast_input: Vec<_> = slow_input
+                .iter()
+                .flat_map(|x| x.iter())
+                .map(|x| *x as f32)
+                .collect();
+
+            let mut output = [0.0; $rows * $cols * 64];
+
+            $fun(d, &mut fast_input, &mut output);
+
+            let on = slow_output.len();
+            let om = slow_output[0].len();
+
+            for r in 0..on {
+                for c in 0..om {
+                    check_close(output[r * om * 8 + c] as f64, slow_output[r][c], $tol);
+                }
+            }
+        }
+        test_all_instruction_sets!($test_name);
+    };
+}
+
+test_reinterpreting_dct_eq_slow!(
+    test_reinterpreting_dct_1x2_eq_slow,
+    reinterpreting_dct2d_1_2,
+    1,
+    2,
+    1e-6
+);
+test_reinterpreting_dct_eq_slow!(
+    test_reinterpreting_dct_2x1_eq_slow,
+    reinterpreting_dct2d_2_1,
+    2,
+    1,
+    1e-6
+);
+test_reinterpreting_dct_eq_slow!(
+    test_reinterpreting_dct_2x2_eq_slow,
+    reinterpreting_dct2d_2_2,
+    2,
+    2,
+    1e-6
+);
+test_reinterpreting_dct_eq_slow!(
+    test_reinterpreting_dct_1x4_eq_slow,
+    reinterpreting_dct2d_1_4,
+    1,
+    4,
+    1e-6
+);
+test_reinterpreting_dct_eq_slow!(
+    test_reinterpreting_dct_4x1_eq_slow,
+    reinterpreting_dct2d_4_1,
+    4,
+    1,
+    1e-6
+);
+test_reinterpreting_dct_eq_slow!(
+    test_reinterpreting_dct_2x4_eq_slow,
+    reinterpreting_dct2d_2_4,
+    2,
+    4,
+    1e-6
+);
+test_reinterpreting_dct_eq_slow!(
+    test_reinterpreting_dct_4x2_eq_slow,
+    reinterpreting_dct2d_4_2,
+    4,
+    2,
+    1e-6
+);
+test_reinterpreting_dct_eq_slow!(
+    test_reinterpreting_dct_4x4_eq_slow,
+    reinterpreting_dct2d_4_4,
+    4,
+    4,
+    1e-6
+);
+test_reinterpreting_dct_eq_slow!(
+    test_reinterpreting_dct_8x4_eq_slow,
+    reinterpreting_dct2d_8_4,
+    8,
+    4,
+    1e-6
+);
+test_reinterpreting_dct_eq_slow!(
+    test_reinterpreting_dct_4x8_eq_slow,
+    reinterpreting_dct2d_4_8,
+    4,
+    8,
+    1e-6
+);
+test_reinterpreting_dct_eq_slow!(
+    test_reinterpreting_dct_8x8_eq_slow,
+    reinterpreting_dct2d_8_8,
+    8,
+    8,
+    1e-6
+);
+test_reinterpreting_dct_eq_slow!(
+    test_reinterpreting_dct_8x16_eq_slow,
+    reinterpreting_dct2d_8_16,
+    8,
+    16,
+    5e-6
+);
+test_reinterpreting_dct_eq_slow!(
+    test_reinterpreting_dct_16x8_eq_slow,
+    reinterpreting_dct2d_16_8,
+    16,
+    8,
+    5e-6
+);
+test_reinterpreting_dct_eq_slow!(
+    test_reinterpreting_dct_16x16_eq_slow,
+    reinterpreting_dct2d_16_16,
+    16,
+    16,
+    5e-6
+);
+test_reinterpreting_dct_eq_slow!(
+    test_reinterpreting_dct_32x16_eq_slow,
+    reinterpreting_dct2d_32_16,
+    32,
+    16,
+    5e-6
+);
+test_reinterpreting_dct_eq_slow!(
+    test_reinterpreting_dct_16x32_eq_slow,
+    reinterpreting_dct2d_16_32,
+    16,
+    32,
+    5e-6
+);
+test_reinterpreting_dct_eq_slow!(
+    test_reinterpreting_dct_32x32_eq_slow,
+    reinterpreting_dct2d_32_32,
+    32,
+    32,
+    5e-6
+);
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/transform.rs b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/transform.rs
new file mode 100644
index 0000000..6a8f7528
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/transform.rs
@@ -0,0 +1,672 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+use crate::{transform_map::HfTransformType, *};
+use jxl_simd::{simd_function, SimdDescriptor};
+
+fn idct2_top_block(s: usize, block_in: &[f32], block_out: &mut [f32]) {
+    let num_2x2 = s / 2;
+    for y in 0..num_2x2 {
+        for x in 0..num_2x2 {
+            let c00 = block_in[y * 8 + x];
+            let c01 = block_in[y * 8 + num_2x2 + x];
+            let c10 = block_in[(y + num_2x2) * 8 + x];
+            let c11 = block_in[(y + num_2x2) * 8 + num_2x2 + x];
+            let r00 = c00 + c01 + c10 + c11;
+            let r01 = c00 + c01 - c10 - c11;
+            let r10 = c00 - c01 + c10 - c11;
+            let r11 = c00 - c01 - c10 + c11;
+            block_out[y * 2 * 8 + x * 2] = r00;
+            block_out[y * 2 * 8 + x * 2 + 1] = r01;
+            block_out[(y * 2 + 1) * 8 + x * 2] = r10;
+            block_out[(y * 2 + 1) * 8 + x * 2 + 1] = r11;
+        }
+    }
+}
+
+const AFV4X4BASIS: [f32; 256] = [
+    0.25,
+    0.25,
+    0.25,
+    0.25,
+    0.25,
+    0.25,
+    0.25,
+    0.25,
+    0.25,
+    0.25,
+    0.25,
+    0.25,
+    0.25,
+    0.25,
+    0.25,
+    0.25,
+    0.876902929799142,
+    0.2206518106944235,
+    -0.10140050393753763,
+    -0.1014005039375375,
+    0.2206518106944236,
+    -0.10140050393753777,
+    -0.10140050393753772,
+    -0.10140050393753763,
+    -0.10140050393753758,
+    -0.10140050393753769,
+    -0.1014005039375375,
+    -0.10140050393753768,
+    -0.10140050393753768,
+    -0.10140050393753759,
+    -0.10140050393753763,
+    -0.10140050393753741,
+    0.0,
+    0.0,
+    0.40670075830260755,
+    0.44444816619734445,
+    0.0,
+    0.0,
+    0.19574399372042936,
+    0.2929100136981264,
+    -0.40670075830260716,
+    -0.19574399372042872,
+    0.0,
+    0.11379074460448091,
+    -0.44444816619734384,
+    -0.29291001369812636,
+    -0.1137907446044814,
+    0.0,
+    0.0,
+    0.0,
+    -0.21255748058288748,
+    0.3085497062849767,
+    0.0,
+    0.4706702258572536,
+    -0.1621205195722993,
+    0.0,
+    -0.21255748058287047,
+    -0.16212051957228327,
+    -0.47067022585725277,
+    -0.1464291867126764,
+    0.3085497062849487,
+    0.0,
+    -0.14642918671266536,
+    0.4251149611657548,
+    0.0,
+    -0.7071067811865474,
+    0.0,
+    0.0,
+    0.7071067811865476,
+    0.0,
+    0.0,
+    0.0,
+    0.0,
+    0.0,
+    0.0,
+    0.0,
+    0.0,
+    0.0,
+    0.0,
+    0.0,
+    -0.4105377591765233,
+    0.6235485373547691,
+    -0.06435071657946274,
+    -0.06435071657946266,
+    0.6235485373547694,
+    -0.06435071657946284,
+    -0.0643507165794628,
+    -0.06435071657946274,
+    -0.06435071657946272,
+    -0.06435071657946279,
+    -0.06435071657946266,
+    -0.06435071657946277,
+    -0.06435071657946277,
+    -0.06435071657946273,
+    -0.06435071657946274,
+    -0.0643507165794626,
+    0.0,
+    0.0,
+    -0.4517556589999482,
+    0.15854503551840063,
+    0.0,
+    -0.04038515160822202,
+    0.0074182263792423875,
+    0.39351034269210167,
+    -0.45175565899994635,
+    0.007418226379244351,
+    0.1107416575309343,
+    0.08298163094882051,
+    0.15854503551839705,
+    0.3935103426921022,
+    0.0829816309488214,
+    -0.45175565899994796,
+    0.0,
+    0.0,
+    -0.304684750724869,
+    0.5112616136591823,
+    0.0,
+    0.0,
+    -0.290480129728998,
+    -0.06578701549142804,
+    0.304684750724884,
+    0.2904801297290076,
+    0.0,
+    -0.23889773523344604,
+    -0.5112616136592012,
+    0.06578701549142545,
+    0.23889773523345467,
+    0.0,
+    0.0,
+    0.0,
+    0.3017929516615495,
+    0.25792362796341184,
+    0.0,
+    0.16272340142866204,
+    0.09520022653475037,
+    0.0,
+    0.3017929516615503,
+    0.09520022653475055,
+    -0.16272340142866173,
+    -0.35312385449816297,
+    0.25792362796341295,
+    0.0,
+    -0.3531238544981624,
+    -0.6035859033230976,
+    0.0,
+    0.0,
+    0.40824829046386274,
+    0.0,
+    0.0,
+    0.0,
+    0.0,
+    -0.4082482904638628,
+    -0.4082482904638635,
+    0.0,
+    0.0,
+    -0.40824829046386296,
+    0.0,
+    0.4082482904638634,
+    0.408248290463863,
+    0.0,
+    0.0,
+    0.0,
+    0.1747866975480809,
+    0.0812611176717539,
+    0.0,
+    0.0,
+    -0.3675398009862027,
+    -0.307882213957909,
+    -0.17478669754808135,
+    0.3675398009862011,
+    0.0,
+    0.4826689115059883,
+    -0.08126111767175039,
+    0.30788221395790305,
+    -0.48266891150598584,
+    0.0,
+    0.0,
+    0.0,
+    -0.21105601049335784,
+    0.18567180916109802,
+    0.0,
+    0.0,
+    0.49215859013738733,
+    -0.38525013709251915,
+    0.21105601049335806,
+    -0.49215859013738905,
+    0.0,
+    0.17419412659916217,
+    -0.18567180916109904,
+    0.3852501370925211,
+    -0.1741941265991621,
+    0.0,
+    0.0,
+    0.0,
+    -0.14266084808807264,
+    -0.3416446842253372,
+    0.0,
+    0.7367497537172237,
+    0.24627107722075148,
+    -0.08574019035519306,
+    -0.14266084808807344,
+    0.24627107722075137,
+    0.14883399227113567,
+    -0.04768680350229251,
+    -0.3416446842253373,
+    -0.08574019035519267,
+    -0.047686803502292804,
+    -0.14266084808807242,
+    0.0,
+    0.0,
+    -0.13813540350758585,
+    0.3302282550303788,
+    0.0,
+    0.08755115000587084,
+    -0.07946706605909573,
+    -0.4613374887461511,
+    -0.13813540350758294,
+    -0.07946706605910261,
+    0.49724647109535086,
+    0.12538059448563663,
+    0.3302282550303805,
+    -0.4613374887461554,
+    0.12538059448564315,
+    -0.13813540350758452,
+    0.0,
+    0.0,
+    -0.17437602599651067,
+    0.0702790691196284,
+    0.0,
+    -0.2921026642334881,
+    0.3623817333531167,
+    0.0,
+    -0.1743760259965108,
+    0.36238173335311646,
+    0.29210266423348785,
+    -0.4326608024727445,
+    0.07027906911962818,
+    0.0,
+    -0.4326608024727457,
+    0.34875205199302267,
+    0.0,
+    0.0,
+    0.11354987314994337,
+    -0.07417504595810355,
+    0.0,
+    0.19402893032594343,
+    -0.435190496523228,
+    0.21918684838857466,
+    0.11354987314994257,
+    -0.4351904965232251,
+    0.5550443808910661,
+    -0.25468277124066463,
+    -0.07417504595810233,
+    0.2191868483885728,
+    -0.25468277124066413,
+    0.1135498731499429,
+];
+
+#[allow(clippy::excessive_precision)]
+#[allow(clippy::approx_constant)]
+fn avfidct4x4(coeffs: &[f32], pixels: &mut [f32]) {
+    for i in 0..16 {
+        let mut pixel: f32 = 0.0;
+        for j in 0..16 {
+            pixel += coeffs[j] * AFV4X4BASIS[j * 16 + i];
+        }
+        pixels[i] = pixel;
+    }
+}
+
+#[inline(always)]
+fn afv_transform_to_pixels<D: SimdDescriptor>(
+    d: D,
+    afv_kind: usize,
+    coefficients: &[f32],
+    pixels: &mut [f32],
+) {
+    let afv_x = afv_kind & 1;
+    let afv_y = afv_kind / 2;
+    let block00 = coefficients[0];
+    let block01 = coefficients[1];
+    let block10 = coefficients[8];
+    let dcs: [f32; 3] = [
+        (block00 + block10 + block01) * 4.0,
+        block00 + block10 - block01,
+        block00 - block10,
+    ];
+    // IAFV: (even, even) positions.
+    let mut coeff: Vec<f32> = vec![0.0; 4 * 4];
+    for iy in 0..4 {
+        for ix in 0..4 {
+            coeff[iy * 4 + ix] = if ix == 0 && iy == 0 {
+                dcs[0]
+            } else {
+                coefficients[iy * 2 * 8 + ix * 2]
+            };
+        }
+    }
+    let mut block: Vec<f32> = vec![0.0; 4 * 8];
+    avfidct4x4(&coeff, &mut block);
+    for iy in 0..4 {
+        let block_y = if afv_y == 1 { 3 - iy } else { iy };
+        for ix in 0..4 {
+            let block_x = if afv_x == 1 { 3 - ix } else { ix };
+            pixels[(iy + afv_y * 4) * 8 + afv_x * 4 + ix] = block[block_y * 4 + block_x];
+        }
+    }
+    // IDCT4x4 in (odd, even) positions.
+    for iy in 0..4 {
+        for ix in 0..4 {
+            block[iy * 4 + ix] = if ix == 0 && iy == 0 {
+                dcs[1]
+            } else {
+                coefficients[iy * 2 * 8 + ix * 2 + 1]
+            };
+        }
+    }
+    idct2d_4_4(d, &mut block[0..16]);
+    for iy in 0..4 {
+        for ix in 0..4 {
+            pixels[(iy + afv_y * 4) * 8 + (1 - afv_x) * 4 + ix] = block[iy * 4 + ix];
+        }
+    }
+    // IDCT4x8.
+    for iy in 0..4 {
+        for ix in 0..8 {
+            block[iy * 8 + ix] = if ix == 0 && iy == 0 {
+                dcs[2]
+            } else {
+                coefficients[(1 + iy * 2) * 8 + ix]
+            };
+        }
+    }
+    idct2d_4_8(d, &mut block);
+    for iy in 0..4 {
+        for ix in 0..8 {
+            pixels[(iy + (1 - afv_y) * 4) * 8 + ix] = block[iy * 8 + ix];
+        }
+    }
+}
+
+#[inline(always)]
+pub fn transform_to_pixels_impl<D: SimdDescriptor>(
+    d: D,
+    transform_type: HfTransformType,
+    lf: &mut [f32],
+    transform_buffer: &mut [f32],
+) {
+    match transform_type {
+        HfTransformType::DCT => d.call(
+            #[inline(always)]
+            |_| {
+                transform_buffer[0] = lf[0];
+                idct2d_8_8(d, &mut transform_buffer[0..64]);
+            },
+        ),
+        HfTransformType::DCT16X16 => d.call(
+            #[inline(always)]
+            |_| {
+                reinterpreting_dct2d_2_2(d, &mut lf[..4], transform_buffer);
+                idct2d_16_16(d, &mut transform_buffer[0..256]);
+            },
+        ),
+        HfTransformType::DCT32X32 => d.call(
+            #[inline(always)]
+            |_| {
+                reinterpreting_dct2d_4_4(d, &mut lf[..16], transform_buffer);
+                idct2d_32_32(d, &mut transform_buffer[0..1024]);
+            },
+        ),
+        HfTransformType::DCT16X8 => d.call(
+            #[inline(always)]
+            |_| {
+                reinterpreting_dct2d_2_1(d, &mut lf[..2], transform_buffer);
+                idct2d_16_8(d, &mut transform_buffer[0..128]);
+            },
+        ),
+        HfTransformType::DCT8X16 => d.call(
+            #[inline(always)]
+            |_| {
+                reinterpreting_dct2d_1_2(d, &mut lf[..2], transform_buffer);
+                idct2d_8_16(d, &mut transform_buffer[0..128]);
+            },
+        ),
+        HfTransformType::DCT32X8 => d.call(
+            #[inline(always)]
+            |_| {
+                reinterpreting_dct2d_4_1(d, &mut lf[..4], transform_buffer);
+                idct2d_32_8(d, &mut transform_buffer[0..256]);
+            },
+        ),
+        HfTransformType::DCT8X32 => d.call(
+            #[inline(always)]
+            |_| {
+                reinterpreting_dct2d_1_4(d, &mut lf[..4], transform_buffer);
+                idct2d_8_32(d, &mut transform_buffer[0..256]);
+            },
+        ),
+        HfTransformType::DCT32X16 => d.call(
+            #[inline(always)]
+            |_| {
+                reinterpreting_dct2d_4_2(d, &mut lf[..8], transform_buffer);
+                idct2d_32_16(d, &mut transform_buffer[0..512]);
+            },
+        ),
+        HfTransformType::DCT16X32 => d.call(
+            #[inline(always)]
+            |_| {
+                reinterpreting_dct2d_2_4(d, &mut lf[..8], transform_buffer);
+                idct2d_16_32(d, &mut transform_buffer[0..512]);
+            },
+        ),
+        HfTransformType::DCT64X64 => d.call(
+            #[inline(always)]
+            |_| {
+                reinterpreting_dct2d_8_8(d, &mut lf[..64], transform_buffer);
+                idct2d_64_64(d, &mut transform_buffer[0..4096]);
+            },
+        ),
+        HfTransformType::DCT64X32 => d.call(
+            #[inline(always)]
+            |_| {
+                reinterpreting_dct2d_8_4(d, &mut lf[..32], transform_buffer);
+                idct2d_64_32(d, &mut transform_buffer[0..2048]);
+            },
+        ),
+        HfTransformType::DCT32X64 => d.call(
+            #[inline(always)]
+            |_| {
+                reinterpreting_dct2d_4_8(d, &mut lf[..32], transform_buffer);
+                idct2d_32_64(d, &mut transform_buffer[0..2048]);
+            },
+        ),
+        HfTransformType::DCT128X128 => d.call(
+            #[inline(always)]
+            |_| {
+                reinterpreting_dct2d_16_16(d, &mut lf[..256], transform_buffer);
+                idct2d_128_128(d, &mut transform_buffer[0..16384]);
+            },
+        ),
+        HfTransformType::DCT128X64 => d.call(
+            #[inline(always)]
+            |_| {
+                reinterpreting_dct2d_16_8(d, &mut lf[..128], transform_buffer);
+                idct2d_128_64(d, &mut transform_buffer[0..8192]);
+            },
+        ),
+        HfTransformType::DCT64X128 => d.call(
+            #[inline(always)]
+            |_| {
+                reinterpreting_dct2d_8_16(d, &mut lf[..128], transform_buffer);
+                idct2d_64_128(d, &mut transform_buffer[0..8192]);
+            },
+        ),
+        HfTransformType::DCT256X256 => d.call(
+            #[inline(always)]
+            |_| {
+                reinterpreting_dct2d_32_32(d, &mut lf[..1024], transform_buffer);
+                idct2d_256_256(d, &mut transform_buffer[0..65536]);
+            },
+        ),
+        HfTransformType::DCT256X128 => d.call(
+            #[inline(always)]
+            |_| {
+                reinterpreting_dct2d_32_16(d, &mut lf[..512], transform_buffer);
+                idct2d_256_128(d, &mut transform_buffer[0..32768]);
+            },
+        ),
+        HfTransformType::DCT128X256 => d.call(
+            #[inline(always)]
+            |_| {
+                reinterpreting_dct2d_16_32(d, &mut lf[..512], transform_buffer);
+                idct2d_128_256(d, &mut transform_buffer[0..32768]);
+            },
+        ),
+        HfTransformType::AFV0 => {
+            transform_buffer[0] = lf[0];
+            let block: Vec<f32> = transform_buffer[0..64].to_vec();
+            afv_transform_to_pixels::<D>(d, 0, &block, &mut transform_buffer[0..64]);
+        }
+        HfTransformType::AFV1 => {
+            transform_buffer[0] = lf[0];
+            let block: Vec<f32> = transform_buffer[0..64].to_vec();
+            afv_transform_to_pixels::<D>(d, 1, &block, &mut transform_buffer[0..64]);
+        }
+        HfTransformType::AFV2 => {
+            transform_buffer[0] = lf[0];
+            let block: Vec<f32> = transform_buffer[0..64].to_vec();
+            afv_transform_to_pixels::<D>(d, 2, &block, &mut transform_buffer[0..64]);
+        }
+        HfTransformType::AFV3 => {
+            transform_buffer[0] = lf[0];
+            let block: Vec<f32> = transform_buffer[0..64].to_vec();
+            afv_transform_to_pixels::<D>(d, 3, &block, &mut transform_buffer[0..64]);
+        }
+        HfTransformType::IDENTITY => {
+            transform_buffer[0] = lf[0];
+            let coefficients: [f32; 64] = transform_buffer[0..64].try_into().unwrap();
+            let block00 = coefficients[0];
+            let block01 = coefficients[1];
+            let block10 = coefficients[8];
+            let block11 = coefficients[9];
+            let dcs: [f32; 4] = [
+                block00 + block01 + block10 + block11,
+                block00 + block01 - block10 - block11,
+                block00 - block01 + block10 - block11,
+                block00 - block01 - block10 + block11,
+            ];
+            for y in 0..2 {
+                for x in 0..2 {
+                    let block_dc = dcs[y * 2 + x];
+                    let mut residual_sum = 0.0;
+                    for iy in 0..4 {
+                        for ix in 0..4 {
+                            if ix == 0 && iy == 0 {
+                                continue;
+                            }
+                            residual_sum += coefficients[(y + iy * 2) * 8 + x + ix * 2];
+                        }
+                    }
+                    transform_buffer[(4 * y + 1) * 8 + 4 * x + 1] =
+                        block_dc - residual_sum * (1.0 / 16.0);
+                    for iy in 0..4 {
+                        for ix in 0..4 {
+                            if ix == 1 && iy == 1 {
+                                continue;
+                            }
+                            transform_buffer[(y * 4 + iy) * 8 + x * 4 + ix] = coefficients
+                                [(y + iy * 2) * 8 + x + ix * 2]
+                                + transform_buffer[(4 * y + 1) * 8 + 4 * x + 1];
+                        }
+                    }
+                    transform_buffer[y * 4 * 8 + x * 4] = coefficients[(y + 2) * 8 + x + 2]
+                        + transform_buffer[(4 * y + 1) * 8 + 4 * x + 1];
+                }
+            }
+        }
+        HfTransformType::DCT2X2 => {
+            transform_buffer[0] = lf[0];
+            let mut tmp: [f32; 64] = transform_buffer[0..64].try_into().unwrap();
+            idct2_top_block(2, &tmp, &mut transform_buffer[0..64]);
+            idct2_top_block(4, &transform_buffer[0..64], &mut tmp);
+            idct2_top_block(8, &tmp, &mut transform_buffer[0..64]);
+        }
+        HfTransformType::DCT4X4 => {
+            transform_buffer[0] = lf[0];
+            let coefficients: [f32; 64] = transform_buffer[0..64].try_into().unwrap();
+            let block00 = coefficients[0];
+            let block01 = coefficients[1];
+            let block10 = coefficients[8];
+            let block11 = coefficients[9];
+            let dcs: [f32; 4] = [
+                block00 + block01 + block10 + block11,
+                block00 + block01 - block10 - block11,
+                block00 - block01 + block10 - block11,
+                block00 - block01 - block10 + block11,
+            ];
+            for y in 0..2 {
+                for x in 0..2 {
+                    let mut block = [0.0; 4 * 4];
+                    block[0] = dcs[y * 2 + x];
+                    for iy in 0..4 {
+                        for ix in 0..4 {
+                            if ix == 0 && iy == 0 {
+                                continue;
+                            }
+                            block[iy * 4 + ix] = coefficients[(y + iy * 2) * 8 + x + ix * 2];
+                        }
+                    }
+                    idct2d_4_4(d, &mut block);
+                    for iy in 0..4 {
+                        for ix in 0..4 {
+                            transform_buffer[(y * 4 + iy) * 8 + x * 4 + ix] = block[iy * 4 + ix];
+                        }
+                    }
+                }
+            }
+        }
+        HfTransformType::DCT8X4 => {
+            transform_buffer[0] = lf[0];
+            let coefficients: [f32; 64] = transform_buffer[0..64].try_into().unwrap();
+            let block0 = coefficients[0];
+            let block1 = coefficients[8];
+            let dcs: [f32; 2] = [block0 + block1, block0 - block1];
+            for x in 0..2 {
+                let mut block = [0.0; 8 * 4];
+                for iy in 0..4 {
+                    for ix in 0..8 {
+                        block[iy * 8 + ix] = if ix == 0 && iy == 0 {
+                            dcs[x]
+                        } else {
+                            coefficients[(x + iy * 2) * 8 + ix]
+                        }
+                    }
+                }
+                idct2d_8_4(d, &mut block);
+                for iy in 0..8 {
+                    for ix in 0..4 {
+                        transform_buffer[iy * 8 + x * 4 + ix] = block[iy * 4 + ix];
+                    }
+                }
+            }
+        }
+        HfTransformType::DCT4X8 => {
+            transform_buffer[0] = lf[0];
+            let coefficients: [f32; 64] = transform_buffer[0..64].try_into().unwrap();
+            let block0 = coefficients[0];
+            let block1 = coefficients[8];
+            let dcs: [f32; 2] = [block0 + block1, block0 - block1];
+            for y in 0..2 {
+                let mut block = [0.0; 4 * 8];
+                for iy in 0..4 {
+                    for ix in 0..8 {
+                        block[iy * 8 + ix] = if ix == 0 && iy == 0 {
+                            dcs[y]
+                        } else {
+                            coefficients[(y + iy * 2) * 8 + ix]
+                        }
+                    }
+                }
+                idct2d_4_8(d, &mut block);
+                for iy in 0..4 {
+                    for ix in 0..8 {
+                        transform_buffer[(y * 4 + iy) * 8 + ix] = block[iy * 8 + ix];
+                    }
+                }
+            }
+        }
+    };
+}
+
+simd_function!(
+    transform_to_pixels,
+    d: D,
+    /// This includes a call to what libjxl calls lowest_frequencies_from_lf.
+    pub fn transform_to_pixels_trampoline(
+        transform_type: HfTransformType,
+        lf: &mut [f32],
+        transform_buffer: &mut [f32],
+    ) {
+        transform_to_pixels_impl(d, transform_type, lf, transform_buffer);
+    }
+);
diff --git a/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/transform_map.rs b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/transform_map.rs
new file mode 100644
index 0000000..ea1902a9
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/transform_map.rs
@@ -0,0 +1,116 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+pub const MAX_COEFF_BLOCKS: usize = 32;
+pub const MAX_BLOCK_DIM: usize = 8 * MAX_COEFF_BLOCKS;
+pub const MAX_COEFF_AREA: usize = MAX_BLOCK_DIM * MAX_BLOCK_DIM;
+
+#[allow(clippy::upper_case_acronyms)]
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub enum HfTransformType {
+    // Update HfTransformType::VALUES when changing this!
+    // Regular block size DCT
+    DCT = 0,
+    // Encode pixels without transforming
+    // a.k.a "Hornuss"
+    IDENTITY = 1,
+    // Use 2-by-2 DCT
+    DCT2X2 = 2,
+    // Use 4-by-4 DCT
+    DCT4X4 = 3,
+    // Use 16-by-16 DCT
+    DCT16X16 = 4,
+    // Use 32-by-32 DCT
+    DCT32X32 = 5,
+    // Use 16-by-8 DCT
+    DCT16X8 = 6,
+    // Use 8-by-16 DCT
+    DCT8X16 = 7,
+    // Use 32-by-8 DCT
+    DCT32X8 = 8,
+    // Use 8-by-32 DCT
+    DCT8X32 = 9,
+    // Use 32-by-16 DCT
+    DCT32X16 = 10,
+    // Use 16-by-32 DCT
+    DCT16X32 = 11,
+    // 4x8 and 8x4 DCT
+    DCT4X8 = 12,
+    DCT8X4 = 13,
+    // Corner-DCT.
+    AFV0 = 14,
+    AFV1 = 15,
+    AFV2 = 16,
+    AFV3 = 17,
+    // Larger DCTs
+    DCT64X64 = 18,
+    DCT64X32 = 19,
+    DCT32X64 = 20,
+    // No transforms smaller than 64x64 are allowed below.
+    DCT128X128 = 21,
+    DCT128X64 = 22,
+    DCT64X128 = 23,
+    DCT256X256 = 24,
+    DCT256X128 = 25,
+    DCT128X256 = 26,
+}
+
+impl HfTransformType {
+    pub const INVALID_TRANSFORM: u8 = Self::CARDINALITY as u8;
+    pub const CARDINALITY: usize = Self::VALUES.len();
+    pub const VALUES: [HfTransformType; 27] = [
+        HfTransformType::DCT,
+        HfTransformType::IDENTITY,
+        HfTransformType::DCT2X2,
+        HfTransformType::DCT4X4,
+        HfTransformType::DCT16X16,
+        HfTransformType::DCT32X32,
+        HfTransformType::DCT16X8,
+        HfTransformType::DCT8X16,
+        HfTransformType::DCT32X8,
+        HfTransformType::DCT8X32,
+        HfTransformType::DCT32X16,
+        HfTransformType::DCT16X32,
+        HfTransformType::DCT4X8,
+        HfTransformType::DCT8X4,
+        HfTransformType::AFV0,
+        HfTransformType::AFV1,
+        HfTransformType::AFV2,
+        HfTransformType::AFV3,
+        HfTransformType::DCT64X64,
+        HfTransformType::DCT64X32,
+        HfTransformType::DCT32X64,
+        HfTransformType::DCT128X128,
+        HfTransformType::DCT128X64,
+        HfTransformType::DCT64X128,
+        HfTransformType::DCT256X256,
+        HfTransformType::DCT256X128,
+        HfTransformType::DCT128X256,
+    ];
+    pub fn from_usize(idx: usize) -> Option<HfTransformType> {
+        HfTransformType::VALUES.get(idx).copied()
+    }
+}
+
+pub fn covered_blocks_x(transform: HfTransformType) -> u32 {
+    let lut: [u32; HfTransformType::CARDINALITY] = [
+        1, 1, 1, 1, 2, 4, 1, 2, 1, 4, 2, 4, 1, 1, 1, 1, 1, 1, 8, 4, 8, 16, 8, 16, 32, 16, 32,
+    ];
+    lut[transform as usize]
+}
+
+pub fn covered_blocks_y(transform: HfTransformType) -> u32 {
+    let lut: [u32; HfTransformType::CARDINALITY] = [
+        1, 1, 1, 1, 2, 4, 2, 1, 4, 1, 4, 2, 1, 1, 1, 1, 1, 1, 8, 8, 4, 16, 16, 8, 32, 32, 16,
+    ];
+    lut[transform as usize]
+}
+
+pub fn block_shape_id(transform: HfTransformType) -> u32 {
+    let lut: [u32; HfTransformType::CARDINALITY] = [
+        0, 1, 1, 1, 2, 3, 4, 4, 5, 5, 6, 6, 1, 1, 1, 1, 1, 1, 7, 8, 8, 9, 10, 10, 11, 12, 12,
+    ];
+    lut[transform as usize]
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/.cargo-checksum.json b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/.cargo-checksum.json
new file mode 100644
index 0000000..697c9ce
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{}}
diff --git a/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/.cargo_vcs_info.json
new file mode 100644
index 0000000..a00bc5f
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+  "git": {
+    "sha1": "7cc33515dd2ae0eb43c5795c50ce49c554e8ba02"
+  },
+  "path_in_vcs": ""
+}
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/.gitignore b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/.gitignore
new file mode 100644
index 0000000..fa8d85ac
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/.gitignore
@@ -0,0 +1,2 @@
+Cargo.lock
+target
diff --git a/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/Cargo.toml
new file mode 100644
index 0000000..36a8899f
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/Cargo.toml
@@ -0,0 +1,68 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2021"
+rust-version = "1.56.0"
+name = "num-derive"
+version = "0.4.2"
+authors = ["The Rust Project Developers"]
+exclude = [
+    "/ci/*",
+    "/.github/*",
+]
+description = "Numeric syntax extensions"
+homepage = "https://github.com/rust-num/num-derive"
+documentation = "https://docs.rs/num-derive"
+readme = "README.md"
+keywords = [
+    "mathematics",
+    "numerics",
+]
+categories = ["science"]
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/rust-num/num-derive"
+
+[lib]
+name = "num_derive"
+test = false
+proc-macro = true
+
+[[test]]
+name = "newtype-2015"
+edition = "2015"
+
+[[test]]
+name = "newtype-2018"
+edition = "2018"
+
+[[test]]
+name = "trivial-2015"
+edition = "2015"
+
+[[test]]
+name = "trivial-2018"
+edition = "2018"
+
+[dependencies.proc-macro2]
+version = "1"
+
+[dependencies.quote]
+version = "1"
+
+[dependencies.syn]
+version = "2.0.5"
+
+[dev-dependencies.num]
+version = "0.4"
+
+[dev-dependencies.num-traits]
+version = "0.2"
diff --git a/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/Cargo.toml.orig
new file mode 100644
index 0000000..4a13a07a
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/Cargo.toml.orig
@@ -0,0 +1,48 @@
+[package]
+authors = ["The Rust Project Developers"]
+description = "Numeric syntax extensions"
+documentation = "https://docs.rs/num-derive"
+homepage = "https://github.com/rust-num/num-derive"
+keywords = ["mathematics", "numerics"]
+categories = [ "science" ]
+license = "MIT OR Apache-2.0"
+name = "num-derive"
+repository = "https://github.com/rust-num/num-derive"
+version = "0.4.2"
+readme = "README.md"
+exclude = ["/ci/*", "/.github/*"]
+edition = "2021"
+rust-version = "1.56.0"
+
+[dependencies]
+proc-macro2 = "1"
+quote = "1"
+syn = "2.0.5"
+
+[dev-dependencies]
+num = "0.4"
+num-traits = "0.2"
+
+[lib]
+name = "num_derive"
+proc-macro = true
+test = false
+
+# Most of the tests are left implicily detected, compiled for Rust 2021,
+# but let's try a few of them with the older editions too.
+
+[[test]]
+name = "newtype-2015"
+edition = "2015"
+
+[[test]]
+name = "newtype-2018"
+edition = "2018"
+
+[[test]]
+name = "trivial-2015"
+edition = "2015"
+
+[[test]]
+name = "trivial-2018"
+edition = "2018"
diff --git a/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/LICENSE-APACHE b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/LICENSE-APACHE
new file mode 100644
index 0000000..16fe87b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/LICENSE-APACHE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/LICENSE-MIT b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/LICENSE-MIT
new file mode 100644
index 0000000..39d4bdb
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2014 The Rust Project Developers
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/README.md b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/README.md
new file mode 100644
index 0000000..20d66a63
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/README.md
@@ -0,0 +1,69 @@
+# num-derive
+
+[![crate](https://img.shields.io/crates/v/num-derive.svg)](https://crates.io/crates/num-derive)
+[![documentation](https://docs.rs/num-derive/badge.svg)](https://docs.rs/num-derive)
+[![minimum rustc 1.56](https://img.shields.io/badge/rustc-1.56+-red.svg)](https://rust-lang.github.io/rfcs/2495-min-rust-version.html)
+[![build status](https://github.com/rust-num/num-derive/workflows/master/badge.svg)](https://github.com/rust-num/num-derive/actions)
+
+Procedural macros to derive numeric traits in Rust.
+
+## Usage
+
+Add this to your `Cargo.toml`:
+
+```toml
+[dependencies]
+num-traits = "0.2"
+num-derive = "0.4"
+```
+
+and this to your crate root:
+
+```rust
+#[macro_use]
+extern crate num_derive;
+```
+
+Then you can derive traits on your own types:
+
+```rust
+#[derive(FromPrimitive, ToPrimitive)]
+enum Color {
+    Red,
+    Blue,
+    Green,
+}
+```
+
+## Optional features
+
+- **`full-syntax`** — Enables `num-derive` to handle enum discriminants
+  represented by complex expressions. Usually can be avoided by
+  [utilizing constants], so only use this feature if namespace pollution is
+  undesired and [compile time doubling] is acceptable.
+
+[utilizing constants]: https://github.com/rust-num/num-derive/pull/3#issuecomment-359044704
+[compile time doubling]: https://github.com/rust-num/num-derive/pull/3#issuecomment-359172588
+
+## Releases
+
+Release notes are available in [RELEASES.md](RELEASES.md).
+
+## Compatibility
+
+The `num-derive` crate is tested for rustc 1.56 and greater.
+
+## License
+
+Licensed under either of
+
+ * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
+ * [MIT license](http://opensource.org/licenses/MIT)
+
+at your option.
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
+dual licensed as above, without any additional terms or conditions.
diff --git a/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/RELEASES.md b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/RELEASES.md
new file mode 100644
index 0000000..bbf6d533
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/RELEASES.md
@@ -0,0 +1,129 @@
+# Release 0.4.2 (2024-02-06)
+
+- [Use anon-const to avoid RFC 3373 warnings.][62]
+
+[62]: https://github.com/rust-num/num-derive/pull/62
+
+# Release 0.4.1 (2023-10-07)
+
+- [Make `Float` work with `no_std`][56] -- thanks @vkahl!
+- [Emit full paths for `Option` and `Result`.][57]
+- [Add derive macro for `num_traits::Signed` and `Unsigned`][55] -- thanks @tdelabro!
+
+[55]: https://github.com/rust-num/num-derive/pull/55
+[56]: https://github.com/rust-num/num-derive/pull/56
+[57]: https://github.com/rust-num/num-derive/pull/57
+
+# Release 0.4.0 (2023-06-29)
+
+- [Update to syn-2][54] -- thanks @maurer!
+  - This raises the minimum supported rustc to 1.56.
+  - The "full-syntax" feature has also been removed.
+
+[54]: https://github.com/rust-num/num-derive/pull/54
+
+# Release 0.3.3 (2020-10-29)
+
+- [Make `NumOps` work with `no_std`][41] -- thanks @jedrzejboczar!
+
+[41]: https://github.com/rust-num/num-derive/pull/41
+
+# Release 0.3.2 (2020-08-24)
+
+- [Add `#[inline]` to all derived functions][40] -- thanks @Amanieu!
+
+[40]: https://github.com/rust-num/num-derive/pull/40
+
+# Release 0.3.1 (2020-07-28)
+
+- [Add `num_traits` proc_macro helper for explicit import][35] - thanks @jean-airoldie!
+- [Provide nicer parse errors and suggest "full-syntax"][39]
+
+[35]: https://github.com/rust-num/num-derive/pull/35
+[39]: https://github.com/rust-num/num-derive/pull/39
+
+# Release 0.3.0 (2019-09-27)
+
+- [Updated the `proc-macro2`, `quote`, and `syn` dependencies to 1.0][28],
+  which raises the minimum supported rustc to 1.31.
+
+[28]: https://github.com/rust-num/num-derive/pull/28
+
+# Release 0.2.5 (2019-04-23)
+
+- [Improved the masking of lints in derived code][23].
+
+[23]: https://github.com/rust-num/num-derive/pull/23
+
+# Release 0.2.4 (2019-01-25)
+
+- [Adjusted dependencies to allow no-std targets][22].
+
+[22]: https://github.com/rust-num/num-derive/pull/22
+
+# Release 0.2.3 (2018-10-03)
+
+- [Added newtype deriving][17] for `FromPrimitive`, `ToPrimitive`,
+  `NumOps<Self, Self>`, `NumCast`, `Zero`, `One`, `Num`, and `Float`.
+  Thanks @asayers!
+
+[17]: https://github.com/rust-num/num-derive/pull/17
+
+# Release 0.2.2 (2018-05-22)
+
+- [Updated dependencies][14].
+
+[14]: https://github.com/rust-num/num-derive/pull/14
+
+# Release 0.2.1 (2018-05-09)
+
+- [Updated dependencies][12] -- thanks @spearman!
+
+[12]: https://github.com/rust-num/num-derive/pull/12
+
+# Release 0.2.0 (2018-02-21)
+
+- [Discriminant matching is now simplified][10], casting values directly by
+  name, rather than trying to compute offsets from known values manually.
+- **breaking change**: [Derivations now import the traits from `num-traits`][11]
+  instead of the full `num` crate.  These are still compatible, but users need
+  to have an explicit `num-traits = "0.2"` dependency in their `Cargo.toml`.
+
+[10]: https://github.com/rust-num/num-derive/pull/10
+[11]: https://github.com/rust-num/num-derive/pull/11
+
+
+# Release 0.1.44 (2018-01-26)
+
+- [The derived code now explicitly allows `unused_qualifications`][9], so users
+  that globally deny that lint don't encounter an error.
+
+[9]: https://github.com/rust-num/num-derive/pull/9
+
+
+# Release 0.1.43 (2018-01-23)
+
+- [The derived code now explicitly allows `trivial_numeric_casts`][7], so users
+  that globally deny that lint don't encounter an error.
+
+[7]: https://github.com/rust-num/num-derive/pull/7
+
+
+# Release 0.1.42 (2018-01-22)
+
+- [num-derive now has its own source repository][num-356] at [rust-num/num-derive][home].
+- [The derivation macros have been updated][3] to using `syn` 0.12.  Support for complex
+  expressions in enum values can be enabled with the `full-syntax` feature.
+
+Thanks to @cuviper and @hcpl for their contributions!
+
+[home]: https://github.com/rust-num/num-derive
+[num-356]: https://github.com/rust-num/num/pull/356
+[3]: https://github.com/rust-num/num-derive/pull/3
+
+
+# Prior releases
+
+No prior release notes were kept.  Thanks all the same to the many
+contributors that have made this crate what it is!
+
diff --git a/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/src/lib.rs
new file mode 100644
index 0000000..207602b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/src/lib.rs
@@ -0,0 +1,1004 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "proc-macro"]
+#![doc(html_root_url = "https://docs.rs/num-derive/0.3")]
+#![recursion_limit = "512"]
+
+//! Procedural macros to derive numeric traits in Rust.
+//!
+//! ## Usage
+//!
+//! Add this to your `Cargo.toml`:
+//!
+//! ```toml
+//! [dependencies]
+//! num-traits = "0.2"
+//! num-derive = "0.3"
+//! ```
+//!
+//! Then you can derive traits on your own types:
+//!
+//! ```rust
+//! #[macro_use]
+//! extern crate num_derive;
+//!
+//! #[derive(FromPrimitive, ToPrimitive)]
+//! enum Color {
+//!     Red,
+//!     Blue,
+//!     Green,
+//! }
+//! # fn main() {}
+//! ```
+//!
+//! ## Explicit import
+//!
+//! By default the `num_derive` procedural macros assume that the
+//! `num_traits` crate is a direct dependency. If `num_traits` is instead
+//! a transitive dependency, the `num_traits` helper attribute can be
+//! used to tell `num_derive` to use a specific identifier for its imports.
+//!
+//! ```rust
+//! #[macro_use]
+//! extern crate num_derive;
+//! // Lets pretend this is a transitive dependency from another crate
+//! // reexported as `some_other_ident`.
+//! extern crate num_traits as some_other_ident;
+//!
+//! #[derive(FromPrimitive, ToPrimitive)]
+//! #[num_traits = "some_other_ident"]
+//! enum Color {
+//!     Red,
+//!     Blue,
+//!     Green,
+//! }
+//! # fn main() {}
+//! ```
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+use proc_macro2::{Span, TokenStream as TokenStream2};
+use quote::quote;
+use syn::{Data, Fields, Ident};
+
+/// Try to parse the tokens, or else return a compilation error
+macro_rules! parse {
+    ($tokens:ident as $type:ty) => {
+        match syn::parse::<$type>($tokens) {
+            Ok(parsed) => parsed,
+            Err(error) => {
+                return TokenStream::from(error.to_compile_error());
+            }
+        }
+    };
+}
+
+// Within `exp`, you can bring things into scope with `extern crate`.
+//
+// We don't want to assume that `num_traits::` is in scope - the user may have imported it under a
+// different name, or may have imported it in a non-toplevel module (common when putting impls
+// behind a feature gate).
+//
+// Solution: let's just generate `extern crate num_traits as _num_traits` and then refer to
+// `_num_traits` in the derived code.  However, macros are not allowed to produce `extern crate`
+// statements at the toplevel.
+//
+// Solution: let's generate `mod _impl_foo` and import num_traits within that.  However, now we
+// lose access to private members of the surrounding module.  This is a problem if, for example,
+// we're deriving for a newtype, where the inner type is defined in the same module, but not
+// exported.
+//
+// Solution: use the anonymous const trick.  For some reason, `extern crate` statements are allowed
+// here, but everything from the surrounding module is in scope.  This trick is taken from serde.
+fn anon_const_trick(exp: TokenStream2) -> TokenStream2 {
+    quote! {
+        #[allow(non_upper_case_globals, unused_qualifications)]
+        const _: () = {
+            #[allow(clippy::useless_attribute)]
+            #[allow(rust_2018_idioms)]
+            extern crate num_traits as _num_traits;
+            #exp
+        };
+    }
+}
+
+// If `data` is a newtype, return the type it's wrapping.
+fn newtype_inner(data: &syn::Data) -> Option<syn::Type> {
+    match *data {
+        Data::Struct(ref s) => {
+            match s.fields {
+                Fields::Unnamed(ref fs) => {
+                    if fs.unnamed.len() == 1 {
+                        Some(fs.unnamed[0].ty.clone())
+                    } else {
+                        None
+                    }
+                }
+                Fields::Named(ref fs) => {
+                    if fs.named.len() == 1 {
+                        panic!("num-derive doesn't know how to handle newtypes with named fields yet. \
+                           Please use a tuple-style newtype, or submit a PR!");
+                    }
+                    None
+                }
+                _ => None,
+            }
+        }
+        _ => None,
+    }
+}
+
+struct NumTraits {
+    import: Ident,
+    explicit: bool,
+}
+
+impl quote::ToTokens for NumTraits {
+    fn to_tokens(&self, tokens: &mut TokenStream2) {
+        self.import.to_tokens(tokens);
+    }
+}
+
+impl NumTraits {
+    fn new(ast: &syn::DeriveInput) -> Self {
+        // If there is a `num_traits` MetaNameValue attribute on the input,
+        // retrieve its value, and use it to create an `Ident` to be used
+        // to import the `num_traits` crate.
+        for attr in &ast.attrs {
+            if attr.path().is_ident("num_traits") {
+                if let Ok(syn::MetaNameValue {
+                    value:
+                        syn::Expr::Lit(syn::ExprLit {
+                            lit: syn::Lit::Str(ref lit_str),
+                            ..
+                        }),
+                    ..
+                }) = attr.meta.require_name_value()
+                {
+                    return NumTraits {
+                        import: syn::Ident::new(&lit_str.value(), lit_str.span()),
+                        explicit: true,
+                    };
+                } else {
+                    panic!("#[num_traits] attribute value must be a str");
+                }
+            }
+        }
+
+        // Otherwise, we'll implicitly import our own.
+        NumTraits {
+            import: Ident::new("_num_traits", Span::call_site()),
+            explicit: false,
+        }
+    }
+
+    fn wrap(&self, output: TokenStream2) -> TokenStream2 {
+        if self.explicit {
+            output
+        } else {
+            anon_const_trick(output)
+        }
+    }
+}
+
+/// Derives [`num_traits::FromPrimitive`][from] for simple enums and newtypes.
+///
+/// [from]: https://docs.rs/num-traits/0.2/num_traits/cast/trait.FromPrimitive.html
+///
+/// # Examples
+///
+/// Simple enums can be derived:
+///
+/// ```rust
+/// # #[macro_use]
+/// # extern crate num_derive;
+///
+/// #[derive(FromPrimitive)]
+/// enum Color {
+///     Red,
+///     Blue,
+///     Green = 42,
+/// }
+/// # fn main() {}
+/// ```
+///
+/// Enums that contain data are not allowed:
+///
+/// ```compile_fail
+/// # #[macro_use]
+/// # extern crate num_derive;
+///
+/// #[derive(FromPrimitive)]
+/// enum Color {
+///     Rgb(u8, u8, u8),
+///     Hsv(u8, u8, u8),
+/// }
+/// # fn main() {}
+/// ```
+///
+/// Structs are not allowed:
+///
+/// ```compile_fail
+/// # #[macro_use]
+/// # extern crate num_derive;
+/// #[derive(FromPrimitive)]
+/// struct Color {
+///     r: u8,
+///     g: u8,
+///     b: u8,
+/// }
+/// # fn main() {}
+/// ```
+#[proc_macro_derive(FromPrimitive, attributes(num_traits))]
+pub fn from_primitive(input: TokenStream) -> TokenStream {
+    let ast = parse!(input as syn::DeriveInput);
+    let name = &ast.ident;
+
+    let import = NumTraits::new(&ast);
+
+    let impl_ = if let Some(inner_ty) = newtype_inner(&ast.data) {
+        quote! {
+            impl #import::FromPrimitive for #name {
+                #[inline]
+                fn from_i64(n: i64) -> ::core::option::Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_i64(n).map(#name)
+                }
+                #[inline]
+                fn from_u64(n: u64) -> ::core::option::Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_u64(n).map(#name)
+                }
+                #[inline]
+                fn from_isize(n: isize) -> ::core::option::Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_isize(n).map(#name)
+                }
+                #[inline]
+                fn from_i8(n: i8) -> ::core::option::Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_i8(n).map(#name)
+                }
+                #[inline]
+                fn from_i16(n: i16) -> ::core::option::Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_i16(n).map(#name)
+                }
+                #[inline]
+                fn from_i32(n: i32) -> ::core::option::Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_i32(n).map(#name)
+                }
+                #[inline]
+                fn from_i128(n: i128) -> ::core::option::Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_i128(n).map(#name)
+                }
+                #[inline]
+                fn from_usize(n: usize) -> ::core::option::Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_usize(n).map(#name)
+                }
+                #[inline]
+                fn from_u8(n: u8) -> ::core::option::Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_u8(n).map(#name)
+                }
+                #[inline]
+                fn from_u16(n: u16) -> ::core::option::Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_u16(n).map(#name)
+                }
+                #[inline]
+                fn from_u32(n: u32) -> ::core::option::Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_u32(n).map(#name)
+                }
+                #[inline]
+                fn from_u128(n: u128) -> ::core::option::Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_u128(n).map(#name)
+                }
+                #[inline]
+                fn from_f32(n: f32) -> ::core::option::Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_f32(n).map(#name)
+                }
+                #[inline]
+                fn from_f64(n: f64) -> ::core::option::Option<Self> {
+                    <#inner_ty as #import::FromPrimitive>::from_f64(n).map(#name)
+                }
+            }
+        }
+    } else {
+        let variants = match ast.data {
+            Data::Enum(ref data_enum) => &data_enum.variants,
+            _ => panic!(
+                "`FromPrimitive` can be applied only to enums and newtypes, {} is neither",
+                name
+            ),
+        };
+
+        let from_i64_var = quote! { n };
+        let clauses: Vec<_> = variants
+            .iter()
+            .map(|variant| {
+                let ident = &variant.ident;
+                match variant.fields {
+                    Fields::Unit => (),
+                    _ => panic!(
+                        "`FromPrimitive` can be applied only to unitary enums and newtypes, \
+                         {}::{} is either struct or tuple",
+                        name, ident
+                    ),
+                }
+
+                quote! {
+                    if #from_i64_var == #name::#ident as i64 {
+                        ::core::option::Option::Some(#name::#ident)
+                    }
+                }
+            })
+            .collect();
+
+        let from_i64_var = if clauses.is_empty() {
+            quote!(_)
+        } else {
+            from_i64_var
+        };
+
+        quote! {
+            impl #import::FromPrimitive for #name {
+                #[allow(trivial_numeric_casts)]
+                #[inline]
+                fn from_i64(#from_i64_var: i64) -> ::core::option::Option<Self> {
+                    #(#clauses else)* {
+                        ::core::option::Option::None
+                    }
+                }
+
+                #[inline]
+                fn from_u64(n: u64) -> ::core::option::Option<Self> {
+                    Self::from_i64(n as i64)
+                }
+            }
+        }
+    };
+
+    import.wrap(impl_).into()
+}
+
+/// Derives [`num_traits::ToPrimitive`][to] for simple enums and newtypes.
+///
+/// [to]: https://docs.rs/num-traits/0.2/num_traits/cast/trait.ToPrimitive.html
+///
+/// # Examples
+///
+/// Simple enums can be derived:
+///
+/// ```rust
+/// # #[macro_use]
+/// # extern crate num_derive;
+///
+/// #[derive(ToPrimitive)]
+/// enum Color {
+///     Red,
+///     Blue,
+///     Green = 42,
+/// }
+/// # fn main() {}
+/// ```
+///
+/// Enums that contain data are not allowed:
+///
+/// ```compile_fail
+/// # #[macro_use]
+/// # extern crate num_derive;
+///
+/// #[derive(ToPrimitive)]
+/// enum Color {
+///     Rgb(u8, u8, u8),
+///     Hsv(u8, u8, u8),
+/// }
+/// # fn main() {}
+/// ```
+///
+/// Structs are not allowed:
+///
+/// ```compile_fail
+/// # #[macro_use]
+/// # extern crate num_derive;
+/// #[derive(ToPrimitive)]
+/// struct Color {
+///     r: u8,
+///     g: u8,
+///     b: u8,
+/// }
+/// # fn main() {}
+/// ```
+#[proc_macro_derive(ToPrimitive, attributes(num_traits))]
+pub fn to_primitive(input: TokenStream) -> TokenStream {
+    let ast = parse!(input as syn::DeriveInput);
+    let name = &ast.ident;
+
+    let import = NumTraits::new(&ast);
+
+    let impl_ = if let Some(inner_ty) = newtype_inner(&ast.data) {
+        quote! {
+            impl #import::ToPrimitive for #name {
+                #[inline]
+                fn to_i64(&self) -> ::core::option::Option<i64> {
+                    <#inner_ty as #import::ToPrimitive>::to_i64(&self.0)
+                }
+                #[inline]
+                fn to_u64(&self) -> ::core::option::Option<u64> {
+                    <#inner_ty as #import::ToPrimitive>::to_u64(&self.0)
+                }
+                #[inline]
+                fn to_isize(&self) -> ::core::option::Option<isize> {
+                    <#inner_ty as #import::ToPrimitive>::to_isize(&self.0)
+                }
+                #[inline]
+                fn to_i8(&self) -> ::core::option::Option<i8> {
+                    <#inner_ty as #import::ToPrimitive>::to_i8(&self.0)
+                }
+                #[inline]
+                fn to_i16(&self) -> ::core::option::Option<i16> {
+                    <#inner_ty as #import::ToPrimitive>::to_i16(&self.0)
+                }
+                #[inline]
+                fn to_i32(&self) -> ::core::option::Option<i32> {
+                    <#inner_ty as #import::ToPrimitive>::to_i32(&self.0)
+                }
+                #[inline]
+                fn to_i128(&self) -> ::core::option::Option<i128> {
+                    <#inner_ty as #import::ToPrimitive>::to_i128(&self.0)
+                }
+                #[inline]
+                fn to_usize(&self) -> ::core::option::Option<usize> {
+                    <#inner_ty as #import::ToPrimitive>::to_usize(&self.0)
+                }
+                #[inline]
+                fn to_u8(&self) -> ::core::option::Option<u8> {
+                    <#inner_ty as #import::ToPrimitive>::to_u8(&self.0)
+                }
+                #[inline]
+                fn to_u16(&self) -> ::core::option::Option<u16> {
+                    <#inner_ty as #import::ToPrimitive>::to_u16(&self.0)
+                }
+                #[inline]
+                fn to_u32(&self) -> ::core::option::Option<u32> {
+                    <#inner_ty as #import::ToPrimitive>::to_u32(&self.0)
+                }
+                #[inline]
+                fn to_u128(&self) -> ::core::option::Option<u128> {
+                    <#inner_ty as #import::ToPrimitive>::to_u128(&self.0)
+                }
+                #[inline]
+                fn to_f32(&self) -> ::core::option::Option<f32> {
+                    <#inner_ty as #import::ToPrimitive>::to_f32(&self.0)
+                }
+                #[inline]
+                fn to_f64(&self) -> ::core::option::Option<f64> {
+                    <#inner_ty as #import::ToPrimitive>::to_f64(&self.0)
+                }
+            }
+        }
+    } else {
+        let variants = match ast.data {
+            Data::Enum(ref data_enum) => &data_enum.variants,
+            _ => panic!(
+                "`ToPrimitive` can be applied only to enums and newtypes, {} is neither",
+                name
+            ),
+        };
+
+        let variants: Vec<_> = variants
+            .iter()
+            .map(|variant| {
+                let ident = &variant.ident;
+                match variant.fields {
+                    Fields::Unit => (),
+                    _ => {
+                        panic!("`ToPrimitive` can be applied only to unitary enums and newtypes, {}::{} is either struct or tuple", name, ident)
+                    },
+                }
+
+                // NB: We have to check each variant individually, because we'll only have `&self`
+                // for the input.  We can't move from that, and it might not be `Clone` or `Copy`.
+                // (Otherwise we could just do `*self as i64` without a `match` at all.)
+                quote!(#name::#ident => #name::#ident as i64)
+            })
+            .collect();
+
+        let match_expr = if variants.is_empty() {
+            // No variants found, so do not use Some to not to trigger `unreachable_code` lint
+            quote! {
+                match *self {}
+            }
+        } else {
+            quote! {
+                ::core::option::Option::Some(match *self {
+                    #(#variants,)*
+                })
+            }
+        };
+
+        quote! {
+            impl #import::ToPrimitive for #name {
+                #[inline]
+                #[allow(trivial_numeric_casts)]
+                fn to_i64(&self) -> ::core::option::Option<i64> {
+                    #match_expr
+                }
+
+                #[inline]
+                fn to_u64(&self) -> ::core::option::Option<u64> {
+                    self.to_i64().map(|x| x as u64)
+                }
+            }
+        }
+    };
+
+    import.wrap(impl_).into()
+}
+
+const NEWTYPE_ONLY: &str = "This trait can only be derived for newtypes";
+
+/// Derives [`num_traits::NumOps`][num_ops] for newtypes.  The inner type must already implement
+/// `NumOps`.
+///
+/// [num_ops]: https://docs.rs/num-traits/0.2/num_traits/trait.NumOps.html
+///
+/// Note that, since `NumOps` is really a trait alias for `Add + Sub + Mul + Div + Rem`, this macro
+/// generates impls for _those_ traits.  Furthermore, in all generated impls, `RHS=Self` and
+/// `Output=Self`.
+#[proc_macro_derive(NumOps)]
+pub fn num_ops(input: TokenStream) -> TokenStream {
+    let ast = parse!(input as syn::DeriveInput);
+    let name = &ast.ident;
+    let inner_ty = newtype_inner(&ast.data).expect(NEWTYPE_ONLY);
+    let impl_ = quote! {
+        impl ::core::ops::Add for #name {
+            type Output = Self;
+            #[inline]
+            fn add(self, other: Self) -> Self {
+                #name(<#inner_ty as ::core::ops::Add>::add(self.0, other.0))
+            }
+        }
+        impl ::core::ops::Sub for #name {
+            type Output = Self;
+            #[inline]
+            fn sub(self, other: Self) -> Self {
+                #name(<#inner_ty as ::core::ops::Sub>::sub(self.0, other.0))
+            }
+        }
+        impl ::core::ops::Mul for #name {
+            type Output = Self;
+            #[inline]
+            fn mul(self, other: Self) -> Self {
+                #name(<#inner_ty as ::core::ops::Mul>::mul(self.0, other.0))
+            }
+        }
+        impl ::core::ops::Div for #name {
+            type Output = Self;
+            #[inline]
+            fn div(self, other: Self) -> Self {
+                #name(<#inner_ty as ::core::ops::Div>::div(self.0, other.0))
+            }
+        }
+        impl ::core::ops::Rem for #name {
+            type Output = Self;
+            #[inline]
+            fn rem(self, other: Self) -> Self {
+                #name(<#inner_ty as ::core::ops::Rem>::rem(self.0, other.0))
+            }
+        }
+    };
+    impl_.into()
+}
+
+/// Derives [`num_traits::NumCast`][num_cast] for newtypes.  The inner type must already implement
+/// `NumCast`.
+///
+/// [num_cast]: https://docs.rs/num-traits/0.2/num_traits/cast/trait.NumCast.html
+#[proc_macro_derive(NumCast, attributes(num_traits))]
+pub fn num_cast(input: TokenStream) -> TokenStream {
+    let ast = parse!(input as syn::DeriveInput);
+    let name = &ast.ident;
+    let inner_ty = newtype_inner(&ast.data).expect(NEWTYPE_ONLY);
+
+    let import = NumTraits::new(&ast);
+
+    let impl_ = quote! {
+        impl #import::NumCast for #name {
+            #[inline]
+            fn from<T: #import::ToPrimitive>(n: T) -> ::core::option::Option<Self> {
+                <#inner_ty as #import::NumCast>::from(n).map(#name)
+            }
+        }
+    };
+
+    import.wrap(impl_).into()
+}
+
+/// Derives [`num_traits::Zero`][zero] for newtypes.  The inner type must already implement `Zero`.
+///
+/// [zero]: https://docs.rs/num-traits/0.2/num_traits/identities/trait.Zero.html
+#[proc_macro_derive(Zero, attributes(num_traits))]
+pub fn zero(input: TokenStream) -> TokenStream {
+    let ast = parse!(input as syn::DeriveInput);
+    let name = &ast.ident;
+    let inner_ty = newtype_inner(&ast.data).expect(NEWTYPE_ONLY);
+
+    let import = NumTraits::new(&ast);
+
+    let impl_ = quote! {
+        impl #import::Zero for #name {
+            #[inline]
+            fn zero() -> Self {
+                #name(<#inner_ty as #import::Zero>::zero())
+            }
+            #[inline]
+            fn is_zero(&self) -> bool {
+                <#inner_ty as #import::Zero>::is_zero(&self.0)
+            }
+        }
+    };
+
+    import.wrap(impl_).into()
+}
+
+/// Derives [`num_traits::One`][one] for newtypes.  The inner type must already implement `One`.
+///
+/// [one]: https://docs.rs/num-traits/0.2/num_traits/identities/trait.One.html
+#[proc_macro_derive(One, attributes(num_traits))]
+pub fn one(input: TokenStream) -> TokenStream {
+    let ast = parse!(input as syn::DeriveInput);
+    let name = &ast.ident;
+    let inner_ty = newtype_inner(&ast.data).expect(NEWTYPE_ONLY);
+
+    let import = NumTraits::new(&ast);
+
+    let impl_ = quote! {
+        impl #import::One for #name {
+            #[inline]
+            fn one() -> Self {
+                #name(<#inner_ty as #import::One>::one())
+            }
+            #[inline]
+            fn is_one(&self) -> bool {
+                <#inner_ty as #import::One>::is_one(&self.0)
+            }
+        }
+    };
+
+    import.wrap(impl_).into()
+}
+
+/// Derives [`num_traits::Num`][num] for newtypes.  The inner type must already implement `Num`.
+///
+/// [num]: https://docs.rs/num-traits/0.2/num_traits/trait.Num.html
+#[proc_macro_derive(Num, attributes(num_traits))]
+pub fn num(input: TokenStream) -> TokenStream {
+    let ast = parse!(input as syn::DeriveInput);
+    let name = &ast.ident;
+    let inner_ty = newtype_inner(&ast.data).expect(NEWTYPE_ONLY);
+
+    let import = NumTraits::new(&ast);
+
+    let impl_ = quote! {
+        impl #import::Num for #name {
+            type FromStrRadixErr = <#inner_ty as #import::Num>::FromStrRadixErr;
+            #[inline]
+            fn from_str_radix(s: &str, radix: u32) -> ::core::result::Result<Self, Self::FromStrRadixErr> {
+                <#inner_ty as #import::Num>::from_str_radix(s, radix).map(#name)
+            }
+        }
+    };
+
+    import.wrap(impl_).into()
+}
+
+/// Derives [`num_traits::Float`][float] for newtypes.  The inner type must already implement
+/// `Float`.
+///
+/// [float]: https://docs.rs/num-traits/0.2/num_traits/float/trait.Float.html
+#[proc_macro_derive(Float, attributes(num_traits))]
+pub fn float(input: TokenStream) -> TokenStream {
+    let ast = parse!(input as syn::DeriveInput);
+    let name = &ast.ident;
+    let inner_ty = newtype_inner(&ast.data).expect(NEWTYPE_ONLY);
+
+    let import = NumTraits::new(&ast);
+
+    let impl_ = quote! {
+        impl #import::Float for #name {
+            #[inline]
+            fn nan() -> Self {
+                #name(<#inner_ty as #import::Float>::nan())
+            }
+            #[inline]
+            fn infinity() -> Self {
+                #name(<#inner_ty as #import::Float>::infinity())
+            }
+            #[inline]
+            fn neg_infinity() -> Self {
+                #name(<#inner_ty as #import::Float>::neg_infinity())
+            }
+            #[inline]
+            fn neg_zero() -> Self {
+                #name(<#inner_ty as #import::Float>::neg_zero())
+            }
+            #[inline]
+            fn min_value() -> Self {
+                #name(<#inner_ty as #import::Float>::min_value())
+            }
+            #[inline]
+            fn min_positive_value() -> Self {
+                #name(<#inner_ty as #import::Float>::min_positive_value())
+            }
+            #[inline]
+            fn max_value() -> Self {
+                #name(<#inner_ty as #import::Float>::max_value())
+            }
+            #[inline]
+            fn is_nan(self) -> bool {
+                <#inner_ty as #import::Float>::is_nan(self.0)
+            }
+            #[inline]
+            fn is_infinite(self) -> bool {
+                <#inner_ty as #import::Float>::is_infinite(self.0)
+            }
+            #[inline]
+            fn is_finite(self) -> bool {
+                <#inner_ty as #import::Float>::is_finite(self.0)
+            }
+            #[inline]
+            fn is_normal(self) -> bool {
+                <#inner_ty as #import::Float>::is_normal(self.0)
+            }
+            #[inline]
+            fn classify(self) -> ::core::num::FpCategory {
+                <#inner_ty as #import::Float>::classify(self.0)
+            }
+            #[inline]
+            fn floor(self) -> Self {
+                #name(<#inner_ty as #import::Float>::floor(self.0))
+            }
+            #[inline]
+            fn ceil(self) -> Self {
+                #name(<#inner_ty as #import::Float>::ceil(self.0))
+            }
+            #[inline]
+            fn round(self) -> Self {
+                #name(<#inner_ty as #import::Float>::round(self.0))
+            }
+            #[inline]
+            fn trunc(self) -> Self {
+                #name(<#inner_ty as #import::Float>::trunc(self.0))
+            }
+            #[inline]
+            fn fract(self) -> Self {
+                #name(<#inner_ty as #import::Float>::fract(self.0))
+            }
+            #[inline]
+            fn abs(self) -> Self {
+                #name(<#inner_ty as #import::Float>::abs(self.0))
+            }
+            #[inline]
+            fn signum(self) -> Self {
+                #name(<#inner_ty as #import::Float>::signum(self.0))
+            }
+            #[inline]
+            fn is_sign_positive(self) -> bool {
+                <#inner_ty as #import::Float>::is_sign_positive(self.0)
+            }
+            #[inline]
+            fn is_sign_negative(self) -> bool {
+                <#inner_ty as #import::Float>::is_sign_negative(self.0)
+            }
+            #[inline]
+            fn mul_add(self, a: Self, b: Self) -> Self {
+                #name(<#inner_ty as #import::Float>::mul_add(self.0, a.0, b.0))
+            }
+            #[inline]
+            fn recip(self) -> Self {
+                #name(<#inner_ty as #import::Float>::recip(self.0))
+            }
+            #[inline]
+            fn powi(self, n: i32) -> Self {
+                #name(<#inner_ty as #import::Float>::powi(self.0, n))
+            }
+            #[inline]
+            fn powf(self, n: Self) -> Self {
+                #name(<#inner_ty as #import::Float>::powf(self.0, n.0))
+            }
+            #[inline]
+            fn sqrt(self) -> Self {
+                #name(<#inner_ty as #import::Float>::sqrt(self.0))
+            }
+            #[inline]
+            fn exp(self) -> Self {
+                #name(<#inner_ty as #import::Float>::exp(self.0))
+            }
+            #[inline]
+            fn exp2(self) -> Self {
+                #name(<#inner_ty as #import::Float>::exp2(self.0))
+            }
+            #[inline]
+            fn ln(self) -> Self {
+                #name(<#inner_ty as #import::Float>::ln(self.0))
+            }
+            #[inline]
+            fn log(self, base: Self) -> Self {
+                #name(<#inner_ty as #import::Float>::log(self.0, base.0))
+            }
+            #[inline]
+            fn log2(self) -> Self {
+                #name(<#inner_ty as #import::Float>::log2(self.0))
+            }
+            #[inline]
+            fn log10(self) -> Self {
+                #name(<#inner_ty as #import::Float>::log10(self.0))
+            }
+            #[inline]
+            fn max(self, other: Self) -> Self {
+                #name(<#inner_ty as #import::Float>::max(self.0, other.0))
+            }
+            #[inline]
+            fn min(self, other: Self) -> Self {
+                #name(<#inner_ty as #import::Float>::min(self.0, other.0))
+            }
+            #[inline]
+            fn abs_sub(self, other: Self) -> Self {
+                #name(<#inner_ty as #import::Float>::abs_sub(self.0, other.0))
+            }
+            #[inline]
+            fn cbrt(self) -> Self {
+                #name(<#inner_ty as #import::Float>::cbrt(self.0))
+            }
+            #[inline]
+            fn hypot(self, other: Self) -> Self {
+                #name(<#inner_ty as #import::Float>::hypot(self.0, other.0))
+            }
+            #[inline]
+            fn sin(self) -> Self {
+                #name(<#inner_ty as #import::Float>::sin(self.0))
+            }
+            #[inline]
+            fn cos(self) -> Self {
+                #name(<#inner_ty as #import::Float>::cos(self.0))
+            }
+            #[inline]
+            fn tan(self) -> Self {
+                #name(<#inner_ty as #import::Float>::tan(self.0))
+            }
+            #[inline]
+            fn asin(self) -> Self {
+                #name(<#inner_ty as #import::Float>::asin(self.0))
+            }
+            #[inline]
+            fn acos(self) -> Self {
+                #name(<#inner_ty as #import::Float>::acos(self.0))
+            }
+            #[inline]
+            fn atan(self) -> Self {
+                #name(<#inner_ty as #import::Float>::atan(self.0))
+            }
+            #[inline]
+            fn atan2(self, other: Self) -> Self {
+                #name(<#inner_ty as #import::Float>::atan2(self.0, other.0))
+            }
+            #[inline]
+            fn sin_cos(self) -> (Self, Self) {
+                let (x, y) = <#inner_ty as #import::Float>::sin_cos(self.0);
+                (#name(x), #name(y))
+            }
+            #[inline]
+            fn exp_m1(self) -> Self {
+                #name(<#inner_ty as #import::Float>::exp_m1(self.0))
+            }
+            #[inline]
+            fn ln_1p(self) -> Self {
+                #name(<#inner_ty as #import::Float>::ln_1p(self.0))
+            }
+            #[inline]
+            fn sinh(self) -> Self {
+                #name(<#inner_ty as #import::Float>::sinh(self.0))
+            }
+            #[inline]
+            fn cosh(self) -> Self {
+                #name(<#inner_ty as #import::Float>::cosh(self.0))
+            }
+            #[inline]
+            fn tanh(self) -> Self {
+                #name(<#inner_ty as #import::Float>::tanh(self.0))
+            }
+            #[inline]
+            fn asinh(self) -> Self {
+                #name(<#inner_ty as #import::Float>::asinh(self.0))
+            }
+            #[inline]
+            fn acosh(self) -> Self {
+                #name(<#inner_ty as #import::Float>::acosh(self.0))
+            }
+            #[inline]
+            fn atanh(self) -> Self {
+                #name(<#inner_ty as #import::Float>::atanh(self.0))
+            }
+            #[inline]
+            fn integer_decode(self) -> (u64, i16, i8) {
+                <#inner_ty as #import::Float>::integer_decode(self.0)
+            }
+            #[inline]
+            fn epsilon() -> Self {
+                #name(<#inner_ty as #import::Float>::epsilon())
+            }
+            #[inline]
+            fn to_degrees(self) -> Self {
+                #name(<#inner_ty as #import::Float>::to_degrees(self.0))
+            }
+            #[inline]
+            fn to_radians(self) -> Self {
+                #name(<#inner_ty as #import::Float>::to_radians(self.0))
+            }
+        }
+    };
+
+    import.wrap(impl_).into()
+}
+
+/// Derives [`num_traits::Signed`][signed] for newtypes.  The inner type must already implement
+/// `Signed`.
+///
+/// [signed]: https://docs.rs/num-traits/0.2/num_traits/sign/trait.Signed.html
+#[proc_macro_derive(Signed, attributes(num_traits))]
+pub fn signed(input: TokenStream) -> TokenStream {
+    let ast = parse!(input as syn::DeriveInput);
+    let name = &ast.ident;
+    let inner_ty = newtype_inner(&ast.data).expect(NEWTYPE_ONLY);
+
+    let import = NumTraits::new(&ast);
+
+    let impl_ = quote! {
+        impl #import::Signed for #name {
+            #[inline]
+            fn abs(&self) -> Self {
+                #name(<#inner_ty as #import::Signed>::abs(&self.0))
+            }
+            #[inline]
+            fn abs_sub(&self, other: &Self) -> Self {
+                #name(<#inner_ty as #import::Signed>::abs_sub(&self.0, &other.0))
+            }
+            #[inline]
+            fn signum(&self) -> Self {
+                #name(<#inner_ty as #import::Signed>::signum(&self.0))
+            }
+            #[inline]
+            fn is_positive(&self) -> bool {
+                <#inner_ty as #import::Signed>::is_positive(&self.0)
+            }
+            #[inline]
+            fn is_negative(&self) -> bool {
+                <#inner_ty as #import::Signed>::is_negative(&self.0)
+            }
+        }
+    };
+
+    import.wrap(impl_).into()
+}
+
+/// Derives [`num_traits::Unsigned`][unsigned].  The inner type must already implement
+/// `Unsigned`.
+///
+/// [unsigned]: https://docs.rs/num/latest/num/traits/trait.Unsigned.html
+#[proc_macro_derive(Unsigned, attributes(num_traits))]
+pub fn unsigned(input: TokenStream) -> TokenStream {
+    let ast = parse!(input as syn::DeriveInput);
+    let name = &ast.ident;
+
+    let import = NumTraits::new(&ast);
+
+    let impl_ = quote! {
+        impl #import::Unsigned for #name {}
+    };
+
+    import.wrap(impl_).into()
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/empty_enum.rs b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/empty_enum.rs
new file mode 100644
index 0000000..173996c8
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/empty_enum.rs
@@ -0,0 +1,23 @@
+// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate num as num_renamed;
+#[macro_use]
+extern crate num_derive;
+
+#[derive(Debug, PartialEq, FromPrimitive, ToPrimitive)]
+enum Color {}
+
+#[test]
+fn test_empty_enum() {
+    let v: [Option<Color>; 1] = [num_renamed::FromPrimitive::from_u64(0)];
+
+    assert_eq!(v, [None]);
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/issue-16.rs b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/issue-16.rs
new file mode 100644
index 0000000..48cc2fb
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/issue-16.rs
@@ -0,0 +1,11 @@
+macro_rules! get_an_isize {
+    () => {
+        0_isize
+    };
+}
+
+#[derive(num_derive::FromPrimitive)]
+pub enum CLikeEnum {
+    VarA = get_an_isize!(),
+    VarB = 2,
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/issue-6.rs b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/issue-6.rs
new file mode 100644
index 0000000..9eae7fb
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/issue-6.rs
@@ -0,0 +1,17 @@
+#![deny(trivial_numeric_casts)]
+
+#[macro_use]
+extern crate num_derive;
+
+#[derive(FromPrimitive, ToPrimitive)]
+pub enum SomeEnum {
+    A = 1,
+}
+
+#[test]
+fn test_trivial_numeric_casts() {
+    use num::{FromPrimitive, ToPrimitive};
+    assert!(SomeEnum::from_u64(1).is_some());
+    assert!(SomeEnum::from_i64(-1).is_none());
+    assert_eq!(SomeEnum::A.to_u64(), Some(1));
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/issue-9.rs b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/issue-9.rs
new file mode 100644
index 0000000..30c04d2
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/issue-9.rs
@@ -0,0 +1,18 @@
+#![deny(unused_qualifications)]
+
+#[macro_use]
+extern crate num_derive;
+use num::FromPrimitive;
+use num::ToPrimitive;
+
+#[derive(FromPrimitive, ToPrimitive)]
+pub enum SomeEnum {
+    A = 1,
+}
+
+#[test]
+fn test_unused_qualifications() {
+    assert!(SomeEnum::from_u64(1).is_some());
+    assert!(SomeEnum::from_i64(-1).is_none());
+    assert!(SomeEnum::A.to_i64().is_some());
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/newtype-2015.rs b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/newtype-2015.rs
new file mode 100644
index 0000000..2b58190
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/newtype-2015.rs
@@ -0,0 +1,2 @@
+// Same source, just compiled for 2015 edition
+include!("newtype.rs");
diff --git a/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/newtype-2018.rs b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/newtype-2018.rs
new file mode 100644
index 0000000..814529e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/newtype-2018.rs
@@ -0,0 +1,2 @@
+// Same source, just compiled for 2018 edition
+include!("newtype.rs");
diff --git a/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/newtype.rs b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/newtype.rs
new file mode 100644
index 0000000..71b06b3
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/newtype.rs
@@ -0,0 +1,108 @@
+extern crate num as num_renamed;
+#[macro_use]
+extern crate num_derive;
+
+use crate::num_renamed::{
+    Float, FromPrimitive, Num, NumCast, One, Signed, ToPrimitive, Unsigned, Zero,
+};
+use std::ops::Neg;
+
+#[derive(PartialEq, Zero, One, NumOps, Num, Unsigned)]
+struct MyNum(u32);
+
+#[test]
+fn test_derive_unsigned_works() {
+    fn do_nothing_on_unsigned(_input: impl Unsigned) {}
+
+    let x = MyNum(42);
+    do_nothing_on_unsigned(x);
+}
+
+#[derive(
+    Debug,
+    Clone,
+    Copy,
+    PartialEq,
+    PartialOrd,
+    ToPrimitive,
+    FromPrimitive,
+    NumOps,
+    NumCast,
+    One,
+    Zero,
+    Num,
+    Float,
+    Signed,
+)]
+struct MyFloat(f64);
+
+impl Neg for MyFloat {
+    type Output = MyFloat;
+    fn neg(self) -> Self {
+        MyFloat(self.0.neg())
+    }
+}
+
+#[test]
+fn test_from_primitive() {
+    assert_eq!(MyFloat::from_u32(25), Some(MyFloat(25.0)));
+}
+
+#[test]
+fn test_from_primitive_128() {
+    assert_eq!(
+        MyFloat::from_i128(std::i128::MIN),
+        Some(MyFloat((-2.0).powi(127)))
+    );
+}
+
+#[test]
+fn test_to_primitive() {
+    assert_eq!(MyFloat(25.0).to_u32(), Some(25));
+}
+
+#[test]
+fn test_to_primitive_128() {
+    let f = MyFloat::from_f32(std::f32::MAX).unwrap();
+    assert_eq!(f.to_i128(), None);
+    assert_eq!(f.to_u128(), Some(0xffff_ff00_0000_0000_0000_0000_0000_0000));
+}
+
+#[test]
+fn test_num_ops() {
+    assert_eq!(MyFloat(25.0) + MyFloat(10.0), MyFloat(35.0));
+    assert_eq!(MyFloat(25.0) - MyFloat(10.0), MyFloat(15.0));
+    assert_eq!(MyFloat(25.0) * MyFloat(2.0), MyFloat(50.0));
+    assert_eq!(MyFloat(25.0) / MyFloat(10.0), MyFloat(2.5));
+    assert_eq!(MyFloat(25.0) % MyFloat(10.0), MyFloat(5.0));
+}
+
+#[test]
+fn test_num_cast() {
+    assert_eq!(<MyFloat as NumCast>::from(25u8), Some(MyFloat(25.0)));
+}
+
+#[test]
+fn test_zero() {
+    assert_eq!(MyFloat::zero(), MyFloat(0.0));
+}
+
+#[test]
+fn test_one() {
+    assert_eq!(MyFloat::one(), MyFloat(1.0));
+}
+
+#[test]
+fn test_num() {
+    assert_eq!(MyFloat::from_str_radix("25", 10).ok(), Some(MyFloat(25.0)));
+}
+
+#[test]
+fn test_float() {
+    assert_eq!(MyFloat(4.0).log(MyFloat(2.0)), MyFloat(2.0));
+}
+
+#[test]
+fn test_signed() {
+    assert!(MyFloat(-2.0).is_negative())
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/no_implicit_prelude.rs b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/no_implicit_prelude.rs
new file mode 100644
index 0000000..cb82decb
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/no_implicit_prelude.rs
@@ -0,0 +1,13 @@
+#![no_implicit_prelude]
+
+use ::num_derive::*;
+
+#[derive(FromPrimitive, ToPrimitive)]
+enum Color {
+    Red,
+    Blue,
+    Green,
+}
+
+#[derive(FromPrimitive, ToPrimitive, NumCast, PartialEq, Zero, One, NumOps, Num)]
+struct NewI32(i32);
diff --git a/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/num_derive_without_num.rs b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/num_derive_without_num.rs
new file mode 100644
index 0000000..edebbec
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/num_derive_without_num.rs
@@ -0,0 +1,20 @@
+// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[macro_use]
+extern crate num_derive;
+
+#[derive(Debug, FromPrimitive, ToPrimitive)]
+enum Direction {
+    Up,
+    Down,
+    Left,
+    Right,
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/trivial-2015.rs b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/trivial-2015.rs
new file mode 100644
index 0000000..8309f0e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/trivial-2015.rs
@@ -0,0 +1,2 @@
+// Same source, just compiled for 2015 edition
+include!("trivial.rs");
diff --git a/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/trivial-2018.rs b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/trivial-2018.rs
new file mode 100644
index 0000000..92b971bc
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/trivial-2018.rs
@@ -0,0 +1,2 @@
+// Same source, just compiled for 2018 edition
+include!("trivial.rs");
diff --git a/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/trivial.rs b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/trivial.rs
new file mode 100644
index 0000000..d3b56b6a
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/trivial.rs
@@ -0,0 +1,64 @@
+// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate num as num_renamed;
+#[macro_use]
+extern crate num_derive;
+
+#[derive(Debug, PartialEq, FromPrimitive, ToPrimitive)]
+enum Color {
+    Red,
+    Blue,
+    Green,
+}
+
+#[test]
+fn test_from_primitive_for_trivial_case() {
+    let v: [Option<Color>; 4] = [
+        num_renamed::FromPrimitive::from_u64(0),
+        num_renamed::FromPrimitive::from_u64(1),
+        num_renamed::FromPrimitive::from_u64(2),
+        num_renamed::FromPrimitive::from_u64(3),
+    ];
+
+    assert_eq!(
+        v,
+        [
+            Some(Color::Red),
+            Some(Color::Blue),
+            Some(Color::Green),
+            None
+        ]
+    );
+}
+
+#[test]
+fn test_to_primitive_for_trivial_case() {
+    let v: [Option<u64>; 3] = [
+        num_renamed::ToPrimitive::to_u64(&Color::Red),
+        num_renamed::ToPrimitive::to_u64(&Color::Blue),
+        num_renamed::ToPrimitive::to_u64(&Color::Green),
+    ];
+
+    assert_eq!(v, [Some(0), Some(1), Some(2)]);
+}
+
+#[test]
+fn test_reflexive_for_trivial_case() {
+    let before: [u64; 3] = [0, 1, 2];
+    let after: Vec<Option<u64>> = before
+        .iter()
+        .map(|&x| -> Option<Color> { num_renamed::FromPrimitive::from_u64(x) })
+        .map(|x| x.and_then(|x| num_renamed::ToPrimitive::to_u64(&x)))
+        .collect();
+    let before = before.iter().cloned().map(Some).collect::<Vec<_>>();
+
+    assert_eq!(before, after);
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/with_custom_values.rs b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/with_custom_values.rs
new file mode 100644
index 0000000..9b202f4c
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/tests/with_custom_values.rs
@@ -0,0 +1,68 @@
+// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate num as num_renamed;
+#[macro_use]
+extern crate num_derive;
+
+#[derive(Debug, PartialEq, FromPrimitive, ToPrimitive)]
+enum Color {
+    Red,
+    Blue = 5,
+    Green,
+    Alpha = (-3 - (-5isize)) - 10,
+}
+
+#[test]
+fn test_from_primitive_for_enum_with_custom_value() {
+    let v: [Option<Color>; 5] = [
+        num_renamed::FromPrimitive::from_u64(0),
+        num_renamed::FromPrimitive::from_u64(5),
+        num_renamed::FromPrimitive::from_u64(6),
+        num_renamed::FromPrimitive::from_u64(-8isize as u64),
+        num_renamed::FromPrimitive::from_u64(3),
+    ];
+
+    assert_eq!(
+        v,
+        [
+            Some(Color::Red),
+            Some(Color::Blue),
+            Some(Color::Green),
+            Some(Color::Alpha),
+            None
+        ]
+    );
+}
+
+#[test]
+fn test_to_primitive_for_enum_with_custom_value() {
+    let v: [Option<u64>; 4] = [
+        num_renamed::ToPrimitive::to_u64(&Color::Red),
+        num_renamed::ToPrimitive::to_u64(&Color::Blue),
+        num_renamed::ToPrimitive::to_u64(&Color::Green),
+        num_renamed::ToPrimitive::to_u64(&Color::Alpha),
+    ];
+
+    assert_eq!(v, [Some(0), Some(5), Some(6), Some(-8isize as u64)]);
+}
+
+#[test]
+fn test_reflexive_for_enum_with_custom_value() {
+    let before: [u64; 3] = [0, 5, 6];
+    let after: Vec<Option<u64>> = before
+        .iter()
+        .map(|&x| -> Option<Color> { num_renamed::FromPrimitive::from_u64(x) })
+        .map(|x| x.and_then(|x| num_renamed::ToPrimitive::to_u64(&x)))
+        .collect();
+    let before = before.iter().cloned().map(Some).collect::<Vec<_>>();
+
+    assert_eq!(before, after);
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/.cargo-checksum.json b/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/.cargo-checksum.json
new file mode 100644
index 0000000..697c9ce
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{}}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/.cargo_vcs_info.json
new file mode 100644
index 0000000..ab8ca3a
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+  "git": {
+    "sha1": "4302a1d749def2b2929b1292bf418bd58df04486"
+  },
+  "path_in_vcs": "proc-macro-error-attr"
+}
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/.gitignore b/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/.gitignore
new file mode 100644
index 0000000..5e81b66
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/.gitignore
@@ -0,0 +1,4 @@
+/target
+**/*.rs.bk
+Cargo.lock
+.fuse_hidden*
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/Cargo.toml
new file mode 100644
index 0000000..45223d0
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/Cargo.toml
@@ -0,0 +1,44 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2021"
+rust-version = "1.61"
+name = "proc-macro-error-attr2"
+version = "2.0.0"
+authors = [
+    "CreepySkeleton <creepy-skeleton@yandex.ru>",
+    "GnomedDev <david2005thomas@gmail.com>",
+]
+build = false
+autobins = false
+autoexamples = false
+autotests = false
+autobenches = false
+description = "Attribute macro for the proc-macro-error2 crate"
+readme = false
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/GnomedDev/proc-macro-error-2"
+
+[lib]
+name = "proc_macro_error_attr2"
+path = "src/lib.rs"
+proc-macro = true
+
+[dependencies.proc-macro2]
+version = "1"
+
+[dependencies.quote]
+version = "1"
+
+[lints.clippy.pedantic]
+level = "warn"
+priority = -1
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/Cargo.toml.orig
new file mode 100644
index 0000000..29a4f0c
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/Cargo.toml.orig
@@ -0,0 +1,22 @@
+[package]
+name = "proc-macro-error-attr2"
+version = "2.0.0"
+authors = [
+    "CreepySkeleton <creepy-skeleton@yandex.ru>",
+    "GnomedDev <david2005thomas@gmail.com>",
+]
+edition = "2021"
+rust-version = "1.61"
+description = "Attribute macro for the proc-macro-error2 crate"
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/GnomedDev/proc-macro-error-2"
+
+[lib]
+proc-macro = true
+
+[dependencies]
+quote = "1"
+proc-macro2 = "1"
+
+[lints.clippy]
+pedantic = { level = "warn", priority = -1 }
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/LICENSE-APACHE b/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/LICENSE-APACHE
new file mode 100644
index 0000000..658240a8
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/LICENSE-APACHE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright 2019-2020 CreepySkeleton <creepy-skeleton@yandex.ru>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/LICENSE-MIT b/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/LICENSE-MIT
new file mode 100644
index 0000000..fc73e59
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/LICENSE-MIT
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019-2020 CreepySkeleton
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/src/lib.rs
new file mode 100644
index 0000000..0f25931
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/src/lib.rs
@@ -0,0 +1,111 @@
+//! This is `#[proc_macro_error]` attribute to be used with
+//! [`proc-macro-error`](https://docs.rs/proc-macro-error2/). There you go.
+
+use crate::parse::parse_input;
+use crate::parse::Attribute;
+use proc_macro::TokenStream;
+use proc_macro2::{Literal, Span, TokenStream as TokenStream2, TokenTree};
+use quote::{quote, quote_spanned};
+
+use crate::settings::{
+    parse_settings,
+    Setting::{AllowNotMacro, AssertUnwindSafe, ProcMacroHack},
+    Settings,
+};
+
+mod parse;
+mod settings;
+
+type Result<T> = std::result::Result<T, Error>;
+
+struct Error {
+    span: Span,
+    message: String,
+}
+
+impl Error {
+    fn new(span: Span, message: String) -> Self {
+        Error { span, message }
+    }
+
+    fn into_compile_error(self) -> TokenStream2 {
+        let mut message = Literal::string(&self.message);
+        message.set_span(self.span);
+        quote_spanned!(self.span=> compile_error!{#message})
+    }
+}
+
+#[proc_macro_attribute]
+pub fn proc_macro_error(attr: TokenStream, input: TokenStream) -> TokenStream {
+    match impl_proc_macro_error(attr.into(), input.clone().into()) {
+        Ok(ts) => ts,
+        Err(e) => {
+            let error = e.into_compile_error();
+            let input = TokenStream2::from(input);
+
+            quote!(#input #error).into()
+        }
+    }
+}
+
+fn impl_proc_macro_error(attr: TokenStream2, input: TokenStream2) -> Result<TokenStream> {
+    let (attrs, signature, body) = parse_input(input)?;
+    let mut settings = parse_settings(attr)?;
+
+    let is_proc_macro = is_proc_macro(&attrs);
+    if is_proc_macro {
+        settings.set(AssertUnwindSafe);
+    }
+
+    if detect_proc_macro_hack(&attrs) {
+        settings.set(ProcMacroHack);
+    }
+
+    if settings.is_set(ProcMacroHack) {
+        settings.set(AllowNotMacro);
+    }
+
+    if !(settings.is_set(AllowNotMacro) || is_proc_macro) {
+        return Err(Error::new(
+            Span::call_site(),
+            "#[proc_macro_error] attribute can be used only with procedural macros\n\n  \
+            = hint: if you are really sure that #[proc_macro_error] should be applied \
+            to this exact function, use #[proc_macro_error(allow_not_macro)]\n"
+                .into(),
+        ));
+    }
+
+    let body = gen_body(&body, &settings);
+
+    let res = quote! {
+        #(#attrs)*
+        #(#signature)*
+        { #body }
+    };
+    Ok(res.into())
+}
+
+fn gen_body(block: &TokenTree, settings: &Settings) -> proc_macro2::TokenStream {
+    let is_proc_macro_hack = settings.is_set(ProcMacroHack);
+    let closure = if settings.is_set(AssertUnwindSafe) {
+        quote!(::std::panic::AssertUnwindSafe(|| #block ))
+    } else {
+        quote!(|| #block)
+    };
+
+    quote!( ::proc_macro_error2::entry_point(#closure, #is_proc_macro_hack) )
+}
+
+fn detect_proc_macro_hack(attrs: &[Attribute]) -> bool {
+    attrs
+        .iter()
+        .any(|attr| attr.path_is_ident("proc_macro_hack"))
+}
+
+fn is_proc_macro(attrs: &[Attribute]) -> bool {
+    attrs.iter().any(|attr| {
+        attr.path_is_ident("proc_macro")
+            || attr.path_is_ident("proc_macro_derive")
+            || attr.path_is_ident("proc_macro_attribute")
+    })
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/src/parse.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/src/parse.rs
new file mode 100644
index 0000000..eedb495
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/src/parse.rs
@@ -0,0 +1,89 @@
+use crate::{Error, Result};
+use proc_macro2::{Delimiter, Ident, Span, TokenStream, TokenTree};
+use quote::ToTokens;
+use std::iter::Peekable;
+
+pub(crate) fn parse_input(
+    input: TokenStream,
+) -> Result<(Vec<Attribute>, Vec<TokenTree>, TokenTree)> {
+    let mut input = input.into_iter().peekable();
+    let mut attrs = Vec::new();
+
+    while let Some(attr) = parse_next_attr(&mut input)? {
+        attrs.push(attr);
+    }
+
+    let sig = parse_signature(&mut input);
+    let body = input.next().ok_or_else(|| {
+        Error::new(
+            Span::call_site(),
+            "`#[proc_macro_error]` can be applied only to functions".to_string(),
+        )
+    })?;
+
+    Ok((attrs, sig, body))
+}
+
+fn parse_next_attr(
+    input: &mut Peekable<impl Iterator<Item = TokenTree>>,
+) -> Result<Option<Attribute>> {
+    let shebang = match input.peek() {
+        Some(TokenTree::Punct(ref punct)) if punct.as_char() == '#' => input.next().unwrap(),
+        _ => return Ok(None),
+    };
+
+    let group = match input.peek() {
+        Some(TokenTree::Group(ref group)) if group.delimiter() == Delimiter::Bracket => {
+            let res = group.clone();
+            input.next();
+            res
+        }
+        other => {
+            let span = other.map_or(Span::call_site(), TokenTree::span);
+            return Err(Error::new(span, "expected `[`".to_string()));
+        }
+    };
+
+    let path = match group.stream().into_iter().next() {
+        Some(TokenTree::Ident(ident)) => Some(ident),
+        _ => None,
+    };
+
+    Ok(Some(Attribute {
+        shebang,
+        group: TokenTree::Group(group),
+        path,
+    }))
+}
+
+fn parse_signature(input: &mut Peekable<impl Iterator<Item = TokenTree>>) -> Vec<TokenTree> {
+    let mut sig = Vec::new();
+    loop {
+        match input.peek() {
+            Some(TokenTree::Group(ref group)) if group.delimiter() == Delimiter::Brace => {
+                return sig;
+            }
+            None => return sig,
+            _ => sig.push(input.next().unwrap()),
+        }
+    }
+}
+
+pub(crate) struct Attribute {
+    pub(crate) shebang: TokenTree,
+    pub(crate) group: TokenTree,
+    pub(crate) path: Option<Ident>,
+}
+
+impl Attribute {
+    pub(crate) fn path_is_ident(&self, ident: &str) -> bool {
+        self.path.as_ref().map_or(false, |p| *p == ident)
+    }
+}
+
+impl ToTokens for Attribute {
+    fn to_tokens(&self, ts: &mut TokenStream) {
+        self.shebang.to_tokens(ts);
+        self.group.to_tokens(ts);
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/src/settings.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/src/settings.rs
new file mode 100644
index 0000000..f87bd0b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/src/settings.rs
@@ -0,0 +1,72 @@
+use crate::{Error, Result};
+use proc_macro2::{Ident, Span, TokenStream, TokenTree};
+
+macro_rules! decl_settings {
+    ($($val:expr => $variant:ident),+ $(,)*) => {
+        #[derive(PartialEq, Clone, Copy)]
+        pub(crate) enum Setting {
+            $($variant),*
+        }
+
+        fn ident_to_setting(ident: Ident) -> Result<Setting> {
+            match &*ident.to_string() {
+                $($val => Ok(Setting::$variant),)*
+                _ => {
+                    let possible_vals = [$($val),*]
+                        .iter()
+                        .map(|v| format!("`{}`", v))
+                        .collect::<Vec<_>>()
+                        .join(", ");
+
+                    Err(Error::new(
+                        ident.span(),
+                        format!("unknown setting `{}`, expected one of {}", ident, possible_vals)))
+                }
+            }
+        }
+    };
+}
+
+decl_settings! {
+    "assert_unwind_safe" => AssertUnwindSafe,
+    "allow_not_macro"    => AllowNotMacro,
+    "proc_macro_hack"    => ProcMacroHack,
+}
+
+pub(crate) fn parse_settings(input: TokenStream) -> Result<Settings> {
+    let mut input = input.into_iter();
+    let mut res = Settings(Vec::new());
+    loop {
+        match input.next() {
+            Some(TokenTree::Ident(ident)) => {
+                res.0.push(ident_to_setting(ident)?);
+            }
+            None => return Ok(res),
+            other => {
+                let span = other.map_or(Span::call_site(), |tt| tt.span());
+                return Err(Error::new(span, "expected identifier".to_string()));
+            }
+        }
+
+        match input.next() {
+            Some(TokenTree::Punct(ref punct)) if punct.as_char() == ',' => {}
+            None => return Ok(res),
+            other => {
+                let span = other.map_or(Span::call_site(), |tt| tt.span());
+                return Err(Error::new(span, "expected `,`".to_string()));
+            }
+        }
+    }
+}
+
+pub(crate) struct Settings(Vec<Setting>);
+
+impl Settings {
+    pub(crate) fn is_set(&self, setting: Setting) -> bool {
+        self.0.iter().any(|s| *s == setting)
+    }
+
+    pub(crate) fn set(&mut self, setting: Setting) {
+        self.0.push(setting);
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/.cargo-checksum.json b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/.cargo-checksum.json
new file mode 100644
index 0000000..697c9ce
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{}}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/.cargo_vcs_info.json
new file mode 100644
index 0000000..b654f73
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+  "git": {
+    "sha1": "9b129234ed8f50d3ff8da09041dcbd980b63fc8c"
+  },
+  "path_in_vcs": ""
+}
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/.github/workflows/ci.yml b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/.github/workflows/ci.yml
new file mode 100644
index 0000000..8f6988c
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/.github/workflows/ci.yml
@@ -0,0 +1,34 @@
+on:
+  pull_request:
+  push:
+
+jobs:
+  test:
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        rust-version: ["stable", "beta", "nightly"]
+
+    steps:
+      - uses: actions/checkout@v4
+      - run: rustup toolchain install ${{ matrix.rust-version }}
+      - run: cargo +${{ matrix.rust-version }} test --all
+
+  msrv-check:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - run: rustup toolchain install 1.61
+      - run: cargo +1.61 check --all
+
+  ui-test:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - run: RUSTFLAGS='--cfg run_ui_tests' cargo +stable test ui
+
+  test-fmt:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - run: cargo fmt --check --all
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/.gitignore b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/.gitignore
new file mode 100644
index 0000000..5e81b66
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/.gitignore
@@ -0,0 +1,4 @@
+/target
+**/*.rs.bk
+Cargo.lock
+.fuse_hidden*
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/CHANGELOG.md b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/CHANGELOG.md
new file mode 100644
index 0000000..4f22c85
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/CHANGELOG.md
@@ -0,0 +1,180 @@
+# v2.0.1 (2024-09-06)
+
+* Fixed a span location issue due to mistake in refactoring (#2)
+
+# v2.0.0 (2024-09-05)
+
+No changes, simply releasing pre-release as full release.
+
+# v2.0.0-pre.1 (2024-09-01)
+
+* __Crate has been renamed to `proc-macro-error2`, due to the old maintainer's inactivity.__
+
+* `syn` has been upgraded to `2`
+* MSRV has been bumped to `1.61`
+* Warnings have been fixed, including `clippy::pedantic` lints
+* CI has been converted to GitHub actions, and testing infrastructure significantly simplified.
+* Automatic nightly detection has been removed, use the `nightly` feature for improved diagnostics at the cost of stablity.
+
+# v1.0.4 (2020-7-31)
+
+* `SpanRange` facility is now public.
+* Docs have been improved.
+* Introduced the `syn-error` feature so you can opt-out from the `syn` dependency.
+
+# v1.0.3 (2020-6-26)
+
+* Corrected a few typos.
+* Fixed the `emit_call_site_warning` macro.
+
+# v1.0.2 (2020-4-9)
+
+* An obsolete note was removed from documentation.
+
+# v1.0.1 (2020-4-9)
+
+* `proc-macro-hack` is now well tested and supported. Not sure about `proc-macro-nested`,
+  please fill a request if you need it.
+* Fixed `emit_call_site_error`.
+* Documentation improvements.
+
+# v1.0.0 (2020-3-25)
+
+I believe the API can be considered stable because it's been a few months without
+breaking changes, and I also don't think this crate will receive much further evolution.
+It's perfect, admit it.
+
+Hence, meet the new, stable release!
+
+### Improvements
+
+* Supported nested `#[proc_macro_error]` attributes. Well, you aren't supposed to do that,
+  but I caught myself doing it by accident on one occasion and the behavior was... surprising.
+  Better to handle this smooth.
+
+# v0.4.12 (2020-3-23)
+
+* Error message on macros' misuse is now a bit more understandable.
+
+# v0.4.11 (2020-3-02)
+
+* `build.rs` no longer fails when `rustc` date could not be determined,
+  (thanks to [`Fabian Möller`](https://gitlab.com/CreepySkeleton/proc-macro-error/issues/8)
+  for noticing and to [`Igor Gnatenko`](https://gitlab.com/CreepySkeleton/proc-macro-error/-/merge_requests/25)
+  for fixing).
+
+# v0.4.10 (2020-2-29)
+
+* `proc-macro-error` doesn't depend on syn\[full\] anymore, the compilation
+  is \~30secs faster.
+
+# v0.4.9 (2020-2-13)
+
+* New function: `append_dummy`.
+
+# v0.4.8 (2020-2-01)
+
+* Support for children messages
+
+# v0.4.7 (2020-1-31)
+
+* Now any type that implements `quote::ToTokens` can be used instead of spans.
+  This allows for high quality error messages.
+
+# v0.4.6 (2020-1-31)
+
+* `From<syn::Error>` implementation doesn't lose span info anymore, see
+  [#6](https://gitlab.com/CreepySkeleton/proc-macro-error/issues/6).
+
+# v0.4.5 (2020-1-20)
+Just a small intermediate release.
+
+* Fix some bugs.
+* Populate license files into subfolders.
+
+# v0.4.4 (2019-11-13)
+* Fix `abort_if_dirty` + warnings bug
+* Allow trailing commas in macros
+
+# v0.4.2 (2019-11-7)
+* FINALLY fixed `__pme__suggestions not found` bug
+
+# v0.4.1 (2019-11-7) YANKED
+* Fixed `__pme__suggestions not found` bug
+* Documentation improvements, links checked
+
+# v0.4.0 (2019-11-6) YANKED
+
+## New features
+* "help" messages that can have their own span on nightly, they
+    inherit parent span on stable.
+    ```rust
+    let cond_help = if condition { Some("some help message") else { None } };
+    abort!(
+        span, // parent span
+        "something's wrong, {} wrongs in total", 10; // main message
+        help = "here's a help for you, {}", "take it"; // unconditional help message
+        help =? cond_help; // conditional help message, must be Option
+        note = note_span => "don't forget the note, {}", "would you?" // notes can have their own span but it's effective only on nightly
+    )
+    ```
+* Warnings via `emit_warning` and `emit_warning_call_site`. Nightly only, they're ignored on stable.
+* Now `proc-macro-error` delegates to `proc_macro::Diagnostic` on nightly.
+
+## Breaking changes
+* `MacroError` is now replaced by `Diagnostic`. Its API resembles `proc_macro::Diagnostic`.
+* `Diagnostic` does not implement `From<&str/String>` so `Result<T, &str/String>::abort_or_exit()`
+    won't work anymore (nobody used it anyway).
+* `macro_error!` macro is replaced with `diagnostic!`.
+
+## Improvements
+* Now `proc-macro-error` renders notes exactly just like rustc does.
+* We don't parse a body of a function annotated with `#[proc_macro_error]` anymore,
+  only looking at the signature. This should somewhat decrease expansion time for large functions.
+
+# v0.3.3 (2019-10-16)
+* Now you can use any word instead of "help", undocumented.
+
+# v0.3.2 (2019-10-16)
+* Introduced support for "help" messages, undocumented.
+
+# v0.3.0 (2019-10-8)
+
+## The crate has been completely rewritten from scratch!
+
+## Changes (most are breaking):
+* Renamed macros:
+  * `span_error` => `abort`
+  * `call_site_error` => `abort_call_site`
+* `filter_macro_errors` was replaced by `#[proc_macro_error]` attribute.
+* `set_dummy` now takes `TokenStream` instead of `Option<TokenStream>`
+* Support for multiple errors via `emit_error` and `emit_call_site_error`
+* New `macro_error` macro for building errors in format=like style.
+* `MacroError` API had been reconsidered. It also now implements `quote::ToTokens`.
+
+# v0.2.6 (2019-09-02)
+* Introduce support for dummy implementations via `dummy::set_dummy`
+* `multi::*` is now deprecated, will be completely rewritten in v0.3
+
+# v0.2.0 (2019-08-15)
+
+## Breaking changes
+* `trigger_error` replaced with `MacroError::trigger` and `filter_macro_error_panics`
+  is hidden from docs.
+  This is not quite a breaking change since users weren't supposed to use these functions directly anyway.
+* All dependencies are updated to `v1.*`.
+
+## New features
+* Ability to stack multiple errors via `multi::MultiMacroErrors` and emit them at once.
+
+## Improvements
+* Now `MacroError` implements `std::fmt::Display` instead of `std::string::ToString`.
+* `MacroError::span` inherent method.
+* `From<MacroError> for proc_macro/proc_macro2::TokenStream` implementations.
+* `AsRef/AsMut<String> for MacroError` implementations.
+
+# v0.1.x (2019-07-XX)
+
+## New features
+* An easy way to report errors inside within a proc-macro via `span_error`,
+  `call_site_error` and `filter_macro_errors`.
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/Cargo.toml
new file mode 100644
index 0000000..f623e6c1
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/Cargo.toml
@@ -0,0 +1,91 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2021"
+rust-version = "1.61"
+name = "proc-macro-error2"
+version = "2.0.1"
+authors = [
+    "CreepySkeleton <creepy-skeleton@yandex.ru>",
+    "GnomedDev <david2005thomas@gmail.com>",
+]
+build = false
+autobins = false
+autoexamples = false
+autotests = false
+autobenches = false
+description = "Almost drop-in replacement to panics in proc-macros"
+readme = "README.md"
+keywords = [
+    "proc-macro",
+    "error",
+    "errors",
+]
+categories = ["development-tools::procedural-macro-helpers"]
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/GnomedDev/proc-macro-error-2"
+
+[lib]
+name = "proc_macro_error2"
+path = "src/lib.rs"
+
+[[test]]
+name = "macro-errors"
+path = "tests/macro-errors.rs"
+
+[[test]]
+name = "ok"
+path = "tests/ok.rs"
+
+[[test]]
+name = "runtime-errors"
+path = "tests/runtime-errors.rs"
+
+[dependencies.proc-macro-error-attr2]
+version = "=2.0.0"
+
+[dependencies.proc-macro2]
+version = "1"
+
+[dependencies.quote]
+version = "1"
+
+[dependencies.syn]
+version = "2"
+optional = true
+default-features = false
+
+[dev-dependencies.syn]
+version = "2"
+features = ["full"]
+
+[dev-dependencies.trybuild]
+version = "1.0.99"
+features = ["diff"]
+
+[features]
+default = ["syn-error"]
+nightly = []
+syn-error = ["dep:syn"]
+
+[lints.clippy.module_name_repetitions]
+level = "allow"
+priority = 0
+
+[lints.clippy.pedantic]
+level = "warn"
+priority = -1
+
+[lints.rust.unexpected_cfgs]
+level = "warn"
+priority = 0
+check-cfg = ["cfg(run_ui_tests)"]
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/Cargo.toml.orig
new file mode 100644
index 0000000..fcc6161f
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/Cargo.toml.orig
@@ -0,0 +1,41 @@
+[package]
+name = "proc-macro-error2"
+authors = [
+    "CreepySkeleton <creepy-skeleton@yandex.ru>",
+    "GnomedDev <david2005thomas@gmail.com>",
+]
+version = "2.0.1"
+description = "Almost drop-in replacement to panics in proc-macros"
+repository = "https://github.com/GnomedDev/proc-macro-error-2"
+rust-version = "1.61"
+keywords = ["proc-macro", "error", "errors"]
+categories = ["development-tools::procedural-macro-helpers"]
+license = "MIT OR Apache-2.0"
+edition = "2021"
+
+[dependencies]
+quote = "1"
+proc-macro2 = "1"
+proc-macro-error-attr2 = { path = "./proc-macro-error-attr", version = "=2.0.0" }
+
+[dependencies.syn]
+version = "2"
+optional = true
+default-features = false
+
+[dev-dependencies]
+test-crate = { path = "./test-crate" }
+syn = { version = "2", features = ["full"] }
+trybuild = { version = "1.0.99", features = ["diff"] }
+
+[features]
+default = ["syn-error"]
+syn-error = ["dep:syn"]
+nightly = []
+
+[lints.rust]
+unexpected_cfgs = { level = "warn", check-cfg = ['cfg(run_ui_tests)'] }
+
+[lints.clippy]
+pedantic = { level = "warn", priority = -1 }
+module_name_repetitions = { level = "allow" }
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/LICENSE-APACHE b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/LICENSE-APACHE
new file mode 100644
index 0000000..cc17374
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/LICENSE-APACHE
@@ -0,0 +1,201 @@
+                              Apache License

+                        Version 2.0, January 2004

+                     http://www.apache.org/licenses/

+

+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

+

+1. Definitions.

+

+   "License" shall mean the terms and conditions for use, reproduction,

+   and distribution as defined by Sections 1 through 9 of this document.

+

+   "Licensor" shall mean the copyright owner or entity authorized by

+   the copyright owner that is granting the License.

+

+   "Legal Entity" shall mean the union of the acting entity and all

+   other entities that control, are controlled by, or are under common

+   control with that entity. For the purposes of this definition,

+   "control" means (i) the power, direct or indirect, to cause the

+   direction or management of such entity, whether by contract or

+   otherwise, or (ii) ownership of fifty percent (50%) or more of the

+   outstanding shares, or (iii) beneficial ownership of such entity.

+

+   "You" (or "Your") shall mean an individual or Legal Entity

+   exercising permissions granted by this License.

+

+   "Source" form shall mean the preferred form for making modifications,

+   including but not limited to software source code, documentation

+   source, and configuration files.

+

+   "Object" form shall mean any form resulting from mechanical

+   transformation or translation of a Source form, including but

+   not limited to compiled object code, generated documentation,

+   and conversions to other media types.

+

+   "Work" shall mean the work of authorship, whether in Source or

+   Object form, made available under the License, as indicated by a

+   copyright notice that is included in or attached to the work

+   (an example is provided in the Appendix below).

+

+   "Derivative Works" shall mean any work, whether in Source or Object

+   form, that is based on (or derived from) the Work and for which the

+   editorial revisions, annotations, elaborations, or other modifications

+   represent, as a whole, an original work of authorship. For the purposes

+   of this License, Derivative Works shall not include works that remain

+   separable from, or merely link (or bind by name) to the interfaces of,

+   the Work and Derivative Works thereof.

+

+   "Contribution" shall mean any work of authorship, including

+   the original version of the Work and any modifications or additions

+   to that Work or Derivative Works thereof, that is intentionally

+   submitted to Licensor for inclusion in the Work by the copyright owner

+   or by an individual or Legal Entity authorized to submit on behalf of

+   the copyright owner. For the purposes of this definition, "submitted"

+   means any form of electronic, verbal, or written communication sent

+   to the Licensor or its representatives, including but not limited to

+   communication on electronic mailing lists, source code control systems,

+   and issue tracking systems that are managed by, or on behalf of, the

+   Licensor for the purpose of discussing and improving the Work, but

+   excluding communication that is conspicuously marked or otherwise

+   designated in writing by the copyright owner as "Not a Contribution."

+

+   "Contributor" shall mean Licensor and any individual or Legal Entity

+   on behalf of whom a Contribution has been received by Licensor and

+   subsequently incorporated within the Work.

+

+2. Grant of Copyright License. Subject to the terms and conditions of

+   this License, each Contributor hereby grants to You a perpetual,

+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable

+   copyright license to reproduce, prepare Derivative Works of,

+   publicly display, publicly perform, sublicense, and distribute the

+   Work and such Derivative Works in Source or Object form.

+

+3. Grant of Patent License. Subject to the terms and conditions of

+   this License, each Contributor hereby grants to You a perpetual,

+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable

+   (except as stated in this section) patent license to make, have made,

+   use, offer to sell, sell, import, and otherwise transfer the Work,

+   where such license applies only to those patent claims licensable

+   by such Contributor that are necessarily infringed by their

+   Contribution(s) alone or by combination of their Contribution(s)

+   with the Work to which such Contribution(s) was submitted. If You

+   institute patent litigation against any entity (including a

+   cross-claim or counterclaim in a lawsuit) alleging that the Work

+   or a Contribution incorporated within the Work constitutes direct

+   or contributory patent infringement, then any patent licenses

+   granted to You under this License for that Work shall terminate

+   as of the date such litigation is filed.

+

+4. Redistribution. You may reproduce and distribute copies of the

+   Work or Derivative Works thereof in any medium, with or without

+   modifications, and in Source or Object form, provided that You

+   meet the following conditions:

+

+   (a) You must give any other recipients of the Work or

+       Derivative Works a copy of this License; and

+

+   (b) You must cause any modified files to carry prominent notices

+       stating that You changed the files; and

+

+   (c) You must retain, in the Source form of any Derivative Works

+       that You distribute, all copyright, patent, trademark, and

+       attribution notices from the Source form of the Work,

+       excluding those notices that do not pertain to any part of

+       the Derivative Works; and

+

+   (d) If the Work includes a "NOTICE" text file as part of its

+       distribution, then any Derivative Works that You distribute must

+       include a readable copy of the attribution notices contained

+       within such NOTICE file, excluding those notices that do not

+       pertain to any part of the Derivative Works, in at least one

+       of the following places: within a NOTICE text file distributed

+       as part of the Derivative Works; within the Source form or

+       documentation, if provided along with the Derivative Works; or,

+       within a display generated by the Derivative Works, if and

+       wherever such third-party notices normally appear. The contents

+       of the NOTICE file are for informational purposes only and

+       do not modify the License. You may add Your own attribution

+       notices within Derivative Works that You distribute, alongside

+       or as an addendum to the NOTICE text from the Work, provided

+       that such additional attribution notices cannot be construed

+       as modifying the License.

+

+   You may add Your own copyright statement to Your modifications and

+   may provide additional or different license terms and conditions

+   for use, reproduction, or distribution of Your modifications, or

+   for any such Derivative Works as a whole, provided Your use,

+   reproduction, and distribution of the Work otherwise complies with

+   the conditions stated in this License.

+

+5. Submission of Contributions. Unless You explicitly state otherwise,

+   any Contribution intentionally submitted for inclusion in the Work

+   by You to the Licensor shall be under the terms and conditions of

+   this License, without any additional terms or conditions.

+   Notwithstanding the above, nothing herein shall supersede or modify

+   the terms of any separate license agreement you may have executed

+   with Licensor regarding such Contributions.

+

+6. Trademarks. This License does not grant permission to use the trade

+   names, trademarks, service marks, or product names of the Licensor,

+   except as required for reasonable and customary use in describing the

+   origin of the Work and reproducing the content of the NOTICE file.

+

+7. Disclaimer of Warranty. Unless required by applicable law or

+   agreed to in writing, Licensor provides the Work (and each

+   Contributor provides its Contributions) on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or

+   implied, including, without limitation, any warranties or conditions

+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A

+   PARTICULAR PURPOSE. You are solely responsible for determining the

+   appropriateness of using or redistributing the Work and assume any

+   risks associated with Your exercise of permissions under this License.

+

+8. Limitation of Liability. In no event and under no legal theory,

+   whether in tort (including negligence), contract, or otherwise,

+   unless required by applicable law (such as deliberate and grossly

+   negligent acts) or agreed to in writing, shall any Contributor be

+   liable to You for damages, including any direct, indirect, special,

+   incidental, or consequential damages of any character arising as a

+   result of this License or out of the use or inability to use the

+   Work (including but not limited to damages for loss of goodwill,

+   work stoppage, computer failure or malfunction, or any and all

+   other commercial damages or losses), even if such Contributor

+   has been advised of the possibility of such damages.

+

+9. Accepting Warranty or Additional Liability. While redistributing

+   the Work or Derivative Works thereof, You may choose to offer,

+   and charge a fee for, acceptance of support, warranty, indemnity,

+   or other liability obligations and/or rights consistent with this

+   License. However, in accepting such obligations, You may act only

+   on Your own behalf and on Your sole responsibility, not on behalf

+   of any other Contributor, and only if You agree to indemnify,

+   defend, and hold each Contributor harmless for any liability

+   incurred by, or claims asserted against, such Contributor by reason

+   of your accepting any such warranty or additional liability.

+

+END OF TERMS AND CONDITIONS

+

+APPENDIX: How to apply the Apache License to your work.

+

+   To apply the Apache License to your work, attach the following

+   boilerplate notice, with the fields enclosed by brackets "[]"

+   replaced with your own identifying information. (Don't include

+   the brackets!)  The text should be enclosed in the appropriate

+   comment syntax for the file format. We also recommend that a

+   file or class name and description of purpose be included on the

+   same "printed page" as the copyright notice for easier

+   identification within third-party archives.

+

+Copyright 2019-2020 CreepySkeleton <creepy-skeleton@yandex.ru>

+

+Licensed under the Apache License, Version 2.0 (the "License");

+you may not use this file except in compliance with the License.

+You may obtain a copy of the License at

+

+    http://www.apache.org/licenses/LICENSE-2.0

+

+Unless required by applicable law or agreed to in writing, software

+distributed under the License is distributed on an "AS IS" BASIS,

+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+See the License for the specific language governing permissions and

+limitations under the License.

diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/LICENSE-MIT b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/LICENSE-MIT
new file mode 100644
index 0000000..fc73e59
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/LICENSE-MIT
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019-2020 CreepySkeleton
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/README.md b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/README.md
new file mode 100644
index 0000000..0910eac
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/README.md
@@ -0,0 +1,250 @@
+# Makes error reporting in procedural macros nice and easy
+
+[![docs.rs](https://docs.rs/proc-macro-error2/badge.svg)](https://docs.rs/proc-macro-error2)
+[![unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg)](https://github.com/rust-secure-code/safety-dance/)
+
+This crate aims to make error reporting in proc-macros simple and easy to use.
+Migrate from `panic!`-based errors for as little effort as possible!
+
+Also, you can explicitly [append a dummy token stream][crate::dummy] to your errors.
+
+To achieve this, this crate serves as a tiny shim around `proc_macro::Diagnostic` and
+`compile_error!`. It detects the most preferable way to emit errors based on compiler's version.
+When the underlying diagnostic type is finally stabilized, this crate will be simply
+delegating to it, requiring no changes in your code!
+
+So you can just use this crate and have *both* some of `proc_macro::Diagnostic` functionality
+available on stable ahead of time and your error-reporting code future-proof.
+
+```toml
+[dependencies]
+proc-macro-error2 = "2.0"
+```
+
+*Supports rustc 1.61 and up*
+
+[Documentation and guide][guide]
+
+## Quick example
+
+Code:
+
+```rust
+#[proc_macro]
+#[proc_macro_error]
+pub fn make_fn(input: TokenStream) -> TokenStream {
+    let mut input = TokenStream2::from(input).into_iter();
+    let name = input.next().unwrap();
+    if let Some(second) = input.next() {
+        abort! { second,
+            "I don't like this part!";
+                note = "I see what you did there...";
+                help = "I need only one part, you know?";
+        }
+    }
+
+    quote!( fn #name() {} ).into()
+}
+```
+
+This is how the error is rendered in a terminal:
+
+<p align="center">
+<img src="https://user-images.githubusercontent.com/50968528/78830016-d3b46a80-79d6-11ea-9de2-972e8d7904ef.png" width="600">
+</p>
+
+And this is what your users will see in their IDE:
+
+<p align="center">
+<img src="https://user-images.githubusercontent.com/50968528/78830547-a9af7800-79d7-11ea-822e-59e29bda335c.png" width="600">
+</p>
+
+## Examples
+
+### Panic-like usage
+
+```rust
+use proc_macro_error2::{
+    proc_macro_error,
+    abort,
+    abort_call_site,
+    ResultExt,
+    OptionExt,
+};
+use proc_macro::TokenStream;
+use syn::{DeriveInput, parse_macro_input};
+use quote::quote;
+
+// This is your main entry point
+#[proc_macro]
+// This attribute *MUST* be placed on top of the #[proc_macro] function
+#[proc_macro_error]
+pub fn make_answer(input: TokenStream) -> TokenStream {
+    let input = parse_macro_input!(input as DeriveInput);
+
+    if let Err(err) = some_logic(&input) {
+        // we've got a span to blame, let's use it
+        // This immediately aborts the proc-macro and shows the error
+        //
+        // You can use `proc_macro::Span`, `proc_macro2::Span`, and
+        // anything that implements `quote::ToTokens` (almost every type from
+        // `syn` and `proc_macro2`)
+        abort!(err, "You made an error, go fix it: {}", err.msg);
+    }
+
+    // `Result` has some handy shortcuts if your error type implements
+    // `Into<Diagnostic>`. `Option` has one unconditionally.
+    more_logic(&input).expect_or_abort("What a careless user, behave!");
+
+    if !more_logic_for_logic_god(&input) {
+        // We don't have an exact location this time,
+        // so just highlight the proc-macro invocation itself
+        abort_call_site!(
+            "Bad, bad user! Now go stand in the corner and think about what you did!");
+    }
+
+    // Now all the processing is done, return `proc_macro::TokenStream`
+    quote!(/* stuff */).into()
+}
+```
+
+### `proc_macro::Diagnostic`-like usage
+
+```rust
+use proc_macro_error2::*;
+use proc_macro::TokenStream;
+use syn::{spanned::Spanned, DeriveInput, ItemStruct, Fields, Attribute , parse_macro_input};
+use quote::quote;
+
+fn process_attrs(attrs: &[Attribute]) -> Vec<Attribute> {
+    attrs
+        .iter()
+        .filter_map(|attr| match process_attr(attr) {
+            Ok(res) => Some(res),
+            Err(msg) => {
+                emit_error!(attr, "Invalid attribute: {}", msg);
+                None
+            }
+        })
+        .collect()
+}
+
+fn process_fields(_attrs: &Fields) -> Vec<TokenStream> {
+    // processing fields in pretty much the same way as attributes
+    unimplemented!()
+}
+
+#[proc_macro]
+#[proc_macro_error]
+pub fn make_answer(input: TokenStream) -> TokenStream {
+    let input = parse_macro_input!(input as ItemStruct);
+    let attrs = process_attrs(&input.attrs);
+
+    // abort right now if some errors were encountered
+    // at the attributes processing stage
+    abort_if_dirty();
+
+    let fields = process_fields(&input.fields);
+
+    // no need to think about emitted errors
+    // #[proc_macro_error] will handle them for you
+    //
+    // just return a TokenStream as you normally would
+    quote!(/* stuff */).into()
+}
+```
+
+## Real world examples
+
+* [`structopt-derive`](https://github.com/TeXitoi/structopt/tree/master/structopt-derive)
+  (abort-like usage)
+* [`auto-impl`](https://github.com/auto-impl-rs/auto_impl/) (emit-like usage)
+
+## Limitations
+
+- Warnings are emitted only on nightly, they are ignored on stable.
+- "help" suggestions can't have their own span info on stable,
+  (essentially inheriting the parent span).
+- If your macro happens to trigger a panic, no errors will be displayed. This is not a
+  technical limitation but rather intentional design. `panic` is not for error reporting.
+
+## MSRV policy
+
+The MSRV is currently `1.61`, and this is considered a breaking change to increase.
+
+However, if an existing dependency requires a higher MSRV without a semver breaking update, this may be raised.
+
+## Motivation
+
+Error handling in proc-macros sucks. There's not much of a choice today:
+you either "bubble up" the error up to the top-level of the macro and convert it to
+a [`compile_error!`][compl_err] invocation or just use a good old panic. Both these ways suck:
+
+- Former sucks because it's quite redundant to unroll a proper error handling
+    just for critical errors that will crash the macro anyway; so people mostly
+    choose not to bother with it at all and use panic. Simple `.expect` is too tempting.
+
+    Also, if you do decide to implement this `Result`-based architecture in your macro
+    you're going to have to rewrite it entirely once [`proc_macro::Diagnostic`][] is finally
+    stable. Not cool.
+
+- Later sucks because there's no way to carry out the span info via `panic!`.
+    `rustc` will highlight the invocation itself but not some specific token inside it.
+
+    Furthermore, panics aren't for error-reporting at all; panics are for bug-detecting
+    (like unwrapping on `None` or out-of-range indexing) or for early development stages
+    when you need a prototype ASAP so error handling can wait. Mixing these usages only
+    messes things up.
+
+- There is [`proc_macro::Diagnostic`][] which is awesome but it has been experimental
+    for more than a year and is unlikely to be stabilized any time soon.
+
+    This crate's API is intentionally designed to be compatible with `proc_macro::Diagnostic`
+    and delegates to it whenever possible. Once `Diagnostics` is stable this crate
+    will **always** delegate to it, no code changes will be required on user side.
+
+That said, we need a solution, but this solution must meet these conditions:
+
+- It must be better than `panic!`. The main point: it must offer a way to carry the span information
+    over to user.
+- It must take as little effort as possible to migrate from `panic!`. Ideally, a new
+    macro with similar semantics plus ability to carry out span info.
+- It must maintain compatibility with [`proc_macro::Diagnostic`][] .
+- **It must be usable on stable**.
+
+This crate aims to provide such a mechanism. All you have to do is annotate your top-level
+`#[proc_macro]` function with `#[proc_macro_error]` attribute and change panics to
+[`abort!`]/[`abort_call_site!`] where appropriate, see [the Guide][guide].
+
+## Disclaimer
+Please note that **this crate is not intended to be used in any way other
+than error reporting in procedural macros**, use `Result` and `?` (possibly along with one of the
+many helpers out there) for anything else.
+
+<br>
+
+#### License
+
+<sup>
+Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
+2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
+</sup>
+
+<br>
+
+<sub>
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in this crate by you, as defined in the Apache-2.0 license, shall
+be dual licensed as above, without any additional terms or conditions.
+</sub>
+
+
+[compl_err]: https://doc.rust-lang.org/std/macro.compile_error.html
+[`proc_macro::Diagnostic`]: https://doc.rust-lang.org/proc_macro/struct.Diagnostic.html
+
+[crate::dummy]: https://docs.rs/proc-macro-error2/1/proc_macro_error/dummy/index.html
+[crate::multi]: https://docs.rs/proc-macro-error2/1/proc_macro_error/multi/index.html
+
+[`abort_call_site!`]: https://docs.rs/proc-macro-error2/1/proc_macro_error/macro.abort_call_site.html
+[`abort!`]: https://docs.rs/proc-macro-error2/1/proc_macro_error/macro.abort.html
+[guide]: https://docs.rs/proc-macro-error2
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/diagnostic.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/diagnostic.rs
new file mode 100644
index 0000000..04555112
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/diagnostic.rs
@@ -0,0 +1,360 @@
+use crate::{abort_now, check_correctness, sealed::Sealed, SpanRange};
+use proc_macro2::Span;
+use proc_macro2::TokenStream;
+
+use quote::{quote_spanned, ToTokens};
+
+/// Represents a diagnostic level
+///
+/// # Warnings
+///
+/// Warnings are ignored on stable/beta
+#[derive(Debug, PartialEq)]
+#[non_exhaustive]
+pub enum Level {
+    Error,
+    Warning,
+}
+
+/// Represents a single diagnostic message
+#[derive(Debug)]
+#[must_use = "A diagnostic does nothing unless emitted"]
+pub struct Diagnostic {
+    pub(crate) level: Level,
+    pub(crate) span_range: SpanRange,
+    pub(crate) msg: String,
+    pub(crate) suggestions: Vec<(SuggestionKind, String, Option<SpanRange>)>,
+    pub(crate) children: Vec<(SpanRange, String)>,
+}
+
+/// A collection of methods that do not exist in `proc_macro::Diagnostic`
+/// but still useful to have around.
+///
+/// This trait is sealed and cannot be implemented outside of `proc_macro_error`.
+pub trait DiagnosticExt: Sealed {
+    /// Create a new diagnostic message that points to the `span_range`.
+    ///
+    /// This function is the same as `Diagnostic::spanned` but produces considerably
+    /// better error messages for multi-token spans on stable.
+    fn spanned_range(span_range: SpanRange, level: Level, message: String) -> Self;
+
+    /// Add another error message to self such that it will be emitted right after
+    /// the main message.
+    ///
+    /// This function is the same as `Diagnostic::span_error` but produces considerably
+    /// better error messages for multi-token spans on stable.
+    #[must_use]
+    fn span_range_error(self, span_range: SpanRange, msg: String) -> Self;
+
+    /// Attach a "help" note to your main message, the note will have it's own span on nightly.
+    ///
+    /// This function is the same as `Diagnostic::span_help` but produces considerably
+    /// better error messages for multi-token spans on stable.
+    ///
+    /// # Span
+    ///
+    /// The span is ignored on stable, the note effectively inherits its parent's (main message) span
+    #[must_use]
+    fn span_range_help(self, span_range: SpanRange, msg: String) -> Self;
+
+    /// Attach a note to your main message, the note will have it's own span on nightly.
+    ///
+    /// This function is the same as `Diagnostic::span_note` but produces considerably
+    /// better error messages for multi-token spans on stable.
+    ///
+    /// # Span
+    ///
+    /// The span is ignored on stable, the note effectively inherits its parent's (main message) span
+    #[must_use]
+    fn span_range_note(self, span_range: SpanRange, msg: String) -> Self;
+}
+
+impl DiagnosticExt for Diagnostic {
+    fn spanned_range(span_range: SpanRange, level: Level, message: String) -> Self {
+        Diagnostic {
+            level,
+            span_range,
+            msg: message,
+            suggestions: vec![],
+            children: vec![],
+        }
+    }
+
+    fn span_range_error(mut self, span_range: SpanRange, msg: String) -> Self {
+        self.children.push((span_range, msg));
+        self
+    }
+
+    fn span_range_help(mut self, span_range: SpanRange, msg: String) -> Self {
+        self.suggestions
+            .push((SuggestionKind::Help, msg, Some(span_range)));
+        self
+    }
+
+    fn span_range_note(mut self, span_range: SpanRange, msg: String) -> Self {
+        self.suggestions
+            .push((SuggestionKind::Note, msg, Some(span_range)));
+        self
+    }
+}
+
+impl Diagnostic {
+    /// Create a new diagnostic message that points to `Span::call_site()`
+    pub fn new(level: Level, message: String) -> Self {
+        Diagnostic::spanned(Span::call_site(), level, message)
+    }
+
+    /// Create a new diagnostic message that points to the `span`
+    pub fn spanned(span: Span, level: Level, message: String) -> Self {
+        Diagnostic::spanned_range(
+            SpanRange {
+                first: span,
+                last: span,
+            },
+            level,
+            message,
+        )
+    }
+
+    /// Add another error message to self such that it will be emitted right after
+    /// the main message.
+    pub fn span_error(self, span: Span, msg: String) -> Self {
+        self.span_range_error(
+            SpanRange {
+                first: span,
+                last: span,
+            },
+            msg,
+        )
+    }
+
+    /// Attach a "help" note to your main message, the note will have it's own span on nightly.
+    ///
+    /// # Span
+    ///
+    /// The span is ignored on stable, the note effectively inherits its parent's (main message) span
+    pub fn span_help(self, span: Span, msg: String) -> Self {
+        self.span_range_help(
+            SpanRange {
+                first: span,
+                last: span,
+            },
+            msg,
+        )
+    }
+
+    /// Attach a "help" note to your main message.
+    pub fn help(mut self, msg: String) -> Self {
+        self.suggestions.push((SuggestionKind::Help, msg, None));
+        self
+    }
+
+    /// Attach a note to your main message, the note will have it's own span on nightly.
+    ///
+    /// # Span
+    ///
+    /// The span is ignored on stable, the note effectively inherits its parent's (main message) span
+    pub fn span_note(self, span: Span, msg: String) -> Self {
+        self.span_range_note(
+            SpanRange {
+                first: span,
+                last: span,
+            },
+            msg,
+        )
+    }
+
+    /// Attach a note to your main message
+    pub fn note(mut self, msg: String) -> Self {
+        self.suggestions.push((SuggestionKind::Note, msg, None));
+        self
+    }
+
+    /// The message of main warning/error (no notes attached)
+    #[must_use]
+    pub fn message(&self) -> &str {
+        &self.msg
+    }
+
+    /// Abort the proc-macro's execution and display the diagnostic.
+    ///
+    /// # Warnings
+    ///
+    /// Warnings are not emitted on stable and beta, but this function will abort anyway.
+    pub fn abort(self) -> ! {
+        self.emit();
+        abort_now()
+    }
+
+    /// Display the diagnostic while not aborting macro execution.
+    ///
+    /// # Warnings
+    ///
+    /// Warnings are ignored on stable/beta
+    pub fn emit(self) {
+        check_correctness();
+        crate::imp::emit_diagnostic(self);
+    }
+}
+
+/// **NOT PUBLIC API! NOTHING TO SEE HERE!!!**
+#[doc(hidden)]
+impl Diagnostic {
+    pub fn span_suggestion(self, span: Span, suggestion: &str, msg: String) -> Self {
+        match suggestion {
+            "help" | "hint" => self.span_help(span, msg),
+            _ => self.span_note(span, msg),
+        }
+    }
+
+    pub fn suggestion(self, suggestion: &str, msg: String) -> Self {
+        match suggestion {
+            "help" | "hint" => self.help(msg),
+            _ => self.note(msg),
+        }
+    }
+}
+
+impl ToTokens for Diagnostic {
+    fn to_tokens(&self, ts: &mut TokenStream) {
+        use std::borrow::Cow;
+
+        fn ensure_lf(buf: &mut String, s: &str) {
+            if s.ends_with('\n') {
+                buf.push_str(s);
+            } else {
+                buf.push_str(s);
+                buf.push('\n');
+            }
+        }
+
+        fn diag_to_tokens(
+            span_range: SpanRange,
+            level: &Level,
+            msg: &str,
+            suggestions: &[(SuggestionKind, String, Option<SpanRange>)],
+        ) -> TokenStream {
+            if *level == Level::Warning {
+                return TokenStream::new();
+            }
+
+            let message = if suggestions.is_empty() {
+                Cow::Borrowed(msg)
+            } else {
+                let mut message = String::new();
+                ensure_lf(&mut message, msg);
+                message.push('\n');
+
+                for (kind, note, _span) in suggestions {
+                    message.push_str("  = ");
+                    message.push_str(kind.name());
+                    message.push_str(": ");
+                    ensure_lf(&mut message, note);
+                }
+                message.push('\n');
+
+                Cow::Owned(message)
+            };
+
+            let mut msg = proc_macro2::Literal::string(&message);
+            msg.set_span(span_range.last);
+            let group = quote_spanned!(span_range.last=> { #msg } );
+            quote_spanned!(span_range.first=> compile_error!#group)
+        }
+
+        ts.extend(diag_to_tokens(
+            self.span_range,
+            &self.level,
+            &self.msg,
+            &self.suggestions,
+        ));
+        ts.extend(
+            self.children
+                .iter()
+                .map(|(span_range, msg)| diag_to_tokens(*span_range, &Level::Error, msg, &[])),
+        );
+    }
+}
+
+#[derive(Debug)]
+pub(crate) enum SuggestionKind {
+    Help,
+    Note,
+}
+
+impl SuggestionKind {
+    fn name(&self) -> &'static str {
+        match self {
+            SuggestionKind::Note => "note",
+            SuggestionKind::Help => "help",
+        }
+    }
+}
+
+#[cfg(feature = "syn-error")]
+impl From<syn::Error> for Diagnostic {
+    fn from(err: syn::Error) -> Self {
+        use proc_macro2::{Delimiter, TokenTree};
+
+        fn gut_error(ts: &mut impl Iterator<Item = TokenTree>) -> Option<(SpanRange, String)> {
+            let start_span = ts.next()?.span();
+            ts.next().expect(":1");
+            ts.next().expect("core");
+            ts.next().expect(":2");
+            ts.next().expect(":3");
+            ts.next().expect("compile_error");
+            ts.next().expect("!");
+
+            let lit = match ts.next().unwrap() {
+                TokenTree::Group(group) => {
+                    // Currently `syn` builds `compile_error!` invocations
+                    // exclusively in `ident{"..."}` (braced) form which is not
+                    // followed by `;` (semicolon).
+                    //
+                    // But if it changes to `ident("...");` (parenthesized)
+                    // or `ident["..."];` (bracketed) form,
+                    // we will need to skip the `;` as well.
+                    // Highly unlikely, but better safe than sorry.
+
+                    if group.delimiter() == Delimiter::Parenthesis
+                        || group.delimiter() == Delimiter::Bracket
+                    {
+                        ts.next().unwrap(); // ;
+                    }
+
+                    match group.stream().into_iter().next().unwrap() {
+                        TokenTree::Literal(lit) => lit,
+                        _ => unreachable!(""),
+                    }
+                }
+                _ => unreachable!(""),
+            };
+
+            let last = lit.span();
+            let mut msg = lit.to_string();
+
+            // "abc" => abc
+            msg.pop();
+            msg.remove(0);
+
+            Some((
+                SpanRange {
+                    first: start_span,
+                    last,
+                },
+                msg,
+            ))
+        }
+
+        let mut ts = err.to_compile_error().into_iter();
+
+        let (span_range, msg) = gut_error(&mut ts).unwrap();
+        let mut res = Diagnostic::spanned_range(span_range, Level::Error, msg);
+
+        while let Some((span_range, msg)) = gut_error(&mut ts) {
+            res = res.span_range_error(span_range, msg);
+        }
+
+        res
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/dummy.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/dummy.rs
new file mode 100644
index 0000000..5bc98bd0
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/dummy.rs
@@ -0,0 +1,151 @@
+//! Facility to emit dummy implementations (or whatever) in case
+//! an error happen.
+//!
+//! `compile_error!` does not abort a compilation right away. This means
+//! `rustc` doesn't just show you the error and abort, it carries on the
+//! compilation process looking for other errors to report.
+//!
+//! Let's consider an example:
+//!
+//! ```rust,ignore
+//! use proc_macro::TokenStream;
+//! use proc_macro_error2::*;
+//!
+//! trait MyTrait {
+//!     fn do_thing();
+//! }
+//!
+//! // this proc macro is supposed to generate MyTrait impl
+//! #[proc_macro_derive(MyTrait)]
+//! #[proc_macro_error]
+//! fn example(input: TokenStream) -> TokenStream {
+//!     // somewhere deep inside
+//!     abort!(span, "something's wrong");
+//!
+//!     // this implementation will be generated if no error happened
+//!     quote! {
+//!         impl MyTrait for #name {
+//!             fn do_thing() {/* whatever */}
+//!         }
+//!     }
+//! }
+//!
+//! // ================
+//! // in main.rs
+//!
+//! // this derive triggers an error
+//! #[derive(MyTrait)] // first BOOM!
+//! struct Foo;
+//!
+//! fn main() {
+//!     Foo::do_thing(); // second BOOM!
+//! }
+//! ```
+//!
+//! The problem is: the generated token stream contains only `compile_error!`
+//! invocation, the impl was not generated. That means user will see two compilation
+//! errors:
+//!
+//! ```text
+//! error: something's wrong
+//!  --> $DIR/probe.rs:9:10
+//!   |
+//! 9 |#[proc_macro_derive(MyTrait)]
+//!   |                    ^^^^^^^
+//!
+//! error[E0599]: no function or associated item named `do_thing` found for type `Foo` in the current scope
+//!  --> src\main.rs:3:10
+//!   |
+//! 1 | struct Foo;
+//!   | ----------- function or associated item `do_thing` not found for this
+//! 2 | fn main() {
+//! 3 |     Foo::do_thing(); // second BOOM!
+//!   |          ^^^^^^^^ function or associated item not found in `Foo`
+//! ```
+//!
+//! But the second error is meaningless! We definitely need to fix this.
+//!
+//! Most used approach in cases like this is "dummy implementation" -
+//! omit `impl MyTrait for #name` and fill functions bodies with `unimplemented!()`.
+//!
+//! This is how you do it:
+//!
+//! ```rust,ignore
+//! use proc_macro::TokenStream;
+//! use proc_macro_error2::*;
+//!
+//!  trait MyTrait {
+//!      fn do_thing();
+//!  }
+//!
+//!  // this proc macro is supposed to generate MyTrait impl
+//!  #[proc_macro_derive(MyTrait)]
+//!  #[proc_macro_error]
+//!  fn example(input: TokenStream) -> TokenStream {
+//!      // first of all - we set a dummy impl which will be appended to
+//!      // `compile_error!` invocations in case a trigger does happen
+//!      set_dummy(quote! {
+//!          impl MyTrait for #name {
+//!              fn do_thing() { unimplemented!() }
+//!          }
+//!      });
+//!
+//!      // somewhere deep inside
+//!      abort!(span, "something's wrong");
+//!
+//!      // this implementation will be generated if no error happened
+//!      quote! {
+//!          impl MyTrait for #name {
+//!              fn do_thing() {/* whatever */}
+//!          }
+//!      }
+//!  }
+//!
+//!  // ================
+//!  // in main.rs
+//!
+//!  // this derive triggers an error
+//!  #[derive(MyTrait)] // first BOOM!
+//!  struct Foo;
+//!
+//!  fn main() {
+//!      Foo::do_thing(); // no more errors!
+//!  }
+//! ```
+
+use proc_macro2::TokenStream;
+use std::cell::RefCell;
+
+use crate::check_correctness;
+
+thread_local! {
+    static DUMMY_IMPL: RefCell<Option<TokenStream>> = const { RefCell::new(None) };
+}
+
+/// Sets dummy token stream which will be appended to `compile_error!(msg);...`
+/// invocations in case you'll emit any errors.
+///
+/// See [guide](../index.html#guide).
+#[allow(clippy::must_use_candidate)] // Mutates thread local state
+pub fn set_dummy(dummy: TokenStream) -> Option<TokenStream> {
+    check_correctness();
+    DUMMY_IMPL.with(|old_dummy| old_dummy.replace(Some(dummy)))
+}
+
+/// Same as [`set_dummy`] but, instead of resetting, appends tokens to the
+/// existing dummy (if any). Behaves as `set_dummy` if no dummy is present.
+pub fn append_dummy(dummy: TokenStream) {
+    check_correctness();
+    DUMMY_IMPL.with(|old_dummy| {
+        let mut cell = old_dummy.borrow_mut();
+        if let Some(ts) = cell.as_mut() {
+            ts.extend(dummy);
+        } else {
+            *cell = Some(dummy);
+        }
+    });
+}
+
+pub(crate) fn cleanup() -> Option<TokenStream> {
+    DUMMY_IMPL.with(|old_dummy| old_dummy.replace(None))
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/imp/delegate.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/imp/delegate.rs
new file mode 100644
index 0000000..a3e6a80
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/imp/delegate.rs
@@ -0,0 +1,68 @@
+//! This implementation uses [`proc_macro::Diagnostic`], nightly only.
+
+use std::cell::Cell;
+
+use proc_macro::{Diagnostic as PDiag, Level as PLevel};
+
+use crate::{
+    abort_now, check_correctness,
+    diagnostic::{Diagnostic, Level, SuggestionKind},
+};
+
+pub fn abort_if_dirty() {
+    check_correctness();
+    if IS_DIRTY.with(|c| c.get()) {
+        abort_now()
+    }
+}
+
+pub(crate) fn cleanup() -> Vec<Diagnostic> {
+    IS_DIRTY.with(|c| c.set(false));
+    vec![]
+}
+
+pub(crate) fn emit_diagnostic(diag: Diagnostic) {
+    let Diagnostic {
+        level,
+        span_range,
+        msg,
+        suggestions,
+        children,
+    } = diag;
+
+    let span = span_range.collapse().unwrap();
+
+    let level = match level {
+        Level::Warning => PLevel::Warning,
+        Level::Error => {
+            IS_DIRTY.with(|c| c.set(true));
+            PLevel::Error
+        }
+    };
+
+    let mut res = PDiag::spanned(span, level, msg);
+
+    for (kind, msg, span) in suggestions {
+        res = match (kind, span) {
+            (SuggestionKind::Note, Some(span_range)) => {
+                res.span_note(span_range.collapse().unwrap(), msg)
+            }
+            (SuggestionKind::Help, Some(span_range)) => {
+                res.span_help(span_range.collapse().unwrap(), msg)
+            }
+            (SuggestionKind::Note, None) => res.note(msg),
+            (SuggestionKind::Help, None) => res.help(msg),
+        }
+    }
+
+    for (span_range, msg) in children {
+        let span = span_range.collapse().unwrap();
+        res = res.span_error(span, msg);
+    }
+
+    res.emit()
+}
+
+thread_local! {
+    static IS_DIRTY: Cell<bool> = Cell::new(false);
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/imp/fallback.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/imp/fallback.rs
new file mode 100644
index 0000000..c10eb9a
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/imp/fallback.rs
@@ -0,0 +1,30 @@
+//! This implementation uses self-written stable facilities.
+
+use crate::{
+    abort_now, check_correctness,
+    diagnostic::{Diagnostic, Level},
+};
+use std::cell::RefCell;
+
+pub fn abort_if_dirty() {
+    check_correctness();
+    ERR_STORAGE.with(|storage| {
+        if !storage.borrow().is_empty() {
+            abort_now()
+        }
+    });
+}
+
+pub(crate) fn cleanup() -> Vec<Diagnostic> {
+    ERR_STORAGE.with(|storage| storage.replace(Vec::new()))
+}
+
+pub(crate) fn emit_diagnostic(diag: Diagnostic) {
+    if diag.level == Level::Error {
+        ERR_STORAGE.with(|storage| storage.borrow_mut().push(diag));
+    }
+}
+
+thread_local! {
+    static ERR_STORAGE: RefCell<Vec<Diagnostic>> = const { RefCell::new(Vec::new()) };
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/lib.rs
new file mode 100644
index 0000000..a00c924
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/lib.rs
@@ -0,0 +1,565 @@
+//! # proc-macro-error2
+//!
+//! This crate aims to make error reporting in proc-macros simple and easy to use.
+//! Migrate from `panic!`-based errors for as little effort as possible!
+//!
+//! (Also, you can explicitly [append a dummy token stream](dummy/index.html) to your errors).
+//!
+//! To achieve his, this crate serves as a tiny shim around `proc_macro::Diagnostic` and
+//! `compile_error!`. It detects the best way of emitting available based on compiler's version.
+//! When the underlying diagnostic type is finally stabilized, this crate will simply be
+//! delegating to it requiring no changes in your code!
+//!
+//! So you can just use this crate and have *both* some of `proc_macro::Diagnostic` functionality
+//! available on stable ahead of time *and* your error-reporting code future-proof.
+//!
+//! ## Cargo features
+//!
+//! This crate provides *enabled by default* `syn-error` feature that gates
+//! `impl From<syn::Error> for Diagnostic` conversion. If you don't use `syn` and want
+//! to cut off some of compilation time, you can disable it via
+//!
+//! ```toml
+//! [dependencies]
+//! proc-macro-error2 = { version = "2.0.0", default-features = false }
+//! ```
+//!
+//! ***Please note that disabling this feature makes sense only if you don't depend on `syn`
+//! directly or indirectly, and you very likely do.**
+//!
+//! ## Real world examples
+//!
+//! * [`structopt-derive`](https://github.com/TeXitoi/structopt/tree/master/structopt-derive)
+//!   (abort-like usage)
+//! * [`auto-impl`](https://github.com/auto-impl-rs/auto_impl/) (emit-like usage)
+//!
+//! ## Limitations
+//!
+//! - Warnings are emitted only on nightly, they are ignored on stable.
+//! - "help" suggestions can't have their own span info on stable,
+//!   (essentially inheriting the parent span).
+//! - If a panic occurs somewhere in your macro no errors will be displayed. This is not a
+//!   technical limitation but rather intentional design. `panic` is not for error reporting.
+//!
+//! ### `#[proc_macro_error]` attribute
+//!
+//! **This attribute MUST be present on the top level of your macro** (the function
+//! annotated with any of `#[proc_macro]`, `#[proc_macro_derive]`, `#[proc_macro_attribute]`).
+//!
+//! This attribute performs the setup and cleanup necessary to make things work.
+//!
+//! In most cases you'll need the simple `#[proc_macro_error]` form without any
+//! additional settings. Feel free to [skip the "Syntax" section](#macros).
+//!
+//! #### Syntax
+//!
+//! `#[proc_macro_error]` or `#[proc_macro_error(settings...)]`, where `settings...`
+//! is a comma-separated list of:
+//!
+//! - `proc_macro_hack`:
+//!
+//!     In order to correctly cooperate with `#[proc_macro_hack]`, `#[proc_macro_error]`
+//!     attribute must be placed *before* (above) it, like this:
+//!
+//!     ```no_run
+//!     # use proc_macro2::TokenStream;
+//!     # const IGNORE: &str = "
+//!     #[proc_macro_error]
+//!     #[proc_macro_hack]
+//!     #[proc_macro]
+//!     # ";
+//!     fn my_macro(input: TokenStream) -> TokenStream {
+//!         unimplemented!()
+//!     }
+//!     ```
+//!
+//!     If, for some reason, you can't place it like that you can use
+//!     `#[proc_macro_error(proc_macro_hack)]` instead.
+//!
+//!     # Note
+//!
+//!     If `proc-macro-hack` was detected (by any means) `allow_not_macro`
+//!     and `assert_unwind_safe` will be applied automatically.
+//!
+//! - `allow_not_macro`:
+//!
+//!     By default, the attribute checks that it's applied to a proc-macro.
+//!     If none of `#[proc_macro]`, `#[proc_macro_derive]` nor `#[proc_macro_attribute]` are
+//!     present it will panic. It's the intention - this crate is supposed to be used only with
+//!     proc-macros.
+//!
+//!     This setting is made to bypass the check, useful in certain circumstances.
+//!
+//!     Pay attention: the function this attribute is applied to must return
+//!     `proc_macro::TokenStream`.
+//!
+//!     This setting is implied if `proc-macro-hack` was detected.
+//!
+//! - `assert_unwind_safe`:
+//!
+//!     By default, your code must be [unwind safe]. If your code is not unwind safe,
+//!     but you believe it's correct, you can use this setting to bypass the check.
+//!     You would need this for code that uses `lazy_static` or `thread_local` with
+//!     `Cell/RefCell` inside (and the like).
+//!
+//!     This setting is implied if `#[proc_macro_error]` is applied to a function
+//!     marked as `#[proc_macro]`, `#[proc_macro_derive]` or `#[proc_macro_attribute]`.
+//!
+//!     This setting is also implied if `proc-macro-hack` was detected.
+//!
+//! ## Macros
+//!
+//! Most of the time you want to use the macros. Syntax is described in the next section below.
+//!
+//! You'll need to decide how you want to emit errors:
+//!
+//! * Emit the error and abort. Very much panic-like usage. Served by [`abort!`] and
+//!   [`abort_call_site!`].
+//! * Emit the error but do not abort right away, looking for other errors to report.
+//!   Served by [`emit_error!`] and [`emit_call_site_error!`].
+//!
+//! You **can** mix these usages.
+//!
+//! `abort` and `emit_error` take a "source span" as the first argument. This source
+//! will be used to highlight the place the error originates from. It must be one of:
+//!
+//! * *Something* that implements [`ToTokens`] (most types in `syn` and `proc-macro2` do).
+//!   This source is the preferable one since it doesn't lose span information on multi-token
+//!   spans, see [this issue](https://gitlab.com/CreepySkeleton/proc-macro-error/-/issues/6)
+//!   for details.
+//! * [`proc_macro::Span`]
+//! * [`proc-macro2::Span`]
+//!
+//! The rest is your message in format-like style.
+//!
+//! See [the next section](#syntax-1) for detailed syntax.
+//!
+//! - [`abort!`]:
+//!
+//!     Very much panic-like usage - abort right away and show the error.
+//!     Expands to [`!`] (never type).
+//!
+//! - [`abort_call_site!`]:
+//!
+//!     Shortcut for `abort!(Span::call_site(), ...)`. Expands to [`!`] (never type).
+//!
+//! - [`emit_error!`]:
+//!
+//!     [`proc_macro::Diagnostic`]-like usage - emit the error but keep going,
+//!     looking for other errors to report.
+//!     The compilation will fail nonetheless. Expands to [`()`] (unit type).
+//!
+//! - [`emit_call_site_error!`]:
+//!
+//!     Shortcut for `emit_error!(Span::call_site(), ...)`. Expands to [`()`] (unit type).
+//!
+//! - [`emit_warning!`]:
+//!
+//!     Like `emit_error!` but emit a warning instead of error. The compilation won't fail
+//!     because of warnings.
+//!     Expands to [`()`] (unit type).
+//!
+//!     **Beware**: warnings are nightly only, they are completely ignored on stable.
+//!
+//! - [`emit_call_site_warning!`]:
+//!
+//!     Shortcut for `emit_warning!(Span::call_site(), ...)`. Expands to [`()`] (unit type).
+//!
+//! - [`diagnostic`]:
+//!
+//!     Build an instance of `Diagnostic` in format-like style.
+//!
+//! #### Syntax
+//!
+//! All the macros have pretty much the same syntax:
+//!
+//! 1.  ```ignore
+//!     abort!(single_expr)
+//!     ```
+//!     Shortcut for `Diagnostic::from(expr).abort()`.
+//!
+//! 2.  ```ignore
+//!     abort!(span, message)
+//!     ```
+//!     The first argument is an expression the span info should be taken from.
+//!
+//!     The second argument is the error message, it must implement [`ToString`].
+//!
+//! 3.  ```ignore
+//!     abort!(span, format_literal, format_args...)
+//!     ```
+//!
+//!     This form is pretty much the same as 2, except `format!(format_literal, format_args...)`
+//!     will be used to for the message instead of [`ToString`].
+//!
+//! That's it. `abort!`, `emit_warning`, `emit_error` share this exact syntax.
+//!
+//! `abort_call_site!`, `emit_call_site_warning`, `emit_call_site_error` lack 1 form
+//! and do not take span in 2'th and 3'th forms. Those are essentially shortcuts for
+//! `macro!(Span::call_site(), args...)`.
+//!
+//! `diagnostic!` requires a [`Level`] instance between `span` and second argument
+//! (1'th form is the same).
+//!
+//! > **Important!**
+//! >
+//! > If you have some type from `proc_macro` or `syn` to point to, do not call `.span()`
+//! > on it but rather use it directly:
+//! > ```no_run
+//! > # use proc_macro_error2::abort;
+//! > # let input = proc_macro2::TokenStream::new();
+//! > let ty: syn::Type = syn::parse2(input).unwrap();
+//! > abort!(ty, "BOOM");
+//! > //     ^^ <-- avoid .span()
+//! > ```
+//! >
+//! > `.span()` calls work too, but you may experience regressions in message quality.
+//!
+//! #### Note attachments
+//!
+//! 3.  Every macro can have "note" attachments (only 2 and 3 form).
+//!   ```ignore
+//!   let opt_help = if have_some_info { Some("did you mean `this`?") } else { None };
+//!
+//!   abort!(
+//!       span, message; // <--- attachments start with `;` (semicolon)
+//!
+//!       help = "format {} {}", "arg1", "arg2"; // <--- every attachment ends with `;`,
+//!                                              //      maybe except the last one
+//!
+//!       note = "to_string"; // <--- one arg uses `.to_string()` instead of `format!()`
+//!
+//!       yay = "I see what {} did here", "you"; // <--- "help =" and "hint =" are mapped
+//!                                              // to Diagnostic::help,
+//!                                              // anything else is Diagnostic::note
+//!
+//!       wow = note_span => "custom span"; // <--- attachments can have their own span
+//!                                         //      it takes effect only on nightly though
+//!
+//!       hint =? opt_help; // <-- "optional" attachment, get displayed only if `Some`
+//!                         //     must be single `Option` expression
+//!
+//!       note =? note_span => opt_help // <-- optional attachments can have custom spans too
+//!   );
+//!   ```
+//!
+
+//! ### Diagnostic type
+//!
+//! [`Diagnostic`] type is intentionally designed to be API compatible with [`proc_macro::Diagnostic`].
+//! Not all API is implemented, only the part that can be reasonably implemented on stable.
+//!
+//!
+//! [`abort!`]: macro.abort.html
+//! [`abort_call_site!`]: macro.abort_call_site.html
+//! [`emit_warning!`]: macro.emit_warning.html
+//! [`emit_error!`]: macro.emit_error.html
+//! [`emit_call_site_warning!`]: macro.emit_call_site_error.html
+//! [`emit_call_site_error!`]: macro.emit_call_site_warning.html
+//! [`diagnostic!`]: macro.diagnostic.html
+//! [`Diagnostic`]: struct.Diagnostic.html
+//!
+//! [`proc_macro::Span`]: https://doc.rust-lang.org/proc_macro/struct.Span.html
+//! [`proc_macro::Diagnostic`]: https://doc.rust-lang.org/proc_macro/struct.Diagnostic.html
+//!
+//! [unwind safe]: https://doc.rust-lang.org/std/panic/trait.UnwindSafe.html#what-is-unwind-safety
+//! [`!`]: https://doc.rust-lang.org/std/primitive.never.html
+//! [`()`]: https://doc.rust-lang.org/std/primitive.unit.html
+//! [`ToString`]: https://doc.rust-lang.org/std/string/trait.ToString.html
+//!
+//! [`proc-macro2::Span`]: https://docs.rs/proc-macro2/1.0.10/proc_macro2/struct.Span.html
+//! [`ToTokens`]: https://docs.rs/quote/1.0.3/quote/trait.ToTokens.html
+//!
+
+#![cfg_attr(feature = "nightly", feature(proc_macro_diagnostic))]
+#![forbid(unsafe_code)]
+
+extern crate proc_macro;
+
+pub use crate::{
+    diagnostic::{Diagnostic, DiagnosticExt, Level},
+    dummy::{append_dummy, set_dummy},
+};
+pub use proc_macro_error_attr2::proc_macro_error;
+
+use proc_macro2::Span;
+use quote::{quote, ToTokens};
+
+use std::cell::Cell;
+use std::panic::{catch_unwind, resume_unwind, UnwindSafe};
+
+pub mod dummy;
+
+mod diagnostic;
+mod macros;
+mod sealed;
+
+#[cfg(not(feature = "nightly"))]
+#[path = "imp/fallback.rs"]
+mod imp;
+
+#[cfg(feature = "nightly")]
+#[path = "imp/delegate.rs"]
+mod imp;
+
+#[derive(Debug, Clone, Copy)]
+#[must_use = "A SpanRange does nothing unless used"]
+pub struct SpanRange {
+    pub first: Span,
+    pub last: Span,
+}
+
+impl SpanRange {
+    /// Create a range with the `first` and `last` spans being the same.
+    pub fn single_span(span: Span) -> Self {
+        SpanRange {
+            first: span,
+            last: span,
+        }
+    }
+
+    /// Create a `SpanRange` resolving at call site.
+    pub fn call_site() -> Self {
+        SpanRange::single_span(Span::call_site())
+    }
+
+    /// Construct span range from a `TokenStream`. This method always preserves all the
+    /// range.
+    ///
+    /// ### Note
+    ///
+    /// If the stream is empty, the result is `SpanRange::call_site()`. If the stream
+    /// consists of only one `TokenTree`, the result is `SpanRange::single_span(tt.span())`
+    /// that doesn't lose anything.
+    pub fn from_tokens(ts: &dyn ToTokens) -> Self {
+        let mut spans = ts.to_token_stream().into_iter().map(|tt| tt.span());
+        let first = spans.next().unwrap_or_else(Span::call_site);
+        let last = spans.last().unwrap_or(first);
+
+        SpanRange { first, last }
+    }
+
+    /// Join two span ranges. The resulting range will start at `self.first` and end at
+    /// `other.last`.
+    pub fn join_range(self, other: SpanRange) -> Self {
+        SpanRange {
+            first: self.first,
+            last: other.last,
+        }
+    }
+
+    /// Collapse the range into single span, preserving as much information as possible.
+    #[must_use]
+    pub fn collapse(self) -> Span {
+        self.first.join(self.last).unwrap_or(self.first)
+    }
+}
+
+/// This traits expands `Result<T, Into<Diagnostic>>` with some handy shortcuts.
+pub trait ResultExt {
+    type Ok;
+
+    /// Behaves like `Result::unwrap`: if self is `Ok` yield the contained value,
+    /// otherwise abort macro execution via `abort!`.
+    fn unwrap_or_abort(self) -> Self::Ok;
+
+    /// Behaves like `Result::expect`: if self is `Ok` yield the contained value,
+    /// otherwise abort macro execution via `abort!`.
+    /// If it aborts then resulting error message will be preceded with `message`.
+    fn expect_or_abort(self, msg: &str) -> Self::Ok;
+}
+
+/// This traits expands `Option` with some handy shortcuts.
+pub trait OptionExt {
+    type Some;
+
+    /// Behaves like `Option::expect`: if self is `Some` yield the contained value,
+    /// otherwise abort macro execution via `abort_call_site!`.
+    /// If it aborts the `message` will be used for [`compile_error!`][compl_err] invocation.
+    ///
+    /// [compl_err]: https://doc.rust-lang.org/std/macro.compile_error.html
+    fn expect_or_abort(self, msg: &str) -> Self::Some;
+}
+
+/// Abort macro execution and display all the emitted errors, if any.
+///
+/// Does nothing if no errors were emitted (warnings do not count).
+pub fn abort_if_dirty() {
+    imp::abort_if_dirty();
+}
+
+impl<T, E: Into<Diagnostic>> ResultExt for Result<T, E> {
+    type Ok = T;
+
+    fn unwrap_or_abort(self) -> T {
+        match self {
+            Ok(res) => res,
+            Err(e) => e.into().abort(),
+        }
+    }
+
+    fn expect_or_abort(self, message: &str) -> T {
+        match self {
+            Ok(res) => res,
+            Err(e) => {
+                let mut e = e.into();
+                e.msg = format!("{}: {}", message, e.msg);
+                e.abort()
+            }
+        }
+    }
+}
+
+impl<T> OptionExt for Option<T> {
+    type Some = T;
+
+    fn expect_or_abort(self, message: &str) -> T {
+        match self {
+            Some(res) => res,
+            None => abort_call_site!(message),
+        }
+    }
+}
+
+/// This is the entry point for a proc-macro.
+///
+/// **NOT PUBLIC API, SUBJECT TO CHANGE WITHOUT ANY NOTICE**
+#[doc(hidden)]
+pub fn entry_point<F>(f: F, proc_macro_hack: bool) -> proc_macro::TokenStream
+where
+    F: FnOnce() -> proc_macro::TokenStream + UnwindSafe,
+{
+    ENTERED_ENTRY_POINT.with(|flag| flag.set(flag.get() + 1));
+    let caught = catch_unwind(f);
+    let dummy = dummy::cleanup();
+    let err_storage = imp::cleanup();
+    ENTERED_ENTRY_POINT.with(|flag| flag.set(flag.get() - 1));
+
+    let gen_error = || {
+        if proc_macro_hack {
+            quote! {{
+                macro_rules! proc_macro_call {
+                    () => ( unimplemented!() )
+                }
+
+                #(#err_storage)*
+                #dummy
+
+                unimplemented!()
+            }}
+        } else {
+            quote!( #(#err_storage)* #dummy )
+        }
+    };
+
+    match caught {
+        Ok(ts) => {
+            if err_storage.is_empty() {
+                ts
+            } else {
+                gen_error().into()
+            }
+        }
+
+        Err(boxed) => match boxed.downcast::<AbortNow>() {
+            Ok(_) => gen_error().into(),
+            Err(boxed) => resume_unwind(boxed),
+        },
+    }
+}
+
+fn abort_now() -> ! {
+    check_correctness();
+    std::panic::panic_any(AbortNow)
+}
+
+thread_local! {
+    static ENTERED_ENTRY_POINT: Cell<usize> = const { Cell::new(0) };
+}
+
+struct AbortNow;
+
+fn check_correctness() {
+    assert!(
+        ENTERED_ENTRY_POINT.with(Cell::get) != 0,
+        "proc-macro-error2 API cannot be used outside of `entry_point` invocation, \
+             perhaps you forgot to annotate your #[proc_macro] function with `#[proc_macro_error]"
+    );
+}
+
+/// **ALL THE STUFF INSIDE IS NOT PUBLIC API!!!**
+#[doc(hidden)]
+pub mod __export {
+    // reexports for use in macros
+    pub use proc_macro;
+    pub use proc_macro2;
+
+    use proc_macro2::Span;
+    use quote::ToTokens;
+
+    use crate::SpanRange;
+
+    // inspired by
+    // https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md#simple-application
+
+    pub trait SpanAsSpanRange {
+        #[allow(non_snake_case)]
+        fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange;
+    }
+
+    pub trait Span2AsSpanRange {
+        #[allow(non_snake_case)]
+        fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange;
+    }
+
+    pub trait ToTokensAsSpanRange {
+        #[allow(non_snake_case)]
+        fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange;
+    }
+
+    pub trait SpanRangeAsSpanRange {
+        #[allow(non_snake_case)]
+        fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange;
+    }
+
+    impl<T: ToTokens> ToTokensAsSpanRange for &T {
+        fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange {
+            let mut ts = self.to_token_stream().into_iter();
+            let first = match ts.next() {
+                Some(t) => t.span(),
+                None => Span::call_site(),
+            };
+
+            let last = match ts.last() {
+                Some(t) => t.span(),
+                None => first,
+            };
+
+            SpanRange { first, last }
+        }
+    }
+
+    impl Span2AsSpanRange for Span {
+        fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange {
+            SpanRange {
+                first: *self,
+                last: *self,
+            }
+        }
+    }
+
+    impl SpanAsSpanRange for proc_macro::Span {
+        fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange {
+            SpanRange {
+                first: (*self).into(),
+                last: (*self).into(),
+            }
+        }
+    }
+
+    impl SpanRangeAsSpanRange for SpanRange {
+        fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange {
+            *self
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/macros.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/macros.rs
new file mode 100644
index 0000000..747b684
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/macros.rs
@@ -0,0 +1,288 @@
+// FIXME: this can be greatly simplified via $()?
+// as soon as MRSV hits 1.32
+
+/// Build [`Diagnostic`](struct.Diagnostic.html) instance from provided arguments.
+///
+/// # Syntax
+///
+/// See [the guide](index.html#guide).
+///
+#[macro_export]
+macro_rules! diagnostic {
+    // from alias
+    ($err:expr) => { $crate::Diagnostic::from($err) };
+
+    // span, message, help
+    ($span:expr, $level:expr, $fmt:expr, $($args:expr),+ ; $($rest:tt)+) => {{
+        #[allow(unused_imports)]
+        use $crate::__export::{
+            ToTokensAsSpanRange,
+            Span2AsSpanRange,
+            SpanAsSpanRange,
+            SpanRangeAsSpanRange
+        };
+        use $crate::DiagnosticExt;
+        let span_range = (&$span).FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange();
+
+        let diag = $crate::Diagnostic::spanned_range(
+            span_range,
+            $level,
+            format!($fmt, $($args),*)
+        );
+        $crate::__pme__suggestions!(diag $($rest)*);
+        diag
+    }};
+
+    ($span:expr, $level:expr, $msg:expr ; $($rest:tt)+) => {{
+        #[allow(unused_imports)]
+        use $crate::__export::{
+            ToTokensAsSpanRange,
+            Span2AsSpanRange,
+            SpanAsSpanRange,
+            SpanRangeAsSpanRange
+        };
+        use $crate::DiagnosticExt;
+        let span_range = (&$span).FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange();
+
+        let diag = $crate::Diagnostic::spanned_range(span_range, $level, $msg.to_string());
+        $crate::__pme__suggestions!(diag $($rest)*);
+        diag
+    }};
+
+    // span, message, no help
+    ($span:expr, $level:expr, $fmt:expr, $($args:expr),+) => {{
+        #[allow(unused_imports)]
+        use $crate::__export::{
+            ToTokensAsSpanRange,
+            Span2AsSpanRange,
+            SpanAsSpanRange,
+            SpanRangeAsSpanRange
+        };
+        use $crate::DiagnosticExt;
+        let span_range = (&$span).FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange();
+
+        $crate::Diagnostic::spanned_range(
+            span_range,
+            $level,
+            format!($fmt, $($args),*)
+        )
+    }};
+
+    ($span:expr, $level:expr, $msg:expr) => {{
+        #[allow(unused_imports)]
+        use $crate::__export::{
+            ToTokensAsSpanRange,
+            Span2AsSpanRange,
+            SpanAsSpanRange,
+            SpanRangeAsSpanRange
+        };
+        use $crate::DiagnosticExt;
+        let span_range = (&$span).FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange();
+
+        $crate::Diagnostic::spanned_range(span_range, $level, $msg.to_string())
+    }};
+
+
+    // trailing commas
+
+    ($span:expr, $level:expr, $fmt:expr, $($args:expr),+, ; $($rest:tt)+) => {
+        $crate::diagnostic!($span, $level, $fmt, $($args),* ; $($rest)*)
+    };
+    ($span:expr, $level:expr, $msg:expr, ; $($rest:tt)+) => {
+        $crate::diagnostic!($span, $level, $msg ; $($rest)*)
+    };
+    ($span:expr, $level:expr, $fmt:expr, $($args:expr),+,) => {
+        $crate::diagnostic!($span, $level, $fmt, $($args),*)
+    };
+    ($span:expr, $level:expr, $msg:expr,) => {
+        $crate::diagnostic!($span, $level, $msg)
+    };
+    // ($err:expr,) => { $crate::diagnostic!($err) };
+}
+
+/// Abort proc-macro execution right now and display the error.
+///
+/// # Syntax
+///
+/// See [the guide](index.html#guide).
+#[macro_export]
+macro_rules! abort {
+    ($err:expr) => {
+        $crate::diagnostic!($err).abort()
+    };
+
+    ($span:expr, $($tts:tt)*) => {
+        $crate::diagnostic!($span, $crate::Level::Error, $($tts)*).abort()
+    };
+}
+
+/// Shortcut for `abort!(Span::call_site(), msg...)`. This macro
+/// is still preferable over plain panic, panics are not for error reporting.
+///
+/// # Syntax
+///
+/// See [the guide](index.html#guide).
+///
+#[macro_export]
+macro_rules! abort_call_site {
+    ($($tts:tt)*) => {
+        $crate::abort!($crate::__export::proc_macro2::Span::call_site(), $($tts)*)
+    };
+}
+
+/// Emit an error while not aborting the proc-macro right away.
+///
+/// # Syntax
+///
+/// See [the guide](index.html#guide).
+///
+#[macro_export]
+macro_rules! emit_error {
+    ($err:expr) => {
+        $crate::diagnostic!($err).emit()
+    };
+
+    ($span:expr, $($tts:tt)*) => {{
+        let level = $crate::Level::Error;
+        $crate::diagnostic!($span, level, $($tts)*).emit()
+    }};
+}
+
+/// Shortcut for `emit_error!(Span::call_site(), ...)`. This macro
+/// is still preferable over plain panic, panics are not for error reporting..
+///
+/// # Syntax
+///
+/// See [the guide](index.html#guide).
+///
+#[macro_export]
+macro_rules! emit_call_site_error {
+    ($($tts:tt)*) => {
+        $crate::emit_error!($crate::__export::proc_macro2::Span::call_site(), $($tts)*)
+    };
+}
+
+/// Emit a warning. Warnings are not errors and compilation won't fail because of them.
+///
+/// **Does nothing on stable**
+///
+/// # Syntax
+///
+/// See [the guide](index.html#guide).
+///
+#[macro_export]
+macro_rules! emit_warning {
+    ($span:expr, $($tts:tt)*) => {
+        $crate::diagnostic!($span, $crate::Level::Warning, $($tts)*).emit()
+    };
+}
+
+/// Shortcut for `emit_warning!(Span::call_site(), ...)`.
+///
+/// **Does nothing on stable**
+///
+/// # Syntax
+///
+/// See [the guide](index.html#guide).
+///
+#[macro_export]
+macro_rules! emit_call_site_warning {
+    ($($tts:tt)*) => {{
+        $crate::emit_warning!($crate::__export::proc_macro2::Span::call_site(), $($tts)*)
+    }};
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! __pme__suggestions {
+    ($var:ident) => ();
+
+    ($var:ident $help:ident =? $msg:expr) => {
+        let $var = if let Some(msg) = $msg {
+            $var.suggestion(stringify!($help), msg.to_string())
+        } else {
+            $var
+        };
+    };
+    ($var:ident $help:ident =? $span:expr => $msg:expr) => {
+        let $var = if let Some(msg) = $msg {
+            $var.span_suggestion($span.into(), stringify!($help), msg.to_string())
+        } else {
+            $var
+        };
+    };
+
+    ($var:ident $help:ident =? $msg:expr ; $($rest:tt)*) => {
+        $crate::__pme__suggestions!($var $help =? $msg);
+        $crate::__pme__suggestions!($var $($rest)*);
+    };
+    ($var:ident $help:ident =? $span:expr => $msg:expr ; $($rest:tt)*) => {
+        $crate::__pme__suggestions!($var $help =? $span => $msg);
+        $crate::__pme__suggestions!($var $($rest)*);
+    };
+
+
+    ($var:ident $help:ident = $msg:expr) => {
+        let $var = $var.suggestion(stringify!($help), $msg.to_string());
+    };
+    ($var:ident $help:ident = $fmt:expr, $($args:expr),+) => {
+        let $var = $var.suggestion(
+            stringify!($help),
+            format!($fmt, $($args),*)
+        );
+    };
+    ($var:ident $help:ident = $span:expr => $msg:expr) => {
+        let $var = $var.span_suggestion($span.into(), stringify!($help), $msg.to_string());
+    };
+    ($var:ident $help:ident = $span:expr => $fmt:expr, $($args:expr),+) => {
+        let $var = $var.span_suggestion(
+            $span.into(),
+            stringify!($help),
+            format!($fmt, $($args),*)
+        );
+    };
+
+    ($var:ident $help:ident = $msg:expr ; $($rest:tt)*) => {
+        $crate::__pme__suggestions!($var $help = $msg);
+        $crate::__pme__suggestions!($var $($rest)*);
+    };
+    ($var:ident $help:ident = $fmt:expr, $($args:expr),+ ; $($rest:tt)*) => {
+        $crate::__pme__suggestions!($var $help = $fmt, $($args),*);
+        $crate::__pme__suggestions!($var $($rest)*);
+    };
+    ($var:ident $help:ident = $span:expr => $msg:expr ; $($rest:tt)*) => {
+        $crate::__pme__suggestions!($var $help = $span => $msg);
+        $crate::__pme__suggestions!($var $($rest)*);
+    };
+    ($var:ident $help:ident = $span:expr => $fmt:expr, $($args:expr),+ ; $($rest:tt)*) => {
+        $crate::__pme__suggestions!($var $help = $span => $fmt, $($args),*);
+        $crate::__pme__suggestions!($var $($rest)*);
+    };
+
+    // trailing commas
+
+    ($var:ident $help:ident = $msg:expr,) => {
+        $crate::__pme__suggestions!($var $help = $msg)
+    };
+    ($var:ident $help:ident = $fmt:expr, $($args:expr),+,) => {
+        $crate::__pme__suggestions!($var $help = $fmt, $($args)*)
+    };
+    ($var:ident $help:ident = $span:expr => $msg:expr,) => {
+        $crate::__pme__suggestions!($var $help = $span => $msg)
+    };
+    ($var:ident $help:ident = $span:expr => $fmt:expr, $($args:expr),*,) => {
+        $crate::__pme__suggestions!($var $help = $span => $fmt, $($args)*)
+    };
+    ($var:ident $help:ident = $msg:expr, ; $($rest:tt)*) => {
+        $crate::__pme__suggestions!($var $help = $msg; $($rest)*)
+    };
+    ($var:ident $help:ident = $fmt:expr, $($args:expr),+, ; $($rest:tt)*) => {
+        $crate::__pme__suggestions!($var $help = $fmt, $($args),*; $($rest)*)
+    };
+    ($var:ident $help:ident = $span:expr => $msg:expr, ; $($rest:tt)*) => {
+        $crate::__pme__suggestions!($var $help = $span => $msg; $($rest)*)
+    };
+    ($var:ident $help:ident = $span:expr => $fmt:expr, $($args:expr),+, ; $($rest:tt)*) => {
+        $crate::__pme__suggestions!($var $help = $span => $fmt, $($args),*; $($rest)*)
+    };
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/sealed.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/sealed.rs
new file mode 100644
index 0000000..a2d5081e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/sealed.rs
@@ -0,0 +1,3 @@
+pub trait Sealed {}
+
+impl Sealed for crate::Diagnostic {}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/macro-errors.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/macro-errors.rs
new file mode 100644
index 0000000..bfe1ea3
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/macro-errors.rs
@@ -0,0 +1,6 @@
+#[test]
+#[cfg(run_ui_tests)]
+fn ui() {
+    let t = trybuild::TestCases::new();
+    t.compile_fail("tests/ui/*.rs");
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ok.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ok.rs
new file mode 100644
index 0000000..402edbe9
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ok.rs
@@ -0,0 +1,8 @@
+use test_crate::*;
+
+ok!(it_works);
+
+#[test]
+fn check_it_works() {
+    it_works();
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/runtime-errors.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/runtime-errors.rs
new file mode 100644
index 0000000..bb7e726
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/runtime-errors.rs
@@ -0,0 +1,13 @@
+use proc_macro_error2::*;
+
+#[test]
+#[should_panic = "proc-macro-error2 API cannot be used outside of"]
+fn missing_attr_emit() {
+    emit_call_site_error!("You won't see me");
+}
+
+#[test]
+#[should_panic = "proc-macro-error2 API cannot be used outside of"]
+fn missing_attr_abort() {
+    abort_call_site!("You won't see me");
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/abort.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/abort.rs
new file mode 100644
index 0000000..e998e90
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/abort.rs
@@ -0,0 +1,10 @@
+use test_crate::*;
+
+abort_from!(one, two);
+abort_to_string!(one, two);
+abort_format!(one, two);
+direct_abort!(one, two);
+abort_notes!(one, two);
+abort_call_site_test!(one, two);
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/abort.stderr b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/abort.stderr
new file mode 100644
index 0000000..2a210c5e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/abort.stderr
@@ -0,0 +1,48 @@
+error: abort!(span, from) test
+ --> tests/ui/abort.rs:3:13
+  |
+3 | abort_from!(one, two);
+  |             ^^^
+
+error: abort!(span, single_expr) test
+ --> tests/ui/abort.rs:4:18
+  |
+4 | abort_to_string!(one, two);
+  |                  ^^^
+
+error: abort!(span, expr1, expr2) test
+ --> tests/ui/abort.rs:5:15
+  |
+5 | abort_format!(one, two);
+  |               ^^^
+
+error: Diagnostic::abort() test
+ --> tests/ui/abort.rs:6:15
+  |
+6 | direct_abort!(one, two);
+  |               ^^^
+
+error: This is an error
+
+         = note: simple note
+         = help: simple help
+         = help: simple hint
+         = note: simple yay
+         = note: format note
+         = note: Some note
+         = note: spanned simple note
+         = note: spanned format note
+         = note: Some note
+
+ --> tests/ui/abort.rs:7:14
+  |
+7 | abort_notes!(one, two);
+  |              ^^^
+
+error: abort_call_site! test
+ --> tests/ui/abort.rs:8:1
+  |
+8 | abort_call_site_test!(one, two);
+  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  |
+  = note: this error originates in the macro `abort_call_site_test` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/append_dummy.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/append_dummy.rs
new file mode 100644
index 0000000..8838404
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/append_dummy.rs
@@ -0,0 +1,12 @@
+use test_crate::*;
+
+enum NeedDefault {
+    A,
+    B,
+}
+
+append_dummy!(need_default);
+
+fn main() {
+    let _ = NeedDefault::default();
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/append_dummy.stderr b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/append_dummy.stderr
new file mode 100644
index 0000000..c53708b3
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/append_dummy.stderr
@@ -0,0 +1,5 @@
+error: append_dummy test
+ --> tests/ui/append_dummy.rs:8:15
+  |
+8 | append_dummy!(need_default);
+  |               ^^^^^^^^^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/children_messages.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/children_messages.rs
new file mode 100644
index 0000000..a10ca7c1
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/children_messages.rs
@@ -0,0 +1,5 @@
+use test_crate::*;
+
+children_messages!(one, two, three, four);
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/children_messages.stderr b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/children_messages.stderr
new file mode 100644
index 0000000..092eb05
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/children_messages.stderr
@@ -0,0 +1,23 @@
+error: main macro message
+ --> tests/ui/children_messages.rs:3:20
+  |
+3 | children_messages!(one, two, three, four);
+  |                    ^^^
+
+error: child message
+ --> tests/ui/children_messages.rs:3:25
+  |
+3 | children_messages!(one, two, three, four);
+  |                         ^^^
+
+error: main syn::Error
+ --> tests/ui/children_messages.rs:3:30
+  |
+3 | children_messages!(one, two, three, four);
+  |                              ^^^^^
+
+error: child syn::Error
+ --> tests/ui/children_messages.rs:3:37
+  |
+3 | children_messages!(one, two, three, four);
+  |                                     ^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/dummy.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/dummy.rs
new file mode 100644
index 0000000..ba146a5a
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/dummy.rs
@@ -0,0 +1,12 @@
+use test_crate::*;
+
+enum NeedDefault {
+    A,
+    B,
+}
+
+dummy!(need_default);
+
+fn main() {
+    let _ = NeedDefault::default();
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/dummy.stderr b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/dummy.stderr
new file mode 100644
index 0000000..197d5ca
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/dummy.stderr
@@ -0,0 +1,5 @@
+error: set_dummy test
+ --> tests/ui/dummy.rs:8:8
+  |
+8 | dummy!(need_default);
+  |        ^^^^^^^^^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/emit.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/emit.rs
new file mode 100644
index 0000000..6f1e389c
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/emit.rs
@@ -0,0 +1,6 @@
+use test_crate::*;
+
+emit!(one, two, three, four, five);
+emit_notes!(one, two);
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/emit.stderr b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/emit.stderr
new file mode 100644
index 0000000..02fc95e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/emit.stderr
@@ -0,0 +1,48 @@
+error: emit!(span, from) test
+ --> tests/ui/emit.rs:3:7
+  |
+3 | emit!(one, two, three, four, five);
+  |       ^^^
+
+error: emit!(span, expr1, expr2) test
+ --> tests/ui/emit.rs:3:12
+  |
+3 | emit!(one, two, three, four, five);
+  |            ^^^
+
+error: emit!(span, single_expr) test
+ --> tests/ui/emit.rs:3:17
+  |
+3 | emit!(one, two, three, four, five);
+  |                 ^^^^^
+
+error: Diagnostic::emit() test
+ --> tests/ui/emit.rs:3:24
+  |
+3 | emit!(one, two, three, four, five);
+  |                        ^^^^
+
+error: emit_call_site_error!(expr) test
+ --> tests/ui/emit.rs:3:1
+  |
+3 | emit!(one, two, three, four, five);
+  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  |
+  = note: this error originates in the macro `emit` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: This is an error
+
+         = note: simple note
+         = help: simple help
+         = help: simple hint
+         = note: simple yay
+         = note: format note
+         = note: Some note
+         = note: spanned simple note
+         = note: spanned format note
+         = note: Some note
+
+ --> tests/ui/emit.rs:4:13
+  |
+4 | emit_notes!(one, two);
+  |             ^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/explicit_span_range.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/explicit_span_range.rs
new file mode 100644
index 0000000..7f0ff2459
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/explicit_span_range.rs
@@ -0,0 +1,5 @@
+use test_crate::*;
+
+explicit_span_range!(one, two, three, four);
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/explicit_span_range.stderr b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/explicit_span_range.stderr
new file mode 100644
index 0000000..dd480c62
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/explicit_span_range.stderr
@@ -0,0 +1,5 @@
+error: explicit SpanRange
+ --> tests/ui/explicit_span_range.rs:3:22
+  |
+3 | explicit_span_range!(one, two, three, four);
+  |                      ^^^^^^^^^^^^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/misuse.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/misuse.rs
new file mode 100644
index 0000000..dd86c0f
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/misuse.rs
@@ -0,0 +1,10 @@
+use proc_macro_error2::abort;
+
+struct Foo;
+
+#[allow(unused)]
+fn foo() {
+    abort!(Foo, "BOOM");
+}
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/misuse.stderr b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/misuse.stderr
new file mode 100644
index 0000000..ac17d0f
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/misuse.stderr
@@ -0,0 +1,24 @@
+error[E0599]: the method `FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange` exists for reference `&Foo`, but its trait bounds were not satisfied
+ --> tests/ui/misuse.rs:7:5
+  |
+3 | struct Foo;
+  | ---------- doesn't satisfy `Foo: quote::to_tokens::ToTokens`
+...
+7 |     abort!(Foo, "BOOM");
+  |     ^^^^^^^^^^^^^^^^^^^ method cannot be called on `&Foo` due to unsatisfied trait bounds
+  |
+  = note: the following trait bounds were not satisfied:
+          `Foo: quote::to_tokens::ToTokens`
+          which is required by `&Foo: ToTokensAsSpanRange`
+note: the trait `quote::to_tokens::ToTokens` must be implemented
+ --> $CARGO/quote-1.0.37/src/to_tokens.rs
+  |
+  | pub trait ToTokens {
+  | ^^^^^^^^^^^^^^^^^^
+  = help: items from traits can only be used if the trait is implemented and in scope
+  = note: the following traits define an item `FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange`, perhaps you need to implement one of them:
+          candidate #1: `Span2AsSpanRange`
+          candidate #2: `SpanAsSpanRange`
+          candidate #3: `SpanRangeAsSpanRange`
+          candidate #4: `ToTokensAsSpanRange`
+  = note: this error originates in the macro `$crate::diagnostic` which comes from the expansion of the macro `abort` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/multiple_tokens.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/multiple_tokens.rs
new file mode 100644
index 0000000..50fc2dd8
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/multiple_tokens.rs
@@ -0,0 +1,4 @@
+#[test_crate::multiple_tokens]
+type T = ();
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/multiple_tokens.stderr b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/multiple_tokens.stderr
new file mode 100644
index 0000000..af0cab0
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/multiple_tokens.stderr
@@ -0,0 +1,5 @@
+error: ...
+ --> tests/ui/multiple_tokens.rs:2:1
+  |
+2 | type T = ();
+  | ^^^^^^^^^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/not_proc_macro.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/not_proc_macro.rs
new file mode 100644
index 0000000..03c596b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/not_proc_macro.rs
@@ -0,0 +1,4 @@
+use proc_macro_error2::proc_macro_error;
+
+#[proc_macro_error]
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/not_proc_macro.stderr b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/not_proc_macro.stderr
new file mode 100644
index 0000000..67012aab
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/not_proc_macro.stderr
@@ -0,0 +1,9 @@
+error: #[proc_macro_error] attribute can be used only with procedural macros
+
+         = hint: if you are really sure that #[proc_macro_error] should be applied to this exact function, use #[proc_macro_error(allow_not_macro)]
+ --> tests/ui/not_proc_macro.rs:3:1
+  |
+3 | #[proc_macro_error]
+  | ^^^^^^^^^^^^^^^^^^^
+  |
+  = note: this error originates in the attribute macro `proc_macro_error` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/option_ext.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/option_ext.rs
new file mode 100644
index 0000000..19a650db
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/option_ext.rs
@@ -0,0 +1,5 @@
+use test_crate::*;
+
+option_ext!(one, two);
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/option_ext.stderr b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/option_ext.stderr
new file mode 100644
index 0000000..49bb22d
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/option_ext.stderr
@@ -0,0 +1,7 @@
+error: Option::expect_or_abort() test
+ --> tests/ui/option_ext.rs:3:1
+  |
+3 | option_ext!(one, two);
+  | ^^^^^^^^^^^^^^^^^^^^^
+  |
+  = note: this error originates in the macro `option_ext` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/result_ext.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/result_ext.rs
new file mode 100644
index 0000000..b5a7951
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/result_ext.rs
@@ -0,0 +1,6 @@
+use test_crate::*;
+
+result_unwrap_or_abort!(one, two);
+result_expect_or_abort!(one, two);
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/result_ext.stderr b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/result_ext.stderr
new file mode 100644
index 0000000..f9321f9
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/result_ext.stderr
@@ -0,0 +1,11 @@
+error: Result::unwrap_or_abort() test
+ --> tests/ui/result_ext.rs:3:25
+  |
+3 | result_unwrap_or_abort!(one, two);
+  |                         ^^^
+
+error: BOOM: Result::expect_or_abort() test
+ --> tests/ui/result_ext.rs:4:25
+  |
+4 | result_expect_or_abort!(one, two);
+  |                         ^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/to_tokens_span.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/to_tokens_span.rs
new file mode 100644
index 0000000..942e94a
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/to_tokens_span.rs
@@ -0,0 +1,5 @@
+use test_crate::*;
+
+to_tokens_span!(std::option::Option);
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/to_tokens_span.stderr b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/to_tokens_span.stderr
new file mode 100644
index 0000000..bb3b543
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/to_tokens_span.stderr
@@ -0,0 +1,11 @@
+error: whole type
+ --> tests/ui/to_tokens_span.rs:3:17
+  |
+3 | to_tokens_span!(std::option::Option);
+  |                 ^^^^^^^^^^^^^^^^^^^
+
+error: explicit .span()
+ --> tests/ui/to_tokens_span.rs:3:17
+  |
+3 | to_tokens_span!(std::option::Option);
+  |                 ^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/unknown_setting.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/unknown_setting.rs
new file mode 100644
index 0000000..5e54a89
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/unknown_setting.rs
@@ -0,0 +1,4 @@
+use proc_macro_error2::proc_macro_error;
+
+#[proc_macro_error(allow_not_macro, assert_unwind_safe, trololo)]
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/unknown_setting.stderr b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/unknown_setting.stderr
new file mode 100644
index 0000000..eb349cc8
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/unknown_setting.stderr
@@ -0,0 +1,5 @@
+error: unknown setting `trololo`, expected one of `assert_unwind_safe`, `allow_not_macro`, `proc_macro_hack`
+ --> tests/ui/unknown_setting.rs:3:57
+  |
+3 | #[proc_macro_error(allow_not_macro, assert_unwind_safe, trololo)]
+  |                                                         ^^^^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/unrelated_panic.rs b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/unrelated_panic.rs
new file mode 100644
index 0000000..9d450ff
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/unrelated_panic.rs
@@ -0,0 +1,5 @@
+use test_crate::*;
+
+unrelated_panic!();
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/unrelated_panic.stderr b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/unrelated_panic.stderr
new file mode 100644
index 0000000..a1dec9c
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/tests/ui/unrelated_panic.stderr
@@ -0,0 +1,7 @@
+error: proc macro panicked
+ --> tests/ui/unrelated_panic.rs:3:1
+  |
+3 | unrelated_panic!();
+  | ^^^^^^^^^^^^^^^^^^
+  |
+  = help: message: unrelated panic test
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/.cargo-checksum.json b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/.cargo-checksum.json
new file mode 100644
index 0000000..697c9ce
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{}}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/.cargo_vcs_info.json
new file mode 100644
index 0000000..9d0927c
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+  "git": {
+    "sha1": "72ae716e6d6a7f7fdabdc394018c745b4d39ca45"
+  },
+  "path_in_vcs": "impl"
+}
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/Cargo.lock b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/Cargo.lock
new file mode 100644
index 0000000..0c38d39b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/Cargo.lock
@@ -0,0 +1,47 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.101"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.17"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/Cargo.toml
new file mode 100644
index 0000000..32d3ef8
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/Cargo.toml
@@ -0,0 +1,52 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2021"
+rust-version = "1.61"
+name = "thiserror-impl"
+version = "2.0.17"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+build = false
+autolib = false
+autobins = false
+autoexamples = false
+autotests = false
+autobenches = false
+description = "Implementation detail of the `thiserror` crate"
+readme = false
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/dtolnay/thiserror"
+
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
+rustdoc-args = [
+    "--generate-link-to-definition",
+    "--generate-macro-expansion",
+    "--extern-html-root-url=core=https://doc.rust-lang.org",
+    "--extern-html-root-url=alloc=https://doc.rust-lang.org",
+    "--extern-html-root-url=std=https://doc.rust-lang.org",
+    "--extern-html-root-url=proc_macro=https://doc.rust-lang.org",
+]
+
+[lib]
+name = "thiserror_impl"
+path = "src/lib.rs"
+proc-macro = true
+
+[dependencies.proc-macro2]
+version = "1.0.74"
+
+[dependencies.quote]
+version = "1.0.35"
+
+[dependencies.syn]
+version = "2.0.87"
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/Cargo.toml.orig
new file mode 100644
index 0000000..0e95d32
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/Cargo.toml.orig
@@ -0,0 +1,28 @@
+[package]
+name = "thiserror-impl"
+version = "2.0.17"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+description = "Implementation detail of the `thiserror` crate"
+edition = "2021"
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/dtolnay/thiserror"
+rust-version = "1.61"
+
+[lib]
+proc-macro = true
+
+[dependencies]
+proc-macro2 = "1.0.74"
+quote = "1.0.35"
+syn = "2.0.87"
+
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
+rustdoc-args = [
+    "--generate-link-to-definition",
+    "--generate-macro-expansion",
+    "--extern-html-root-url=core=https://doc.rust-lang.org",
+    "--extern-html-root-url=alloc=https://doc.rust-lang.org",
+    "--extern-html-root-url=std=https://doc.rust-lang.org",
+    "--extern-html-root-url=proc_macro=https://doc.rust-lang.org",
+]
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/LICENSE-APACHE b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/LICENSE-APACHE
new file mode 100644
index 0000000..1b5ec8b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/LICENSE-APACHE
@@ -0,0 +1,176 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/LICENSE-MIT b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/LICENSE-MIT
new file mode 100644
index 0000000..31aa7938
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/LICENSE-MIT
@@ -0,0 +1,23 @@
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/ast.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/ast.rs
new file mode 100644
index 0000000..77f9583
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/ast.rs
@@ -0,0 +1,185 @@
+use crate::attr::{self, Attrs};
+use crate::generics::ParamsInScope;
+use crate::unraw::{IdentUnraw, MemberUnraw};
+use proc_macro2::Span;
+use std::fmt::{self, Display};
+use syn::{
+    Data, DataEnum, DataStruct, DeriveInput, Error, Fields, Generics, Ident, Index, Result, Type,
+};
+
+pub enum Input<'a> {
+    Struct(Struct<'a>),
+    Enum(Enum<'a>),
+}
+
+pub struct Struct<'a> {
+    pub attrs: Attrs<'a>,
+    pub ident: Ident,
+    pub generics: &'a Generics,
+    pub fields: Vec<Field<'a>>,
+}
+
+pub struct Enum<'a> {
+    pub attrs: Attrs<'a>,
+    pub ident: Ident,
+    pub generics: &'a Generics,
+    pub variants: Vec<Variant<'a>>,
+}
+
+pub struct Variant<'a> {
+    pub original: &'a syn::Variant,
+    pub attrs: Attrs<'a>,
+    pub ident: Ident,
+    pub fields: Vec<Field<'a>>,
+}
+
+pub struct Field<'a> {
+    pub original: &'a syn::Field,
+    pub attrs: Attrs<'a>,
+    pub member: MemberUnraw,
+    pub ty: &'a Type,
+    pub contains_generic: bool,
+}
+
+#[derive(Copy, Clone)]
+pub enum ContainerKind {
+    Struct,
+    TupleStruct,
+    UnitStruct,
+    StructVariant,
+    TupleVariant,
+    UnitVariant,
+}
+
+impl<'a> Input<'a> {
+    pub fn from_syn(node: &'a DeriveInput) -> Result<Self> {
+        match &node.data {
+            Data::Struct(data) => Struct::from_syn(node, data).map(Input::Struct),
+            Data::Enum(data) => Enum::from_syn(node, data).map(Input::Enum),
+            Data::Union(_) => Err(Error::new_spanned(
+                node,
+                "union as errors are not supported",
+            )),
+        }
+    }
+}
+
+impl<'a> Struct<'a> {
+    fn from_syn(node: &'a DeriveInput, data: &'a DataStruct) -> Result<Self> {
+        let mut attrs = attr::get(&node.attrs)?;
+        let scope = ParamsInScope::new(&node.generics);
+        let fields = Field::multiple_from_syn(&data.fields, &scope)?;
+        if let Some(display) = &mut attrs.display {
+            let container = ContainerKind::from_struct(data);
+            display.expand_shorthand(&fields, container)?;
+        }
+        Ok(Struct {
+            attrs,
+            ident: node.ident.clone(),
+            generics: &node.generics,
+            fields,
+        })
+    }
+}
+
+impl<'a> Enum<'a> {
+    fn from_syn(node: &'a DeriveInput, data: &'a DataEnum) -> Result<Self> {
+        let attrs = attr::get(&node.attrs)?;
+        let scope = ParamsInScope::new(&node.generics);
+        let variants = data
+            .variants
+            .iter()
+            .map(|node| {
+                let mut variant = Variant::from_syn(node, &scope)?;
+                if variant.attrs.display.is_none()
+                    && variant.attrs.transparent.is_none()
+                    && variant.attrs.fmt.is_none()
+                {
+                    variant.attrs.display.clone_from(&attrs.display);
+                    variant.attrs.transparent = attrs.transparent;
+                    variant.attrs.fmt.clone_from(&attrs.fmt);
+                }
+                if let Some(display) = &mut variant.attrs.display {
+                    let container = ContainerKind::from_variant(node);
+                    display.expand_shorthand(&variant.fields, container)?;
+                }
+                Ok(variant)
+            })
+            .collect::<Result<_>>()?;
+        Ok(Enum {
+            attrs,
+            ident: node.ident.clone(),
+            generics: &node.generics,
+            variants,
+        })
+    }
+}
+
+impl<'a> Variant<'a> {
+    fn from_syn(node: &'a syn::Variant, scope: &ParamsInScope<'a>) -> Result<Self> {
+        let attrs = attr::get(&node.attrs)?;
+        Ok(Variant {
+            original: node,
+            attrs,
+            ident: node.ident.clone(),
+            fields: Field::multiple_from_syn(&node.fields, scope)?,
+        })
+    }
+}
+
+impl<'a> Field<'a> {
+    fn multiple_from_syn(fields: &'a Fields, scope: &ParamsInScope<'a>) -> Result<Vec<Self>> {
+        fields
+            .iter()
+            .enumerate()
+            .map(|(i, field)| Field::from_syn(i, field, scope))
+            .collect()
+    }
+
+    fn from_syn(i: usize, node: &'a syn::Field, scope: &ParamsInScope<'a>) -> Result<Self> {
+        Ok(Field {
+            original: node,
+            attrs: attr::get(&node.attrs)?,
+            member: match &node.ident {
+                Some(name) => MemberUnraw::Named(IdentUnraw::new(name.clone())),
+                None => MemberUnraw::Unnamed(Index {
+                    index: i as u32,
+                    span: Span::call_site(),
+                }),
+            },
+            ty: &node.ty,
+            contains_generic: scope.intersects(&node.ty),
+        })
+    }
+}
+
+impl ContainerKind {
+    fn from_struct(node: &DataStruct) -> Self {
+        match node.fields {
+            Fields::Named(_) => ContainerKind::Struct,
+            Fields::Unnamed(_) => ContainerKind::TupleStruct,
+            Fields::Unit => ContainerKind::UnitStruct,
+        }
+    }
+
+    fn from_variant(node: &syn::Variant) -> Self {
+        match node.fields {
+            Fields::Named(_) => ContainerKind::StructVariant,
+            Fields::Unnamed(_) => ContainerKind::TupleVariant,
+            Fields::Unit => ContainerKind::UnitVariant,
+        }
+    }
+}
+
+impl Display for ContainerKind {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        formatter.write_str(match self {
+            ContainerKind::Struct => "struct",
+            ContainerKind::TupleStruct => "tuple struct",
+            ContainerKind::UnitStruct => "unit struct",
+            ContainerKind::StructVariant => "struct variant",
+            ContainerKind::TupleVariant => "tuple variant",
+            ContainerKind::UnitVariant => "unit variant",
+        })
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/attr.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/attr.rs
new file mode 100644
index 0000000..7ad83e0
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/attr.rs
@@ -0,0 +1,358 @@
+use proc_macro2::{Delimiter, Group, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
+use quote::{format_ident, quote, quote_spanned, ToTokens};
+use std::collections::BTreeSet as Set;
+use syn::parse::discouraged::Speculative;
+use syn::parse::{End, ParseStream};
+use syn::{
+    braced, bracketed, parenthesized, token, Attribute, Error, ExprPath, Ident, Index, LitFloat,
+    LitInt, LitStr, Meta, Result, Token,
+};
+
+pub struct Attrs<'a> {
+    pub display: Option<Display<'a>>,
+    pub source: Option<Source<'a>>,
+    pub backtrace: Option<&'a Attribute>,
+    pub from: Option<From<'a>>,
+    pub transparent: Option<Transparent<'a>>,
+    pub fmt: Option<Fmt<'a>>,
+}
+
+#[derive(Clone)]
+pub struct Display<'a> {
+    pub original: &'a Attribute,
+    pub fmt: LitStr,
+    pub args: TokenStream,
+    pub requires_fmt_machinery: bool,
+    pub has_bonus_display: bool,
+    pub infinite_recursive: bool,
+    pub implied_bounds: Set<(usize, Trait)>,
+    pub bindings: Vec<(Ident, TokenStream)>,
+}
+
+#[derive(Copy, Clone)]
+pub struct Source<'a> {
+    pub original: &'a Attribute,
+    pub span: Span,
+}
+
+#[derive(Copy, Clone)]
+pub struct From<'a> {
+    pub original: &'a Attribute,
+    pub span: Span,
+}
+
+#[derive(Copy, Clone)]
+pub struct Transparent<'a> {
+    pub original: &'a Attribute,
+    pub span: Span,
+}
+
+#[derive(Clone)]
+pub struct Fmt<'a> {
+    pub original: &'a Attribute,
+    pub path: ExprPath,
+}
+
+#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
+pub enum Trait {
+    Debug,
+    Display,
+    Octal,
+    LowerHex,
+    UpperHex,
+    Pointer,
+    Binary,
+    LowerExp,
+    UpperExp,
+}
+
+pub fn get(input: &[Attribute]) -> Result<Attrs> {
+    let mut attrs = Attrs {
+        display: None,
+        source: None,
+        backtrace: None,
+        from: None,
+        transparent: None,
+        fmt: None,
+    };
+
+    for attr in input {
+        if attr.path().is_ident("error") {
+            parse_error_attribute(&mut attrs, attr)?;
+        } else if attr.path().is_ident("source") {
+            attr.meta.require_path_only()?;
+            if attrs.source.is_some() {
+                return Err(Error::new_spanned(attr, "duplicate #[source] attribute"));
+            }
+            let span = (attr.pound_token.span)
+                .join(attr.bracket_token.span.join())
+                .unwrap_or(attr.path().get_ident().unwrap().span());
+            attrs.source = Some(Source {
+                original: attr,
+                span,
+            });
+        } else if attr.path().is_ident("backtrace") {
+            attr.meta.require_path_only()?;
+            if attrs.backtrace.is_some() {
+                return Err(Error::new_spanned(attr, "duplicate #[backtrace] attribute"));
+            }
+            attrs.backtrace = Some(attr);
+        } else if attr.path().is_ident("from") {
+            match attr.meta {
+                Meta::Path(_) => {}
+                Meta::List(_) | Meta::NameValue(_) => {
+                    // Assume this is meant for derive_more crate or something.
+                    continue;
+                }
+            }
+            if attrs.from.is_some() {
+                return Err(Error::new_spanned(attr, "duplicate #[from] attribute"));
+            }
+            let span = (attr.pound_token.span)
+                .join(attr.bracket_token.span.join())
+                .unwrap_or(attr.path().get_ident().unwrap().span());
+            attrs.from = Some(From {
+                original: attr,
+                span,
+            });
+        }
+    }
+
+    Ok(attrs)
+}
+
+fn parse_error_attribute<'a>(attrs: &mut Attrs<'a>, attr: &'a Attribute) -> Result<()> {
+    mod kw {
+        syn::custom_keyword!(transparent);
+        syn::custom_keyword!(fmt);
+    }
+
+    attr.parse_args_with(|input: ParseStream| {
+        let lookahead = input.lookahead1();
+        let fmt = if lookahead.peek(LitStr) {
+            input.parse::<LitStr>()?
+        } else if lookahead.peek(kw::transparent) {
+            let kw: kw::transparent = input.parse()?;
+            if attrs.transparent.is_some() {
+                return Err(Error::new_spanned(
+                    attr,
+                    "duplicate #[error(transparent)] attribute",
+                ));
+            }
+            attrs.transparent = Some(Transparent {
+                original: attr,
+                span: kw.span,
+            });
+            return Ok(());
+        } else if lookahead.peek(kw::fmt) {
+            input.parse::<kw::fmt>()?;
+            input.parse::<Token![=]>()?;
+            let path: ExprPath = input.parse()?;
+            if attrs.fmt.is_some() {
+                return Err(Error::new_spanned(
+                    attr,
+                    "duplicate #[error(fmt = ...)] attribute",
+                ));
+            }
+            attrs.fmt = Some(Fmt {
+                original: attr,
+                path,
+            });
+            return Ok(());
+        } else {
+            return Err(lookahead.error());
+        };
+
+        let args = if input.is_empty() || input.peek(Token![,]) && input.peek2(End) {
+            input.parse::<Option<Token![,]>>()?;
+            TokenStream::new()
+        } else {
+            parse_token_expr(input, false)?
+        };
+
+        let requires_fmt_machinery = !args.is_empty();
+
+        let display = Display {
+            original: attr,
+            fmt,
+            args,
+            requires_fmt_machinery,
+            has_bonus_display: false,
+            infinite_recursive: false,
+            implied_bounds: Set::new(),
+            bindings: Vec::new(),
+        };
+        if attrs.display.is_some() {
+            return Err(Error::new_spanned(
+                attr,
+                "only one #[error(...)] attribute is allowed",
+            ));
+        }
+        attrs.display = Some(display);
+        Ok(())
+    })
+}
+
+fn parse_token_expr(input: ParseStream, mut begin_expr: bool) -> Result<TokenStream> {
+    let mut tokens = Vec::new();
+    while !input.is_empty() {
+        if input.peek(token::Group) {
+            let group: TokenTree = input.parse()?;
+            tokens.push(group);
+            begin_expr = false;
+            continue;
+        }
+
+        if begin_expr && input.peek(Token![.]) {
+            if input.peek2(Ident) {
+                input.parse::<Token![.]>()?;
+                begin_expr = false;
+                continue;
+            } else if input.peek2(LitInt) {
+                input.parse::<Token![.]>()?;
+                let int: Index = input.parse()?;
+                tokens.push({
+                    let ident = format_ident!("_{}", int.index, span = int.span);
+                    TokenTree::Ident(ident)
+                });
+                begin_expr = false;
+                continue;
+            } else if input.peek2(LitFloat) {
+                let ahead = input.fork();
+                ahead.parse::<Token![.]>()?;
+                let float: LitFloat = ahead.parse()?;
+                let repr = float.to_string();
+                let mut indices = repr.split('.').map(syn::parse_str::<Index>);
+                if let (Some(Ok(first)), Some(Ok(second)), None) =
+                    (indices.next(), indices.next(), indices.next())
+                {
+                    input.advance_to(&ahead);
+                    tokens.push({
+                        let ident = format_ident!("_{}", first, span = float.span());
+                        TokenTree::Ident(ident)
+                    });
+                    tokens.push({
+                        let mut punct = Punct::new('.', Spacing::Alone);
+                        punct.set_span(float.span());
+                        TokenTree::Punct(punct)
+                    });
+                    tokens.push({
+                        let mut literal = Literal::u32_unsuffixed(second.index);
+                        literal.set_span(float.span());
+                        TokenTree::Literal(literal)
+                    });
+                    begin_expr = false;
+                    continue;
+                }
+            }
+        }
+
+        begin_expr = input.peek(Token![break])
+            || input.peek(Token![continue])
+            || input.peek(Token![if])
+            || input.peek(Token![in])
+            || input.peek(Token![match])
+            || input.peek(Token![mut])
+            || input.peek(Token![return])
+            || input.peek(Token![while])
+            || input.peek(Token![+])
+            || input.peek(Token![&])
+            || input.peek(Token![!])
+            || input.peek(Token![^])
+            || input.peek(Token![,])
+            || input.peek(Token![/])
+            || input.peek(Token![=])
+            || input.peek(Token![>])
+            || input.peek(Token![<])
+            || input.peek(Token![|])
+            || input.peek(Token![%])
+            || input.peek(Token![;])
+            || input.peek(Token![*])
+            || input.peek(Token![-]);
+
+        let token: TokenTree = if input.peek(token::Paren) {
+            let content;
+            let delimiter = parenthesized!(content in input);
+            let nested = parse_token_expr(&content, true)?;
+            let mut group = Group::new(Delimiter::Parenthesis, nested);
+            group.set_span(delimiter.span.join());
+            TokenTree::Group(group)
+        } else if input.peek(token::Brace) {
+            let content;
+            let delimiter = braced!(content in input);
+            let nested = parse_token_expr(&content, true)?;
+            let mut group = Group::new(Delimiter::Brace, nested);
+            group.set_span(delimiter.span.join());
+            TokenTree::Group(group)
+        } else if input.peek(token::Bracket) {
+            let content;
+            let delimiter = bracketed!(content in input);
+            let nested = parse_token_expr(&content, true)?;
+            let mut group = Group::new(Delimiter::Bracket, nested);
+            group.set_span(delimiter.span.join());
+            TokenTree::Group(group)
+        } else {
+            input.parse()?
+        };
+        tokens.push(token);
+    }
+    Ok(TokenStream::from_iter(tokens))
+}
+
+impl ToTokens for Display<'_> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        if self.infinite_recursive {
+            let span = self.fmt.span();
+            tokens.extend(quote_spanned! {span=>
+                #[warn(unconditional_recursion)]
+                fn _fmt() { _fmt() }
+            });
+        }
+
+        let fmt = &self.fmt;
+        let args = &self.args;
+
+        // Currently `write!(f, "text")` produces less efficient code than
+        // `f.write_str("text")`. We recognize the case when the format string
+        // has no braces and no interpolated values, and generate simpler code.
+        let write = if self.requires_fmt_machinery {
+            quote! {
+                ::core::write!(__formatter, #fmt #args)
+            }
+        } else {
+            quote! {
+                __formatter.write_str(#fmt)
+            }
+        };
+
+        tokens.extend(if self.bindings.is_empty() {
+            write
+        } else {
+            let locals = self.bindings.iter().map(|(local, _value)| local);
+            let values = self.bindings.iter().map(|(_local, value)| value);
+            quote! {
+                match (#(#values,)*) {
+                    (#(#locals,)*) => #write
+                }
+            }
+        });
+    }
+}
+
+impl ToTokens for Trait {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        let trait_name = match self {
+            Trait::Debug => "Debug",
+            Trait::Display => "Display",
+            Trait::Octal => "Octal",
+            Trait::LowerHex => "LowerHex",
+            Trait::UpperHex => "UpperHex",
+            Trait::Pointer => "Pointer",
+            Trait::Binary => "Binary",
+            Trait::LowerExp => "LowerExp",
+            Trait::UpperExp => "UpperExp",
+        };
+        let ident = Ident::new(trait_name, Span::call_site());
+        tokens.extend(quote!(::core::fmt::#ident));
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/expand.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/expand.rs
new file mode 100644
index 0000000..97466dd
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/expand.rs
@@ -0,0 +1,584 @@
+use crate::ast::{Enum, Field, Input, Struct};
+use crate::attr::Trait;
+use crate::fallback;
+use crate::generics::InferredBounds;
+use crate::private;
+use crate::unraw::MemberUnraw;
+use proc_macro2::{Ident, Span, TokenStream};
+use quote::{format_ident, quote, quote_spanned, ToTokens};
+use std::collections::BTreeSet as Set;
+use syn::{DeriveInput, GenericArgument, PathArguments, Result, Token, Type};
+
+pub fn derive(input: &DeriveInput) -> TokenStream {
+    match try_expand(input) {
+        Ok(expanded) => expanded,
+        // If there are invalid attributes in the input, expand to an Error impl
+        // anyway to minimize spurious secondary errors in other code that uses
+        // this type as an Error.
+        Err(error) => fallback::expand(input, error),
+    }
+}
+
+fn try_expand(input: &DeriveInput) -> Result<TokenStream> {
+    let input = Input::from_syn(input)?;
+    input.validate()?;
+    Ok(match input {
+        Input::Struct(input) => impl_struct(input),
+        Input::Enum(input) => impl_enum(input),
+    })
+}
+
+fn impl_struct(input: Struct) -> TokenStream {
+    let ty = call_site_ident(&input.ident);
+    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
+    let mut error_inferred_bounds = InferredBounds::new();
+
+    let source_body = if let Some(transparent_attr) = &input.attrs.transparent {
+        let only_field = &input.fields[0];
+        if only_field.contains_generic {
+            error_inferred_bounds.insert(only_field.ty, quote!(::thiserror::#private::Error));
+        }
+        let member = &only_field.member;
+        Some(quote_spanned! {transparent_attr.span=>
+            ::thiserror::#private::Error::source(self.#member.as_dyn_error())
+        })
+    } else if let Some(source_field) = input.source_field() {
+        let source = &source_field.member;
+        if source_field.contains_generic {
+            let ty = unoptional_type(source_field.ty);
+            error_inferred_bounds.insert(ty, quote!(::thiserror::#private::Error + 'static));
+        }
+        let asref = if type_is_option(source_field.ty) {
+            Some(quote_spanned!(source.span()=> .as_ref()?))
+        } else {
+            None
+        };
+        let dyn_error = quote_spanned! {source_field.source_span()=>
+            self.#source #asref.as_dyn_error()
+        };
+        Some(quote! {
+            ::core::option::Option::Some(#dyn_error)
+        })
+    } else {
+        None
+    };
+    let source_method = source_body.map(|body| {
+        quote! {
+            fn source(&self) -> ::core::option::Option<&(dyn ::thiserror::#private::Error + 'static)> {
+                use ::thiserror::#private::AsDynError as _;
+                #body
+            }
+        }
+    });
+
+    let provide_method = input.backtrace_field().map(|backtrace_field| {
+        let request = quote!(request);
+        let backtrace = &backtrace_field.member;
+        let body = if let Some(source_field) = input.source_field() {
+            let source = &source_field.member;
+            let source_provide = if type_is_option(source_field.ty) {
+                quote_spanned! {source.span()=>
+                    if let ::core::option::Option::Some(source) = &self.#source {
+                        source.thiserror_provide(#request);
+                    }
+                }
+            } else {
+                quote_spanned! {source.span()=>
+                    self.#source.thiserror_provide(#request);
+                }
+            };
+            let self_provide = if source == backtrace {
+                None
+            } else if type_is_option(backtrace_field.ty) {
+                Some(quote! {
+                    if let ::core::option::Option::Some(backtrace) = &self.#backtrace {
+                        #request.provide_ref::<::thiserror::#private::Backtrace>(backtrace);
+                    }
+                })
+            } else {
+                Some(quote! {
+                    #request.provide_ref::<::thiserror::#private::Backtrace>(&self.#backtrace);
+                })
+            };
+            quote! {
+                use ::thiserror::#private::ThiserrorProvide as _;
+                #source_provide
+                #self_provide
+            }
+        } else if type_is_option(backtrace_field.ty) {
+            quote! {
+                if let ::core::option::Option::Some(backtrace) = &self.#backtrace {
+                    #request.provide_ref::<::thiserror::#private::Backtrace>(backtrace);
+                }
+            }
+        } else {
+            quote! {
+                #request.provide_ref::<::thiserror::#private::Backtrace>(&self.#backtrace);
+            }
+        };
+        quote! {
+            fn provide<'_request>(&'_request self, #request: &mut ::core::error::Request<'_request>) {
+                #body
+            }
+        }
+    });
+
+    let mut display_implied_bounds = Set::new();
+    let display_body = if input.attrs.transparent.is_some() {
+        let only_field = &input.fields[0].member;
+        display_implied_bounds.insert((0, Trait::Display));
+        Some(quote! {
+            ::core::fmt::Display::fmt(&self.#only_field, __formatter)
+        })
+    } else if let Some(display) = &input.attrs.display {
+        display_implied_bounds.clone_from(&display.implied_bounds);
+        let use_as_display = use_as_display(display.has_bonus_display);
+        let pat = fields_pat(&input.fields);
+        Some(quote! {
+            #use_as_display
+            #[allow(unused_variables, deprecated)]
+            let Self #pat = self;
+            #display
+        })
+    } else {
+        None
+    };
+    let display_impl = display_body.map(|body| {
+        let mut display_inferred_bounds = InferredBounds::new();
+        for (field, bound) in display_implied_bounds {
+            let field = &input.fields[field];
+            if field.contains_generic {
+                display_inferred_bounds.insert(field.ty, bound);
+            }
+        }
+        let display_where_clause = display_inferred_bounds.augment_where_clause(input.generics);
+        quote! {
+            #[allow(unused_qualifications)]
+            #[automatically_derived]
+            impl #impl_generics ::core::fmt::Display for #ty #ty_generics #display_where_clause {
+                #[allow(clippy::used_underscore_binding)]
+                fn fmt(&self, __formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+                    #body
+                }
+            }
+        }
+    });
+
+    let from_impl = input.from_field().map(|from_field| {
+        let span = from_field.attrs.from.unwrap().span;
+        let backtrace_field = input.distinct_backtrace_field();
+        let from = unoptional_type(from_field.ty);
+        let source_var = Ident::new("source", span);
+        let body = from_initializer(from_field, backtrace_field, &source_var);
+        let from_function = quote! {
+            fn from(#source_var: #from) -> Self {
+                #ty #body
+            }
+        };
+        let from_impl = quote_spanned! {span=>
+            #[automatically_derived]
+            impl #impl_generics ::core::convert::From<#from> for #ty #ty_generics #where_clause {
+                #from_function
+            }
+        };
+        Some(quote! {
+            #[allow(
+                deprecated,
+                unused_qualifications,
+                clippy::elidable_lifetime_names,
+                clippy::needless_lifetimes,
+            )]
+            #from_impl
+        })
+    });
+
+    if input.generics.type_params().next().is_some() {
+        let self_token = <Token![Self]>::default();
+        error_inferred_bounds.insert(self_token, Trait::Debug);
+        error_inferred_bounds.insert(self_token, Trait::Display);
+    }
+    let error_where_clause = error_inferred_bounds.augment_where_clause(input.generics);
+
+    quote! {
+        #[allow(unused_qualifications)]
+        #[automatically_derived]
+        impl #impl_generics ::thiserror::#private::Error for #ty #ty_generics #error_where_clause {
+            #source_method
+            #provide_method
+        }
+        #display_impl
+        #from_impl
+    }
+}
+
+fn impl_enum(input: Enum) -> TokenStream {
+    let ty = call_site_ident(&input.ident);
+    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
+    let mut error_inferred_bounds = InferredBounds::new();
+
+    let source_method = if input.has_source() {
+        let arms = input.variants.iter().map(|variant| {
+            let ident = &variant.ident;
+            if let Some(transparent_attr) = &variant.attrs.transparent {
+                let only_field = &variant.fields[0];
+                if only_field.contains_generic {
+                    error_inferred_bounds.insert(only_field.ty, quote!(::thiserror::#private::Error));
+                }
+                let member = &only_field.member;
+                let source = quote_spanned! {transparent_attr.span=>
+                    ::thiserror::#private::Error::source(transparent.as_dyn_error())
+                };
+                quote! {
+                    #ty::#ident {#member: transparent} => #source,
+                }
+            } else if let Some(source_field) = variant.source_field() {
+                let source = &source_field.member;
+                if source_field.contains_generic {
+                    let ty = unoptional_type(source_field.ty);
+                    error_inferred_bounds.insert(ty, quote!(::thiserror::#private::Error + 'static));
+                }
+                let asref = if type_is_option(source_field.ty) {
+                    Some(quote_spanned!(source.span()=> .as_ref()?))
+                } else {
+                    None
+                };
+                let varsource = quote!(source);
+                let dyn_error = quote_spanned! {source_field.source_span()=>
+                    #varsource #asref.as_dyn_error()
+                };
+                quote! {
+                    #ty::#ident {#source: #varsource, ..} => ::core::option::Option::Some(#dyn_error),
+                }
+            } else {
+                quote! {
+                    #ty::#ident {..} => ::core::option::Option::None,
+                }
+            }
+        });
+        Some(quote! {
+            fn source(&self) -> ::core::option::Option<&(dyn ::thiserror::#private::Error + 'static)> {
+                use ::thiserror::#private::AsDynError as _;
+                #[allow(deprecated)]
+                match self {
+                    #(#arms)*
+                }
+            }
+        })
+    } else {
+        None
+    };
+
+    let provide_method = if input.has_backtrace() {
+        let request = quote!(request);
+        let arms = input.variants.iter().map(|variant| {
+            let ident = &variant.ident;
+            match (variant.backtrace_field(), variant.source_field()) {
+                (Some(backtrace_field), Some(source_field))
+                    if backtrace_field.attrs.backtrace.is_none() =>
+                {
+                    let backtrace = &backtrace_field.member;
+                    let source = &source_field.member;
+                    let varsource = quote!(source);
+                    let source_provide = if type_is_option(source_field.ty) {
+                        quote_spanned! {source.span()=>
+                            if let ::core::option::Option::Some(source) = #varsource {
+                                source.thiserror_provide(#request);
+                            }
+                        }
+                    } else {
+                        quote_spanned! {source.span()=>
+                            #varsource.thiserror_provide(#request);
+                        }
+                    };
+                    let self_provide = if type_is_option(backtrace_field.ty) {
+                        quote! {
+                            if let ::core::option::Option::Some(backtrace) = backtrace {
+                                #request.provide_ref::<::thiserror::#private::Backtrace>(backtrace);
+                            }
+                        }
+                    } else {
+                        quote! {
+                            #request.provide_ref::<::thiserror::#private::Backtrace>(backtrace);
+                        }
+                    };
+                    quote! {
+                        #ty::#ident {
+                            #backtrace: backtrace,
+                            #source: #varsource,
+                            ..
+                        } => {
+                            use ::thiserror::#private::ThiserrorProvide as _;
+                            #source_provide
+                            #self_provide
+                        }
+                    }
+                }
+                (Some(backtrace_field), Some(source_field))
+                    if backtrace_field.member == source_field.member =>
+                {
+                    let backtrace = &backtrace_field.member;
+                    let varsource = quote!(source);
+                    let source_provide = if type_is_option(source_field.ty) {
+                        quote_spanned! {backtrace.span()=>
+                            if let ::core::option::Option::Some(source) = #varsource {
+                                source.thiserror_provide(#request);
+                            }
+                        }
+                    } else {
+                        quote_spanned! {backtrace.span()=>
+                            #varsource.thiserror_provide(#request);
+                        }
+                    };
+                    quote! {
+                        #ty::#ident {#backtrace: #varsource, ..} => {
+                            use ::thiserror::#private::ThiserrorProvide as _;
+                            #source_provide
+                        }
+                    }
+                }
+                (Some(backtrace_field), _) => {
+                    let backtrace = &backtrace_field.member;
+                    let body = if type_is_option(backtrace_field.ty) {
+                        quote! {
+                            if let ::core::option::Option::Some(backtrace) = backtrace {
+                                #request.provide_ref::<::thiserror::#private::Backtrace>(backtrace);
+                            }
+                        }
+                    } else {
+                        quote! {
+                            #request.provide_ref::<::thiserror::#private::Backtrace>(backtrace);
+                        }
+                    };
+                    quote! {
+                        #ty::#ident {#backtrace: backtrace, ..} => {
+                            #body
+                        }
+                    }
+                }
+                (None, _) => quote! {
+                    #ty::#ident {..} => {}
+                },
+            }
+        });
+        Some(quote! {
+            fn provide<'_request>(&'_request self, #request: &mut ::core::error::Request<'_request>) {
+                #[allow(deprecated)]
+                match self {
+                    #(#arms)*
+                }
+            }
+        })
+    } else {
+        None
+    };
+
+    let display_impl = if input.has_display() {
+        let mut display_inferred_bounds = InferredBounds::new();
+        let has_bonus_display = input.variants.iter().any(|v| {
+            v.attrs
+                .display
+                .as_ref()
+                .map_or(false, |display| display.has_bonus_display)
+        });
+        let use_as_display = use_as_display(has_bonus_display);
+        let void_deref = if input.variants.is_empty() {
+            Some(quote!(*))
+        } else {
+            None
+        };
+        let arms = input.variants.iter().map(|variant| {
+            let mut display_implied_bounds = Set::new();
+            let display = if let Some(display) = &variant.attrs.display {
+                display_implied_bounds.clone_from(&display.implied_bounds);
+                display.to_token_stream()
+            } else if let Some(fmt) = &variant.attrs.fmt {
+                let fmt_path = &fmt.path;
+                let vars = variant.fields.iter().map(|field| match &field.member {
+                    MemberUnraw::Named(ident) => ident.to_local(),
+                    MemberUnraw::Unnamed(index) => format_ident!("_{}", index),
+                });
+                quote!(#fmt_path(#(#vars,)* __formatter))
+            } else {
+                let only_field = match &variant.fields[0].member {
+                    MemberUnraw::Named(ident) => ident.to_local(),
+                    MemberUnraw::Unnamed(index) => format_ident!("_{}", index),
+                };
+                display_implied_bounds.insert((0, Trait::Display));
+                quote!(::core::fmt::Display::fmt(#only_field, __formatter))
+            };
+            for (field, bound) in display_implied_bounds {
+                let field = &variant.fields[field];
+                if field.contains_generic {
+                    display_inferred_bounds.insert(field.ty, bound);
+                }
+            }
+            let ident = &variant.ident;
+            let pat = fields_pat(&variant.fields);
+            quote! {
+                #ty::#ident #pat => #display
+            }
+        });
+        let arms = arms.collect::<Vec<_>>();
+        let display_where_clause = display_inferred_bounds.augment_where_clause(input.generics);
+        Some(quote! {
+            #[allow(unused_qualifications)]
+            #[automatically_derived]
+            impl #impl_generics ::core::fmt::Display for #ty #ty_generics #display_where_clause {
+                fn fmt(&self, __formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+                    #use_as_display
+                    #[allow(unused_variables, deprecated, clippy::used_underscore_binding)]
+                    match #void_deref self {
+                        #(#arms,)*
+                    }
+                }
+            }
+        })
+    } else {
+        None
+    };
+
+    let from_impls = input.variants.iter().filter_map(|variant| {
+        let from_field = variant.from_field()?;
+        let span = from_field.attrs.from.unwrap().span;
+        let backtrace_field = variant.distinct_backtrace_field();
+        let variant = &variant.ident;
+        let from = unoptional_type(from_field.ty);
+        let source_var = Ident::new("source", span);
+        let body = from_initializer(from_field, backtrace_field, &source_var);
+        let from_function = quote! {
+            fn from(#source_var: #from) -> Self {
+                #ty::#variant #body
+            }
+        };
+        let from_impl = quote_spanned! {span=>
+            #[automatically_derived]
+            impl #impl_generics ::core::convert::From<#from> for #ty #ty_generics #where_clause {
+                #from_function
+            }
+        };
+        Some(quote! {
+            #[allow(
+                deprecated,
+                unused_qualifications,
+                clippy::elidable_lifetime_names,
+                clippy::needless_lifetimes,
+            )]
+            #from_impl
+        })
+    });
+
+    if input.generics.type_params().next().is_some() {
+        let self_token = <Token![Self]>::default();
+        error_inferred_bounds.insert(self_token, Trait::Debug);
+        error_inferred_bounds.insert(self_token, Trait::Display);
+    }
+    let error_where_clause = error_inferred_bounds.augment_where_clause(input.generics);
+
+    quote! {
+        #[allow(unused_qualifications)]
+        #[automatically_derived]
+        impl #impl_generics ::thiserror::#private::Error for #ty #ty_generics #error_where_clause {
+            #source_method
+            #provide_method
+        }
+        #display_impl
+        #(#from_impls)*
+    }
+}
+
+// Create an ident with which we can expand `impl Trait for #ident {}` on a
+// deprecated type without triggering deprecation warning on the generated impl.
+pub(crate) fn call_site_ident(ident: &Ident) -> Ident {
+    let mut ident = ident.clone();
+    ident.set_span(ident.span().resolved_at(Span::call_site()));
+    ident
+}
+
+fn fields_pat(fields: &[Field]) -> TokenStream {
+    let mut members = fields.iter().map(|field| &field.member).peekable();
+    match members.peek() {
+        Some(MemberUnraw::Named(_)) => quote!({ #(#members),* }),
+        Some(MemberUnraw::Unnamed(_)) => {
+            let vars = members.map(|member| match member {
+                MemberUnraw::Unnamed(index) => format_ident!("_{}", index),
+                MemberUnraw::Named(_) => unreachable!(),
+            });
+            quote!((#(#vars),*))
+        }
+        None => quote!({}),
+    }
+}
+
+fn use_as_display(needs_as_display: bool) -> Option<TokenStream> {
+    if needs_as_display {
+        Some(quote! {
+            use ::thiserror::#private::AsDisplay as _;
+        })
+    } else {
+        None
+    }
+}
+
+fn from_initializer(
+    from_field: &Field,
+    backtrace_field: Option<&Field>,
+    source_var: &Ident,
+) -> TokenStream {
+    let from_member = &from_field.member;
+    let some_source = if type_is_option(from_field.ty) {
+        quote!(::core::option::Option::Some(#source_var))
+    } else {
+        quote!(#source_var)
+    };
+    let backtrace = backtrace_field.map(|backtrace_field| {
+        let backtrace_member = &backtrace_field.member;
+        if type_is_option(backtrace_field.ty) {
+            quote! {
+                #backtrace_member: ::core::option::Option::Some(::thiserror::#private::Backtrace::capture()),
+            }
+        } else {
+            quote! {
+                #backtrace_member: ::core::convert::From::from(::thiserror::#private::Backtrace::capture()),
+            }
+        }
+    });
+    quote!({
+        #from_member: #some_source,
+        #backtrace
+    })
+}
+
+fn type_is_option(ty: &Type) -> bool {
+    type_parameter_of_option(ty).is_some()
+}
+
+fn unoptional_type(ty: &Type) -> TokenStream {
+    let unoptional = type_parameter_of_option(ty).unwrap_or(ty);
+    quote!(#unoptional)
+}
+
+fn type_parameter_of_option(ty: &Type) -> Option<&Type> {
+    let path = match ty {
+        Type::Path(ty) => &ty.path,
+        _ => return None,
+    };
+
+    let last = path.segments.last().unwrap();
+    if last.ident != "Option" {
+        return None;
+    }
+
+    let bracketed = match &last.arguments {
+        PathArguments::AngleBracketed(bracketed) => bracketed,
+        _ => return None,
+    };
+
+    if bracketed.args.len() != 1 {
+        return None;
+    }
+
+    match &bracketed.args[0] {
+        GenericArgument::Type(arg) => Some(arg),
+        _ => None,
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/fallback.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/fallback.rs
new file mode 100644
index 0000000..9914aa5f
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/fallback.rs
@@ -0,0 +1,33 @@
+use crate::expand::call_site_ident;
+use crate::private;
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::DeriveInput;
+
+pub(crate) fn expand(input: &DeriveInput, error: syn::Error) -> TokenStream {
+    let ty = call_site_ident(&input.ident);
+    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
+
+    let error = error.to_compile_error();
+
+    quote! {
+        #error
+
+        #[allow(unused_qualifications)]
+        #[automatically_derived]
+        impl #impl_generics ::thiserror::#private::Error for #ty #ty_generics #where_clause
+        where
+            // Work around trivial bounds being unstable.
+            // https://github.com/rust-lang/rust/issues/48214
+            for<'workaround> #ty #ty_generics: ::core::fmt::Debug,
+        {}
+
+        #[allow(unused_qualifications)]
+        #[automatically_derived]
+        impl #impl_generics ::core::fmt::Display for #ty #ty_generics #where_clause {
+            fn fmt(&self, __formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+                ::core::unreachable!()
+            }
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/fmt.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/fmt.rs
new file mode 100644
index 0000000..2988ca37
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/fmt.rs
@@ -0,0 +1,323 @@
+use crate::ast::{ContainerKind, Field};
+use crate::attr::{Display, Trait};
+use crate::private;
+use crate::scan_expr::scan_expr;
+use crate::unraw::{IdentUnraw, MemberUnraw};
+use proc_macro2::{Delimiter, TokenStream, TokenTree};
+use quote::{format_ident, quote, quote_spanned, ToTokens as _};
+use std::collections::{BTreeSet, HashMap};
+use std::iter;
+use syn::ext::IdentExt;
+use syn::parse::discouraged::Speculative;
+use syn::parse::{Error, ParseStream, Parser, Result};
+use syn::{Expr, Ident, Index, LitStr, Token};
+
+impl Display<'_> {
+    pub fn expand_shorthand(&mut self, fields: &[Field], container: ContainerKind) -> Result<()> {
+        let raw_args = self.args.clone();
+        let FmtArguments {
+            named: user_named_args,
+            first_unnamed,
+        } = explicit_named_args.parse2(raw_args).unwrap();
+
+        let mut member_index = HashMap::new();
+        let mut extra_positional_arguments_allowed = true;
+        for (i, field) in fields.iter().enumerate() {
+            member_index.insert(&field.member, i);
+            extra_positional_arguments_allowed &= matches!(&field.member, MemberUnraw::Named(_));
+        }
+
+        let span = self.fmt.span();
+        let fmt = self.fmt.value();
+        let mut read = fmt.as_str();
+        let mut out = String::new();
+        let mut has_bonus_display = false;
+        let mut infinite_recursive = false;
+        let mut implied_bounds = BTreeSet::new();
+        let mut bindings = Vec::new();
+        let mut macro_named_args = BTreeSet::new();
+
+        self.requires_fmt_machinery = self.requires_fmt_machinery || fmt.contains('}');
+
+        while let Some(brace) = read.find('{') {
+            self.requires_fmt_machinery = true;
+            out += &read[..brace + 1];
+            read = &read[brace + 1..];
+            if read.starts_with('{') {
+                out.push('{');
+                read = &read[1..];
+                continue;
+            }
+            let next = match read.chars().next() {
+                Some(next) => next,
+                None => return Ok(()),
+            };
+            let member = match next {
+                '0'..='9' => {
+                    let int = take_int(&mut read);
+                    if !extra_positional_arguments_allowed {
+                        if let Some(first_unnamed) = &first_unnamed {
+                            let msg = format!("ambiguous reference to positional arguments by number in a {container}; change this to a named argument");
+                            return Err(Error::new_spanned(first_unnamed, msg));
+                        }
+                    }
+                    match int.parse::<u32>() {
+                        Ok(index) => MemberUnraw::Unnamed(Index { index, span }),
+                        Err(_) => return Ok(()),
+                    }
+                }
+                'a'..='z' | 'A'..='Z' | '_' => {
+                    if read.starts_with("r#") {
+                        continue;
+                    }
+                    let repr = take_ident(&mut read);
+                    if repr == "_" {
+                        // Invalid. Let rustc produce the diagnostic.
+                        out += repr;
+                        continue;
+                    }
+                    let ident = IdentUnraw::new(Ident::new(repr, span));
+                    if user_named_args.contains(&ident) {
+                        // Refers to a named argument written by the user, not to field.
+                        out += repr;
+                        continue;
+                    }
+                    MemberUnraw::Named(ident)
+                }
+                _ => continue,
+            };
+            let end_spec = match read.find('}') {
+                Some(end_spec) => end_spec,
+                None => return Ok(()),
+            };
+            let mut bonus_display = false;
+            let bound = match read[..end_spec].chars().next_back() {
+                Some('?') => Trait::Debug,
+                Some('o') => Trait::Octal,
+                Some('x') => Trait::LowerHex,
+                Some('X') => Trait::UpperHex,
+                Some('p') => Trait::Pointer,
+                Some('b') => Trait::Binary,
+                Some('e') => Trait::LowerExp,
+                Some('E') => Trait::UpperExp,
+                Some(_) => Trait::Display,
+                None => {
+                    bonus_display = true;
+                    has_bonus_display = true;
+                    Trait::Display
+                }
+            };
+            infinite_recursive |= member == *"self" && bound == Trait::Display;
+            let field = match member_index.get(&member) {
+                Some(&field) => field,
+                None => {
+                    out += &member.to_string();
+                    continue;
+                }
+            };
+            implied_bounds.insert((field, bound));
+            let formatvar_prefix = if bonus_display {
+                "__display"
+            } else if bound == Trait::Pointer {
+                "__pointer"
+            } else {
+                "__field"
+            };
+            let mut formatvar = IdentUnraw::new(match &member {
+                MemberUnraw::Unnamed(index) => format_ident!("{}{}", formatvar_prefix, index),
+                MemberUnraw::Named(ident) => {
+                    format_ident!("{}_{}", formatvar_prefix, ident.to_string())
+                }
+            });
+            while user_named_args.contains(&formatvar) {
+                formatvar = IdentUnraw::new(format_ident!("_{}", formatvar.to_string()));
+            }
+            formatvar.set_span(span);
+            out += &formatvar.to_string();
+            if !macro_named_args.insert(formatvar.clone()) {
+                // Already added to bindings by a previous use.
+                continue;
+            }
+            let mut binding_value = match &member {
+                MemberUnraw::Unnamed(index) => format_ident!("_{}", index),
+                MemberUnraw::Named(ident) => ident.to_local(),
+            };
+            binding_value.set_span(span.resolved_at(fields[field].member.span()));
+            let wrapped_binding_value = if bonus_display {
+                quote_spanned!(span=> #binding_value.as_display())
+            } else if bound == Trait::Pointer {
+                quote!(::thiserror::#private::Var(#binding_value))
+            } else {
+                binding_value.into_token_stream()
+            };
+            bindings.push((formatvar.to_local(), wrapped_binding_value));
+        }
+
+        out += read;
+        self.fmt = LitStr::new(&out, self.fmt.span());
+        self.has_bonus_display = has_bonus_display;
+        self.infinite_recursive = infinite_recursive;
+        self.implied_bounds = implied_bounds;
+        self.bindings = bindings;
+        Ok(())
+    }
+}
+
+struct FmtArguments {
+    named: BTreeSet<IdentUnraw>,
+    first_unnamed: Option<TokenStream>,
+}
+
+#[allow(clippy::unnecessary_wraps)]
+fn explicit_named_args(input: ParseStream) -> Result<FmtArguments> {
+    let ahead = input.fork();
+    if let Ok(set) = try_explicit_named_args(&ahead) {
+        input.advance_to(&ahead);
+        return Ok(set);
+    }
+
+    let ahead = input.fork();
+    if let Ok(set) = fallback_explicit_named_args(&ahead) {
+        input.advance_to(&ahead);
+        return Ok(set);
+    }
+
+    input.parse::<TokenStream>().unwrap();
+    Ok(FmtArguments {
+        named: BTreeSet::new(),
+        first_unnamed: None,
+    })
+}
+
+fn try_explicit_named_args(input: ParseStream) -> Result<FmtArguments> {
+    let mut syn_full = None;
+    let mut args = FmtArguments {
+        named: BTreeSet::new(),
+        first_unnamed: None,
+    };
+
+    while !input.is_empty() {
+        input.parse::<Token![,]>()?;
+        if input.is_empty() {
+            break;
+        }
+
+        let mut begin_unnamed = None;
+        if input.peek(Ident::peek_any) && input.peek2(Token![=]) && !input.peek2(Token![==]) {
+            let ident: IdentUnraw = input.parse()?;
+            input.parse::<Token![=]>()?;
+            args.named.insert(ident);
+        } else {
+            begin_unnamed = Some(input.fork());
+        }
+
+        let ahead = input.fork();
+        if *syn_full.get_or_insert_with(is_syn_full) && ahead.parse::<Expr>().is_ok() {
+            input.advance_to(&ahead);
+        } else {
+            scan_expr(input)?;
+        }
+
+        if let Some(begin_unnamed) = begin_unnamed {
+            if args.first_unnamed.is_none() {
+                args.first_unnamed = Some(between(&begin_unnamed, input));
+            }
+        }
+    }
+
+    Ok(args)
+}
+
+fn fallback_explicit_named_args(input: ParseStream) -> Result<FmtArguments> {
+    let mut args = FmtArguments {
+        named: BTreeSet::new(),
+        first_unnamed: None,
+    };
+
+    while !input.is_empty() {
+        if input.peek(Token![,])
+            && input.peek2(Ident::peek_any)
+            && input.peek3(Token![=])
+            && !input.peek3(Token![==])
+        {
+            input.parse::<Token![,]>()?;
+            let ident: IdentUnraw = input.parse()?;
+            input.parse::<Token![=]>()?;
+            args.named.insert(ident);
+        } else {
+            input.parse::<TokenTree>()?;
+        }
+    }
+
+    Ok(args)
+}
+
+fn is_syn_full() -> bool {
+    // Expr::Block contains syn::Block which contains Vec<syn::Stmt>. In the
+    // current version of Syn, syn::Stmt is exhaustive and could only plausibly
+    // represent `trait Trait {}` in Stmt::Item which contains syn::Item. Most
+    // of the point of syn's non-"full" mode is to avoid compiling Item and the
+    // entire expansive syntax tree it comprises. So the following expression
+    // being parsed to Expr::Block is a reliable indication that "full" is
+    // enabled.
+    let test = quote!({
+        trait Trait {}
+    });
+    match syn::parse2(test) {
+        Ok(Expr::Verbatim(_)) | Err(_) => false,
+        Ok(Expr::Block(_)) => true,
+        Ok(_) => unreachable!(),
+    }
+}
+
+fn take_int<'a>(read: &mut &'a str) -> &'a str {
+    let mut int_len = 0;
+    for ch in read.chars() {
+        match ch {
+            '0'..='9' => int_len += 1,
+            _ => break,
+        }
+    }
+    let (int, rest) = read.split_at(int_len);
+    *read = rest;
+    int
+}
+
+fn take_ident<'a>(read: &mut &'a str) -> &'a str {
+    let mut ident_len = 0;
+    for ch in read.chars() {
+        match ch {
+            'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => ident_len += 1,
+            _ => break,
+        }
+    }
+    let (ident, rest) = read.split_at(ident_len);
+    *read = rest;
+    ident
+}
+
+fn between<'a>(begin: ParseStream<'a>, end: ParseStream<'a>) -> TokenStream {
+    let end = end.cursor();
+    let mut cursor = begin.cursor();
+    let mut tokens = TokenStream::new();
+
+    while cursor < end {
+        let (tt, next) = cursor.token_tree().unwrap();
+
+        if end < next {
+            if let Some((inside, _span, _after)) = cursor.group(Delimiter::None) {
+                cursor = inside;
+                continue;
+            }
+            if tokens.is_empty() {
+                tokens.extend(iter::once(tt));
+            }
+            break;
+        }
+
+        tokens.extend(iter::once(tt));
+        cursor = next;
+    }
+
+    tokens
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/generics.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/generics.rs
new file mode 100644
index 0000000..26fe0a9a
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/generics.rs
@@ -0,0 +1,83 @@
+use proc_macro2::TokenStream;
+use quote::ToTokens;
+use std::collections::btree_map::Entry;
+use std::collections::{BTreeMap as Map, BTreeSet as Set};
+use syn::punctuated::Punctuated;
+use syn::{parse_quote, GenericArgument, Generics, Ident, PathArguments, Token, Type, WhereClause};
+
+pub struct ParamsInScope<'a> {
+    names: Set<&'a Ident>,
+}
+
+impl<'a> ParamsInScope<'a> {
+    pub fn new(generics: &'a Generics) -> Self {
+        ParamsInScope {
+            names: generics.type_params().map(|param| &param.ident).collect(),
+        }
+    }
+
+    pub fn intersects(&self, ty: &Type) -> bool {
+        let mut found = false;
+        crawl(self, ty, &mut found);
+        found
+    }
+}
+
+fn crawl(in_scope: &ParamsInScope, ty: &Type, found: &mut bool) {
+    if let Type::Path(ty) = ty {
+        if let Some(qself) = &ty.qself {
+            crawl(in_scope, &qself.ty, found);
+        } else {
+            let front = ty.path.segments.first().unwrap();
+            if front.arguments.is_none() && in_scope.names.contains(&front.ident) {
+                *found = true;
+            }
+        }
+        for segment in &ty.path.segments {
+            if let PathArguments::AngleBracketed(arguments) = &segment.arguments {
+                for arg in &arguments.args {
+                    if let GenericArgument::Type(ty) = arg {
+                        crawl(in_scope, ty, found);
+                    }
+                }
+            }
+        }
+    }
+}
+
+pub struct InferredBounds {
+    bounds: Map<String, (Set<String>, Punctuated<TokenStream, Token![+]>)>,
+    order: Vec<TokenStream>,
+}
+
+impl InferredBounds {
+    pub fn new() -> Self {
+        InferredBounds {
+            bounds: Map::new(),
+            order: Vec::new(),
+        }
+    }
+
+    pub fn insert(&mut self, ty: impl ToTokens, bound: impl ToTokens) {
+        let ty = ty.to_token_stream();
+        let bound = bound.to_token_stream();
+        let entry = self.bounds.entry(ty.to_string());
+        if let Entry::Vacant(_) = entry {
+            self.order.push(ty);
+        }
+        let (set, tokens) = entry.or_default();
+        if set.insert(bound.to_string()) {
+            tokens.push(bound);
+        }
+    }
+
+    pub fn augment_where_clause(&self, generics: &Generics) -> WhereClause {
+        let mut generics = generics.clone();
+        let where_clause = generics.make_where_clause();
+        for ty in &self.order {
+            let (_set, bounds) = &self.bounds[&ty.to_string()];
+            where_clause.predicates.push(parse_quote!(#ty: #bounds));
+        }
+        generics.where_clause.unwrap()
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/lib.rs
new file mode 100644
index 0000000..ce34ad5
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/lib.rs
@@ -0,0 +1,54 @@
+#![allow(
+    clippy::blocks_in_conditions,
+    clippy::cast_lossless,
+    clippy::cast_possible_truncation,
+    clippy::enum_glob_use,
+    clippy::manual_find,
+    clippy::manual_let_else,
+    clippy::manual_map,
+    clippy::map_unwrap_or,
+    clippy::module_name_repetitions,
+    clippy::needless_pass_by_value,
+    clippy::range_plus_one,
+    clippy::single_match_else,
+    clippy::struct_field_names,
+    clippy::too_many_lines,
+    clippy::wrong_self_convention
+)]
+#![allow(unknown_lints, mismatched_lifetime_syntaxes)]
+
+extern crate proc_macro;
+
+mod ast;
+mod attr;
+mod expand;
+mod fallback;
+mod fmt;
+mod generics;
+mod prop;
+mod scan_expr;
+mod unraw;
+mod valid;
+
+use proc_macro::TokenStream;
+use proc_macro2::{Ident, Span};
+use quote::{ToTokens, TokenStreamExt as _};
+use syn::{parse_macro_input, DeriveInput};
+
+#[proc_macro_derive(Error, attributes(backtrace, error, from, source))]
+pub fn derive_error(input: TokenStream) -> TokenStream {
+    let input = parse_macro_input!(input as DeriveInput);
+    expand::derive(&input).into()
+}
+
+#[allow(non_camel_case_types)]
+struct private;
+
+impl ToTokens for private {
+    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
+        tokens.append(Ident::new(
+            concat!("__private", env!("CARGO_PKG_VERSION_PATCH")),
+            Span::call_site(),
+        ));
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/prop.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/prop.rs
new file mode 100644
index 0000000..0a101fc
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/prop.rs
@@ -0,0 +1,148 @@
+use crate::ast::{Enum, Field, Struct, Variant};
+use crate::unraw::MemberUnraw;
+use proc_macro2::Span;
+use syn::Type;
+
+impl Struct<'_> {
+    pub(crate) fn from_field(&self) -> Option<&Field> {
+        from_field(&self.fields)
+    }
+
+    pub(crate) fn source_field(&self) -> Option<&Field> {
+        source_field(&self.fields)
+    }
+
+    pub(crate) fn backtrace_field(&self) -> Option<&Field> {
+        backtrace_field(&self.fields)
+    }
+
+    pub(crate) fn distinct_backtrace_field(&self) -> Option<&Field> {
+        let backtrace_field = self.backtrace_field()?;
+        distinct_backtrace_field(backtrace_field, self.from_field())
+    }
+}
+
+impl Enum<'_> {
+    pub(crate) fn has_source(&self) -> bool {
+        self.variants
+            .iter()
+            .any(|variant| variant.source_field().is_some() || variant.attrs.transparent.is_some())
+    }
+
+    pub(crate) fn has_backtrace(&self) -> bool {
+        self.variants
+            .iter()
+            .any(|variant| variant.backtrace_field().is_some())
+    }
+
+    pub(crate) fn has_display(&self) -> bool {
+        self.attrs.display.is_some()
+            || self.attrs.transparent.is_some()
+            || self.attrs.fmt.is_some()
+            || self
+                .variants
+                .iter()
+                .any(|variant| variant.attrs.display.is_some() || variant.attrs.fmt.is_some())
+            || self
+                .variants
+                .iter()
+                .all(|variant| variant.attrs.transparent.is_some())
+    }
+}
+
+impl Variant<'_> {
+    pub(crate) fn from_field(&self) -> Option<&Field> {
+        from_field(&self.fields)
+    }
+
+    pub(crate) fn source_field(&self) -> Option<&Field> {
+        source_field(&self.fields)
+    }
+
+    pub(crate) fn backtrace_field(&self) -> Option<&Field> {
+        backtrace_field(&self.fields)
+    }
+
+    pub(crate) fn distinct_backtrace_field(&self) -> Option<&Field> {
+        let backtrace_field = self.backtrace_field()?;
+        distinct_backtrace_field(backtrace_field, self.from_field())
+    }
+}
+
+impl Field<'_> {
+    pub(crate) fn is_backtrace(&self) -> bool {
+        type_is_backtrace(self.ty)
+    }
+
+    pub(crate) fn source_span(&self) -> Span {
+        if let Some(source_attr) = &self.attrs.source {
+            source_attr.span
+        } else if let Some(from_attr) = &self.attrs.from {
+            from_attr.span
+        } else {
+            self.member.span()
+        }
+    }
+}
+
+fn from_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>> {
+    for field in fields {
+        if field.attrs.from.is_some() {
+            return Some(field);
+        }
+    }
+    None
+}
+
+fn source_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>> {
+    for field in fields {
+        if field.attrs.from.is_some() || field.attrs.source.is_some() {
+            return Some(field);
+        }
+    }
+    for field in fields {
+        match &field.member {
+            MemberUnraw::Named(ident) if ident == "source" => return Some(field),
+            _ => {}
+        }
+    }
+    None
+}
+
+fn backtrace_field<'a, 'b>(fields: &'a [Field<'b>]) -> Option<&'a Field<'b>> {
+    for field in fields {
+        if field.attrs.backtrace.is_some() {
+            return Some(field);
+        }
+    }
+    for field in fields {
+        if field.is_backtrace() {
+            return Some(field);
+        }
+    }
+    None
+}
+
+// The #[backtrace] field, if it is not the same as the #[from] field.
+fn distinct_backtrace_field<'a, 'b>(
+    backtrace_field: &'a Field<'b>,
+    from_field: Option<&Field>,
+) -> Option<&'a Field<'b>> {
+    if from_field.map_or(false, |from_field| {
+        from_field.member == backtrace_field.member
+    }) {
+        None
+    } else {
+        Some(backtrace_field)
+    }
+}
+
+fn type_is_backtrace(ty: &Type) -> bool {
+    let path = match ty {
+        Type::Path(ty) => &ty.path,
+        _ => return false,
+    };
+
+    let last = path.segments.last().unwrap();
+    last.ident == "Backtrace" && last.arguments.is_empty()
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/scan_expr.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/scan_expr.rs
new file mode 100644
index 0000000..155b5b63
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/scan_expr.rs
@@ -0,0 +1,264 @@
+use self::{Action::*, Input::*};
+use proc_macro2::{Delimiter, Ident, Spacing, TokenTree};
+use syn::parse::{ParseStream, Result};
+use syn::{AngleBracketedGenericArguments, BinOp, Expr, ExprPath, Lifetime, Lit, Token, Type};
+
+enum Input {
+    Keyword(&'static str),
+    Punct(&'static str),
+    ConsumeAny,
+    ConsumeBinOp,
+    ConsumeBrace,
+    ConsumeDelimiter,
+    ConsumeIdent,
+    ConsumeLifetime,
+    ConsumeLiteral,
+    ConsumeNestedBrace,
+    ExpectPath,
+    ExpectTurbofish,
+    ExpectType,
+    CanBeginExpr,
+    Otherwise,
+    Empty,
+}
+
+enum Action {
+    SetState(&'static [(Input, Action)]),
+    IncDepth,
+    DecDepth,
+    Finish,
+}
+
+static INIT: [(Input, Action); 28] = [
+    (ConsumeDelimiter, SetState(&POSTFIX)),
+    (Keyword("async"), SetState(&ASYNC)),
+    (Keyword("break"), SetState(&BREAK_LABEL)),
+    (Keyword("const"), SetState(&CONST)),
+    (Keyword("continue"), SetState(&CONTINUE)),
+    (Keyword("for"), SetState(&FOR)),
+    (Keyword("if"), IncDepth),
+    (Keyword("let"), SetState(&PATTERN)),
+    (Keyword("loop"), SetState(&BLOCK)),
+    (Keyword("match"), IncDepth),
+    (Keyword("move"), SetState(&CLOSURE)),
+    (Keyword("return"), SetState(&RETURN)),
+    (Keyword("static"), SetState(&CLOSURE)),
+    (Keyword("unsafe"), SetState(&BLOCK)),
+    (Keyword("while"), IncDepth),
+    (Keyword("yield"), SetState(&RETURN)),
+    (Keyword("_"), SetState(&POSTFIX)),
+    (Punct("!"), SetState(&INIT)),
+    (Punct("#"), SetState(&[(ConsumeDelimiter, SetState(&INIT))])),
+    (Punct("&"), SetState(&REFERENCE)),
+    (Punct("*"), SetState(&INIT)),
+    (Punct("-"), SetState(&INIT)),
+    (Punct("..="), SetState(&INIT)),
+    (Punct(".."), SetState(&RANGE)),
+    (Punct("|"), SetState(&CLOSURE_ARGS)),
+    (ConsumeLifetime, SetState(&[(Punct(":"), SetState(&INIT))])),
+    (ConsumeLiteral, SetState(&POSTFIX)),
+    (ExpectPath, SetState(&PATH)),
+];
+
+static POSTFIX: [(Input, Action); 10] = [
+    (Keyword("as"), SetState(&[(ExpectType, SetState(&POSTFIX))])),
+    (Punct("..="), SetState(&INIT)),
+    (Punct(".."), SetState(&RANGE)),
+    (Punct("."), SetState(&DOT)),
+    (Punct("?"), SetState(&POSTFIX)),
+    (ConsumeBinOp, SetState(&INIT)),
+    (Punct("="), SetState(&INIT)),
+    (ConsumeNestedBrace, SetState(&IF_THEN)),
+    (ConsumeDelimiter, SetState(&POSTFIX)),
+    (Empty, Finish),
+];
+
+static ASYNC: [(Input, Action); 3] = [
+    (Keyword("move"), SetState(&ASYNC)),
+    (Punct("|"), SetState(&CLOSURE_ARGS)),
+    (ConsumeBrace, SetState(&POSTFIX)),
+];
+
+static BLOCK: [(Input, Action); 1] = [(ConsumeBrace, SetState(&POSTFIX))];
+
+static BREAK_LABEL: [(Input, Action); 2] = [
+    (ConsumeLifetime, SetState(&BREAK_VALUE)),
+    (Otherwise, SetState(&BREAK_VALUE)),
+];
+
+static BREAK_VALUE: [(Input, Action); 3] = [
+    (ConsumeNestedBrace, SetState(&IF_THEN)),
+    (CanBeginExpr, SetState(&INIT)),
+    (Otherwise, SetState(&POSTFIX)),
+];
+
+static CLOSURE: [(Input, Action); 6] = [
+    (Keyword("async"), SetState(&CLOSURE)),
+    (Keyword("move"), SetState(&CLOSURE)),
+    (Punct(","), SetState(&CLOSURE)),
+    (Punct(">"), SetState(&CLOSURE)),
+    (Punct("|"), SetState(&CLOSURE_ARGS)),
+    (ConsumeLifetime, SetState(&CLOSURE)),
+];
+
+static CLOSURE_ARGS: [(Input, Action); 2] = [
+    (Punct("|"), SetState(&CLOSURE_RET)),
+    (ConsumeAny, SetState(&CLOSURE_ARGS)),
+];
+
+static CLOSURE_RET: [(Input, Action); 2] = [
+    (Punct("->"), SetState(&[(ExpectType, SetState(&BLOCK))])),
+    (Otherwise, SetState(&INIT)),
+];
+
+static CONST: [(Input, Action); 2] = [
+    (Punct("|"), SetState(&CLOSURE_ARGS)),
+    (ConsumeBrace, SetState(&POSTFIX)),
+];
+
+static CONTINUE: [(Input, Action); 2] = [
+    (ConsumeLifetime, SetState(&POSTFIX)),
+    (Otherwise, SetState(&POSTFIX)),
+];
+
+static DOT: [(Input, Action); 3] = [
+    (Keyword("await"), SetState(&POSTFIX)),
+    (ConsumeIdent, SetState(&METHOD)),
+    (ConsumeLiteral, SetState(&POSTFIX)),
+];
+
+static FOR: [(Input, Action); 2] = [
+    (Punct("<"), SetState(&CLOSURE)),
+    (Otherwise, SetState(&PATTERN)),
+];
+
+static IF_ELSE: [(Input, Action); 2] = [(Keyword("if"), SetState(&INIT)), (ConsumeBrace, DecDepth)];
+static IF_THEN: [(Input, Action); 2] =
+    [(Keyword("else"), SetState(&IF_ELSE)), (Otherwise, DecDepth)];
+
+static METHOD: [(Input, Action); 1] = [(ExpectTurbofish, SetState(&POSTFIX))];
+
+static PATH: [(Input, Action); 4] = [
+    (Punct("!="), SetState(&INIT)),
+    (Punct("!"), SetState(&INIT)),
+    (ConsumeNestedBrace, SetState(&IF_THEN)),
+    (Otherwise, SetState(&POSTFIX)),
+];
+
+static PATTERN: [(Input, Action); 15] = [
+    (ConsumeDelimiter, SetState(&PATTERN)),
+    (Keyword("box"), SetState(&PATTERN)),
+    (Keyword("in"), IncDepth),
+    (Keyword("mut"), SetState(&PATTERN)),
+    (Keyword("ref"), SetState(&PATTERN)),
+    (Keyword("_"), SetState(&PATTERN)),
+    (Punct("!"), SetState(&PATTERN)),
+    (Punct("&"), SetState(&PATTERN)),
+    (Punct("..="), SetState(&PATTERN)),
+    (Punct(".."), SetState(&PATTERN)),
+    (Punct("="), SetState(&INIT)),
+    (Punct("@"), SetState(&PATTERN)),
+    (Punct("|"), SetState(&PATTERN)),
+    (ConsumeLiteral, SetState(&PATTERN)),
+    (ExpectPath, SetState(&PATTERN)),
+];
+
+static RANGE: [(Input, Action); 6] = [
+    (Punct("..="), SetState(&INIT)),
+    (Punct(".."), SetState(&RANGE)),
+    (Punct("."), SetState(&DOT)),
+    (ConsumeNestedBrace, SetState(&IF_THEN)),
+    (Empty, Finish),
+    (Otherwise, SetState(&INIT)),
+];
+
+static RAW: [(Input, Action); 3] = [
+    (Keyword("const"), SetState(&INIT)),
+    (Keyword("mut"), SetState(&INIT)),
+    (Otherwise, SetState(&POSTFIX)),
+];
+
+static REFERENCE: [(Input, Action); 3] = [
+    (Keyword("mut"), SetState(&INIT)),
+    (Keyword("raw"), SetState(&RAW)),
+    (Otherwise, SetState(&INIT)),
+];
+
+static RETURN: [(Input, Action); 2] = [
+    (CanBeginExpr, SetState(&INIT)),
+    (Otherwise, SetState(&POSTFIX)),
+];
+
+pub(crate) fn scan_expr(input: ParseStream) -> Result<()> {
+    let mut state = INIT.as_slice();
+    let mut depth = 0usize;
+    'table: loop {
+        for rule in state {
+            if match rule.0 {
+                Input::Keyword(expected) => input.step(|cursor| match cursor.ident() {
+                    Some((ident, rest)) if ident == expected => Ok((true, rest)),
+                    _ => Ok((false, *cursor)),
+                })?,
+                Input::Punct(expected) => input.step(|cursor| {
+                    let begin = *cursor;
+                    let mut cursor = begin;
+                    for (i, ch) in expected.chars().enumerate() {
+                        match cursor.punct() {
+                            Some((punct, _)) if punct.as_char() != ch => break,
+                            Some((_, rest)) if i == expected.len() - 1 => {
+                                return Ok((true, rest));
+                            }
+                            Some((punct, rest)) if punct.spacing() == Spacing::Joint => {
+                                cursor = rest;
+                            }
+                            _ => break,
+                        }
+                    }
+                    Ok((false, begin))
+                })?,
+                Input::ConsumeAny => input.parse::<Option<TokenTree>>()?.is_some(),
+                Input::ConsumeBinOp => input.parse::<BinOp>().is_ok(),
+                Input::ConsumeBrace | Input::ConsumeNestedBrace => {
+                    (matches!(rule.0, Input::ConsumeBrace) || depth > 0)
+                        && input.step(|cursor| match cursor.group(Delimiter::Brace) {
+                            Some((_inside, _span, rest)) => Ok((true, rest)),
+                            None => Ok((false, *cursor)),
+                        })?
+                }
+                Input::ConsumeDelimiter => input.step(|cursor| match cursor.any_group() {
+                    Some((_inside, _delimiter, _span, rest)) => Ok((true, rest)),
+                    None => Ok((false, *cursor)),
+                })?,
+                Input::ConsumeIdent => input.parse::<Option<Ident>>()?.is_some(),
+                Input::ConsumeLifetime => input.parse::<Option<Lifetime>>()?.is_some(),
+                Input::ConsumeLiteral => input.parse::<Option<Lit>>()?.is_some(),
+                Input::ExpectPath => {
+                    input.parse::<ExprPath>()?;
+                    true
+                }
+                Input::ExpectTurbofish => {
+                    if input.peek(Token![::]) {
+                        input.parse::<AngleBracketedGenericArguments>()?;
+                    }
+                    true
+                }
+                Input::ExpectType => {
+                    Type::without_plus(input)?;
+                    true
+                }
+                Input::CanBeginExpr => Expr::peek(input),
+                Input::Otherwise => true,
+                Input::Empty => input.is_empty() || input.peek(Token![,]),
+            } {
+                state = match rule.1 {
+                    Action::SetState(next) => next,
+                    Action::IncDepth => (depth += 1, &INIT).1,
+                    Action::DecDepth => (depth -= 1, &POSTFIX).1,
+                    Action::Finish => return if depth == 0 { Ok(()) } else { break },
+                };
+                continue 'table;
+            }
+        }
+        return Err(input.error("unsupported expression"));
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/unraw.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/unraw.rs
new file mode 100644
index 0000000..73b9970
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/unraw.rs
@@ -0,0 +1,142 @@
+use proc_macro2::{Ident, Span, TokenStream};
+use quote::ToTokens;
+use std::cmp::Ordering;
+use std::fmt::{self, Display};
+use std::hash::{Hash, Hasher};
+use syn::ext::IdentExt as _;
+use syn::parse::{Parse, ParseStream, Result};
+use syn::Index;
+
+#[derive(Clone)]
+#[repr(transparent)]
+pub struct IdentUnraw(Ident);
+
+impl IdentUnraw {
+    pub fn new(ident: Ident) -> Self {
+        IdentUnraw(ident)
+    }
+
+    pub fn to_local(&self) -> Ident {
+        let unraw = self.0.unraw();
+        let repr = unraw.to_string();
+        if syn::parse_str::<Ident>(&repr).is_err() {
+            if let "_" | "super" | "self" | "Self" | "crate" = repr.as_str() {
+                // Some identifiers are never allowed to appear as raw, like r#self and r#_.
+            } else {
+                return Ident::new_raw(&repr, Span::call_site());
+            }
+        }
+        unraw
+    }
+
+    pub fn set_span(&mut self, span: Span) {
+        self.0.set_span(span);
+    }
+}
+
+impl Display for IdentUnraw {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        Display::fmt(&self.0.unraw(), formatter)
+    }
+}
+
+impl Eq for IdentUnraw {}
+
+impl PartialEq for IdentUnraw {
+    fn eq(&self, other: &Self) -> bool {
+        PartialEq::eq(&self.0.unraw(), &other.0.unraw())
+    }
+}
+
+impl PartialEq<str> for IdentUnraw {
+    fn eq(&self, other: &str) -> bool {
+        self.0 == other
+    }
+}
+
+impl Ord for IdentUnraw {
+    fn cmp(&self, other: &Self) -> Ordering {
+        Ord::cmp(&self.0.unraw(), &other.0.unraw())
+    }
+}
+
+impl PartialOrd for IdentUnraw {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(Self::cmp(self, other))
+    }
+}
+
+impl Parse for IdentUnraw {
+    fn parse(input: ParseStream) -> Result<Self> {
+        input.call(Ident::parse_any).map(IdentUnraw::new)
+    }
+}
+
+impl ToTokens for IdentUnraw {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        self.0.unraw().to_tokens(tokens);
+    }
+}
+
+#[derive(Clone)]
+pub enum MemberUnraw {
+    Named(IdentUnraw),
+    Unnamed(Index),
+}
+
+impl MemberUnraw {
+    pub fn span(&self) -> Span {
+        match self {
+            MemberUnraw::Named(ident) => ident.0.span(),
+            MemberUnraw::Unnamed(index) => index.span,
+        }
+    }
+}
+
+impl Display for MemberUnraw {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            MemberUnraw::Named(this) => Display::fmt(this, formatter),
+            MemberUnraw::Unnamed(this) => Display::fmt(&this.index, formatter),
+        }
+    }
+}
+
+impl Eq for MemberUnraw {}
+
+impl PartialEq for MemberUnraw {
+    fn eq(&self, other: &Self) -> bool {
+        match (self, other) {
+            (MemberUnraw::Named(this), MemberUnraw::Named(other)) => this == other,
+            (MemberUnraw::Unnamed(this), MemberUnraw::Unnamed(other)) => this == other,
+            _ => false,
+        }
+    }
+}
+
+impl PartialEq<str> for MemberUnraw {
+    fn eq(&self, other: &str) -> bool {
+        match self {
+            MemberUnraw::Named(this) => this == other,
+            MemberUnraw::Unnamed(_) => false,
+        }
+    }
+}
+
+impl Hash for MemberUnraw {
+    fn hash<H: Hasher>(&self, hasher: &mut H) {
+        match self {
+            MemberUnraw::Named(ident) => ident.0.unraw().hash(hasher),
+            MemberUnraw::Unnamed(index) => index.hash(hasher),
+        }
+    }
+}
+
+impl ToTokens for MemberUnraw {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        match self {
+            MemberUnraw::Named(ident) => ident.to_local().to_tokens(tokens),
+            MemberUnraw::Unnamed(index) => index.to_tokens(tokens),
+        }
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/valid.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/valid.rs
new file mode 100644
index 0000000..21bd885e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/valid.rs
@@ -0,0 +1,248 @@
+use crate::ast::{Enum, Field, Input, Struct, Variant};
+use crate::attr::Attrs;
+use syn::{Error, GenericArgument, PathArguments, Result, Type};
+
+impl Input<'_> {
+    pub(crate) fn validate(&self) -> Result<()> {
+        match self {
+            Input::Struct(input) => input.validate(),
+            Input::Enum(input) => input.validate(),
+        }
+    }
+}
+
+impl Struct<'_> {
+    fn validate(&self) -> Result<()> {
+        check_non_field_attrs(&self.attrs)?;
+        if let Some(transparent) = self.attrs.transparent {
+            if self.fields.len() != 1 {
+                return Err(Error::new_spanned(
+                    transparent.original,
+                    "#[error(transparent)] requires exactly one field",
+                ));
+            }
+            if let Some(source) = self.fields.iter().find_map(|f| f.attrs.source) {
+                return Err(Error::new_spanned(
+                    source.original,
+                    "transparent error struct can't contain #[source]",
+                ));
+            }
+        }
+        if let Some(fmt) = &self.attrs.fmt {
+            return Err(Error::new_spanned(
+                fmt.original,
+                "#[error(fmt = ...)] is only supported in enums; for a struct, handwrite your own Display impl",
+            ));
+        }
+        check_field_attrs(&self.fields)?;
+        for field in &self.fields {
+            field.validate()?;
+        }
+        Ok(())
+    }
+}
+
+impl Enum<'_> {
+    fn validate(&self) -> Result<()> {
+        check_non_field_attrs(&self.attrs)?;
+        let has_display = self.has_display();
+        for variant in &self.variants {
+            variant.validate()?;
+            if has_display
+                && variant.attrs.display.is_none()
+                && variant.attrs.transparent.is_none()
+                && variant.attrs.fmt.is_none()
+            {
+                return Err(Error::new_spanned(
+                    variant.original,
+                    "missing #[error(\"...\")] display attribute",
+                ));
+            }
+        }
+        Ok(())
+    }
+}
+
+impl Variant<'_> {
+    fn validate(&self) -> Result<()> {
+        check_non_field_attrs(&self.attrs)?;
+        if self.attrs.transparent.is_some() {
+            if self.fields.len() != 1 {
+                return Err(Error::new_spanned(
+                    self.original,
+                    "#[error(transparent)] requires exactly one field",
+                ));
+            }
+            if let Some(source) = self.fields.iter().find_map(|f| f.attrs.source) {
+                return Err(Error::new_spanned(
+                    source.original,
+                    "transparent variant can't contain #[source]",
+                ));
+            }
+        }
+        check_field_attrs(&self.fields)?;
+        for field in &self.fields {
+            field.validate()?;
+        }
+        Ok(())
+    }
+}
+
+impl Field<'_> {
+    fn validate(&self) -> Result<()> {
+        if let Some(unexpected_display_attr) = if let Some(display) = &self.attrs.display {
+            Some(display.original)
+        } else if let Some(fmt) = &self.attrs.fmt {
+            Some(fmt.original)
+        } else {
+            None
+        } {
+            return Err(Error::new_spanned(
+                unexpected_display_attr,
+                "not expected here; the #[error(...)] attribute belongs on top of a struct or an enum variant",
+            ));
+        }
+        Ok(())
+    }
+}
+
+fn check_non_field_attrs(attrs: &Attrs) -> Result<()> {
+    if let Some(from) = &attrs.from {
+        return Err(Error::new_spanned(
+            from.original,
+            "not expected here; the #[from] attribute belongs on a specific field",
+        ));
+    }
+    if let Some(source) = &attrs.source {
+        return Err(Error::new_spanned(
+            source.original,
+            "not expected here; the #[source] attribute belongs on a specific field",
+        ));
+    }
+    if let Some(backtrace) = &attrs.backtrace {
+        return Err(Error::new_spanned(
+            backtrace,
+            "not expected here; the #[backtrace] attribute belongs on a specific field",
+        ));
+    }
+    if attrs.transparent.is_some() {
+        if let Some(display) = &attrs.display {
+            return Err(Error::new_spanned(
+                display.original,
+                "cannot have both #[error(transparent)] and a display attribute",
+            ));
+        }
+        if let Some(fmt) = &attrs.fmt {
+            return Err(Error::new_spanned(
+                fmt.original,
+                "cannot have both #[error(transparent)] and #[error(fmt = ...)]",
+            ));
+        }
+    } else if let (Some(display), Some(_)) = (&attrs.display, &attrs.fmt) {
+        return Err(Error::new_spanned(
+            display.original,
+            "cannot have both #[error(fmt = ...)] and a format arguments attribute",
+        ));
+    }
+
+    Ok(())
+}
+
+fn check_field_attrs(fields: &[Field]) -> Result<()> {
+    let mut from_field = None;
+    let mut source_field = None;
+    let mut backtrace_field = None;
+    let mut has_backtrace = false;
+    for field in fields {
+        if let Some(from) = field.attrs.from {
+            if from_field.is_some() {
+                return Err(Error::new_spanned(
+                    from.original,
+                    "duplicate #[from] attribute",
+                ));
+            }
+            from_field = Some(field);
+        }
+        if let Some(source) = field.attrs.source {
+            if source_field.is_some() {
+                return Err(Error::new_spanned(
+                    source.original,
+                    "duplicate #[source] attribute",
+                ));
+            }
+            source_field = Some(field);
+        }
+        if let Some(backtrace) = field.attrs.backtrace {
+            if backtrace_field.is_some() {
+                return Err(Error::new_spanned(
+                    backtrace,
+                    "duplicate #[backtrace] attribute",
+                ));
+            }
+            backtrace_field = Some(field);
+            has_backtrace = true;
+        }
+        if let Some(transparent) = field.attrs.transparent {
+            return Err(Error::new_spanned(
+                transparent.original,
+                "#[error(transparent)] needs to go outside the enum or struct, not on an individual field",
+            ));
+        }
+        has_backtrace |= field.is_backtrace();
+    }
+    if let (Some(from_field), Some(source_field)) = (from_field, source_field) {
+        if from_field.member != source_field.member {
+            return Err(Error::new_spanned(
+                from_field.attrs.from.unwrap().original,
+                "#[from] is only supported on the source field, not any other field",
+            ));
+        }
+    }
+    if let Some(from_field) = from_field {
+        let max_expected_fields = match backtrace_field {
+            Some(backtrace_field) => 1 + (from_field.member != backtrace_field.member) as usize,
+            None => 1 + has_backtrace as usize,
+        };
+        if fields.len() > max_expected_fields {
+            return Err(Error::new_spanned(
+                from_field.attrs.from.unwrap().original,
+                "deriving From requires no fields other than source and backtrace",
+            ));
+        }
+    }
+    if let Some(source_field) = source_field.or(from_field) {
+        if contains_non_static_lifetime(source_field.ty) {
+            return Err(Error::new_spanned(
+                &source_field.original.ty,
+                "non-static lifetimes are not allowed in the source of an error, because std::error::Error requires the source is dyn Error + 'static",
+            ));
+        }
+    }
+    Ok(())
+}
+
+fn contains_non_static_lifetime(ty: &Type) -> bool {
+    match ty {
+        Type::Path(ty) => {
+            let bracketed = match &ty.path.segments.last().unwrap().arguments {
+                PathArguments::AngleBracketed(bracketed) => bracketed,
+                _ => return false,
+            };
+            for arg in &bracketed.args {
+                match arg {
+                    GenericArgument::Type(ty) if contains_non_static_lifetime(ty) => return true,
+                    GenericArgument::Lifetime(lifetime) if lifetime.ident != "static" => {
+                        return true
+                    }
+                    _ => {}
+                }
+            }
+            false
+        }
+        Type::Reference(ty) => ty
+            .lifetime
+            .as_ref()
+            .map_or(false, |lifetime| lifetime.ident != "static"),
+        _ => false, // maybe implement later if there are common other cases
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/.cargo-checksum.json b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/.cargo-checksum.json
new file mode 100644
index 0000000..697c9ce
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{}}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/.cargo_vcs_info.json b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/.cargo_vcs_info.json
new file mode 100644
index 0000000..559c8b27
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+  "git": {
+    "sha1": "72ae716e6d6a7f7fdabdc394018c745b4d39ca45"
+  },
+  "path_in_vcs": ""
+}
\ No newline at end of file
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/.github/FUNDING.yml b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/.github/FUNDING.yml
new file mode 100644
index 0000000..7507077
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/.github/FUNDING.yml
@@ -0,0 +1 @@
+github: dtolnay
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/.github/workflows/ci.yml b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/.github/workflows/ci.yml
new file mode 100644
index 0000000..f682c34
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/.github/workflows/ci.yml
@@ -0,0 +1,128 @@
+name: CI
+
+on:
+  push:
+  pull_request:
+  workflow_dispatch:
+  schedule: [cron: "40 1 * * *"]
+
+permissions:
+  contents: read
+
+env:
+  RUSTFLAGS: -Dwarnings
+
+jobs:
+  pre_ci:
+    uses: dtolnay/.github/.github/workflows/pre_ci.yml@master
+
+  test:
+    name: Rust ${{matrix.rust}}
+    needs: pre_ci
+    if: needs.pre_ci.outputs.continue
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        rust: [nightly, beta, stable, 1.81.0, 1.76.0]
+    timeout-minutes: 45
+    steps:
+      - uses: actions/checkout@v5
+      - uses: dtolnay/rust-toolchain@master
+        with:
+          toolchain: ${{matrix.rust}}
+          components: rust-src
+      - name: Enable type layout randomization
+        run: echo RUSTFLAGS=${RUSTFLAGS}\ -Zrandomize-layout >> $GITHUB_ENV
+        if: matrix.rust == 'nightly'
+      - name: Enable nightly-only tests
+        run: echo RUSTFLAGS=${RUSTFLAGS}\ --cfg=thiserror_nightly_testing >> $GITHUB_ENV
+        if: matrix.rust == 'nightly'
+      - run: cargo test --workspace --exclude thiserror_no_std_test
+      - run: cargo test --manifest-path tests/no-std/Cargo.toml
+        if: matrix.rust != '1.76.0'
+      - run: cargo test --no-default-features
+      - uses: actions/upload-artifact@v4
+        if: matrix.rust == 'nightly' && always()
+        with:
+          name: Cargo.lock
+          path: Cargo.lock
+        continue-on-error: true
+
+  msrv:
+    name: Rust 1.61.0
+    needs: pre_ci
+    if: needs.pre_ci.outputs.continue
+    runs-on: ubuntu-latest
+    timeout-minutes: 45
+    steps:
+      - uses: actions/checkout@v5
+      - uses: dtolnay/rust-toolchain@1.61.0
+        with:
+          components: rust-src
+      - run: cargo check
+
+  minimal:
+    name: Minimal versions
+    needs: pre_ci
+    if: needs.pre_ci.outputs.continue
+    runs-on: ubuntu-latest
+    timeout-minutes: 45
+    steps:
+      - uses: actions/checkout@v5
+      - uses: dtolnay/rust-toolchain@nightly
+      - run: cargo generate-lockfile -Z minimal-versions
+      - run: cargo check --locked
+
+  doc:
+    name: Documentation
+    needs: pre_ci
+    if: needs.pre_ci.outputs.continue
+    runs-on: ubuntu-latest
+    timeout-minutes: 45
+    env:
+      RUSTDOCFLAGS: -Dwarnings
+    steps:
+      - uses: actions/checkout@v5
+      - uses: dtolnay/rust-toolchain@nightly
+        with:
+          components: rust-src
+      - uses: dtolnay/install@cargo-docs-rs
+      - run: cargo docs-rs
+
+  clippy:
+    name: Clippy
+    runs-on: ubuntu-latest
+    if: github.event_name != 'pull_request'
+    timeout-minutes: 45
+    steps:
+      - uses: actions/checkout@v5
+      - uses: dtolnay/rust-toolchain@nightly
+        with:
+          components: clippy, rust-src
+      - run: cargo clippy --tests --workspace -- -Dclippy::all -Dclippy::pedantic
+
+  miri:
+    name: Miri
+    needs: pre_ci
+    if: needs.pre_ci.outputs.continue
+    runs-on: ubuntu-latest
+    timeout-minutes: 45
+    steps:
+      - uses: actions/checkout@v5
+      - uses: dtolnay/rust-toolchain@miri
+      - run: cargo miri setup
+      - run: cargo miri test
+        env:
+          MIRIFLAGS: -Zmiri-strict-provenance
+
+  outdated:
+    name: Outdated
+    runs-on: ubuntu-latest
+    if: github.event_name != 'pull_request'
+    timeout-minutes: 45
+    steps:
+      - uses: actions/checkout@v5
+      - uses: dtolnay/rust-toolchain@stable
+      - uses: dtolnay/install@cargo-outdated
+      - run: cargo outdated --workspace --exit-code 1
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/.gitignore b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/.gitignore
new file mode 100644
index 0000000..e9e21997
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/.gitignore
@@ -0,0 +1,2 @@
+/target/
+/Cargo.lock
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/Cargo.lock b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/Cargo.lock
new file mode 100644
index 0000000..67bd15f
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/Cargo.lock
@@ -0,0 +1,295 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "anyhow"
+version = "1.0.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
+
+[[package]]
+name = "dissimilar"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8975ffdaa0ef3661bfe02dbdcc06c9f829dfafe6a3c474de366a8d5e44276921"
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
+name = "glob"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
+
+[[package]]
+name = "hashbrown"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
+
+[[package]]
+name = "indexmap"
+version = "2.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+
+[[package]]
+name = "memchr"
+version = "2.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.101"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "ref-cast"
+version = "1.0.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d"
+dependencies = [
+ "ref-cast-impl",
+]
+
+[[package]]
+name = "ref-cast-impl"
+version = "1.0.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
+
+[[package]]
+name = "ryu"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
+
+[[package]]
+name = "serde"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.145"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+ "serde_core",
+]
+
+[[package]]
+name = "serde_spanned"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5417783452c2be558477e104686f7de5dae53dba813c28435e0e70f82d9b04ee"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "target-triple"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ac9aa371f599d22256307c24a9d748c041e548cbf599f35d890f9d365361790"
+
+[[package]]
+name = "termcolor"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.17"
+dependencies = [
+ "anyhow",
+ "ref-cast",
+ "rustversion",
+ "thiserror-impl",
+ "trybuild",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "toml"
+version = "0.9.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00e5e5d9bf2475ac9d4f0d9edab68cc573dc2fd644b0dba36b0c30a92dd9eaa0"
+dependencies = [
+ "indexmap",
+ "serde_core",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_parser",
+ "toml_writer",
+ "winnow",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "toml_parser"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627"
+dependencies = [
+ "winnow",
+]
+
+[[package]]
+name = "toml_writer"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d163a63c116ce562a22cda521fcc4d79152e7aba014456fb5eb442f6d6a10109"
+
+[[package]]
+name = "trybuild"
+version = "1.0.111"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ded9fdb81f30a5708920310bfcd9ea7482ff9cba5f54601f7a19a877d5c2392"
+dependencies = [
+ "dissimilar",
+ "glob",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "target-triple",
+ "termcolor",
+ "toml",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65"
+
+[[package]]
+name = "windows-sys"
+version = "0.61.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "winnow"
+version = "0.7.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf"
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/Cargo.toml b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/Cargo.toml
new file mode 100644
index 0000000..59458a18
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/Cargo.toml
@@ -0,0 +1,119 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2021"
+rust-version = "1.61"
+name = "thiserror"
+version = "2.0.17"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+build = "build.rs"
+autolib = false
+autobins = false
+autoexamples = false
+autotests = false
+autobenches = false
+description = "derive(Error)"
+documentation = "https://docs.rs/thiserror"
+readme = "README.md"
+keywords = [
+    "error",
+    "error-handling",
+    "derive",
+]
+categories = [
+    "rust-patterns",
+    "no-std",
+]
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/dtolnay/thiserror"
+
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
+rustdoc-args = [
+    "--generate-link-to-definition",
+    "--generate-macro-expansion",
+    "--extern-html-root-url=core=https://doc.rust-lang.org",
+    "--extern-html-root-url=alloc=https://doc.rust-lang.org",
+    "--extern-html-root-url=std=https://doc.rust-lang.org",
+]
+
+[features]
+default = ["std"]
+std = []
+
+[lib]
+name = "thiserror"
+path = "src/lib.rs"
+
+[[test]]
+name = "compiletest"
+path = "tests/compiletest.rs"
+
+[[test]]
+name = "test_backtrace"
+path = "tests/test_backtrace.rs"
+
+[[test]]
+name = "test_display"
+path = "tests/test_display.rs"
+
+[[test]]
+name = "test_error"
+path = "tests/test_error.rs"
+
+[[test]]
+name = "test_expr"
+path = "tests/test_expr.rs"
+
+[[test]]
+name = "test_from"
+path = "tests/test_from.rs"
+
+[[test]]
+name = "test_generics"
+path = "tests/test_generics.rs"
+
+[[test]]
+name = "test_lints"
+path = "tests/test_lints.rs"
+
+[[test]]
+name = "test_option"
+path = "tests/test_option.rs"
+
+[[test]]
+name = "test_path"
+path = "tests/test_path.rs"
+
+[[test]]
+name = "test_source"
+path = "tests/test_source.rs"
+
+[[test]]
+name = "test_transparent"
+path = "tests/test_transparent.rs"
+
+[dependencies.thiserror-impl]
+version = "=2.0.17"
+
+[dev-dependencies.anyhow]
+version = "1.0.73"
+
+[dev-dependencies.ref-cast]
+version = "1.0.18"
+
+[dev-dependencies.rustversion]
+version = "1.0.13"
+
+[dev-dependencies.trybuild]
+version = "1.0.108"
+features = ["diff"]
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/Cargo.toml.orig b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/Cargo.toml.orig
new file mode 100644
index 0000000..28718d7f
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/Cargo.toml.orig
@@ -0,0 +1,50 @@
+[package]
+name = "thiserror"
+version = "2.0.17"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+categories = ["rust-patterns", "no-std"]
+description = "derive(Error)"
+documentation = "https://docs.rs/thiserror"
+edition = "2021"
+keywords = ["error", "error-handling", "derive"]
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/dtolnay/thiserror"
+rust-version = "1.61"
+
+[features]
+default = ["std"]
+
+# Std feature enables support for formatting std::path::{Path, PathBuf}
+# conveniently in an error message.
+#
+#     #[derive(Error, Debug)]
+#     #[error("failed to create configuration file {path}")]
+#     pub struct MyError {
+#         pub path: PathBuf,
+#         pub source: std::io::Error,
+#     }
+#
+# Without std, this would need to be written #[error("... {}", path.display())].
+std = []
+
+[dependencies]
+thiserror-impl = { version = "=2.0.17", path = "impl" }
+
+[dev-dependencies]
+anyhow = "1.0.73"
+ref-cast = "1.0.18"
+rustversion = "1.0.13"
+trybuild = { version = "1.0.108", features = ["diff"] }
+
+[workspace]
+members = ["impl", "tests/no-std"]
+
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
+rustdoc-args = [
+    "--generate-link-to-definition",
+    "--generate-macro-expansion",
+    "--extern-html-root-url=core=https://doc.rust-lang.org",
+    "--extern-html-root-url=alloc=https://doc.rust-lang.org",
+    "--extern-html-root-url=std=https://doc.rust-lang.org",
+]
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/LICENSE-APACHE b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/LICENSE-APACHE
new file mode 100644
index 0000000..1b5ec8b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/LICENSE-APACHE
@@ -0,0 +1,176 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/LICENSE-MIT b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/LICENSE-MIT
new file mode 100644
index 0000000..31aa7938
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/LICENSE-MIT
@@ -0,0 +1,23 @@
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/README.md b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/README.md
new file mode 100644
index 0000000..6519e045
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/README.md
@@ -0,0 +1,238 @@
+derive(Error)
+=============
+
+[<img alt="github" src="https://img.shields.io/badge/github-dtolnay/thiserror-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/dtolnay/thiserror)
+[<img alt="crates.io" src="https://img.shields.io/crates/v/thiserror.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/thiserror)
+[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-thiserror-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/thiserror)
+[<img alt="build status" src="https://img.shields.io/github/actions/workflow/status/dtolnay/thiserror/ci.yml?branch=master&style=for-the-badge" height="20">](https://github.com/dtolnay/thiserror/actions?query=branch%3Amaster)
+
+This library provides a convenient derive macro for the standard library's
+[`std::error::Error`] trait.
+
+[`std::error::Error`]: https://doc.rust-lang.org/std/error/trait.Error.html
+
+```toml
+[dependencies]
+thiserror = "2"
+```
+
+*Compiler support: requires rustc 1.61+*
+
+<br>
+
+## Example
+
+```rust
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+pub enum DataStoreError {
+    #[error("data store disconnected")]
+    Disconnect(#[from] io::Error),
+    #[error("the data for key `{0}` is not available")]
+    Redaction(String),
+    #[error("invalid header (expected {expected:?}, found {found:?})")]
+    InvalidHeader {
+        expected: String,
+        found: String,
+    },
+    #[error("unknown data store error")]
+    Unknown,
+}
+```
+
+<br>
+
+## Details
+
+- Thiserror deliberately does not appear in your public API. You get the same
+  thing as if you had written an implementation of `std::error::Error` by hand,
+  and switching from handwritten impls to thiserror or vice versa is not a
+  breaking change.
+
+- Errors may be enums, structs with named fields, tuple structs, or unit
+  structs.
+
+- A `Display` impl is generated for your error if you provide `#[error("...")]`
+  messages on the struct or each variant of your enum, as shown above in the
+  example.
+
+  The messages support a shorthand for interpolating fields from the error.
+
+    - `#[error("{var}")]`&ensp;⟶&ensp;`write!("{}", self.var)`
+    - `#[error("{0}")]`&ensp;⟶&ensp;`write!("{}", self.0)`
+    - `#[error("{var:?}")]`&ensp;⟶&ensp;`write!("{:?}", self.var)`
+    - `#[error("{0:?}")]`&ensp;⟶&ensp;`write!("{:?}", self.0)`
+
+  These shorthands can be used together with any additional format args, which
+  may be arbitrary expressions. For example:
+
+  ```rust
+  #[derive(Error, Debug)]
+  pub enum Error {
+      #[error("invalid rdo_lookahead_frames {0} (expected < {max})", max = i32::MAX)]
+      InvalidLookahead(u32),
+  }
+  ```
+
+  If one of the additional expression arguments needs to refer to a field of the
+  struct or enum, then refer to named fields as `.var` and tuple fields as `.0`.
+
+  ```rust
+  #[derive(Error, Debug)]
+  pub enum Error {
+      #[error("first letter must be lowercase but was {:?}", first_char(.0))]
+      WrongCase(String),
+      #[error("invalid index {idx}, expected at least {} and at most {}", .limits.lo, .limits.hi)]
+      OutOfBounds { idx: usize, limits: Limits },
+  }
+  ```
+
+- A `From` impl is generated for each variant that contains a `#[from]`
+  attribute.
+
+  The variant using `#[from]` must not contain any other fields beyond the
+  source error (and possibly a backtrace &mdash; see below). Usually `#[from]`
+  fields are unnamed, but `#[from]` is allowed on a named field too.
+
+  ```rust
+  #[derive(Error, Debug)]
+  pub enum MyError {
+      Io(#[from] io::Error),
+      Glob(#[from] globset::Error),
+  }
+  ```
+
+- The Error trait's `source()` method is implemented to return whichever field
+  has a `#[source]` attribute or is named `source`, if any. This is for
+  identifying the underlying lower level error that caused your error.
+
+  The `#[from]` attribute always implies that the same field is `#[source]`, so
+  you don't ever need to specify both attributes.
+
+  Any error type that implements `std::error::Error` or dereferences to `dyn
+  std::error::Error` will work as a source.
+
+  ```rust
+  #[derive(Error, Debug)]
+  pub struct MyError {
+      msg: String,
+      #[source]  // optional if field name is `source`
+      source: anyhow::Error,
+  }
+  ```
+
+- The Error trait's `provide()` method is implemented to provide whichever field
+  has a type named `Backtrace`, if any, as a `std::backtrace::Backtrace`. Using
+  `Backtrace` in errors requires a nightly compiler with Rust version 1.73 or
+  newer.
+
+  ```rust
+  use std::backtrace::Backtrace;
+
+  #[derive(Error, Debug)]
+  pub struct MyError {
+      msg: String,
+      backtrace: Backtrace,  // automatically detected
+  }
+  ```
+
+- If a field is both a source (named `source`, or has `#[source]` or `#[from]`
+  attribute) *and* is marked `#[backtrace]`, then the Error trait's `provide()`
+  method is forwarded to the source's `provide` so that both layers of the error
+  share the same backtrace. The `#[backtrace]` attribute requires a nightly
+  compiler with Rust version 1.73 or newer.
+
+
+  ```rust
+  #[derive(Error, Debug)]
+  pub enum MyError {
+      Io {
+          #[backtrace]
+          source: io::Error,
+      },
+  }
+  ```
+
+- For variants that use `#[from]` and also contain a `Backtrace` field, a
+  backtrace is captured from within the `From` impl.
+
+  ```rust
+  #[derive(Error, Debug)]
+  pub enum MyError {
+      Io {
+          #[from]
+          source: io::Error,
+          backtrace: Backtrace,
+      },
+  }
+  ```
+
+- Errors may use `error(transparent)` to forward the source and Display methods
+  straight through to an underlying error without adding an additional message.
+  This would be appropriate for enums that need an "anything else" variant.
+
+  ```rust
+  #[derive(Error, Debug)]
+  pub enum MyError {
+      ...
+
+      #[error(transparent)]
+      Other(#[from] anyhow::Error),  // source and Display delegate to anyhow::Error
+  }
+  ```
+
+  Another use case is hiding implementation details of an error representation
+  behind an opaque error type, so that the representation is able to evolve
+  without breaking the crate's public API.
+
+  ```rust
+  // PublicError is public, but opaque and easy to keep compatible.
+  #[derive(Error, Debug)]
+  #[error(transparent)]
+  pub struct PublicError(#[from] ErrorRepr);
+
+  impl PublicError {
+      // Accessors for anything we do want to expose publicly.
+  }
+
+  // Private and free to change across minor version of the crate.
+  #[derive(Error, Debug)]
+  enum ErrorRepr {
+      ...
+  }
+  ```
+
+- See also the [`anyhow`] library for a convenient single error type to use in
+  application code.
+
+  [`anyhow`]: https://github.com/dtolnay/anyhow
+
+<br>
+
+## Comparison to anyhow
+
+Use thiserror if you care about designing your own dedicated error type(s) so
+that the caller receives exactly the information that you choose in the event of
+failure. This most often applies to library-like code. Use [Anyhow] if you don't
+care what error type your functions return, you just want it to be easy. This is
+common in application-like code.
+
+[Anyhow]: https://github.com/dtolnay/anyhow
+
+<br>
+
+#### License
+
+<sup>
+Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
+2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
+</sup>
+
+<br>
+
+<sub>
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in this crate by you, as defined in the Apache-2.0 license, shall
+be dual licensed as above, without any additional terms or conditions.
+</sub>
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/build.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/build.rs
new file mode 100644
index 0000000..3b9fb32
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/build.rs
@@ -0,0 +1,196 @@
+use std::env;
+use std::ffi::OsString;
+use std::fs;
+use std::io::ErrorKind;
+use std::iter;
+use std::path::{Path, PathBuf};
+use std::process::{self, Command, Stdio};
+use std::str;
+
+const PRIVATE: &str = "\
+#[doc(hidden)]
+pub mod __private$$ {
+    #[doc(hidden)]
+    pub use crate::private::*;
+}
+";
+
+fn main() {
+    println!("cargo:rerun-if-changed=build/probe.rs");
+
+    println!("cargo:rustc-check-cfg=cfg(error_generic_member_access)");
+    println!("cargo:rustc-check-cfg=cfg(thiserror_nightly_testing)");
+    println!("cargo:rustc-check-cfg=cfg(thiserror_no_backtrace_type)");
+
+    let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
+    let patch_version = env::var("CARGO_PKG_VERSION_PATCH").unwrap();
+    let module = PRIVATE.replace("$$", &patch_version);
+    fs::write(out_dir.join("private.rs"), module).unwrap();
+
+    let error_generic_member_access;
+    let consider_rustc_bootstrap;
+    if compile_probe(false) {
+        // This is a nightly or dev compiler, so it supports unstable features
+        // regardless of RUSTC_BOOTSTRAP. No need to rerun build script if
+        // RUSTC_BOOTSTRAP is changed.
+        error_generic_member_access = true;
+        consider_rustc_bootstrap = false;
+    } else if let Some(rustc_bootstrap) = env::var_os("RUSTC_BOOTSTRAP") {
+        if compile_probe(true) {
+            // This is a stable or beta compiler for which the user has set
+            // RUSTC_BOOTSTRAP to turn on unstable features. Rerun build script
+            // if they change it.
+            error_generic_member_access = true;
+            consider_rustc_bootstrap = true;
+        } else if rustc_bootstrap == "1" {
+            // This compiler does not support the generic member access API in
+            // the form that thiserror expects. No need to pay attention to
+            // RUSTC_BOOTSTRAP.
+            error_generic_member_access = false;
+            consider_rustc_bootstrap = false;
+        } else {
+            // This is a stable or beta compiler for which RUSTC_BOOTSTRAP is
+            // set to restrict the use of unstable features by this crate.
+            error_generic_member_access = false;
+            consider_rustc_bootstrap = true;
+        }
+    } else {
+        // Without RUSTC_BOOTSTRAP, this compiler does not support the generic
+        // member access API in the form that thiserror expects, but try again
+        // if the user turns on unstable features.
+        error_generic_member_access = false;
+        consider_rustc_bootstrap = true;
+    }
+
+    if error_generic_member_access {
+        println!("cargo:rustc-cfg=error_generic_member_access");
+    }
+
+    if consider_rustc_bootstrap {
+        println!("cargo:rerun-if-env-changed=RUSTC_BOOTSTRAP");
+    }
+
+    // core::error::Error stabilized in Rust 1.81
+    // https://blog.rust-lang.org/2024/09/05/Rust-1.81.0.html#coreerrorerror
+    let rustc = rustc_minor_version();
+    if cfg!(not(feature = "std")) && rustc.map_or(false, |rustc| rustc < 81) {
+        println!("cargo:rustc-cfg=feature=\"std\"");
+    }
+
+    let rustc = match rustc {
+        Some(rustc) => rustc,
+        None => return,
+    };
+
+    // std::backtrace::Backtrace stabilized in Rust 1.65
+    // https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#stabilized-apis
+    if rustc < 65 {
+        println!("cargo:rustc-cfg=thiserror_no_backtrace_type");
+    }
+}
+
+fn compile_probe(rustc_bootstrap: bool) -> bool {
+    if env::var_os("RUSTC_STAGE").is_some() {
+        // We are running inside rustc bootstrap. This is a highly non-standard
+        // environment with issues such as:
+        //
+        //     https://github.com/rust-lang/cargo/issues/11138
+        //     https://github.com/rust-lang/rust/issues/114839
+        //
+        // Let's just not use nightly features here.
+        return false;
+    }
+
+    let rustc = cargo_env_var("RUSTC");
+    let out_dir = cargo_env_var("OUT_DIR");
+    let out_subdir = Path::new(&out_dir).join("probe");
+    let probefile = Path::new("build").join("probe.rs");
+
+    if let Err(err) = fs::create_dir(&out_subdir) {
+        if err.kind() != ErrorKind::AlreadyExists {
+            eprintln!("Failed to create {}: {}", out_subdir.display(), err);
+            process::exit(1);
+        }
+    }
+
+    let rustc_wrapper = env::var_os("RUSTC_WRAPPER").filter(|wrapper| !wrapper.is_empty());
+    let rustc_workspace_wrapper =
+        env::var_os("RUSTC_WORKSPACE_WRAPPER").filter(|wrapper| !wrapper.is_empty());
+    let mut rustc = rustc_wrapper
+        .into_iter()
+        .chain(rustc_workspace_wrapper)
+        .chain(iter::once(rustc));
+    let mut cmd = Command::new(rustc.next().unwrap());
+    cmd.args(rustc);
+
+    if !rustc_bootstrap {
+        cmd.env_remove("RUSTC_BOOTSTRAP");
+    }
+
+    cmd.stderr(Stdio::null())
+        .arg("--edition=2018")
+        .arg("--crate-name=thiserror")
+        .arg("--crate-type=lib")
+        .arg("--cap-lints=allow")
+        .arg("--emit=dep-info,metadata")
+        .arg("--out-dir")
+        .arg(&out_subdir)
+        .arg(probefile);
+
+    if let Some(target) = env::var_os("TARGET") {
+        cmd.arg("--target").arg(target);
+    }
+
+    // If Cargo wants to set RUSTFLAGS, use that.
+    if let Ok(rustflags) = env::var("CARGO_ENCODED_RUSTFLAGS") {
+        if !rustflags.is_empty() {
+            for arg in rustflags.split('\x1f') {
+                cmd.arg(arg);
+            }
+        }
+    }
+
+    let success = match cmd.status() {
+        Ok(status) => status.success(),
+        Err(_) => false,
+    };
+
+    // Clean up to avoid leaving nondeterministic absolute paths in the dep-info
+    // file in OUT_DIR, which causes nonreproducible builds in build systems
+    // that treat the entire OUT_DIR as an artifact.
+    if let Err(err) = fs::remove_dir_all(&out_subdir) {
+        // libc::ENOTEMPTY
+        // Some filesystems (NFSv3) have timing issues under load where '.nfs*'
+        // dummy files can continue to get created for a short period after the
+        // probe command completes, breaking remove_dir_all.
+        // To be replaced with ErrorKind::DirectoryNotEmpty (Rust 1.83+).
+        const ENOTEMPTY: i32 = 39;
+
+        if !(err.kind() == ErrorKind::NotFound
+            || (cfg!(target_os = "linux") && err.raw_os_error() == Some(ENOTEMPTY)))
+        {
+            eprintln!("Failed to clean up {}: {}", out_subdir.display(), err);
+            process::exit(1);
+        }
+    }
+
+    success
+}
+
+fn rustc_minor_version() -> Option<u32> {
+    let rustc = cargo_env_var("RUSTC");
+    let output = Command::new(rustc).arg("--version").output().ok()?;
+    let version = str::from_utf8(&output.stdout).ok()?;
+    let mut pieces = version.split('.');
+    if pieces.next() != Some("rustc 1") {
+        return None;
+    }
+    pieces.next()?.parse().ok()
+}
+
+fn cargo_env_var(key: &str) -> OsString {
+    env::var_os(key).unwrap_or_else(|| {
+        eprintln!("Environment variable ${key} is not set during execution of build script");
+        process::exit(1);
+    })
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/build/probe.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/build/probe.rs
new file mode 100644
index 0000000..ee126d4
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/build/probe.rs
@@ -0,0 +1,33 @@
+// This code exercises the surface area that we expect of the Error generic
+// member access API. If the current toolchain is able to compile it, then
+// thiserror is able to provide backtrace support.
+
+#![no_std]
+#![feature(error_generic_member_access)]
+
+use core::error::{Error, Request};
+use core::fmt::{self, Debug, Display};
+
+struct MyError(Thing);
+struct Thing;
+
+impl Debug for MyError {
+    fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
+        unimplemented!()
+    }
+}
+
+impl Display for MyError {
+    fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
+        unimplemented!()
+    }
+}
+
+impl Error for MyError {
+    fn provide<'a>(&'a self, request: &mut Request<'a>) {
+        request.provide_ref(&self.0);
+    }
+}
+
+// Include in sccache cache key.
+const _: Option<&str> = option_env!("RUSTC_BOOTSTRAP");
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/rust-toolchain.toml b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/rust-toolchain.toml
new file mode 100644
index 0000000..20fe888
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/rust-toolchain.toml
@@ -0,0 +1,2 @@
+[toolchain]
+components = ["rust-src"]
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/aserror.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/aserror.rs
new file mode 100644
index 0000000..ac91cc8
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/aserror.rs
@@ -0,0 +1,50 @@
+use core::error::Error;
+use core::panic::UnwindSafe;
+
+#[doc(hidden)]
+pub trait AsDynError<'a>: Sealed {
+    fn as_dyn_error(&self) -> &(dyn Error + 'a);
+}
+
+impl<'a, T: Error + 'a> AsDynError<'a> for T {
+    #[inline]
+    fn as_dyn_error(&self) -> &(dyn Error + 'a) {
+        self
+    }
+}
+
+impl<'a> AsDynError<'a> for dyn Error + 'a {
+    #[inline]
+    fn as_dyn_error(&self) -> &(dyn Error + 'a) {
+        self
+    }
+}
+
+impl<'a> AsDynError<'a> for dyn Error + Send + 'a {
+    #[inline]
+    fn as_dyn_error(&self) -> &(dyn Error + 'a) {
+        self
+    }
+}
+
+impl<'a> AsDynError<'a> for dyn Error + Send + Sync + 'a {
+    #[inline]
+    fn as_dyn_error(&self) -> &(dyn Error + 'a) {
+        self
+    }
+}
+
+impl<'a> AsDynError<'a> for dyn Error + Send + Sync + UnwindSafe + 'a {
+    #[inline]
+    fn as_dyn_error(&self) -> &(dyn Error + 'a) {
+        self
+    }
+}
+
+#[doc(hidden)]
+pub trait Sealed {}
+impl<T: Error> Sealed for T {}
+impl Sealed for dyn Error + '_ {}
+impl Sealed for dyn Error + Send + '_ {}
+impl Sealed for dyn Error + Send + Sync + '_ {}
+impl Sealed for dyn Error + Send + Sync + UnwindSafe + '_ {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/display.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/display.rs
new file mode 100644
index 0000000..e544657b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/display.rs
@@ -0,0 +1,82 @@
+use core::fmt::Display;
+#[cfg(feature = "std")]
+use std::path::{self, Path, PathBuf};
+
+#[doc(hidden)]
+pub trait AsDisplay<'a>: Sealed {
+    // TODO: convert to generic associated type.
+    // https://github.com/dtolnay/thiserror/pull/253
+    type Target: Display;
+
+    fn as_display(&'a self) -> Self::Target;
+}
+
+impl<'a, T> AsDisplay<'a> for &T
+where
+    T: Display + ?Sized + 'a,
+{
+    type Target = &'a T;
+
+    fn as_display(&'a self) -> Self::Target {
+        *self
+    }
+}
+
+#[cfg(feature = "std")]
+impl<'a> AsDisplay<'a> for Path {
+    type Target = path::Display<'a>;
+
+    #[inline]
+    fn as_display(&'a self) -> Self::Target {
+        self.display()
+    }
+}
+
+#[cfg(feature = "std")]
+impl<'a> AsDisplay<'a> for PathBuf {
+    type Target = path::Display<'a>;
+
+    #[inline]
+    fn as_display(&'a self) -> Self::Target {
+        self.display()
+    }
+}
+
+#[doc(hidden)]
+pub trait Sealed {}
+impl<T: Display + ?Sized> Sealed for &T {}
+#[cfg(feature = "std")]
+impl Sealed for Path {}
+#[cfg(feature = "std")]
+impl Sealed for PathBuf {}
+
+// Add a synthetic second impl of AsDisplay to prevent the "single applicable
+// impl" rule from making too weird inference decision based on the single impl
+// for &T, which could lead to code that compiles with thiserror's std feature
+// off but breaks under feature unification when std is turned on by an
+// unrelated crate.
+#[cfg(not(feature = "std"))]
+mod placeholder {
+    use super::{AsDisplay, Sealed};
+    use core::fmt::{self, Display};
+
+    #[allow(dead_code)]
+    pub struct Placeholder;
+
+    impl<'a> AsDisplay<'a> for Placeholder {
+        type Target = Self;
+
+        #[inline]
+        fn as_display(&'a self) -> Self::Target {
+            Placeholder
+        }
+    }
+
+    impl Display for Placeholder {
+        fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
+            unreachable!()
+        }
+    }
+
+    impl Sealed for Placeholder {}
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/lib.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/lib.rs
new file mode 100644
index 0000000..155272d
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/lib.rs
@@ -0,0 +1,291 @@
+//! [![github]](https://github.com/dtolnay/thiserror)&ensp;[![crates-io]](https://crates.io/crates/thiserror)&ensp;[![docs-rs]](https://docs.rs/thiserror)
+//!
+//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
+//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
+//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
+//!
+//! <br>
+//!
+//! This library provides a convenient derive macro for the standard library's
+//! [`std::error::Error`] trait.
+//!
+//! <br>
+//!
+//! # Example
+//!
+//! ```rust
+//! # use std::io;
+//! use thiserror::Error;
+//!
+//! #[derive(Error, Debug)]
+//! pub enum DataStoreError {
+//!     #[error("data store disconnected")]
+//!     Disconnect(#[from] io::Error),
+//!     #[error("the data for key `{0}` is not available")]
+//!     Redaction(String),
+//!     #[error("invalid header (expected {expected:?}, found {found:?})")]
+//!     InvalidHeader {
+//!         expected: String,
+//!         found: String,
+//!     },
+//!     #[error("unknown data store error")]
+//!     Unknown,
+//! }
+//! ```
+//!
+//! <br>
+//!
+//! # Details
+//!
+//! - Thiserror deliberately does not appear in your public API. You get the
+//!   same thing as if you had written an implementation of
+//!   [`std::error::Error`] by hand, and switching from handwritten impls to
+//!   thiserror or vice versa is not a breaking change.
+//!
+//! - Errors may be enums, structs with named fields, tuple structs, or unit
+//!   structs.
+//!
+//! - A [`Display`] impl is generated for your error if you provide
+//!   `#[error("...")]` messages on the struct or each variant of your enum, as
+//!   shown above in the example.
+//!
+//!   The messages support a shorthand for interpolating fields from the error.
+//!
+//!     - `#[error("{var}")]`&ensp;⟶&ensp;`write!("{}", self.var)`
+//!     - `#[error("{0}")]`&ensp;⟶&ensp;`write!("{}", self.0)`
+//!     - `#[error("{var:?}")]`&ensp;⟶&ensp;`write!("{:?}", self.var)`
+//!     - `#[error("{0:?}")]`&ensp;⟶&ensp;`write!("{:?}", self.0)`
+//!
+//!   These shorthands can be used together with any additional format args,
+//!   which may be arbitrary expressions. For example:
+//!
+//!   ```rust
+//!   # use core::i32;
+//!   # use thiserror::Error;
+//!   #
+//!   #[derive(Error, Debug)]
+//!   pub enum Error {
+//!       #[error("invalid rdo_lookahead_frames {0} (expected < {max})", max = i32::MAX)]
+//!       InvalidLookahead(u32),
+//!   }
+//!   ```
+//!
+//!   If one of the additional expression arguments needs to refer to a field of
+//!   the struct or enum, then refer to named fields as `.var` and tuple fields
+//!   as `.0`.
+//!
+//!   ```rust
+//!   # use thiserror::Error;
+//!   #
+//!   # fn first_char(s: &String) -> char {
+//!   #     s.chars().next().unwrap()
+//!   # }
+//!   #
+//!   # #[derive(Debug)]
+//!   # struct Limits {
+//!   #     lo: usize,
+//!   #     hi: usize,
+//!   # }
+//!   #
+//!   #[derive(Error, Debug)]
+//!   pub enum Error {
+//!       #[error("first letter must be lowercase but was {:?}", first_char(.0))]
+//!       WrongCase(String),
+//!       #[error("invalid index {idx}, expected at least {} and at most {}", .limits.lo, .limits.hi)]
+//!       OutOfBounds { idx: usize, limits: Limits },
+//!   }
+//!   ```
+//!
+//! - A [`From`] impl is generated for each variant that contains a `#[from]`
+//!   attribute.
+//!
+//!   The variant using `#[from]` must not contain any other fields beyond the
+//!   source error (and possibly a backtrace &mdash; see below). Usually
+//!   `#[from]` fields are unnamed, but `#[from]` is allowed on a named field
+//!   too.
+//!
+//!   ```rust
+//!   # use core::fmt::{self, Display};
+//!   # use std::io;
+//!   # use thiserror::Error;
+//!   #
+//!   # mod globset {
+//!   #     #[derive(thiserror::Error, Debug)]
+//!   #     #[error("...")]
+//!   #     pub struct Error;
+//!   # }
+//!   #
+//!   #[derive(Error, Debug)]
+//!   pub enum MyError {
+//!       Io(#[from] io::Error),
+//!       Glob(#[from] globset::Error),
+//!   }
+//!   #
+//!   # impl Display for MyError {
+//!   #     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+//!   #         unimplemented!()
+//!   #     }
+//!   # }
+//!   ```
+//!
+//! - The Error trait's [`source()`] method is implemented to return whichever
+//!   field has a `#[source]` attribute or is named `source`, if any. This is
+//!   for identifying the underlying lower level error that caused your error.
+//!
+//!   The `#[from]` attribute always implies that the same field is `#[source]`,
+//!   so you don't ever need to specify both attributes.
+//!
+//!   Any error type that implements `std::error::Error` or dereferences to `dyn
+//!   std::error::Error` will work as a source.
+//!
+//!   ```rust
+//!   # use core::fmt::{self, Display};
+//!   # use thiserror::Error;
+//!   #
+//!   #[derive(Error, Debug)]
+//!   pub struct MyError {
+//!       msg: String,
+//!       #[source]  // optional if field name is `source`
+//!       source: anyhow::Error,
+//!   }
+//!   #
+//!   # impl Display for MyError {
+//!   #     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+//!   #         unimplemented!()
+//!   #     }
+//!   # }
+//!   ```
+//!
+//! - The Error trait's [`provide()`] method is implemented to provide whichever
+//!   field has a type named `Backtrace`, if any, as a
+//!   [`std::backtrace::Backtrace`]. Using `Backtrace` in errors requires a
+//!   nightly compiler with Rust version 1.73 or newer.
+//!
+//!   ```rust
+//!   # const IGNORE: &str = stringify! {
+//!   use std::backtrace::Backtrace;
+//!
+//!   #[derive(Error, Debug)]
+//!   pub struct MyError {
+//!       msg: String,
+//!       backtrace: Backtrace,  // automatically detected
+//!   }
+//!   # };
+//!   ```
+//!
+//! - If a field is both a source (named `source`, or has `#[source]` or
+//!   `#[from]` attribute) *and* is marked `#[backtrace]`, then the Error
+//!   trait's [`provide()`] method is forwarded to the source's `provide` so
+//!   that both layers of the error share the same backtrace. The `#[backtrace]`
+//!   attribute requires a nightly compiler with Rust version 1.73 or newer.
+//!
+//!   ```rust
+//!   # const IGNORE: &str = stringify! {
+//!   #[derive(Error, Debug)]
+//!   pub enum MyError {
+//!       Io {
+//!           #[backtrace]
+//!           source: io::Error,
+//!       },
+//!   }
+//!   # };
+//!   ```
+//!
+//! - For variants that use `#[from]` and also contain a `Backtrace` field, a
+//!   backtrace is captured from within the `From` impl.
+//!
+//!   ```rust
+//!   # const IGNORE: &str = stringify! {
+//!   #[derive(Error, Debug)]
+//!   pub enum MyError {
+//!       Io {
+//!           #[from]
+//!           source: io::Error,
+//!           backtrace: Backtrace,
+//!       },
+//!   }
+//!   # };
+//!   ```
+//!
+//! - Errors may use `error(transparent)` to forward the source and [`Display`]
+//!   methods straight through to an underlying error without adding an
+//!   additional message. This would be appropriate for enums that need an
+//!   "anything else" variant.
+//!
+//!   ```
+//!   # use thiserror::Error;
+//!   #
+//!   #[derive(Error, Debug)]
+//!   pub enum MyError {
+//!       # /*
+//!       ...
+//!       # */
+//!
+//!       #[error(transparent)]
+//!       Other(#[from] anyhow::Error),  // source and Display delegate to anyhow::Error
+//!   }
+//!   ```
+//!
+//!   Another use case is hiding implementation details of an error
+//!   representation behind an opaque error type, so that the representation is
+//!   able to evolve without breaking the crate's public API.
+//!
+//!   ```
+//!   # use thiserror::Error;
+//!   #
+//!   // PublicError is public, but opaque and easy to keep compatible.
+//!   #[derive(Error, Debug)]
+//!   #[error(transparent)]
+//!   pub struct PublicError(#[from] ErrorRepr);
+//!
+//!   impl PublicError {
+//!       // Accessors for anything we do want to expose publicly.
+//!   }
+//!
+//!   // Private and free to change across minor version of the crate.
+//!   #[derive(Error, Debug)]
+//!   enum ErrorRepr {
+//!       # /*
+//!       ...
+//!       # */
+//!   }
+//!   ```
+//!
+//! - See also the [`anyhow`] library for a convenient single error type to use
+//!   in application code.
+//!
+//! [`anyhow`]: https://github.com/dtolnay/anyhow
+//! [`source()`]: std::error::Error::source
+//! [`provide()`]: std::error::Error::provide
+//! [`Display`]: std::fmt::Display
+
+#![no_std]
+#![doc(html_root_url = "https://docs.rs/thiserror/2.0.17")]
+#![allow(
+    clippy::elidable_lifetime_names,
+    clippy::module_name_repetitions,
+    clippy::needless_lifetimes,
+    clippy::return_self_not_must_use,
+    clippy::wildcard_imports
+)]
+#![cfg_attr(error_generic_member_access, feature(error_generic_member_access))]
+
+#[cfg(all(thiserror_nightly_testing, not(error_generic_member_access)))]
+compile_error!("Build script probe failed to compile.");
+
+#[cfg(feature = "std")]
+extern crate std;
+#[cfg(feature = "std")]
+extern crate std as core;
+
+mod aserror;
+mod display;
+#[cfg(error_generic_member_access)]
+mod provide;
+mod var;
+
+pub use thiserror_impl::*;
+
+mod private;
+
+include!(concat!(env!("OUT_DIR"), "/private.rs"));
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/private.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/private.rs
new file mode 100644
index 0000000..545aa8e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/private.rs
@@ -0,0 +1,14 @@
+#[doc(hidden)]
+pub use crate::aserror::AsDynError;
+#[doc(hidden)]
+pub use crate::display::AsDisplay;
+#[cfg(error_generic_member_access)]
+#[doc(hidden)]
+pub use crate::provide::ThiserrorProvide;
+#[doc(hidden)]
+pub use crate::var::Var;
+#[doc(hidden)]
+pub use core::error::Error;
+#[cfg(all(feature = "std", not(thiserror_no_backtrace_type)))]
+#[doc(hidden)]
+pub use std::backtrace::Backtrace;
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/provide.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/provide.rs
new file mode 100644
index 0000000..4b2f06a9
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/provide.rs
@@ -0,0 +1,20 @@
+use core::error::{Error, Request};
+
+#[doc(hidden)]
+pub trait ThiserrorProvide: Sealed {
+    fn thiserror_provide<'a>(&'a self, request: &mut Request<'a>);
+}
+
+impl<T> ThiserrorProvide for T
+where
+    T: Error + ?Sized,
+{
+    #[inline]
+    fn thiserror_provide<'a>(&'a self, request: &mut Request<'a>) {
+        self.provide(request);
+    }
+}
+
+#[doc(hidden)]
+pub trait Sealed {}
+impl<T: Error + ?Sized> Sealed for T {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/var.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/var.rs
new file mode 100644
index 0000000..ecfcd85
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/var.rs
@@ -0,0 +1,9 @@
+use core::fmt::{self, Pointer};
+
+pub struct Var<'a, T: ?Sized>(pub &'a T);
+
+impl<'a, T: Pointer + ?Sized> Pointer for Var<'a, T> {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        Pointer::fmt(self.0, formatter)
+    }
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/compiletest.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/compiletest.rs
new file mode 100644
index 0000000..23a6a06
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/compiletest.rs
@@ -0,0 +1,7 @@
+#[rustversion::attr(not(nightly), ignore = "requires nightly")]
+#[cfg_attr(miri, ignore = "incompatible with miri")]
+#[test]
+fn ui() {
+    let t = trybuild::TestCases::new();
+    t.compile_fail("tests/ui/*.rs");
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_backtrace.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_backtrace.rs
new file mode 100644
index 0000000..cc25676
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_backtrace.rs
@@ -0,0 +1,289 @@
+#![cfg(feature = "std")]
+#![cfg_attr(thiserror_nightly_testing, feature(error_generic_member_access))]
+
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[error("...")]
+pub struct Inner;
+
+#[cfg(thiserror_nightly_testing)]
+#[derive(Error, Debug)]
+#[error("...")]
+pub struct InnerBacktrace {
+    backtrace: std::backtrace::Backtrace,
+}
+
+#[cfg(thiserror_nightly_testing)]
+pub mod structs {
+    use super::{Inner, InnerBacktrace};
+    use std::backtrace::Backtrace;
+    use std::error::{self, Error};
+    use std::sync::Arc;
+    use thiserror::Error;
+
+    mod not_backtrace {
+        #[derive(Debug)]
+        pub struct Backtrace;
+    }
+
+    #[derive(Error, Debug)]
+    #[error("...")]
+    pub struct PlainBacktrace {
+        backtrace: Backtrace,
+    }
+
+    #[derive(Error, Debug)]
+    #[error("...")]
+    pub struct ExplicitBacktrace {
+        #[backtrace]
+        backtrace: Backtrace,
+    }
+
+    #[derive(Error, Debug)]
+    #[error("...")]
+    pub struct NotBacktrace {
+        backtrace: crate::structs::not_backtrace::r#Backtrace,
+    }
+
+    #[derive(Error, Debug)]
+    #[error("...")]
+    pub struct OptBacktrace {
+        #[backtrace]
+        backtrace: Option<Backtrace>,
+    }
+
+    #[derive(Error, Debug)]
+    #[error("...")]
+    pub struct ArcBacktrace {
+        #[backtrace]
+        backtrace: Arc<Backtrace>,
+    }
+
+    #[derive(Error, Debug)]
+    #[error("...")]
+    pub struct BacktraceFrom {
+        #[from]
+        source: Inner,
+        #[backtrace]
+        backtrace: Backtrace,
+    }
+
+    #[derive(Error, Debug)]
+    #[error("...")]
+    pub struct CombinedBacktraceFrom {
+        #[from]
+        #[backtrace]
+        source: InnerBacktrace,
+    }
+
+    #[derive(Error, Debug)]
+    #[error("...")]
+    pub struct OptBacktraceFrom {
+        #[from]
+        source: Inner,
+        #[backtrace]
+        backtrace: Option<Backtrace>,
+    }
+
+    #[derive(Error, Debug)]
+    #[error("...")]
+    pub struct ArcBacktraceFrom {
+        #[from]
+        source: Inner,
+        #[backtrace]
+        backtrace: Arc<Backtrace>,
+    }
+
+    #[derive(Error, Debug)]
+    #[error("...")]
+    pub struct AnyhowBacktrace {
+        #[backtrace]
+        source: anyhow::Error,
+    }
+
+    #[derive(Error, Debug)]
+    #[error("...")]
+    pub struct BoxDynErrorBacktrace {
+        #[backtrace]
+        source: Box<dyn Error>,
+    }
+
+    #[test]
+    fn test_backtrace() {
+        let error = PlainBacktrace {
+            backtrace: Backtrace::capture(),
+        };
+        assert!(error::request_ref::<Backtrace>(&error).is_some());
+
+        let error = ExplicitBacktrace {
+            backtrace: Backtrace::capture(),
+        };
+        assert!(error::request_ref::<Backtrace>(&error).is_some());
+
+        let error = OptBacktrace {
+            backtrace: Some(Backtrace::capture()),
+        };
+        assert!(error::request_ref::<Backtrace>(&error).is_some());
+
+        let error = ArcBacktrace {
+            backtrace: Arc::new(Backtrace::capture()),
+        };
+        assert!(error::request_ref::<Backtrace>(&error).is_some());
+
+        let error = BacktraceFrom::from(Inner);
+        assert!(error::request_ref::<Backtrace>(&error).is_some());
+
+        let error = CombinedBacktraceFrom::from(InnerBacktrace {
+            backtrace: Backtrace::capture(),
+        });
+        assert!(error::request_ref::<Backtrace>(&error).is_some());
+
+        let error = OptBacktraceFrom::from(Inner);
+        assert!(error::request_ref::<Backtrace>(&error).is_some());
+
+        let error = ArcBacktraceFrom::from(Inner);
+        assert!(error::request_ref::<Backtrace>(&error).is_some());
+
+        let error = AnyhowBacktrace {
+            source: anyhow::Error::msg("..."),
+        };
+        assert!(error::request_ref::<Backtrace>(&error).is_some());
+
+        let error = BoxDynErrorBacktrace {
+            source: Box::new(PlainBacktrace {
+                backtrace: Backtrace::capture(),
+            }),
+        };
+        assert!(error::request_ref::<Backtrace>(&error).is_some());
+    }
+}
+
+#[cfg(thiserror_nightly_testing)]
+pub mod enums {
+    use super::{Inner, InnerBacktrace};
+    use std::backtrace::Backtrace;
+    use std::error;
+    use std::sync::Arc;
+    use thiserror::Error;
+
+    #[derive(Error, Debug)]
+    pub enum PlainBacktrace {
+        #[error("...")]
+        Test { backtrace: Backtrace },
+    }
+
+    #[derive(Error, Debug)]
+    pub enum ExplicitBacktrace {
+        #[error("...")]
+        Test {
+            #[backtrace]
+            backtrace: Backtrace,
+        },
+    }
+
+    #[derive(Error, Debug)]
+    pub enum OptBacktrace {
+        #[error("...")]
+        Test {
+            #[backtrace]
+            backtrace: Option<Backtrace>,
+        },
+    }
+
+    #[derive(Error, Debug)]
+    pub enum ArcBacktrace {
+        #[error("...")]
+        Test {
+            #[backtrace]
+            backtrace: Arc<Backtrace>,
+        },
+    }
+
+    #[derive(Error, Debug)]
+    pub enum BacktraceFrom {
+        #[error("...")]
+        Test {
+            #[from]
+            source: Inner,
+            #[backtrace]
+            backtrace: Backtrace,
+        },
+    }
+
+    #[derive(Error, Debug)]
+    pub enum CombinedBacktraceFrom {
+        #[error("...")]
+        Test {
+            #[from]
+            #[backtrace]
+            source: InnerBacktrace,
+        },
+    }
+
+    #[derive(Error, Debug)]
+    pub enum OptBacktraceFrom {
+        #[error("...")]
+        Test {
+            #[from]
+            source: Inner,
+            #[backtrace]
+            backtrace: Option<Backtrace>,
+        },
+    }
+
+    #[derive(Error, Debug)]
+    pub enum ArcBacktraceFrom {
+        #[error("...")]
+        Test {
+            #[from]
+            source: Inner,
+            #[backtrace]
+            backtrace: Arc<Backtrace>,
+        },
+    }
+
+    #[test]
+    fn test_backtrace() {
+        let error = PlainBacktrace::Test {
+            backtrace: Backtrace::capture(),
+        };
+        assert!(error::request_ref::<Backtrace>(&error).is_some());
+
+        let error = ExplicitBacktrace::Test {
+            backtrace: Backtrace::capture(),
+        };
+        assert!(error::request_ref::<Backtrace>(&error).is_some());
+
+        let error = OptBacktrace::Test {
+            backtrace: Some(Backtrace::capture()),
+        };
+        assert!(error::request_ref::<Backtrace>(&error).is_some());
+
+        let error = ArcBacktrace::Test {
+            backtrace: Arc::new(Backtrace::capture()),
+        };
+        assert!(error::request_ref::<Backtrace>(&error).is_some());
+
+        let error = BacktraceFrom::from(Inner);
+        assert!(error::request_ref::<Backtrace>(&error).is_some());
+
+        let error = CombinedBacktraceFrom::from(InnerBacktrace {
+            backtrace: Backtrace::capture(),
+        });
+        assert!(error::request_ref::<Backtrace>(&error).is_some());
+
+        let error = OptBacktraceFrom::from(Inner);
+        assert!(error::request_ref::<Backtrace>(&error).is_some());
+
+        let error = ArcBacktraceFrom::from(Inner);
+        assert!(error::request_ref::<Backtrace>(&error).is_some());
+    }
+}
+
+#[test]
+#[cfg_attr(
+    not(thiserror_nightly_testing),
+    ignore = "requires `--cfg=thiserror_nightly_testing`"
+)]
+fn test_backtrace() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_display.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_display.rs
new file mode 100644
index 0000000..bb7c923
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_display.rs
@@ -0,0 +1,478 @@
+#![allow(
+    clippy::elidable_lifetime_names,
+    clippy::needless_lifetimes,
+    clippy::needless_raw_string_hashes,
+    clippy::trivially_copy_pass_by_ref,
+    clippy::uninlined_format_args
+)]
+
+use core::fmt::{self, Display};
+use thiserror::Error;
+
+fn assert<T: Display>(expected: &str, value: T) {
+    assert_eq!(expected, value.to_string());
+}
+
+#[test]
+fn test_braced() {
+    #[derive(Error, Debug)]
+    #[error("braced error: {msg}")]
+    struct Error {
+        msg: String,
+    }
+
+    let msg = "T".to_owned();
+    assert("braced error: T", Error { msg });
+}
+
+#[test]
+fn test_braced_unused() {
+    #[derive(Error, Debug)]
+    #[error("braced error")]
+    struct Error {
+        extra: usize,
+    }
+
+    assert("braced error", Error { extra: 0 });
+}
+
+#[test]
+fn test_tuple() {
+    #[derive(Error, Debug)]
+    #[error("tuple error: {0}")]
+    struct Error(usize);
+
+    assert("tuple error: 0", Error(0));
+}
+
+#[test]
+fn test_unit() {
+    #[derive(Error, Debug)]
+    #[error("unit error")]
+    struct Error;
+
+    assert("unit error", Error);
+}
+
+#[test]
+fn test_enum() {
+    #[derive(Error, Debug)]
+    enum Error {
+        #[error("braced error: {id}")]
+        Braced { id: usize },
+        #[error("tuple error: {0}")]
+        Tuple(usize),
+        #[error("unit error")]
+        Unit,
+    }
+
+    assert("braced error: 0", Error::Braced { id: 0 });
+    assert("tuple error: 0", Error::Tuple(0));
+    assert("unit error", Error::Unit);
+}
+
+#[test]
+fn test_constants() {
+    #[derive(Error, Debug)]
+    #[error("{MSG}: {id:?} (code {CODE:?})")]
+    struct Error {
+        id: &'static str,
+    }
+
+    const MSG: &str = "failed to do";
+    const CODE: usize = 9;
+
+    assert("failed to do: \"\" (code 9)", Error { id: "" });
+}
+
+#[test]
+fn test_inherit() {
+    #[derive(Error, Debug)]
+    #[error("{0}")]
+    enum Error {
+        Some(&'static str),
+        #[error("other error")]
+        Other(&'static str),
+    }
+
+    assert("some error", Error::Some("some error"));
+    assert("other error", Error::Other("..."));
+}
+
+#[test]
+fn test_brace_escape() {
+    #[derive(Error, Debug)]
+    #[error("fn main() {{}}")]
+    struct Error;
+
+    assert("fn main() {}", Error);
+}
+
+#[test]
+fn test_expr() {
+    #[derive(Error, Debug)]
+    #[error("1 + 1 = {}", 1 + 1)]
+    struct Error;
+    assert("1 + 1 = 2", Error);
+}
+
+#[test]
+fn test_nested() {
+    #[derive(Error, Debug)]
+    #[error("!bool = {}", not(.0))]
+    struct Error(bool);
+
+    #[allow(clippy::trivially_copy_pass_by_ref)]
+    fn not(bool: &bool) -> bool {
+        !*bool
+    }
+
+    assert("!bool = false", Error(true));
+}
+
+#[test]
+fn test_match() {
+    #[derive(Error, Debug)]
+    #[error("{intro}: {0}", intro = match .1 {
+        Some(n) => format!("error occurred with {}", n),
+        None => "there was an empty error".to_owned(),
+    })]
+    struct Error(String, Option<usize>);
+
+    assert(
+        "error occurred with 1: ...",
+        Error("...".to_owned(), Some(1)),
+    );
+    assert(
+        "there was an empty error: ...",
+        Error("...".to_owned(), None),
+    );
+}
+
+#[test]
+fn test_nested_display() {
+    // Same behavior as the one in `test_match`, but without String allocations.
+    #[derive(Error, Debug)]
+    #[error("{}", {
+        struct Msg<'a>(&'a String, &'a Option<usize>);
+        impl<'a> Display for Msg<'a> {
+            fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+                match self.1 {
+                    Some(n) => write!(formatter, "error occurred with {}", n),
+                    None => write!(formatter, "there was an empty error"),
+                }?;
+                write!(formatter, ": {}", self.0)
+            }
+        }
+        Msg(.0, .1)
+    })]
+    struct Error(String, Option<usize>);
+
+    assert(
+        "error occurred with 1: ...",
+        Error("...".to_owned(), Some(1)),
+    );
+    assert(
+        "there was an empty error: ...",
+        Error("...".to_owned(), None),
+    );
+}
+
+#[test]
+fn test_void() {
+    #[allow(clippy::empty_enum)]
+    #[derive(Error, Debug)]
+    #[error("...")]
+    pub enum Error {}
+
+    let _: Error;
+}
+
+#[test]
+fn test_mixed() {
+    #[derive(Error, Debug)]
+    #[error("a={a} :: b={} :: c={c} :: d={d}", 1, c = 2, d = 3)]
+    struct Error {
+        a: usize,
+        d: usize,
+    }
+
+    assert("a=0 :: b=1 :: c=2 :: d=3", Error { a: 0, d: 0 });
+}
+
+#[test]
+fn test_ints() {
+    #[derive(Error, Debug)]
+    enum Error {
+        #[error("error {0}")]
+        Tuple(usize, usize),
+        #[error("error {0}", '?')]
+        Struct { v: usize },
+    }
+
+    assert("error 9", Error::Tuple(9, 0));
+    assert("error ?", Error::Struct { v: 0 });
+}
+
+#[test]
+fn test_trailing_comma() {
+    #[derive(Error, Debug)]
+    #[error(
+        "error {0}",
+    )]
+    #[rustfmt::skip]
+    struct Error(char);
+
+    assert("error ?", Error('?'));
+}
+
+#[test]
+fn test_field() {
+    #[derive(Debug)]
+    struct Inner {
+        data: usize,
+    }
+
+    #[derive(Error, Debug)]
+    #[error("{}", .0.data)]
+    struct Error(Inner);
+
+    assert("0", Error(Inner { data: 0 }));
+}
+
+#[test]
+fn test_nested_tuple_field() {
+    #[derive(Debug)]
+    struct Inner(usize);
+
+    #[derive(Error, Debug)]
+    #[error("{}", .0.0)]
+    struct Error(Inner);
+
+    assert("0", Error(Inner(0)));
+}
+
+#[test]
+fn test_pointer() {
+    #[derive(Error, Debug)]
+    #[error("{field:p}")]
+    pub struct Struct {
+        field: Box<i32>,
+    }
+
+    let s = Struct {
+        field: Box::new(-1),
+    };
+    assert_eq!(s.to_string(), format!("{:p}", s.field));
+}
+
+#[test]
+fn test_macro_rules_variant_from_call_site() {
+    // Regression test for https://github.com/dtolnay/thiserror/issues/86
+
+    macro_rules! decl_error {
+        ($variant:ident($value:ident)) => {
+            #[derive(Error, Debug)]
+            pub enum Error0 {
+                #[error("{0:?}")]
+                $variant($value),
+            }
+
+            #[derive(Error, Debug)]
+            #[error("{0:?}")]
+            pub enum Error1 {
+                $variant($value),
+            }
+        };
+    }
+
+    decl_error!(Repro(u8));
+
+    assert("0", Error0::Repro(0));
+    assert("0", Error1::Repro(0));
+}
+
+#[test]
+fn test_macro_rules_message_from_call_site() {
+    // Regression test for https://github.com/dtolnay/thiserror/issues/398
+
+    macro_rules! decl_error {
+        ($($errors:tt)*) => {
+            #[derive(Error, Debug)]
+            pub enum Error {
+                $($errors)*
+            }
+        };
+    }
+
+    decl_error! {
+        #[error("{0}")]
+        Unnamed(u8),
+        #[error("{x}")]
+        Named { x: u8 },
+    }
+
+    assert("0", Error::Unnamed(0));
+    assert("0", Error::Named { x: 0 });
+}
+
+#[test]
+fn test_raw() {
+    #[derive(Error, Debug)]
+    #[error("braced raw error: {fn}")]
+    struct Error {
+        r#fn: &'static str,
+    }
+
+    assert("braced raw error: T", Error { r#fn: "T" });
+}
+
+#[test]
+fn test_raw_enum() {
+    #[derive(Error, Debug)]
+    enum Error {
+        #[error("braced raw error: {fn}")]
+        Braced { r#fn: &'static str },
+    }
+
+    assert("braced raw error: T", Error::Braced { r#fn: "T" });
+}
+
+#[test]
+fn test_keyword() {
+    #[derive(Error, Debug)]
+    #[error("error: {type}", type = 1)]
+    struct Error;
+
+    assert("error: 1", Error);
+}
+
+#[test]
+fn test_self() {
+    #[derive(Error, Debug)]
+    #[error("error: {self:?}")]
+    struct Error;
+
+    assert("error: Error", Error);
+}
+
+#[test]
+fn test_str_special_chars() {
+    #[derive(Error, Debug)]
+    pub enum Error {
+        #[error("brace left {{")]
+        BraceLeft,
+        #[error("brace left 2 \x7B\x7B")]
+        BraceLeft2,
+        #[error("brace left 3 \u{7B}\u{7B}")]
+        BraceLeft3,
+        #[error("brace right }}")]
+        BraceRight,
+        #[error("brace right 2 \x7D\x7D")]
+        BraceRight2,
+        #[error("brace right 3 \u{7D}\u{7D}")]
+        BraceRight3,
+        #[error(
+            "new_\
+line"
+        )]
+        NewLine,
+        #[error("escape24 \u{78}")]
+        Escape24,
+    }
+
+    assert("brace left {", Error::BraceLeft);
+    assert("brace left 2 {", Error::BraceLeft2);
+    assert("brace left 3 {", Error::BraceLeft3);
+    assert("brace right }", Error::BraceRight);
+    assert("brace right 2 }", Error::BraceRight2);
+    assert("brace right 3 }", Error::BraceRight3);
+    assert("new_line", Error::NewLine);
+    assert("escape24 x", Error::Escape24);
+}
+
+#[test]
+fn test_raw_str() {
+    #[derive(Error, Debug)]
+    pub enum Error {
+        #[error(r#"raw brace left {{"#)]
+        BraceLeft,
+        #[error(r#"raw brace left 2 \x7B"#)]
+        BraceLeft2,
+        #[error(r#"raw brace right }}"#)]
+        BraceRight,
+        #[error(r#"raw brace right 2 \x7D"#)]
+        BraceRight2,
+    }
+
+    assert(r#"raw brace left {"#, Error::BraceLeft);
+    assert(r#"raw brace left 2 \x7B"#, Error::BraceLeft2);
+    assert(r#"raw brace right }"#, Error::BraceRight);
+    assert(r#"raw brace right 2 \x7D"#, Error::BraceRight2);
+}
+
+mod util {
+    use core::fmt::{self, Octal};
+
+    pub fn octal<T: Octal>(value: &T, formatter: &mut fmt::Formatter) -> fmt::Result {
+        write!(formatter, "0o{:o}", value)
+    }
+}
+
+#[test]
+fn test_fmt_path() {
+    fn unit(formatter: &mut fmt::Formatter) -> fmt::Result {
+        formatter.write_str("unit=")
+    }
+
+    fn pair(k: &i32, v: &i32, formatter: &mut fmt::Formatter) -> fmt::Result {
+        write!(formatter, "pair={k}:{v}")
+    }
+
+    #[derive(Error, Debug)]
+    pub enum Error {
+        #[error(fmt = unit)]
+        Unit,
+        #[error(fmt = pair)]
+        Tuple(i32, i32),
+        #[error(fmt = pair)]
+        Entry { k: i32, v: i32 },
+        #[error(fmt = crate::util::octal)]
+        I16(i16),
+        #[error(fmt = crate::util::octal::<i32>)]
+        I32 { n: i32 },
+        #[error(fmt = core::fmt::Octal::fmt)]
+        I64(i64),
+        #[error("...{0}")]
+        Other(bool),
+    }
+
+    assert("unit=", Error::Unit);
+    assert("pair=10:0", Error::Tuple(10, 0));
+    assert("pair=10:0", Error::Entry { k: 10, v: 0 });
+    assert("0o777", Error::I16(0o777));
+    assert("0o777", Error::I32 { n: 0o777 });
+    assert("777", Error::I64(0o777));
+    assert("...false", Error::Other(false));
+}
+
+#[test]
+fn test_fmt_path_inherited() {
+    #[derive(Error, Debug)]
+    #[error(fmt = crate::util::octal)]
+    pub enum Error {
+        I16(i16),
+        I32 {
+            n: i32,
+        },
+        #[error(fmt = core::fmt::Octal::fmt)]
+        I64(i64),
+        #[error("...{0}")]
+        Other(bool),
+    }
+
+    assert("0o777", Error::I16(0o777));
+    assert("0o777", Error::I32 { n: 0o777 });
+    assert("777", Error::I64(0o777));
+    assert("...false", Error::Other(false));
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_error.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_error.rs
new file mode 100644
index 0000000..eb52cefb
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_error.rs
@@ -0,0 +1,56 @@
+#![allow(dead_code)]
+
+use core::fmt::{self, Display};
+use std::io;
+use thiserror::Error;
+
+macro_rules! unimplemented_display {
+    ($ty:ty) => {
+        impl Display for $ty {
+            fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
+                unimplemented!()
+            }
+        }
+    };
+}
+
+#[derive(Error, Debug)]
+struct BracedError {
+    msg: String,
+    pos: usize,
+}
+
+#[derive(Error, Debug)]
+struct TupleError(String, usize);
+
+#[derive(Error, Debug)]
+struct UnitError;
+
+#[derive(Error, Debug)]
+struct WithSource {
+    #[source]
+    cause: io::Error,
+}
+
+#[derive(Error, Debug)]
+struct WithAnyhow {
+    #[source]
+    cause: anyhow::Error,
+}
+
+#[derive(Error, Debug)]
+enum EnumError {
+    Braced {
+        #[source]
+        cause: io::Error,
+    },
+    Tuple(#[source] io::Error),
+    Unit,
+}
+
+unimplemented_display!(BracedError);
+unimplemented_display!(TupleError);
+unimplemented_display!(UnitError);
+unimplemented_display!(WithSource);
+unimplemented_display!(WithAnyhow);
+unimplemented_display!(EnumError);
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_expr.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_expr.rs
new file mode 100644
index 0000000..1872fb5
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_expr.rs
@@ -0,0 +1,118 @@
+#![allow(clippy::iter_cloned_collect, clippy::uninlined_format_args)]
+
+use core::fmt::Display;
+#[cfg(feature = "std")]
+use std::path::PathBuf;
+use thiserror::Error;
+
+// Some of the elaborate cases from the rcc codebase, which is a C compiler in
+// Rust. https://github.com/jyn514/rcc/blob/0.8.0/src/data/error.rs
+#[derive(Error, Debug)]
+pub enum CompilerError {
+    #[error("cannot shift {} by {maximum} or more bits (got {current})", if *.is_left { "left" } else { "right" })]
+    TooManyShiftBits {
+        is_left: bool,
+        maximum: u64,
+        current: u64,
+    },
+
+    #[error("#error {}", (.0).iter().copied().collect::<Vec<_>>().join(" "))]
+    User(Vec<&'static str>),
+
+    #[error("overflow while parsing {}integer literal",
+        if let Some(signed) = .is_signed {
+            if *signed { "signed "} else { "unsigned "}
+        } else {
+            ""
+        }
+    )]
+    IntegerOverflow { is_signed: Option<bool> },
+
+    #[error("overflow while parsing {}integer literal", match .is_signed {
+        Some(true) => "signed ",
+        Some(false) => "unsigned ",
+        None => "",
+    })]
+    IntegerOverflow2 { is_signed: Option<bool> },
+}
+
+// Examples drawn from Rustup.
+#[derive(Error, Debug)]
+pub enum RustupError {
+    #[error(
+        "toolchain '{name}' does not contain component {component}{}",
+        .suggestion
+            .as_ref()
+            .map_or_else(String::new, |s| format!("; did you mean '{}'?", s)),
+    )]
+    UnknownComponent {
+        name: String,
+        component: String,
+        suggestion: Option<String>,
+    },
+}
+
+#[track_caller]
+fn assert<T: Display>(expected: &str, value: T) {
+    assert_eq!(expected, value.to_string());
+}
+
+#[test]
+fn test_rcc() {
+    assert(
+        "cannot shift left by 32 or more bits (got 50)",
+        CompilerError::TooManyShiftBits {
+            is_left: true,
+            maximum: 32,
+            current: 50,
+        },
+    );
+
+    assert("#error A B C", CompilerError::User(vec!["A", "B", "C"]));
+
+    assert(
+        "overflow while parsing signed integer literal",
+        CompilerError::IntegerOverflow {
+            is_signed: Some(true),
+        },
+    );
+}
+
+#[test]
+fn test_rustup() {
+    assert(
+        "toolchain 'nightly' does not contain component clipy; did you mean 'clippy'?",
+        RustupError::UnknownComponent {
+            name: "nightly".to_owned(),
+            component: "clipy".to_owned(),
+            suggestion: Some("clippy".to_owned()),
+        },
+    );
+}
+
+// Regression test for https://github.com/dtolnay/thiserror/issues/335
+#[cfg(feature = "std")]
+#[test]
+#[allow(non_snake_case)]
+fn test_assoc_type_equality_constraint() {
+    pub trait Trait<T>: Display {
+        type A;
+    }
+
+    impl<T> Trait<T> for i32 {
+        type A = i32;
+    }
+
+    #[derive(Error, Debug)]
+    #[error("{A} {b}", b = &0 as &dyn Trait<i32, A = i32>)]
+    pub struct Error {
+        pub A: PathBuf,
+    }
+
+    assert(
+        "... 0",
+        Error {
+            A: PathBuf::from("..."),
+        },
+    );
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_from.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_from.rs
new file mode 100644
index 0000000..51af40b1
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_from.rs
@@ -0,0 +1,64 @@
+#![allow(clippy::extra_unused_type_parameters)]
+
+use std::io;
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[error("...")]
+pub struct ErrorStruct {
+    #[from]
+    source: io::Error,
+}
+
+#[derive(Error, Debug)]
+#[error("...")]
+pub struct ErrorStructOptional {
+    #[from]
+    source: Option<io::Error>,
+}
+
+#[derive(Error, Debug)]
+#[error("...")]
+pub struct ErrorTuple(#[from] io::Error);
+
+#[derive(Error, Debug)]
+#[error("...")]
+pub struct ErrorTupleOptional(#[from] Option<io::Error>);
+
+#[derive(Error, Debug)]
+#[error("...")]
+pub enum ErrorEnum {
+    Test {
+        #[from]
+        source: io::Error,
+    },
+}
+
+#[derive(Error, Debug)]
+#[error("...")]
+pub enum ErrorEnumOptional {
+    Test {
+        #[from]
+        source: Option<io::Error>,
+    },
+}
+
+#[derive(Error, Debug)]
+#[error("...")]
+pub enum Many {
+    Any(#[from] anyhow::Error),
+    Io(#[from] io::Error),
+}
+
+fn assert_impl<T: From<io::Error>>() {}
+
+#[test]
+fn test_from() {
+    assert_impl::<ErrorStruct>();
+    assert_impl::<ErrorStructOptional>();
+    assert_impl::<ErrorTuple>();
+    assert_impl::<ErrorTupleOptional>();
+    assert_impl::<ErrorEnum>();
+    assert_impl::<ErrorEnumOptional>();
+    assert_impl::<Many>();
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_generics.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_generics.rs
new file mode 100644
index 0000000..bcbfee0
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_generics.rs
@@ -0,0 +1,205 @@
+#![allow(clippy::needless_late_init, clippy::uninlined_format_args)]
+
+use core::fmt::{self, Debug, Display};
+use core::str::FromStr;
+use thiserror::Error;
+
+pub struct NoFormat;
+
+#[derive(Debug)]
+pub struct DebugOnly;
+
+pub struct DisplayOnly;
+
+impl Display for DisplayOnly {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str("display only")
+    }
+}
+
+#[derive(Debug)]
+pub struct DebugAndDisplay;
+
+impl Display for DebugAndDisplay {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str("debug and display")
+    }
+}
+
+// Should expand to:
+//
+//     impl<E> Display for EnumDebugField<E>
+//     where
+//         E: Debug;
+//
+//     impl<E> Error for EnumDebugField<E>
+//     where
+//         Self: Debug + Display;
+//
+#[derive(Error, Debug)]
+pub enum EnumDebugGeneric<E> {
+    #[error("{0:?}")]
+    FatalError(E),
+}
+
+// Should expand to:
+//
+//     impl<E> Display for EnumFromGeneric<E>;
+//
+//     impl<E> Error for EnumFromGeneric<E>
+//     where
+//         EnumDebugGeneric<E>: Error + 'static,
+//         Self: Debug + Display;
+//
+#[derive(Error, Debug)]
+pub enum EnumFromGeneric<E> {
+    #[error("enum from generic")]
+    Source(#[from] EnumDebugGeneric<E>),
+}
+
+// Should expand to:
+//
+//     impl<HasDisplay, HasDebug, HasNeither> Display
+//         for EnumCompound<HasDisplay, HasDebug, HasNeither>
+//     where
+//         HasDisplay: Display,
+//         HasDebug: Debug;
+//
+//     impl<HasDisplay, HasDebug, HasNeither> Error
+//         for EnumCompound<HasDisplay, HasDebug, HasNeither>
+//     where
+//         Self: Debug + Display;
+//
+#[derive(Error)]
+pub enum EnumCompound<HasDisplay, HasDebug, HasNeither> {
+    #[error("{0} {1:?}")]
+    DisplayDebug(HasDisplay, HasDebug),
+    #[error("{0}")]
+    Display(HasDisplay, HasNeither),
+    #[error("{1:?}")]
+    Debug(HasNeither, HasDebug),
+}
+
+impl<HasDisplay, HasDebug, HasNeither> Debug for EnumCompound<HasDisplay, HasDebug, HasNeither> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str("EnumCompound")
+    }
+}
+
+#[test]
+fn test_display_enum_compound() {
+    let mut instance: EnumCompound<DisplayOnly, DebugOnly, NoFormat>;
+
+    instance = EnumCompound::DisplayDebug(DisplayOnly, DebugOnly);
+    assert_eq!(format!("{}", instance), "display only DebugOnly");
+
+    instance = EnumCompound::Display(DisplayOnly, NoFormat);
+    assert_eq!(format!("{}", instance), "display only");
+
+    instance = EnumCompound::Debug(NoFormat, DebugOnly);
+    assert_eq!(format!("{}", instance), "DebugOnly");
+}
+
+// Should expand to:
+//
+//     impl<E> Display for EnumTransparentGeneric<E>
+//     where
+//         E: Display;
+//
+//     impl<E> Error for EnumTransparentGeneric<E>
+//     where
+//         E: Error,
+//         Self: Debug + Display;
+//
+#[derive(Error, Debug)]
+pub enum EnumTransparentGeneric<E> {
+    #[error(transparent)]
+    Other(E),
+}
+
+// Should expand to:
+//
+//     impl<E> Display for StructDebugGeneric<E>
+//     where
+//         E: Debug;
+//
+//     impl<E> Error for StructDebugGeneric<E>
+//     where
+//         Self: Debug + Display;
+//
+#[derive(Error, Debug)]
+#[error("{underlying:?}")]
+pub struct StructDebugGeneric<E> {
+    pub underlying: E,
+}
+
+// Should expand to:
+//
+//     impl<E> Error for StructFromGeneric<E>
+//     where
+//         StructDebugGeneric<E>: Error + 'static,
+//         Self: Debug + Display;
+//
+#[derive(Error, Debug)]
+pub struct StructFromGeneric<E> {
+    #[from]
+    pub source: StructDebugGeneric<E>,
+}
+
+// Should expand to:
+//
+//     impl<E> Display for StructTransparentGeneric<E>
+//     where
+//         E: Display;
+//
+//     impl<E> Error for StructTransparentGeneric<E>
+//     where
+//         E: Error,
+//         Self: Debug + Display;
+//
+#[derive(Error, Debug)]
+#[error(transparent)]
+pub struct StructTransparentGeneric<E>(pub E);
+
+// Should expand to:
+//
+//     impl<T: FromStr> Display for AssociatedTypeError<T>
+//     where
+//         T::Err: Display;
+//
+//     impl<T: FromStr> Error for AssociatedTypeError<T>
+//     where
+//         Self: Debug + Display;
+//
+#[derive(Error, Debug)]
+pub enum AssociatedTypeError<T: FromStr> {
+    #[error("couldn't parse matrix")]
+    Other,
+    #[error("couldn't parse entry: {0}")]
+    EntryParseError(T::Err),
+}
+
+// Regression test for https://github.com/dtolnay/thiserror/issues/345
+#[test]
+fn test_no_bound_on_named_fmt() {
+    #[derive(Error, Debug)]
+    #[error("{thing}", thing = "...")]
+    struct Error<T> {
+        thing: T,
+    }
+
+    let error = Error { thing: DebugOnly };
+    assert_eq!(error.to_string(), "...");
+}
+
+#[test]
+fn test_multiple_bound() {
+    #[derive(Error, Debug)]
+    #[error("0x{thing:x} 0x{thing:X}")]
+    pub struct Error<T> {
+        thing: T,
+    }
+
+    let error = Error { thing: 0xFFi32 };
+    assert_eq!(error.to_string(), "0xff 0xFF");
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_lints.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_lints.rs
new file mode 100644
index 0000000..802ad50
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_lints.rs
@@ -0,0 +1,98 @@
+#![allow(clippy::mixed_attributes_style)]
+
+use thiserror::Error;
+
+pub use std::error::Error;
+
+#[test]
+fn test_allow_attributes() {
+    #![deny(clippy::allow_attributes)]
+
+    #[derive(Error, Debug)]
+    #[error("...")]
+    pub struct MyError(#[from] anyhow::Error);
+
+    let _: MyError;
+}
+
+#[test]
+fn test_unused_qualifications() {
+    #![deny(unused_qualifications)]
+
+    // Expansion of derive(Error) macro can't know whether something like
+    // std::error::Error is already imported in the caller's scope so it must
+    // suppress unused_qualifications.
+
+    #[derive(Error, Debug)]
+    #[error("...")]
+    pub struct MyError;
+
+    let _: MyError;
+}
+
+#[test]
+fn test_needless_lifetimes() {
+    #![allow(dead_code)]
+    #![deny(clippy::elidable_lifetime_names, clippy::needless_lifetimes)]
+
+    #[derive(Error, Debug)]
+    #[error("...")]
+    pub enum MyError<'a> {
+        A(#[from] std::io::Error),
+        B(&'a ()),
+    }
+
+    let _: MyError;
+}
+
+#[test]
+fn test_deprecated() {
+    #![deny(deprecated)]
+
+    #[derive(Error, Debug)]
+    #[deprecated]
+    #[error("...")]
+    pub struct DeprecatedStruct;
+
+    #[derive(Error, Debug)]
+    #[error("{message} {}", .message)]
+    pub struct DeprecatedStructField {
+        #[deprecated]
+        message: String,
+    }
+
+    #[derive(Error, Debug)]
+    #[deprecated]
+    pub enum DeprecatedEnum {
+        #[error("...")]
+        Variant,
+    }
+
+    #[derive(Error, Debug)]
+    pub enum DeprecatedVariant {
+        #[deprecated]
+        #[error("...")]
+        Variant,
+    }
+
+    #[derive(Error, Debug)]
+    pub enum DeprecatedFrom {
+        #[error(transparent)]
+        Variant(
+            #[from]
+            #[allow(deprecated)]
+            DeprecatedStruct,
+        ),
+    }
+
+    #[allow(deprecated)]
+    let _: DeprecatedStruct;
+    #[allow(deprecated)]
+    let _: DeprecatedStructField;
+    #[allow(deprecated)]
+    let _ = DeprecatedEnum::Variant;
+    #[allow(deprecated)]
+    let _ = DeprecatedVariant::Variant;
+    #[allow(deprecated)]
+    let _ = DeprecatedFrom::Variant(DeprecatedStruct);
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_option.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_option.rs
new file mode 100644
index 0000000..21cd5e1
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_option.rs
@@ -0,0 +1,109 @@
+#![cfg(feature = "std")]
+#![cfg_attr(thiserror_nightly_testing, feature(error_generic_member_access))]
+
+#[cfg(thiserror_nightly_testing)]
+pub mod structs {
+    use std::backtrace::Backtrace;
+    use thiserror::Error;
+
+    #[derive(Error, Debug)]
+    #[error("...")]
+    pub struct OptSourceNoBacktrace {
+        #[source]
+        pub source: Option<anyhow::Error>,
+    }
+
+    #[derive(Error, Debug)]
+    #[error("...")]
+    pub struct OptSourceAlwaysBacktrace {
+        #[source]
+        pub source: Option<anyhow::Error>,
+        pub backtrace: Backtrace,
+    }
+
+    #[derive(Error, Debug)]
+    #[error("...")]
+    pub struct NoSourceOptBacktrace {
+        #[backtrace]
+        pub backtrace: Option<Backtrace>,
+    }
+
+    #[derive(Error, Debug)]
+    #[error("...")]
+    pub struct AlwaysSourceOptBacktrace {
+        pub source: anyhow::Error,
+        #[backtrace]
+        pub backtrace: Option<Backtrace>,
+    }
+
+    #[derive(Error, Debug)]
+    #[error("...")]
+    pub struct OptSourceOptBacktrace {
+        #[source]
+        pub source: Option<anyhow::Error>,
+        #[backtrace]
+        pub backtrace: Option<Backtrace>,
+    }
+}
+
+#[cfg(thiserror_nightly_testing)]
+pub mod enums {
+    use std::backtrace::Backtrace;
+    use thiserror::Error;
+
+    #[derive(Error, Debug)]
+    pub enum OptSourceNoBacktrace {
+        #[error("...")]
+        Test {
+            #[source]
+            source: Option<anyhow::Error>,
+        },
+    }
+
+    #[derive(Error, Debug)]
+    pub enum OptSourceAlwaysBacktrace {
+        #[error("...")]
+        Test {
+            #[source]
+            source: Option<anyhow::Error>,
+            backtrace: Backtrace,
+        },
+    }
+
+    #[derive(Error, Debug)]
+    pub enum NoSourceOptBacktrace {
+        #[error("...")]
+        Test {
+            #[backtrace]
+            backtrace: Option<Backtrace>,
+        },
+    }
+
+    #[derive(Error, Debug)]
+    pub enum AlwaysSourceOptBacktrace {
+        #[error("...")]
+        Test {
+            source: anyhow::Error,
+            #[backtrace]
+            backtrace: Option<Backtrace>,
+        },
+    }
+
+    #[derive(Error, Debug)]
+    pub enum OptSourceOptBacktrace {
+        #[error("...")]
+        Test {
+            #[source]
+            source: Option<anyhow::Error>,
+            #[backtrace]
+            backtrace: Option<Backtrace>,
+        },
+    }
+}
+
+#[test]
+#[cfg_attr(
+    not(thiserror_nightly_testing),
+    ignore = "requires `--cfg=thiserror_nightly_testing`"
+)]
+fn test_option() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_path.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_path.rs
new file mode 100644
index 0000000..fa85c1d2
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_path.rs
@@ -0,0 +1,54 @@
+#![cfg(feature = "std")]
+
+use core::fmt::Display;
+use ref_cast::RefCast;
+use std::path::{Path, PathBuf};
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[error("failed to read '{file}'")]
+struct StructPathBuf {
+    file: PathBuf,
+}
+
+#[derive(Error, Debug, RefCast)]
+#[repr(C)]
+#[error("failed to read '{file}'")]
+struct StructPath {
+    file: Path,
+}
+
+#[derive(Error, Debug)]
+enum EnumPathBuf {
+    #[error("failed to read '{0}'")]
+    Read(PathBuf),
+}
+
+#[derive(Error, Debug)]
+#[error("{tail}")]
+pub struct UnsizedError {
+    pub head: i32,
+    pub tail: str,
+}
+
+#[derive(Error, Debug)]
+pub enum BothError {
+    #[error("display:{0} debug:{0:?}")]
+    DisplayDebug(PathBuf),
+    #[error("debug:{0:?} display:{0}")]
+    DebugDisplay(PathBuf),
+}
+
+fn assert<T: Display>(expected: &str, value: T) {
+    assert_eq!(expected, value.to_string());
+}
+
+#[test]
+fn test_display() {
+    let path = Path::new("/thiserror");
+    let file = path.to_owned();
+    assert("failed to read '/thiserror'", StructPathBuf { file });
+    let file = path.to_owned();
+    assert("failed to read '/thiserror'", EnumPathBuf::Read(file));
+    assert("failed to read '/thiserror'", StructPath::ref_cast(path));
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_source.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_source.rs
new file mode 100644
index 0000000..29968be
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_source.rs
@@ -0,0 +1,82 @@
+use std::error::Error as StdError;
+use std::io;
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[error("implicit source")]
+pub struct ImplicitSource {
+    source: io::Error,
+}
+
+#[derive(Error, Debug)]
+#[error("explicit source")]
+pub struct ExplicitSource {
+    source: String,
+    #[source]
+    io: io::Error,
+}
+
+#[derive(Error, Debug)]
+#[error("boxed source")]
+pub struct BoxedSource {
+    #[source]
+    source: Box<dyn StdError + Send + 'static>,
+}
+
+#[test]
+fn test_implicit_source() {
+    let io = io::Error::new(io::ErrorKind::Other, "oh no!");
+    let error = ImplicitSource { source: io };
+    error.source().unwrap().downcast_ref::<io::Error>().unwrap();
+}
+
+#[test]
+fn test_explicit_source() {
+    let io = io::Error::new(io::ErrorKind::Other, "oh no!");
+    let error = ExplicitSource {
+        source: String::new(),
+        io,
+    };
+    error.source().unwrap().downcast_ref::<io::Error>().unwrap();
+}
+
+#[test]
+fn test_boxed_source() {
+    let source = Box::new(io::Error::new(io::ErrorKind::Other, "oh no!"));
+    let error = BoxedSource { source };
+    error.source().unwrap().downcast_ref::<io::Error>().unwrap();
+}
+
+macro_rules! error_from_macro {
+    ($($variants:tt)*) => {
+        #[derive(Error)]
+        #[derive(Debug)]
+        pub enum MacroSource {
+            $($variants)*
+        }
+    }
+}
+
+// Test that we generate impls with the proper hygiene
+#[rustfmt::skip]
+error_from_macro! {
+    #[error("Something")]
+    Variant(#[from] io::Error)
+}
+
+#[test]
+fn test_not_source() {
+    #[derive(Error, Debug)]
+    #[error("{source} ==> {destination}")]
+    pub struct NotSource {
+        r#source: char,
+        destination: char,
+    }
+
+    let error = NotSource {
+        source: 'S',
+        destination: 'D',
+    };
+    assert_eq!(error.to_string(), "S ==> D");
+    assert!(error.source().is_none());
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_transparent.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_transparent.rs
new file mode 100644
index 0000000..ee30f5b2a
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/test_transparent.rs
@@ -0,0 +1,96 @@
+use anyhow::anyhow;
+use std::error::Error as _;
+use std::io;
+use thiserror::Error;
+
+#[test]
+fn test_transparent_struct() {
+    #[derive(Error, Debug)]
+    #[error(transparent)]
+    struct Error(ErrorKind);
+
+    #[derive(Error, Debug)]
+    enum ErrorKind {
+        #[error("E0")]
+        E0,
+        #[error("E1")]
+        E1(#[from] io::Error),
+    }
+
+    let error = Error(ErrorKind::E0);
+    assert_eq!("E0", error.to_string());
+    assert!(error.source().is_none());
+
+    let io = io::Error::new(io::ErrorKind::Other, "oh no!");
+    let error = Error(ErrorKind::from(io));
+    assert_eq!("E1", error.to_string());
+    error.source().unwrap().downcast_ref::<io::Error>().unwrap();
+}
+
+#[test]
+fn test_transparent_enum() {
+    #[derive(Error, Debug)]
+    enum Error {
+        #[error("this failed")]
+        This,
+        #[error(transparent)]
+        Other(anyhow::Error),
+    }
+
+    let error = Error::This;
+    assert_eq!("this failed", error.to_string());
+
+    let error = Error::Other(anyhow!("inner").context("outer"));
+    assert_eq!("outer", error.to_string());
+    assert_eq!("inner", error.source().unwrap().to_string());
+}
+
+#[test]
+fn test_transparent_enum_with_default_message() {
+    #[derive(Error, Debug)]
+    #[error("this failed: {0}_{1}")]
+    enum Error {
+        This(i32, i32),
+        #[error(transparent)]
+        Other(anyhow::Error),
+    }
+
+    let error = Error::This(-1, -1);
+    assert_eq!("this failed: -1_-1", error.to_string());
+
+    let error = Error::Other(anyhow!("inner").context("outer"));
+    assert_eq!("outer", error.to_string());
+    assert_eq!("inner", error.source().unwrap().to_string());
+}
+
+#[test]
+fn test_anyhow() {
+    #[derive(Error, Debug)]
+    #[error(transparent)]
+    struct Any(#[from] anyhow::Error);
+
+    let error = Any::from(anyhow!("inner").context("outer"));
+    assert_eq!("outer", error.to_string());
+    assert_eq!("inner", error.source().unwrap().to_string());
+}
+
+#[test]
+fn test_non_static() {
+    #[derive(Error, Debug)]
+    #[error(transparent)]
+    struct Error<'a> {
+        inner: ErrorKind<'a>,
+    }
+
+    #[derive(Error, Debug)]
+    enum ErrorKind<'a> {
+        #[error("unexpected token: {:?}", token)]
+        Unexpected { token: &'a str },
+    }
+
+    let error = Error {
+        inner: ErrorKind::Unexpected { token: "error" },
+    };
+    assert_eq!("unexpected token: \"error\"", error.to_string());
+    assert!(error.source().is_none());
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/bad-field-attr.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/bad-field-attr.rs
new file mode 100644
index 0000000..d5429b2
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/bad-field-attr.rs
@@ -0,0 +1,7 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[error(transparent)]
+pub struct Error(#[error(transparent)] std::io::Error);
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/bad-field-attr.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/bad-field-attr.stderr
new file mode 100644
index 0000000..5fb5744
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/bad-field-attr.stderr
@@ -0,0 +1,5 @@
+error: #[error(transparent)] needs to go outside the enum or struct, not on an individual field
+ --> tests/ui/bad-field-attr.rs:5:18
+  |
+5 | pub struct Error(#[error(transparent)] std::io::Error);
+  |                  ^^^^^^^^^^^^^^^^^^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/concat-display.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/concat-display.rs
new file mode 100644
index 0000000..8b53cc0
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/concat-display.rs
@@ -0,0 +1,15 @@
+use thiserror::Error;
+
+macro_rules! error_type {
+    ($name:ident, $what:expr) => {
+        // Use #[error("invalid {}", $what)] instead.
+
+        #[derive(Error, Debug)]
+        #[error(concat!("invalid ", $what))]
+        pub struct $name;
+    };
+}
+
+error_type!(Error, "foo");
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/concat-display.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/concat-display.stderr
new file mode 100644
index 0000000..73718aee
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/concat-display.stderr
@@ -0,0 +1,10 @@
+error: expected one of: string literal, `transparent`, `fmt`
+  --> tests/ui/concat-display.rs:8:17
+   |
+ 8 |         #[error(concat!("invalid ", $what))]
+   |                 ^^^^^^
+...
+13 | error_type!(Error, "foo");
+   | ------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `error_type` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/display-underscore.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/display-underscore.rs
new file mode 100644
index 0000000..335614b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/display-underscore.rs
@@ -0,0 +1,7 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[error("{_}")]
+pub struct Error;
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/display-underscore.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/display-underscore.stderr
new file mode 100644
index 0000000..36882b99
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/display-underscore.stderr
@@ -0,0 +1,7 @@
+error: invalid format string: invalid argument name `_`
+ --> tests/ui/display-underscore.rs:4:11
+  |
+4 | #[error("{_}")]
+  |           ^ invalid argument name in format string
+  |
+  = note: argument name cannot be a single underscore
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/duplicate-enum-source.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/duplicate-enum-source.rs
new file mode 100644
index 0000000..15e579f
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/duplicate-enum-source.rs
@@ -0,0 +1,13 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+pub enum ErrorEnum {
+    Confusing {
+        #[source]
+        a: std::io::Error,
+        #[source]
+        b: anyhow::Error,
+    },
+}
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/duplicate-enum-source.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/duplicate-enum-source.stderr
new file mode 100644
index 0000000..4a4b2d3
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/duplicate-enum-source.stderr
@@ -0,0 +1,5 @@
+error: duplicate #[source] attribute
+ --> tests/ui/duplicate-enum-source.rs:8:9
+  |
+8 |         #[source]
+  |         ^^^^^^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/duplicate-fmt.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/duplicate-fmt.rs
new file mode 100644
index 0000000..32f7a23d
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/duplicate-fmt.rs
@@ -0,0 +1,23 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[error("...")]
+#[error("...")]
+pub struct Error;
+
+#[derive(Error, Debug)]
+#[error(fmt = core::fmt::Octal::fmt)]
+#[error(fmt = core::fmt::LowerHex::fmt)]
+pub enum FmtFmt {}
+
+#[derive(Error, Debug)]
+#[error(fmt = core::fmt::Octal::fmt)]
+#[error(transparent)]
+pub enum FmtTransparent {}
+
+#[derive(Error, Debug)]
+#[error(fmt = core::fmt::Octal::fmt)]
+#[error("...")]
+pub enum FmtDisplay {}
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/duplicate-fmt.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/duplicate-fmt.stderr
new file mode 100644
index 0000000..a6c99322
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/duplicate-fmt.stderr
@@ -0,0 +1,23 @@
+error: only one #[error(...)] attribute is allowed
+ --> tests/ui/duplicate-fmt.rs:5:1
+  |
+5 | #[error("...")]
+  | ^^^^^^^^^^^^^^^
+
+error: duplicate #[error(fmt = ...)] attribute
+  --> tests/ui/duplicate-fmt.rs:10:1
+   |
+10 | #[error(fmt = core::fmt::LowerHex::fmt)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: cannot have both #[error(transparent)] and #[error(fmt = ...)]
+  --> tests/ui/duplicate-fmt.rs:14:1
+   |
+14 | #[error(fmt = core::fmt::Octal::fmt)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: cannot have both #[error(fmt = ...)] and a format arguments attribute
+  --> tests/ui/duplicate-fmt.rs:20:1
+   |
+20 | #[error("...")]
+   | ^^^^^^^^^^^^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/duplicate-struct-source.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/duplicate-struct-source.rs
new file mode 100644
index 0000000..569df8d
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/duplicate-struct-source.rs
@@ -0,0 +1,11 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+pub struct ErrorStruct {
+    #[source]
+    a: std::io::Error,
+    #[source]
+    b: anyhow::Error,
+}
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/duplicate-struct-source.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/duplicate-struct-source.stderr
new file mode 100644
index 0000000..c8de574
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/duplicate-struct-source.stderr
@@ -0,0 +1,5 @@
+error: duplicate #[source] attribute
+ --> tests/ui/duplicate-struct-source.rs:7:5
+  |
+7 |     #[source]
+  |     ^^^^^^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/duplicate-transparent.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/duplicate-transparent.rs
new file mode 100644
index 0000000..49c0e466
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/duplicate-transparent.rs
@@ -0,0 +1,8 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[error(transparent)]
+#[error(transparent)]
+pub struct Error(anyhow::Error);
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/duplicate-transparent.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/duplicate-transparent.stderr
new file mode 100644
index 0000000..a8308790
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/duplicate-transparent.stderr
@@ -0,0 +1,5 @@
+error: duplicate #[error(transparent)] attribute
+ --> tests/ui/duplicate-transparent.rs:5:1
+  |
+5 | #[error(transparent)]
+  | ^^^^^^^^^^^^^^^^^^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/expression-fallback.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/expression-fallback.rs
new file mode 100644
index 0000000..7269129
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/expression-fallback.rs
@@ -0,0 +1,7 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[error("".yellow)]
+pub struct ArgError;
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/expression-fallback.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/expression-fallback.stderr
new file mode 100644
index 0000000..8d22c3a
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/expression-fallback.stderr
@@ -0,0 +1,24 @@
+error: expected `,`, found `.`
+ --> tests/ui/expression-fallback.rs:4:11
+  |
+4 | #[error("".yellow)]
+  |           ^ expected `,`
+
+error: argument never used
+ --> tests/ui/expression-fallback.rs:4:12
+  |
+4 | #[error("".yellow)]
+  |         -- ^^^^^^ argument never used
+  |         |
+  |         formatting specifier missing
+  |
+help: format specifiers use curly braces, consider adding a format specifier
+  |
+4 | #[error("{}".yellow)]
+  |          ++
+
+error[E0425]: cannot find value `yellow` in this scope
+ --> tests/ui/expression-fallback.rs:4:12
+  |
+4 | #[error("".yellow)]
+  |            ^^^^^^ not found in this scope
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/fallback-impl-with-display.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/fallback-impl-with-display.rs
new file mode 100644
index 0000000..23dcf28
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/fallback-impl-with-display.rs
@@ -0,0 +1,14 @@
+use core::fmt::{self, Display};
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[error]
+pub struct MyError;
+
+impl Display for MyError {
+    fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
+        unimplemented!()
+    }
+}
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/fallback-impl-with-display.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/fallback-impl-with-display.stderr
new file mode 100644
index 0000000..6bd37307
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/fallback-impl-with-display.stderr
@@ -0,0 +1,16 @@
+error: expected attribute arguments in parentheses: #[error(...)]
+ --> tests/ui/fallback-impl-with-display.rs:5:3
+  |
+5 | #[error]
+  |   ^^^^^
+
+error[E0119]: conflicting implementations of trait `std::fmt::Display` for type `MyError`
+ --> tests/ui/fallback-impl-with-display.rs:4:10
+  |
+4 | #[derive(Error, Debug)]
+  |          ^^^^^ conflicting implementation for `MyError`
+...
+8 | impl Display for MyError {
+  | ------------------------ first implementation here
+  |
+  = note: this error originates in the derive macro `Error` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/from-backtrace-backtrace.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/from-backtrace-backtrace.rs
new file mode 100644
index 0000000..3b781ac
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/from-backtrace-backtrace.rs
@@ -0,0 +1,15 @@
+// https://github.com/dtolnay/thiserror/issues/163
+
+use std::backtrace::Backtrace;
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[error("...")]
+pub struct Error(
+    #[from]
+    #[backtrace]
+    std::io::Error,
+    Backtrace,
+);
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/from-backtrace-backtrace.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/from-backtrace-backtrace.stderr
new file mode 100644
index 0000000..5c0b9a3b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/from-backtrace-backtrace.stderr
@@ -0,0 +1,5 @@
+error: deriving From requires no fields other than source and backtrace
+ --> tests/ui/from-backtrace-backtrace.rs:9:5
+  |
+9 |     #[from]
+  |     ^^^^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/from-not-source.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/from-not-source.rs
new file mode 100644
index 0000000..ad72867
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/from-not-source.rs
@@ -0,0 +1,11 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+pub struct Error {
+    #[source]
+    source: std::io::Error,
+    #[from]
+    other: anyhow::Error,
+}
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/from-not-source.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/from-not-source.stderr
new file mode 100644
index 0000000..97136017
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/from-not-source.stderr
@@ -0,0 +1,5 @@
+error: #[from] is only supported on the source field, not any other field
+ --> tests/ui/from-not-source.rs:7:5
+  |
+7 |     #[from]
+  |     ^^^^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/invalid-input-impl-anyway.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/invalid-input-impl-anyway.rs
new file mode 100644
index 0000000..0a0bcbe
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/invalid-input-impl-anyway.rs
@@ -0,0 +1,11 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[error]
+pub struct MyError;
+
+fn main() {
+    // No error on the following line. Thiserror emits an Error impl despite the
+    // bad attribute.
+    _ = &MyError as &dyn std::error::Error;
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/invalid-input-impl-anyway.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/invalid-input-impl-anyway.stderr
new file mode 100644
index 0000000..b98c31e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/invalid-input-impl-anyway.stderr
@@ -0,0 +1,5 @@
+error: expected attribute arguments in parentheses: #[error(...)]
+ --> tests/ui/invalid-input-impl-anyway.rs:4:3
+  |
+4 | #[error]
+  |   ^^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/lifetime.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/lifetime.rs
new file mode 100644
index 0000000..a82909d
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/lifetime.rs
@@ -0,0 +1,24 @@
+use core::fmt::Debug;
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[error("error")]
+struct Error<'a>(#[from] Inner<'a>);
+
+#[derive(Error, Debug)]
+#[error("{0}")]
+struct Inner<'a>(&'a str);
+
+#[derive(Error, Debug)]
+enum Enum<'a> {
+    #[error("error")]
+    Foo(#[from] Generic<&'a str>),
+}
+
+#[derive(Error, Debug)]
+#[error("{0:?}")]
+struct Generic<T: Debug>(T);
+
+fn main() -> Result<(), Error<'static>> {
+    Err(Error(Inner("some text")))
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/lifetime.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/lifetime.stderr
new file mode 100644
index 0000000..8b58136e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/lifetime.stderr
@@ -0,0 +1,11 @@
+error: non-static lifetimes are not allowed in the source of an error, because std::error::Error requires the source is dyn Error + 'static
+ --> tests/ui/lifetime.rs:6:26
+  |
+6 | struct Error<'a>(#[from] Inner<'a>);
+  |                          ^^^^^^^^^
+
+error: non-static lifetimes are not allowed in the source of an error, because std::error::Error requires the source is dyn Error + 'static
+  --> tests/ui/lifetime.rs:15:17
+   |
+15 |     Foo(#[from] Generic<&'a str>),
+   |                 ^^^^^^^^^^^^^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/missing-display.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/missing-display.rs
new file mode 100644
index 0000000..31e23fe
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/missing-display.rs
@@ -0,0 +1,9 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+pub enum MyError {
+    First,
+    Second,
+}
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/missing-display.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/missing-display.stderr
new file mode 100644
index 0000000..fe7472e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/missing-display.stderr
@@ -0,0 +1,19 @@
+error[E0277]: `MyError` doesn't implement `std::fmt::Display`
+ --> tests/ui/missing-display.rs:4:10
+  |
+3 | #[derive(Error, Debug)]
+  |          ----- in this derive macro expansion
+4 | pub enum MyError {
+  |          ^^^^^^^ unsatisfied trait bound
+  |
+help: the trait `std::fmt::Display` is not implemented for `MyError`
+ --> tests/ui/missing-display.rs:4:1
+  |
+4 | pub enum MyError {
+  | ^^^^^^^^^^^^^^^^
+note: required by a bound in `std::error::Error`
+ --> $RUST/core/src/error.rs
+  |
+  | pub trait Error: Debug + Display {
+  |                          ^^^^^^^ required by this bound in `Error`
+  = note: this error originates in the derive macro `Error` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/missing-fmt.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/missing-fmt.rs
new file mode 100644
index 0000000..d52fbdf
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/missing-fmt.rs
@@ -0,0 +1,10 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+pub enum Error {
+    #[error("...")]
+    A(usize),
+    B(usize),
+}
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/missing-fmt.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/missing-fmt.stderr
new file mode 100644
index 0000000..c0be373
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/missing-fmt.stderr
@@ -0,0 +1,5 @@
+error: missing #[error("...")] display attribute
+ --> tests/ui/missing-fmt.rs:7:5
+  |
+7 |     B(usize),
+  |     ^^^^^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/no-display.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/no-display.rs
new file mode 100644
index 0000000..d804e005
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/no-display.rs
@@ -0,0 +1,18 @@
+use thiserror::Error;
+
+#[derive(Debug)]
+struct NoDisplay;
+
+#[derive(Error, Debug)]
+#[error("thread: {thread}")]
+pub struct Error {
+    thread: NoDisplay,
+}
+
+#[derive(Error, Debug)]
+#[error("thread: {thread:o}")]
+pub struct ErrorOctal {
+    thread: NoDisplay,
+}
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/no-display.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/no-display.stderr
new file mode 100644
index 0000000..9750582
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/no-display.stderr
@@ -0,0 +1,46 @@
+error[E0599]: the method `as_display` exists for reference `&NoDisplay`, but its trait bounds were not satisfied
+ --> tests/ui/no-display.rs:7:9
+  |
+4 | struct NoDisplay;
+  | ---------------- doesn't satisfy `NoDisplay: std::fmt::Display`
+...
+7 | #[error("thread: {thread}")]
+  |         ^^^^^^^^^^^^^^^^^^ method cannot be called on `&NoDisplay` due to unsatisfied trait bounds
+  |
+  = note: the following trait bounds were not satisfied:
+          `NoDisplay: std::fmt::Display`
+          which is required by `&NoDisplay: AsDisplay<'_>`
+note: the trait `std::fmt::Display` must be implemented
+ --> $RUST/core/src/fmt/mod.rs
+  |
+  | pub trait Display: PointeeSized {
+  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  = help: items from traits can only be used if the trait is implemented and in scope
+  = note: the following trait defines an item `as_display`, perhaps you need to implement it:
+          candidate #1: `AsDisplay`
+
+error[E0277]: the trait bound `NoDisplay: Octal` is not satisfied
+  --> tests/ui/no-display.rs:13:9
+   |
+12 | #[derive(Error, Debug)]
+   |          ----- in this derive macro expansion
+13 | #[error("thread: {thread:o}")]
+   |         ^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
+   |
+help: the trait `Octal` is not implemented for `NoDisplay`
+  --> tests/ui/no-display.rs:4:1
+   |
+ 4 | struct NoDisplay;
+   | ^^^^^^^^^^^^^^^^
+   = help: the following other types implement trait `Octal`:
+             &T
+             &mut T
+             NonZero<T>
+             Saturating<T>
+             Wrapping<T>
+             i128
+             i16
+             i32
+           and $N others
+   = note: required for `&NoDisplay` to implement `Octal`
+   = note: this error originates in the macro `$crate::format_args` which comes from the expansion of the derive macro `Error` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/numbered-positional-tuple.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/numbered-positional-tuple.rs
new file mode 100644
index 0000000..6deb658
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/numbered-positional-tuple.rs
@@ -0,0 +1,7 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[error("invalid rdo_lookahead_frames {0} (expected < {})", i32::MAX)]
+pub struct Error(u32);
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/numbered-positional-tuple.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/numbered-positional-tuple.stderr
new file mode 100644
index 0000000..ab13371
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/numbered-positional-tuple.stderr
@@ -0,0 +1,5 @@
+error: ambiguous reference to positional arguments by number in a tuple struct; change this to a named argument
+ --> tests/ui/numbered-positional-tuple.rs:4:61
+  |
+4 | #[error("invalid rdo_lookahead_frames {0} (expected < {})", i32::MAX)]
+  |                                                             ^^^^^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/raw-identifier.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/raw-identifier.rs
new file mode 100644
index 0000000..e7e66d0
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/raw-identifier.rs
@@ -0,0 +1,12 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[error("error: {r#fn}")]
+pub struct Error {
+    r#fn: &'static str,
+}
+
+fn main() {
+    let r#fn = "...";
+    let _ = format!("error: {r#fn}");
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/raw-identifier.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/raw-identifier.stderr
new file mode 100644
index 0000000..a3ce94d
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/raw-identifier.stderr
@@ -0,0 +1,21 @@
+error: invalid format string: raw identifiers are not supported
+ --> tests/ui/raw-identifier.rs:4:18
+  |
+4 | #[error("error: {r#fn}")]
+  |                  --^^
+  |                  |
+  |                  raw identifier used here in format string
+  |                  help: remove the `r#`
+  |
+  = note: identifiers in format strings can be keywords and don't need to be prefixed with `r#`
+
+error: invalid format string: raw identifiers are not supported
+  --> tests/ui/raw-identifier.rs:11:30
+   |
+11 |     let _ = format!("error: {r#fn}");
+   |                              --^^
+   |                              |
+   |                              raw identifier used here in format string
+   |                              help: remove the `r#`
+   |
+   = note: identifiers in format strings can be keywords and don't need to be prefixed with `r#`
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/same-from-type.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/same-from-type.rs
new file mode 100644
index 0000000..0ebdf451
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/same-from-type.rs
@@ -0,0 +1,11 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+pub enum Error {
+    #[error("failed to open")]
+    OpenFile(#[from] std::io::Error),
+    #[error("failed to close")]
+    CloseFile(#[from] std::io::Error),
+}
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/same-from-type.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/same-from-type.stderr
new file mode 100644
index 0000000..a655163
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/same-from-type.stderr
@@ -0,0 +1,8 @@
+error[E0119]: conflicting implementations of trait `From<std::io::Error>` for type `Error`
+ --> tests/ui/same-from-type.rs:8:15
+  |
+6 |     OpenFile(#[from] std::io::Error),
+  |              ------- first implementation here
+7 |     #[error("failed to close")]
+8 |     CloseFile(#[from] std::io::Error),
+  |               ^^^^^^^ conflicting implementation for `Error`
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/source-enum-not-error.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/source-enum-not-error.rs
new file mode 100644
index 0000000..dae2285b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/source-enum-not-error.rs
@@ -0,0 +1,12 @@
+use thiserror::Error;
+
+#[derive(Debug)]
+pub struct NotError;
+
+#[derive(Error, Debug)]
+#[error("...")]
+pub enum ErrorEnum {
+    Broken { source: NotError },
+}
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/source-enum-not-error.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/source-enum-not-error.stderr
new file mode 100644
index 0000000..649d77d
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/source-enum-not-error.stderr
@@ -0,0 +1,22 @@
+error[E0599]: the method `as_dyn_error` exists for reference `&NotError`, but its trait bounds were not satisfied
+ --> tests/ui/source-enum-not-error.rs:9:14
+  |
+4 | pub struct NotError;
+  | ------------------- doesn't satisfy `NotError: AsDynError<'_>` or `NotError: std::error::Error`
+...
+9 |     Broken { source: NotError },
+  |              ^^^^^^ method cannot be called on `&NotError` due to unsatisfied trait bounds
+  |
+  = note: the following trait bounds were not satisfied:
+          `NotError: std::error::Error`
+          which is required by `NotError: AsDynError<'_>`
+          `&NotError: std::error::Error`
+          which is required by `&NotError: AsDynError<'_>`
+note: the trait `std::error::Error` must be implemented
+ --> $RUST/core/src/error.rs
+  |
+  | pub trait Error: Debug + Display {
+  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  = help: items from traits can only be used if the trait is implemented and in scope
+  = note: the following trait defines an item `as_dyn_error`, perhaps you need to implement it:
+          candidate #1: `AsDynError`
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/source-enum-unnamed-field-not-error.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/source-enum-unnamed-field-not-error.rs
new file mode 100644
index 0000000..a877c2c
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/source-enum-unnamed-field-not-error.rs
@@ -0,0 +1,12 @@
+use thiserror::Error;
+
+#[derive(Debug)]
+pub struct NotError;
+
+#[derive(Error, Debug)]
+#[error("...")]
+pub enum ErrorEnum {
+    Broken(#[source] NotError),
+}
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/source-enum-unnamed-field-not-error.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/source-enum-unnamed-field-not-error.stderr
new file mode 100644
index 0000000..dc97a4b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/source-enum-unnamed-field-not-error.stderr
@@ -0,0 +1,22 @@
+error[E0599]: the method `as_dyn_error` exists for reference `&NotError`, but its trait bounds were not satisfied
+ --> tests/ui/source-enum-unnamed-field-not-error.rs:9:12
+  |
+4 | pub struct NotError;
+  | ------------------- doesn't satisfy `NotError: AsDynError<'_>` or `NotError: std::error::Error`
+...
+9 |     Broken(#[source] NotError),
+  |            ^^^^^^^^^ method cannot be called on `&NotError` due to unsatisfied trait bounds
+  |
+  = note: the following trait bounds were not satisfied:
+          `NotError: std::error::Error`
+          which is required by `NotError: AsDynError<'_>`
+          `&NotError: std::error::Error`
+          which is required by `&NotError: AsDynError<'_>`
+note: the trait `std::error::Error` must be implemented
+ --> $RUST/core/src/error.rs
+  |
+  | pub trait Error: Debug + Display {
+  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  = help: items from traits can only be used if the trait is implemented and in scope
+  = note: the following trait defines an item `as_dyn_error`, perhaps you need to implement it:
+          candidate #1: `AsDynError`
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/source-struct-not-error.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/source-struct-not-error.rs
new file mode 100644
index 0000000..d59df1e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/source-struct-not-error.rs
@@ -0,0 +1,12 @@
+use thiserror::Error;
+
+#[derive(Debug)]
+struct NotError;
+
+#[derive(Error, Debug)]
+#[error("...")]
+pub struct ErrorStruct {
+    source: NotError,
+}
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/source-struct-not-error.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/source-struct-not-error.stderr
new file mode 100644
index 0000000..07cd67ac
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/source-struct-not-error.stderr
@@ -0,0 +1,20 @@
+error[E0599]: the method `as_dyn_error` exists for struct `NotError`, but its trait bounds were not satisfied
+ --> tests/ui/source-struct-not-error.rs:9:5
+  |
+4 | struct NotError;
+  | --------------- method `as_dyn_error` not found for this struct because it doesn't satisfy `NotError: AsDynError<'_>` or `NotError: std::error::Error`
+...
+9 |     source: NotError,
+  |     ^^^^^^ method cannot be called on `NotError` due to unsatisfied trait bounds
+  |
+  = note: the following trait bounds were not satisfied:
+          `NotError: std::error::Error`
+          which is required by `NotError: AsDynError<'_>`
+note: the trait `std::error::Error` must be implemented
+ --> $RUST/core/src/error.rs
+  |
+  | pub trait Error: Debug + Display {
+  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  = help: items from traits can only be used if the trait is implemented and in scope
+  = note: the following trait defines an item `as_dyn_error`, perhaps you need to implement it:
+          candidate #1: `AsDynError`
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/source-struct-unnamed-field-not-error.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/source-struct-unnamed-field-not-error.rs
new file mode 100644
index 0000000..160b6b2
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/source-struct-unnamed-field-not-error.rs
@@ -0,0 +1,10 @@
+use thiserror::Error;
+
+#[derive(Debug)]
+struct NotError;
+
+#[derive(Error, Debug)]
+#[error("...")]
+pub struct ErrorStruct(#[source] NotError);
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/source-struct-unnamed-field-not-error.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/source-struct-unnamed-field-not-error.stderr
new file mode 100644
index 0000000..1f5350b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/source-struct-unnamed-field-not-error.stderr
@@ -0,0 +1,20 @@
+error[E0599]: the method `as_dyn_error` exists for struct `NotError`, but its trait bounds were not satisfied
+ --> tests/ui/source-struct-unnamed-field-not-error.rs:8:24
+  |
+4 | struct NotError;
+  | --------------- method `as_dyn_error` not found for this struct because it doesn't satisfy `NotError: AsDynError<'_>` or `NotError: std::error::Error`
+...
+8 | pub struct ErrorStruct(#[source] NotError);
+  |                        ^^^^^^^^^ method cannot be called on `NotError` due to unsatisfied trait bounds
+  |
+  = note: the following trait bounds were not satisfied:
+          `NotError: std::error::Error`
+          which is required by `NotError: AsDynError<'_>`
+note: the trait `std::error::Error` must be implemented
+ --> $RUST/core/src/error.rs
+  |
+  | pub trait Error: Debug + Display {
+  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  = help: items from traits can only be used if the trait is implemented and in scope
+  = note: the following trait defines an item `as_dyn_error`, perhaps you need to implement it:
+          candidate #1: `AsDynError`
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/struct-with-fmt.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/struct-with-fmt.rs
new file mode 100644
index 0000000..73bf79fa
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/struct-with-fmt.rs
@@ -0,0 +1,7 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[error(fmt = core::fmt::Octal::fmt)]
+pub struct Error(i32);
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/struct-with-fmt.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/struct-with-fmt.stderr
new file mode 100644
index 0000000..00463be9
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/struct-with-fmt.stderr
@@ -0,0 +1,5 @@
+error: #[error(fmt = ...)] is only supported in enums; for a struct, handwrite your own Display impl
+ --> tests/ui/struct-with-fmt.rs:4:1
+  |
+4 | #[error(fmt = core::fmt::Octal::fmt)]
+  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-display.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-display.rs
new file mode 100644
index 0000000..2a59f18
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-display.rs
@@ -0,0 +1,8 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[error(transparent)]
+#[error("...")]
+pub struct Error(anyhow::Error);
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-display.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-display.stderr
new file mode 100644
index 0000000..54d958b
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-display.stderr
@@ -0,0 +1,5 @@
+error: cannot have both #[error(transparent)] and a display attribute
+ --> tests/ui/transparent-display.rs:5:1
+  |
+5 | #[error("...")]
+  | ^^^^^^^^^^^^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-enum-many.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-enum-many.rs
new file mode 100644
index 0000000..e2a73a4
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-enum-many.rs
@@ -0,0 +1,9 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+pub enum Error {
+    #[error(transparent)]
+    Other(anyhow::Error, String),
+}
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-enum-many.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-enum-many.stderr
new file mode 100644
index 0000000..a9adfa5
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-enum-many.stderr
@@ -0,0 +1,6 @@
+error: #[error(transparent)] requires exactly one field
+ --> tests/ui/transparent-enum-many.rs:5:5
+  |
+5 | /     #[error(transparent)]
+6 | |     Other(anyhow::Error, String),
+  | |________________________________^
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-enum-not-error.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-enum-not-error.rs
new file mode 100644
index 0000000..80ccfc9
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-enum-not-error.rs
@@ -0,0 +1,9 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+pub enum Error {
+    #[error(transparent)]
+    Other { message: String },
+}
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-enum-not-error.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-enum-not-error.stderr
new file mode 100644
index 0000000..bb836d4e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-enum-not-error.stderr
@@ -0,0 +1,20 @@
+error[E0599]: the method `as_dyn_error` exists for reference `&String`, but its trait bounds were not satisfied
+ --> tests/ui/transparent-enum-not-error.rs:5:13
+  |
+5 |     #[error(transparent)]
+  |             ^^^^^^^^^^^ method cannot be called on `&String` due to unsatisfied trait bounds
+  |
+ ::: $RUST/alloc/src/string.rs
+  |
+  | pub struct String {
+  | ----------------- doesn't satisfy `String: AsDynError<'_>` or `String: std::error::Error`
+  |
+  = note: the following trait bounds were not satisfied:
+          `String: std::error::Error`
+          which is required by `String: AsDynError<'_>`
+          `&String: std::error::Error`
+          which is required by `&String: AsDynError<'_>`
+          `str: Sized`
+          which is required by `str: AsDynError<'_>`
+          `str: std::error::Error`
+          which is required by `str: AsDynError<'_>`
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-enum-source.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-enum-source.rs
new file mode 100644
index 0000000..3849f66
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-enum-source.rs
@@ -0,0 +1,9 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+pub enum Error {
+    #[error(transparent)]
+    Other(#[source] anyhow::Error),
+}
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-enum-source.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-enum-source.stderr
new file mode 100644
index 0000000..ccb90677
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-enum-source.stderr
@@ -0,0 +1,5 @@
+error: transparent variant can't contain #[source]
+ --> tests/ui/transparent-enum-source.rs:6:11
+  |
+6 |     Other(#[source] anyhow::Error),
+  |           ^^^^^^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-enum-unnamed-field-not-error.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-enum-unnamed-field-not-error.rs
new file mode 100644
index 0000000..87c32e0
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-enum-unnamed-field-not-error.rs
@@ -0,0 +1,9 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+pub enum Error {
+    #[error(transparent)]
+    Other(String),
+}
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-enum-unnamed-field-not-error.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-enum-unnamed-field-not-error.stderr
new file mode 100644
index 0000000..f337c59
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-enum-unnamed-field-not-error.stderr
@@ -0,0 +1,20 @@
+error[E0599]: the method `as_dyn_error` exists for reference `&String`, but its trait bounds were not satisfied
+ --> tests/ui/transparent-enum-unnamed-field-not-error.rs:5:13
+  |
+5 |     #[error(transparent)]
+  |             ^^^^^^^^^^^ method cannot be called on `&String` due to unsatisfied trait bounds
+  |
+ ::: $RUST/alloc/src/string.rs
+  |
+  | pub struct String {
+  | ----------------- doesn't satisfy `String: AsDynError<'_>` or `String: std::error::Error`
+  |
+  = note: the following trait bounds were not satisfied:
+          `String: std::error::Error`
+          which is required by `String: AsDynError<'_>`
+          `&String: std::error::Error`
+          which is required by `&String: AsDynError<'_>`
+          `str: Sized`
+          which is required by `str: AsDynError<'_>`
+          `str: std::error::Error`
+          which is required by `str: AsDynError<'_>`
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-struct-many.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-struct-many.rs
new file mode 100644
index 0000000..18f24664
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-struct-many.rs
@@ -0,0 +1,10 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[error(transparent)]
+pub struct Error {
+    inner: anyhow::Error,
+    what: String,
+}
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-struct-many.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-struct-many.stderr
new file mode 100644
index 0000000..c0e3806e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-struct-many.stderr
@@ -0,0 +1,5 @@
+error: #[error(transparent)] requires exactly one field
+ --> tests/ui/transparent-struct-many.rs:4:1
+  |
+4 | #[error(transparent)]
+  | ^^^^^^^^^^^^^^^^^^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-struct-not-error.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-struct-not-error.rs
new file mode 100644
index 0000000..811ff53
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-struct-not-error.rs
@@ -0,0 +1,9 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[error(transparent)]
+pub struct Error {
+    message: String,
+}
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-struct-not-error.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-struct-not-error.stderr
new file mode 100644
index 0000000..ee50d03a
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-struct-not-error.stderr
@@ -0,0 +1,18 @@
+error[E0599]: the method `as_dyn_error` exists for struct `String`, but its trait bounds were not satisfied
+ --> tests/ui/transparent-struct-not-error.rs:4:9
+  |
+4 | #[error(transparent)]
+  |         ^^^^^^^^^^^ method cannot be called on `String` due to unsatisfied trait bounds
+  |
+ ::: $RUST/alloc/src/string.rs
+  |
+  | pub struct String {
+  | ----------------- doesn't satisfy `String: AsDynError<'_>` or `String: std::error::Error`
+  |
+  = note: the following trait bounds were not satisfied:
+          `String: std::error::Error`
+          which is required by `String: AsDynError<'_>`
+          `str: Sized`
+          which is required by `str: AsDynError<'_>`
+          `str: std::error::Error`
+          which is required by `str: AsDynError<'_>`
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-struct-source.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-struct-source.rs
new file mode 100644
index 0000000..d4512c2
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-struct-source.rs
@@ -0,0 +1,7 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[error(transparent)]
+pub struct Error(#[source] anyhow::Error);
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-struct-source.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-struct-source.stderr
new file mode 100644
index 0000000..3012ca3
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-struct-source.stderr
@@ -0,0 +1,5 @@
+error: transparent error struct can't contain #[source]
+ --> tests/ui/transparent-struct-source.rs:5:18
+  |
+5 | pub struct Error(#[source] anyhow::Error);
+  |                  ^^^^^^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-struct-unnamed-field-not-error.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-struct-unnamed-field-not-error.rs
new file mode 100644
index 0000000..b4f7fbbf
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-struct-unnamed-field-not-error.rs
@@ -0,0 +1,7 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[error(transparent)]
+pub struct Error(String);
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-struct-unnamed-field-not-error.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-struct-unnamed-field-not-error.stderr
new file mode 100644
index 0000000..c3d6c002
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/transparent-struct-unnamed-field-not-error.stderr
@@ -0,0 +1,18 @@
+error[E0599]: the method `as_dyn_error` exists for struct `String`, but its trait bounds were not satisfied
+ --> tests/ui/transparent-struct-unnamed-field-not-error.rs:4:9
+  |
+4 | #[error(transparent)]
+  |         ^^^^^^^^^^^ method cannot be called on `String` due to unsatisfied trait bounds
+  |
+ ::: $RUST/alloc/src/string.rs
+  |
+  | pub struct String {
+  | ----------------- doesn't satisfy `String: AsDynError<'_>` or `String: std::error::Error`
+  |
+  = note: the following trait bounds were not satisfied:
+          `String: std::error::Error`
+          which is required by `String: AsDynError<'_>`
+          `str: Sized`
+          which is required by `str: AsDynError<'_>`
+          `str: std::error::Error`
+          which is required by `str: AsDynError<'_>`
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/unconditional-recursion.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/unconditional-recursion.rs
new file mode 100644
index 0000000..035b15e
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/unconditional-recursion.rs
@@ -0,0 +1,9 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[error("{self}")]
+pub struct Error;
+
+fn main() {
+    __FAIL__;
+}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/unconditional-recursion.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/unconditional-recursion.stderr
new file mode 100644
index 0000000..568e891
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/unconditional-recursion.stderr
@@ -0,0 +1,21 @@
+error[E0425]: cannot find value `__FAIL__` in this scope
+ --> tests/ui/unconditional-recursion.rs:8:5
+  |
+8 |     __FAIL__;
+  |     ^^^^^^^^ not found in this scope
+
+warning: function cannot return without recursing
+ --> tests/ui/unconditional-recursion.rs:4:9
+  |
+4 | #[error("{self}")]
+  |         ^^^^^^^^
+  |         |
+  |         cannot return without recursing
+  |         recursive call site
+  |
+  = help: a `loop` may express intention better if this is on purpose
+note: the lint level is defined here
+ --> tests/ui/unconditional-recursion.rs:4:9
+  |
+4 | #[error("{self}")]
+  |         ^^^^^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/unexpected-field-fmt.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/unexpected-field-fmt.rs
new file mode 100644
index 0000000..7c439d94
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/unexpected-field-fmt.rs
@@ -0,0 +1,11 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+pub enum Error {
+    What {
+        #[error("...")]
+        io: std::io::Error,
+    },
+}
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/unexpected-field-fmt.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/unexpected-field-fmt.stderr
new file mode 100644
index 0000000..bf3c24d
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/unexpected-field-fmt.stderr
@@ -0,0 +1,5 @@
+error: not expected here; the #[error(...)] attribute belongs on top of a struct or an enum variant
+ --> tests/ui/unexpected-field-fmt.rs:6:9
+  |
+6 |         #[error("...")]
+  |         ^^^^^^^^^^^^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/unexpected-struct-source.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/unexpected-struct-source.rs
new file mode 100644
index 0000000..f396494
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/unexpected-struct-source.rs
@@ -0,0 +1,7 @@
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[source]
+pub struct Error;
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/unexpected-struct-source.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/unexpected-struct-source.stderr
new file mode 100644
index 0000000..6f15841d
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/unexpected-struct-source.stderr
@@ -0,0 +1,5 @@
+error: not expected here; the #[source] attribute belongs on a specific field
+ --> tests/ui/unexpected-struct-source.rs:4:1
+  |
+4 | #[source]
+  | ^^^^^^^^^
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/union.rs b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/union.rs
new file mode 100644
index 0000000..cd6a934
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/union.rs
@@ -0,0 +1,9 @@
+use thiserror::Error;
+
+#[derive(Error)]
+pub union U {
+    msg: &'static str,
+    num: usize,
+}
+
+fn main() {}
diff --git a/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/union.stderr b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/union.stderr
new file mode 100644
index 0000000..3ec4d71
--- /dev/null
+++ b/third_party/rust/chromium_crates_io/vendor/thiserror-v2/tests/ui/union.stderr
@@ -0,0 +1,8 @@
+error: union as errors are not supported
+ --> tests/ui/union.rs:4:1
+  |
+4 | / pub union U {
+5 | |     msg: &'static str,
+6 | |     num: usize,
+7 | | }
+  | |_^
diff --git a/third_party/rust/jxl/OWNERS b/third_party/rust/jxl/OWNERS
new file mode 100644
index 0000000..4b35b8b
--- /dev/null
+++ b/third_party/rust/jxl/OWNERS
@@ -0,0 +1,2 @@
+veluca@google.com
+file://third_party/blink/renderer/platform/image-decoders/OWNERS
diff --git a/third_party/rust/jxl/v0_1/BUILD.gn b/third_party/rust/jxl/v0_1/BUILD.gn
new file mode 100644
index 0000000..8ad187e
--- /dev/null
+++ b/third_party/rust/jxl/v0_1/BUILD.gn
@@ -0,0 +1,209 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# @generated from third_party/rust/chromium_crates_io/BUILD.gn.hbs by
+# tools/crates/gnrt.
+# Do not edit!
+
+import("//build/rust/cargo_crate.gni")
+
+cargo_crate("lib") {
+  crate_name = "jxl"
+  epoch = "0.1"
+  crate_type = "rlib"
+  crate_root =
+      "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/lib.rs"
+  sources = [
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/color.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/data_types.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/decoder.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/inner/box_parser.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/inner/codestream_parser/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/inner/codestream_parser/non_section.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/inner/codestream_parser/sections.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/inner/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/inner/process.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/input.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/options.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/api/signature.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/bit_reader.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/color/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/color/tf.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/container/box_header.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/container/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/container/parse.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/entropy_coding/ans.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/entropy_coding/context_map.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/entropy_coding/decode.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/entropy_coding/huffman.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/entropy_coding/hybrid_uint.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/entropy_coding/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/error.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/features/blending.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/features/epf.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/features/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/features/noise.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/features/patches.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/features/spline.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/adaptive_lf_smoothing.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/block_context_map.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/coeff_order.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/color_correlation_map.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/decode.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/group.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/borrowed_buffers.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/decode/bitstream.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/decode/channel.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/decode/common.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/decode/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/decode/specialized_trees.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/predict.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/transforms/apply.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/transforms/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/transforms/palette.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/transforms/rct.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/transforms/squeeze.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/modular/tree.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/quant_weights.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/quantizer.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/frame/render.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/bit_depth.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/color_encoding.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/encodings.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/extra_channels.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/frame_header.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/image_metadata.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/modular.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/permutation.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/size.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/toc.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/headers/transform_data.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/icc/header.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/icc/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/icc/stream.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/icc/tag.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/data_type.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/internal.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/output_buffer.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/raw.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/rect.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/test.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/image/typed.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/lib.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/buffer_splitter.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/builder.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/channels.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/internal.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/helpers.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/render_group.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/row_buffers.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/run_stage.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/save/identity.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/save/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/low_memory_pipeline/save/x86_64.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/save.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/simple_pipeline/extend.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/simple_pipeline/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/simple_pipeline/run_stage.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/simple_pipeline/save.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/blending.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/chroma_upsample.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/convert.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/epf/common.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/epf/epf0.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/epf/epf1.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/epf/epf2.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/epf/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/epf/test.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/extend.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/from_linear.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/gaborish.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/nearest_neighbor.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/noise.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/patches.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/splines.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/spot.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/to_linear.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/upsample.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/xyb.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/stages/ycbcr.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/render/test.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/bits.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/cacheline.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/concat_slice.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/fast_math.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/float16.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/linalg.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/log2.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/ndarray.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/rational_poly.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/shift_right_ceil.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/test.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/tracing_wrappers.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/vec_helpers.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl-v0_1/src/util/xorshift128plus.rs",
+  ]
+  inputs = []
+
+  build_native_rust_unit_tests = false
+  edition = "2024"
+  cargo_pkg_authors = "Luca Versari <veluca93@gmail.com>"
+  cargo_pkg_name = "jxl"
+  cargo_pkg_description =
+      "High performance Rust implementation of a JPEG XL decoder"
+  cargo_pkg_repository = "https://github.com/libjxl/jxl-rs"
+  cargo_pkg_version = "0.1.4"
+
+  allow_unsafe = true
+
+  deps = [
+    "//third_party/rust/array_init/v2:lib",
+    "//third_party/rust/byteorder/v1:lib",
+    "//third_party/rust/jxl_macros/v0_1:lib",
+    "//third_party/rust/jxl_simd/v0_1:lib",
+    "//third_party/rust/jxl_transforms/v0_1:lib",
+    "//third_party/rust/num_derive/v0_4:lib",
+    "//third_party/rust/num_traits/v0_2:lib",
+    "//third_party/rust/thiserror/v2:lib",
+  ]
+
+  #####################################################################
+  # Tweaking which GN `config`s apply to this target.
+
+  # Config changes that apply to all `//third_party/rust` crates.
+  _configs_to_remove = [
+    # We don't need code coverage data for any `chromium_crates_io` crates.
+    "//build/config/coverage:default_coverage",
+
+    # This is third-party code, so remove `chromium_code` config.  We are not
+    # at the same time adding `//build/config/compiler:no_chromium_code`,
+    # because 1) we don't want to pull how warnings are handled by that config
+    # and 2) that config doesn't have any non-warnings-related stuff.
+    "//build/config/compiler:chromium_code",
+  ]
+  _configs_to_add = []
+
+  # Changing (if needed) which configs apply to this specific crate (based on
+  # `extra_kv.configs_to_remove` and `extra_kv.configs_to_add` from
+  # `gnrt_config.toml`).
+  _configs_to_remove += []
+  _configs_to_add += []
+
+  # Applying config changes.
+  library_configs -= _configs_to_remove
+  library_configs += _configs_to_add
+  executable_configs -= _configs_to_remove
+  executable_configs += _configs_to_add
+  proc_macro_configs -= _configs_to_remove
+  proc_macro_configs += _configs_to_add
+}
diff --git a/third_party/rust/jxl/v0_1/README.chromium b/third_party/rust/jxl/v0_1/README.chromium
new file mode 100644
index 0000000..33d6571
--- /dev/null
+++ b/third_party/rust/jxl/v0_1/README.chromium
@@ -0,0 +1,11 @@
+Name: jxl
+URL: https://crates.io/crates/jxl
+Version: 0.1.4
+Revision: e3d3eeb3b30c9a50e0c3646046648ae708154099
+Update Mechanism: Manual (https://crbug.com/449898466)
+License: BSD-3-Clause
+License File: //third_party/rust/chromium_crates_io/vendor/jxl-v0_1/LICENSE
+Shipped: yes
+Security Critical: yes
+
+Description: High performance Rust implementation of a JPEG XL decoder
diff --git a/third_party/rust/jxl/v0_1/wrapper/BUILD.gn b/third_party/rust/jxl/v0_1/wrapper/BUILD.gn
new file mode 100644
index 0000000..93cff9d6
--- /dev/null
+++ b/third_party/rust/jxl/v0_1/wrapper/BUILD.gn
@@ -0,0 +1,20 @@
+# 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("//build/rust/rust_static_library.gni")
+
+rust_static_library("jxl_rs") {
+  crate_root = "lib.rs"
+  crate_name = "jxl_rs"
+  edition = "2021"
+  allow_unsafe = true
+
+  sources = [ "lib.rs" ]
+  cxx_bindings = [ "lib.rs" ]
+
+  deps = [
+    "..:lib",
+    "//build/rust:cxx_cppdeps",
+  ]
+}
diff --git a/third_party/rust/jxl/v0_1/wrapper/lib.rs b/third_party/rust/jxl/v0_1/wrapper/lib.rs
new file mode 100644
index 0000000..5ac721a
--- /dev/null
+++ b/third_party/rust/jxl/v0_1/wrapper/lib.rs
@@ -0,0 +1,563 @@
+//! CXX-based FFI wrapper for jxl-rs decoder.
+//!
+//! This provides a C++-compatible API for the jxl-rs decoder using the CXX crate,
+//! designed for integration with Chromium's Blink image decoder infrastructure.
+
+use jxl::api::{
+    JxlBasicInfo as InternalBasicInfo, JxlDecoder, JxlDecoderOptions, JxlOutputBuffer,
+    JxlProgressiveMode, ProcessingResult, check_signature, states,
+};
+use jxl::headers::extra_channels::ExtraChannel;
+use jxl::image::{Image, Rect};
+
+#[cxx::bridge]
+mod ffi {
+    /// Status codes returned by decoder operations
+    #[derive(Debug)]
+    enum JxlRsStatus {
+        Success = 0,
+        Error = 1,
+        NeedMoreInput = 2,
+        BasicInfo = 3,
+        Frame = 5,
+        FullImage = 6,
+    }
+
+    /// Pixel format for decoded output
+    #[derive(Debug)]
+    enum JxlRsPixelFormat {
+        Rgba8 = 0,
+        Rgba16 = 1,
+        RgbaF32 = 2,
+    }
+
+    /// Basic image information
+    #[derive(Debug, Clone)]
+    struct JxlRsBasicInfo {
+        width: u32,
+        height: u32,
+        bits_per_sample: u32,
+        num_extra_channels: u32,
+        has_alpha: bool,
+        alpha_premultiplied: bool,
+        have_animation: bool,
+        animation_loop_count: u32,
+        animation_tps_numerator: u32,
+        animation_tps_denominator: u32,
+        uses_original_profile: bool,
+        orientation: u32,
+    }
+
+    /// Frame header information
+    #[derive(Debug, Clone)]
+    struct JxlRsFrameHeader {
+        duration: u32,
+        is_last: bool,
+        name_length: u32,
+    }
+
+    extern "Rust" {
+        /// Opaque decoder type
+        type JxlRsDecoder;
+
+        /// Create a new decoder instance
+        fn jxl_rs_decoder_create() -> Box<JxlRsDecoder>;
+
+        /// Reset decoder to initial state
+        fn reset(self: &mut JxlRsDecoder);
+
+        /// Set input data for decoding
+        fn set_input(self: &mut JxlRsDecoder, data: &[u8], all_input: bool) -> JxlRsStatus;
+
+        /// Process next decoding step
+        fn process(self: &mut JxlRsDecoder) -> JxlRsStatus;
+
+        /// Get basic image information
+        fn get_basic_info(self: &JxlRsDecoder) -> JxlRsBasicInfo;
+
+        /// Get frame header information
+        fn get_frame_header(self: &JxlRsDecoder) -> JxlRsFrameHeader;
+
+        /// Set output pixel format
+        fn set_pixel_format(self: &mut JxlRsDecoder, format: JxlRsPixelFormat);
+
+        /// Get decoded pixels - writes to provided buffer
+        fn get_pixels(self: &mut JxlRsDecoder, buffer: &mut [u8]) -> JxlRsStatus;
+
+        /// Get ICC color profile data as slice
+        fn get_icc_profile(self: &JxlRsDecoder) -> &[u8];
+
+        /// Get frame count
+        fn get_frame_count(self: &JxlRsDecoder) -> u32;
+
+        /// Check if more frames are available
+        fn has_more_frames(self: &JxlRsDecoder) -> bool;
+
+        /// Get last error message
+        fn get_error(self: &JxlRsDecoder) -> &str;
+
+        /// Check JXL signature in data
+        fn jxl_rs_signature_check(data: &[u8]) -> bool;
+
+        /// Get library version string
+        fn jxl_rs_version() -> &'static str;
+    }
+}
+
+// Re-export types for convenience
+pub use ffi::{JxlRsBasicInfo, JxlRsFrameHeader, JxlRsPixelFormat, JxlRsStatus};
+
+// =============================================================================
+// Decoder Implementation
+// =============================================================================
+
+enum DecoderState {
+    Initialized(JxlDecoder<states::Initialized>),
+    WithImageInfo(JxlDecoder<states::WithImageInfo>),
+    WithFrameInfo(JxlDecoder<states::WithFrameInfo>),
+    Empty,
+}
+
+pub struct JxlRsDecoder {
+    state: DecoderState,
+    input_buffer: Vec<u8>,
+    input_consumed: usize,
+    all_input_received: bool,
+    basic_info: JxlRsBasicInfo,
+    frame_header: JxlRsFrameHeader,
+    current_frame: u32,
+    frame_count: u32,
+    has_more_frames: bool,
+    pixel_format: JxlRsPixelFormat,
+    icc_profile: Vec<u8>,
+    error_message: String,
+    rgb_buffer: Vec<f32>,
+    alpha_buffer: Vec<f32>,
+}
+
+impl JxlRsDecoder {
+    fn new() -> Self {
+        let mut options = JxlDecoderOptions::default();
+        options.xyb_output_linear = false;
+        options.progressive_mode = JxlProgressiveMode::FullFrame;
+
+        Self {
+            state: DecoderState::Initialized(JxlDecoder::new(options)),
+            input_buffer: Vec::new(),
+            input_consumed: 0,
+            all_input_received: false,
+            basic_info: JxlRsBasicInfo::default(),
+            frame_header: JxlRsFrameHeader::default(),
+            current_frame: 0,
+            frame_count: 1,
+            has_more_frames: true,
+            pixel_format: JxlRsPixelFormat::Rgba8,
+            icc_profile: Vec::new(),
+            error_message: String::new(),
+            rgb_buffer: Vec::new(),
+            alpha_buffer: Vec::new(),
+        }
+    }
+
+    fn set_error(&mut self, msg: &str) {
+        self.error_message = msg.to_string();
+    }
+
+    fn process_internal(&mut self) -> JxlRsStatus {
+        let input_slice = &self.input_buffer[self.input_consumed..];
+        if input_slice.is_empty() && !self.all_input_received {
+            return JxlRsStatus::NeedMoreInput;
+        }
+
+        let state = std::mem::replace(&mut self.state, DecoderState::Empty);
+
+        match state {
+            DecoderState::Initialized(decoder) => {
+                let mut input = input_slice;
+                let input_before = input.len();
+                match decoder.process(&mut input) {
+                    Ok(ProcessingResult::Complete { result }) => {
+                        self.input_consumed += input_before - input.len();
+                        self.basic_info = JxlRsBasicInfo::from(result.basic_info());
+
+                        let color_profile = result.embedded_color_profile();
+                        let icc = color_profile.as_icc();
+                        if !icc.is_empty() {
+                            self.icc_profile = icc.into_owned();
+                        }
+                        self.state = DecoderState::WithImageInfo(result);
+                        JxlRsStatus::BasicInfo
+                    }
+                    Ok(ProcessingResult::NeedsMoreInput { fallback, .. }) => {
+                        self.input_consumed += input_before - input.len();
+                        self.state = DecoderState::Initialized(fallback);
+                        if self.all_input_received {
+                            self.set_error("Incomplete JXL header");
+                            JxlRsStatus::Error
+                        } else {
+                            JxlRsStatus::NeedMoreInput
+                        }
+                    }
+                    Err(e) => {
+                        self.set_error(&format!("Decoder error: {}", e));
+                        JxlRsStatus::Error
+                    }
+                }
+            }
+
+            DecoderState::WithImageInfo(decoder) => {
+                let mut input = input_slice;
+                let input_before = input.len();
+                match decoder.process(&mut input) {
+                    Ok(ProcessingResult::Complete { result }) => {
+                        self.input_consumed += input_before - input.len();
+                        let fh = result.frame_header();
+                        self.frame_header.duration = fh.duration.map(|d| d as u32).unwrap_or(0);
+                        self.frame_header.is_last = false;
+                        self.frame_header.name_length = fh.name.len() as u32;
+                        self.state = DecoderState::WithFrameInfo(result);
+                        JxlRsStatus::Frame
+                    }
+                    Ok(ProcessingResult::NeedsMoreInput { fallback, .. }) => {
+                        self.input_consumed += input_before - input.len();
+                        self.state = DecoderState::WithImageInfo(fallback);
+                        if self.all_input_received {
+                            self.set_error("Incomplete frame header");
+                            JxlRsStatus::Error
+                        } else {
+                            JxlRsStatus::NeedMoreInput
+                        }
+                    }
+                    Err(e) => {
+                        self.set_error(&format!("Frame header error: {}", e));
+                        JxlRsStatus::Error
+                    }
+                }
+            }
+
+            DecoderState::WithFrameInfo(decoder) => {
+                let mut input = input_slice;
+                let input_before = input.len();
+
+                let width = self.basic_info.width as usize;
+                let height = self.basic_info.height as usize;
+
+                let mut rgb_image = match Image::<f32>::new_with_value((width * 3, height), 0.0f32) {
+                    Ok(img) => img,
+                    Err(e) => {
+                        self.set_error(&format!("Failed to allocate RGB buffer: {}", e));
+                        return JxlRsStatus::Error;
+                    }
+                };
+
+                let mut alpha_image = if self.basic_info.has_alpha {
+                    match Image::<f32>::new_with_value((width, height), 0.0f32) {
+                        Ok(img) => Some(img),
+                        Err(e) => {
+                            self.set_error(&format!("Failed to allocate alpha buffer: {}", e));
+                            return JxlRsStatus::Error;
+                        }
+                    }
+                } else {
+                    None
+                };
+
+                let result = if let Some(ref mut alpha_img) = alpha_image {
+                    let rgb_output = JxlOutputBuffer::from_image_rect_mut(
+                        rgb_image.get_rect_mut(Rect { origin: (0, 0), size: (width * 3, height) }).into_raw()
+                    );
+                    let alpha_output = JxlOutputBuffer::from_image_rect_mut(
+                        alpha_img.get_rect_mut(Rect { origin: (0, 0), size: (width, height) }).into_raw()
+                    );
+                    decoder.process(&mut input, &mut [rgb_output, alpha_output])
+                } else {
+                    let rgb_output = JxlOutputBuffer::from_image_rect_mut(
+                        rgb_image.get_rect_mut(Rect { origin: (0, 0), size: (width * 3, height) }).into_raw()
+                    );
+                    decoder.process(&mut input, &mut [rgb_output])
+                };
+
+                // Copy RGB data from image rows to flat buffer
+                self.rgb_buffer.clear();
+                self.rgb_buffer.reserve(width * height * 3);
+                for y in 0..height {
+                    let src_row = rgb_image.row(y);
+                    self.rgb_buffer.extend_from_slice(&src_row[..width * 3]);
+                }
+
+                // Copy alpha data if present
+                self.alpha_buffer.clear();
+                if let Some(ref alpha_img) = alpha_image {
+                    self.alpha_buffer.reserve(width * height);
+                    for y in 0..height {
+                        let src_row = alpha_img.row(y);
+                        self.alpha_buffer.extend_from_slice(&src_row[..width]);
+                    }
+                }
+
+                match result {
+                    Ok(ProcessingResult::Complete { result }) => {
+                        self.input_consumed += input_before - input.len();
+                        self.current_frame += 1;
+                        self.has_more_frames = result.has_more_frames();
+                        if self.has_more_frames {
+                            self.state = DecoderState::WithImageInfo(result);
+                        } else {
+                            self.frame_count = self.current_frame;
+                            self.state = DecoderState::WithImageInfo(result);
+                        }
+                        JxlRsStatus::FullImage
+                    }
+                    Ok(ProcessingResult::NeedsMoreInput { fallback, .. }) => {
+                        self.input_consumed += input_before - input.len();
+                        self.state = DecoderState::WithFrameInfo(fallback);
+                        if self.all_input_received {
+                            self.set_error("Incomplete frame data");
+                            JxlRsStatus::Error
+                        } else {
+                            JxlRsStatus::NeedMoreInput
+                        }
+                    }
+                    Err(e) => {
+                        self.set_error(&format!("Frame decode error: {}", e));
+                        JxlRsStatus::Error
+                    }
+                }
+            }
+
+            DecoderState::Empty => {
+                self.set_error("Internal error: decoder in empty state");
+                JxlRsStatus::Error
+            }
+        }
+    }
+}
+
+// =============================================================================
+// CXX Bridge Implementation
+// =============================================================================
+
+fn jxl_rs_decoder_create() -> Box<JxlRsDecoder> {
+    Box::new(JxlRsDecoder::new())
+}
+
+impl JxlRsDecoder {
+    fn reset(&mut self) {
+        let mut options = JxlDecoderOptions::default();
+        options.xyb_output_linear = false;
+        options.progressive_mode = JxlProgressiveMode::FullFrame;
+
+        self.state = DecoderState::Initialized(JxlDecoder::new(options));
+        self.input_buffer.clear();
+        self.input_consumed = 0;
+        self.all_input_received = false;
+        self.basic_info = JxlRsBasicInfo::default();
+        self.frame_header = JxlRsFrameHeader::default();
+        self.current_frame = 0;
+        self.frame_count = 1;
+        self.has_more_frames = true;
+        self.icc_profile.clear();
+        self.error_message.clear();
+        self.rgb_buffer.clear();
+        self.alpha_buffer.clear();
+    }
+
+    fn set_input(&mut self, data: &[u8], all_input: bool) -> JxlRsStatus {
+        if !data.is_empty() {
+            self.input_buffer.clear();
+            self.input_buffer.extend_from_slice(data);
+            self.input_consumed = 0;
+        }
+        self.all_input_received = all_input;
+        JxlRsStatus::Success
+    }
+
+    fn process(&mut self) -> JxlRsStatus {
+        self.process_internal()
+    }
+
+    fn get_basic_info(&self) -> JxlRsBasicInfo {
+        self.basic_info.clone()
+    }
+
+    fn get_frame_header(&self) -> JxlRsFrameHeader {
+        self.frame_header.clone()
+    }
+
+    fn set_pixel_format(&mut self, format: JxlRsPixelFormat) {
+        self.pixel_format = format;
+    }
+
+    fn get_pixels(&mut self, buffer: &mut [u8]) -> JxlRsStatus {
+        if self.rgb_buffer.is_empty() {
+            self.error_message = "No decoded image available".to_string();
+            return JxlRsStatus::Error;
+        }
+
+        let width = self.basic_info.width as usize;
+        let height = self.basic_info.height as usize;
+        let has_alpha = self.basic_info.has_alpha;
+
+        match self.pixel_format {
+            JxlRsPixelFormat::Rgba8 => {
+                let required_size = width * height * 4;
+                if buffer.len() < required_size {
+                    self.error_message = "Buffer too small".to_string();
+                    return JxlRsStatus::Error;
+                }
+                for pixel_idx in 0..(width * height) {
+                    let rgb_idx = pixel_idx * 3;
+                    let dst_idx = pixel_idx * 4;
+                    buffer[dst_idx] = (self.rgb_buffer[rgb_idx].clamp(0.0, 1.0) * 255.0) as u8;
+                    buffer[dst_idx + 1] = (self.rgb_buffer[rgb_idx + 1].clamp(0.0, 1.0) * 255.0) as u8;
+                    buffer[dst_idx + 2] = (self.rgb_buffer[rgb_idx + 2].clamp(0.0, 1.0) * 255.0) as u8;
+                    buffer[dst_idx + 3] = if has_alpha {
+                        (self.alpha_buffer[pixel_idx].clamp(0.0, 1.0) * 255.0) as u8
+                    } else {
+                        255
+                    };
+                }
+            }
+            JxlRsPixelFormat::Rgba16 => {
+                let required_size = width * height * 8;
+                if buffer.len() < required_size {
+                    self.error_message = "Buffer too small".to_string();
+                    return JxlRsStatus::Error;
+                }
+                for pixel_idx in 0..(width * height) {
+                    let rgb_idx = pixel_idx * 3;
+                    let dst_idx = pixel_idx * 8; // 4 u16s = 8 bytes per pixel
+                    let r = (self.rgb_buffer[rgb_idx].clamp(0.0, 1.0) * 65535.0) as u16;
+                    let g = (self.rgb_buffer[rgb_idx + 1].clamp(0.0, 1.0) * 65535.0) as u16;
+                    let b = (self.rgb_buffer[rgb_idx + 2].clamp(0.0, 1.0) * 65535.0) as u16;
+                    let a = if has_alpha {
+                        (self.alpha_buffer[pixel_idx].clamp(0.0, 1.0) * 65535.0) as u16
+                    } else {
+                        65535
+                    };
+                    buffer[dst_idx..dst_idx + 2].copy_from_slice(&r.to_ne_bytes());
+                    buffer[dst_idx + 2..dst_idx + 4].copy_from_slice(&g.to_ne_bytes());
+                    buffer[dst_idx + 4..dst_idx + 6].copy_from_slice(&b.to_ne_bytes());
+                    buffer[dst_idx + 6..dst_idx + 8].copy_from_slice(&a.to_ne_bytes());
+                }
+            }
+            JxlRsPixelFormat::RgbaF32 => {
+                let required_size = width * height * 16;
+                if buffer.len() < required_size {
+                    self.error_message = "Buffer too small".to_string();
+                    return JxlRsStatus::Error;
+                }
+                for pixel_idx in 0..(width * height) {
+                    let rgb_idx = pixel_idx * 3;
+                    let dst_idx = pixel_idx * 16; // 4 f32s = 16 bytes per pixel
+                    let r = self.rgb_buffer[rgb_idx];
+                    let g = self.rgb_buffer[rgb_idx + 1];
+                    let b = self.rgb_buffer[rgb_idx + 2];
+                    let a = if has_alpha {
+                        self.alpha_buffer[pixel_idx]
+                    } else {
+                        1.0
+                    };
+                    buffer[dst_idx..dst_idx + 4].copy_from_slice(&r.to_ne_bytes());
+                    buffer[dst_idx + 4..dst_idx + 8].copy_from_slice(&g.to_ne_bytes());
+                    buffer[dst_idx + 8..dst_idx + 12].copy_from_slice(&b.to_ne_bytes());
+                    buffer[dst_idx + 12..dst_idx + 16].copy_from_slice(&a.to_ne_bytes());
+                }
+            }
+            _ => {
+                self.error_message = "Unknown pixel format".to_string();
+                return JxlRsStatus::Error;
+            }
+        }
+
+        JxlRsStatus::Success
+    }
+
+    fn get_icc_profile(&self) -> &[u8] {
+        &self.icc_profile
+    }
+
+    fn get_frame_count(&self) -> u32 {
+        self.frame_count
+    }
+
+    fn has_more_frames(&self) -> bool {
+        self.has_more_frames
+    }
+
+    fn get_error(&self) -> &str {
+        &self.error_message
+    }
+}
+
+fn jxl_rs_signature_check(data: &[u8]) -> bool {
+    if data.len() < 2 {
+        return false;
+    }
+    let bytes = &data[..data.len().min(12)];
+    matches!(check_signature(bytes), ProcessingResult::Complete { result: Some(_) })
+}
+
+fn jxl_rs_version() -> &'static str {
+    "jxl-rs-capi 0.1.0"
+}
+
+// =============================================================================
+// Default Implementations
+// =============================================================================
+
+impl Default for JxlRsBasicInfo {
+    fn default() -> Self {
+        Self {
+            width: 0,
+            height: 0,
+            bits_per_sample: 8,
+            num_extra_channels: 0,
+            has_alpha: false,
+            alpha_premultiplied: false,
+            have_animation: false,
+            animation_loop_count: 0,
+            animation_tps_numerator: 1,
+            animation_tps_denominator: 1000,
+            uses_original_profile: false,
+            orientation: 1,
+        }
+    }
+}
+
+impl From<&InternalBasicInfo> for JxlRsBasicInfo {
+    fn from(info: &InternalBasicInfo) -> Self {
+        let has_alpha = info.extra_channels.iter().any(|ec| {
+            matches!(ec.ec_type, ExtraChannel::Alpha)
+        });
+        let (animation_loop_count, animation_tps_numerator, animation_tps_denominator) =
+            match &info.animation {
+                Some(anim) => (anim.num_loops, anim.tps_numerator, anim.tps_denominator),
+                None => (0, 1, 1000),
+            };
+        Self {
+            width: info.size.0 as u32,
+            height: info.size.1 as u32,
+            bits_per_sample: info.bit_depth.bits_per_sample(),
+            num_extra_channels: info.extra_channels.len() as u32,
+            has_alpha,
+            alpha_premultiplied: false,
+            have_animation: info.animation.is_some(),
+            animation_loop_count,
+            animation_tps_numerator,
+            animation_tps_denominator,
+            uses_original_profile: info.uses_original_profile,
+            orientation: info.orientation as u32,
+        }
+    }
+}
+
+impl Default for JxlRsFrameHeader {
+    fn default() -> Self {
+        Self {
+            duration: 0,
+            is_last: false,
+            name_length: 0,
+        }
+    }
+}
diff --git a/third_party/rust/jxl_macros/OWNERS b/third_party/rust/jxl_macros/OWNERS
new file mode 100644
index 0000000..0900548
--- /dev/null
+++ b/third_party/rust/jxl_macros/OWNERS
@@ -0,0 +1 @@
+file://third_party/rust/jxl/OWNERS
diff --git a/third_party/rust/jxl_macros/v0_1/BUILD.gn b/third_party/rust/jxl_macros/v0_1/BUILD.gn
new file mode 100644
index 0000000..1d84e769
--- /dev/null
+++ b/third_party/rust/jxl_macros/v0_1/BUILD.gn
@@ -0,0 +1,73 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# @generated from third_party/rust/chromium_crates_io/BUILD.gn.hbs by
+# tools/crates/gnrt.
+# Do not edit!
+
+import("//build/rust/cargo_crate.gni")
+
+cargo_crate("lib") {
+  crate_name = "jxl_macros"
+  epoch = "0.1"
+  crate_type = "proc-macro"
+  crate_root =
+      "//third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/src/lib.rs"
+  sources = [
+    "//third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/src/lib.rs",
+  ]
+  inputs = []
+
+  build_native_rust_unit_tests = false
+  edition = "2024"
+  cargo_pkg_authors = "Luca Versari <veluca93@gmail.com>"
+  cargo_pkg_name = "jxl_macros"
+  cargo_pkg_description = "High performance Rust implementation of a JPEG XL decoder - supporting macros"
+  cargo_pkg_repository = "https://github.com/libjxl/jxl-rs"
+  cargo_pkg_version = "0.1.4"
+
+  allow_unsafe = false
+
+  deps = [
+    "//third_party/rust/proc_macro2/v1:lib",
+    "//third_party/rust/proc_macro_error2/v2:lib",
+    "//third_party/rust/quote/v1:lib",
+    "//third_party/rust/syn/v2:lib",
+  ]
+
+  # Only for usage from third-party crates. Add the crate to
+  # //third_party/rust/chromium_crates_io/Cargo.toml to use
+  # it from first-party code.
+  visibility = [ "//third_party/rust/*" ]
+
+  #####################################################################
+  # Tweaking which GN `config`s apply to this target.
+
+  # Config changes that apply to all `//third_party/rust` crates.
+  _configs_to_remove = [
+    # We don't need code coverage data for any `chromium_crates_io` crates.
+    "//build/config/coverage:default_coverage",
+
+    # This is third-party code, so remove `chromium_code` config.  We are not
+    # at the same time adding `//build/config/compiler:no_chromium_code`,
+    # because 1) we don't want to pull how warnings are handled by that config
+    # and 2) that config doesn't have any non-warnings-related stuff.
+    "//build/config/compiler:chromium_code",
+  ]
+  _configs_to_add = []
+
+  # Changing (if needed) which configs apply to this specific crate (based on
+  # `extra_kv.configs_to_remove` and `extra_kv.configs_to_add` from
+  # `gnrt_config.toml`).
+  _configs_to_remove += []
+  _configs_to_add += []
+
+  # Applying config changes.
+  library_configs -= _configs_to_remove
+  library_configs += _configs_to_add
+  executable_configs -= _configs_to_remove
+  executable_configs += _configs_to_add
+  proc_macro_configs -= _configs_to_remove
+  proc_macro_configs += _configs_to_add
+}
diff --git a/third_party/rust/jxl_macros/v0_1/README.chromium b/third_party/rust/jxl_macros/v0_1/README.chromium
new file mode 100644
index 0000000..17369a0
--- /dev/null
+++ b/third_party/rust/jxl_macros/v0_1/README.chromium
@@ -0,0 +1,11 @@
+Name: jxl_macros
+URL: https://crates.io/crates/jxl_macros
+Version: 0.1.4
+Revision: e3d3eeb3b30c9a50e0c3646046648ae708154099
+Update Mechanism: Manual (https://crbug.com/449898466)
+License: BSD-3-Clause
+License File: //third_party/rust/chromium_crates_io/vendor/jxl_macros-v0_1/LICENSE
+Shipped: yes
+Security Critical: yes
+
+Description: High performance Rust implementation of a JPEG XL decoder - supporting macros
diff --git a/third_party/rust/jxl_simd/OWNERS b/third_party/rust/jxl_simd/OWNERS
new file mode 100644
index 0000000..0900548
--- /dev/null
+++ b/third_party/rust/jxl_simd/OWNERS
@@ -0,0 +1 @@
+file://third_party/rust/jxl/OWNERS
diff --git a/third_party/rust/jxl_simd/v0_1/BUILD.gn b/third_party/rust/jxl_simd/v0_1/BUILD.gn
new file mode 100644
index 0000000..2b81e04
--- /dev/null
+++ b/third_party/rust/jxl_simd/v0_1/BUILD.gn
@@ -0,0 +1,73 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# @generated from third_party/rust/chromium_crates_io/BUILD.gn.hbs by
+# tools/crates/gnrt.
+# Do not edit!
+
+import("//build/rust/cargo_crate.gni")
+
+cargo_crate("lib") {
+  crate_name = "jxl_simd"
+  epoch = "0.1"
+  crate_type = "rlib"
+  crate_root =
+      "//third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/lib.rs"
+  sources = [
+    "//third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/aarch64/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/aarch64/neon.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/lib.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/scalar.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/x86_64/avx.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/x86_64/avx512.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/x86_64/mod.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/src/x86_64/sse42.rs",
+  ]
+  inputs = []
+
+  build_native_rust_unit_tests = false
+  edition = "2024"
+  cargo_pkg_authors = "Luca Versari <veluca93@gmail.com>"
+  cargo_pkg_name = "jxl_simd"
+  cargo_pkg_description = "High performance Rust implementation of a JPEG XL decoder - SIMD support code"
+  cargo_pkg_repository = "https://github.com/libjxl/jxl-rs"
+  cargo_pkg_version = "0.1.4"
+
+  allow_unsafe = true
+
+  # Only for usage from third-party crates. Add the crate to
+  # //third_party/rust/chromium_crates_io/Cargo.toml to use
+  # it from first-party code.
+  visibility = [ "//third_party/rust/*" ]
+
+  #####################################################################
+  # Tweaking which GN `config`s apply to this target.
+
+  # Config changes that apply to all `//third_party/rust` crates.
+  _configs_to_remove = [
+    # We don't need code coverage data for any `chromium_crates_io` crates.
+    "//build/config/coverage:default_coverage",
+
+    # This is third-party code, so remove `chromium_code` config.  We are not
+    # at the same time adding `//build/config/compiler:no_chromium_code`,
+    # because 1) we don't want to pull how warnings are handled by that config
+    # and 2) that config doesn't have any non-warnings-related stuff.
+    "//build/config/compiler:chromium_code",
+  ]
+  _configs_to_add = []
+
+  # Changing (if needed) which configs apply to this specific crate (based on
+  # `extra_kv.configs_to_remove` and `extra_kv.configs_to_add` from
+  # `gnrt_config.toml`).
+  _configs_to_remove += []
+  _configs_to_add += []
+
+  # Applying config changes.
+  library_configs -= _configs_to_remove
+  library_configs += _configs_to_add
+  executable_configs -= _configs_to_remove
+  executable_configs += _configs_to_add
+  proc_macro_configs -= _configs_to_remove
+  proc_macro_configs += _configs_to_add
+}
diff --git a/third_party/rust/jxl_simd/v0_1/README.chromium b/third_party/rust/jxl_simd/v0_1/README.chromium
new file mode 100644
index 0000000..2c5f440
--- /dev/null
+++ b/third_party/rust/jxl_simd/v0_1/README.chromium
@@ -0,0 +1,11 @@
+Name: jxl_simd
+URL: https://crates.io/crates/jxl_simd
+Version: 0.1.4
+Revision: e3d3eeb3b30c9a50e0c3646046648ae708154099
+Update Mechanism: Manual (https://crbug.com/449898466)
+License: BSD-3-Clause
+License File: //third_party/rust/chromium_crates_io/vendor/jxl_simd-v0_1/LICENSE
+Shipped: yes
+Security Critical: yes
+
+Description: High performance Rust implementation of a JPEG XL decoder - SIMD support code
diff --git a/third_party/rust/jxl_transforms/OWNERS b/third_party/rust/jxl_transforms/OWNERS
new file mode 100644
index 0000000..0900548
--- /dev/null
+++ b/third_party/rust/jxl_transforms/OWNERS
@@ -0,0 +1 @@
+file://third_party/rust/jxl/OWNERS
diff --git a/third_party/rust/jxl_transforms/v0_1/BUILD.gn b/third_party/rust/jxl_transforms/v0_1/BUILD.gn
new file mode 100644
index 0000000..fafadf1
--- /dev/null
+++ b/third_party/rust/jxl_transforms/v0_1/BUILD.gn
@@ -0,0 +1,84 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# @generated from third_party/rust/chromium_crates_io/BUILD.gn.hbs by
+# tools/crates/gnrt.
+# Do not edit!
+
+import("//build/rust/cargo_crate.gni")
+
+cargo_crate("lib") {
+  crate_name = "jxl_transforms"
+  epoch = "0.1"
+  crate_type = "rlib"
+  crate_root = "//third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/lib.rs"
+  sources = [
+    "//third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct16.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct2.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct2d.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct32.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct4.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct8.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/idct_large.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/lib.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/reinterpreting_dct16.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/reinterpreting_dct2.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/reinterpreting_dct2d.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/reinterpreting_dct32.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/reinterpreting_dct4.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/reinterpreting_dct8.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/tests.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/transform.rs",
+    "//third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/src/transform_map.rs",
+  ]
+  inputs = []
+
+  build_native_rust_unit_tests = false
+  edition = "2021"
+  cargo_pkg_authors = "Luca Versari <veluca93@gmail.com>"
+  cargo_pkg_name = "jxl_transforms"
+  cargo_pkg_description =
+      "High performance Rust implementation of a JPEG XL decoder - Transforms"
+  cargo_pkg_repository = "https://github.com/libjxl/jxl-rs"
+  cargo_pkg_version = "0.1.4"
+
+  allow_unsafe = true
+
+  deps = [ "//third_party/rust/jxl_simd/v0_1:lib" ]
+
+  # Only for usage from third-party crates. Add the crate to
+  # //third_party/rust/chromium_crates_io/Cargo.toml to use
+  # it from first-party code.
+  visibility = [ "//third_party/rust/*" ]
+
+  #####################################################################
+  # Tweaking which GN `config`s apply to this target.
+
+  # Config changes that apply to all `//third_party/rust` crates.
+  _configs_to_remove = [
+    # We don't need code coverage data for any `chromium_crates_io` crates.
+    "//build/config/coverage:default_coverage",
+
+    # This is third-party code, so remove `chromium_code` config.  We are not
+    # at the same time adding `//build/config/compiler:no_chromium_code`,
+    # because 1) we don't want to pull how warnings are handled by that config
+    # and 2) that config doesn't have any non-warnings-related stuff.
+    "//build/config/compiler:chromium_code",
+  ]
+  _configs_to_add = []
+
+  # Changing (if needed) which configs apply to this specific crate (based on
+  # `extra_kv.configs_to_remove` and `extra_kv.configs_to_add` from
+  # `gnrt_config.toml`).
+  _configs_to_remove += []
+  _configs_to_add += []
+
+  # Applying config changes.
+  library_configs -= _configs_to_remove
+  library_configs += _configs_to_add
+  executable_configs -= _configs_to_remove
+  executable_configs += _configs_to_add
+  proc_macro_configs -= _configs_to_remove
+  proc_macro_configs += _configs_to_add
+}
diff --git a/third_party/rust/jxl_transforms/v0_1/README.chromium b/third_party/rust/jxl_transforms/v0_1/README.chromium
new file mode 100644
index 0000000..276c99f1
--- /dev/null
+++ b/third_party/rust/jxl_transforms/v0_1/README.chromium
@@ -0,0 +1,11 @@
+Name: jxl_transforms
+URL: https://crates.io/crates/jxl_transforms
+Version: 0.1.4
+Revision: e3d3eeb3b30c9a50e0c3646046648ae708154099
+Update Mechanism: Manual (https://crbug.com/449898466)
+License: BSD-3-Clause
+License File: //third_party/rust/chromium_crates_io/vendor/jxl_transforms-v0_1/LICENSE
+Shipped: yes
+Security Critical: yes
+
+Description: High performance Rust implementation of a JPEG XL decoder - Transforms
diff --git a/third_party/rust/num_derive/v0_4/BUILD.gn b/third_party/rust/num_derive/v0_4/BUILD.gn
new file mode 100644
index 0000000..f972750
--- /dev/null
+++ b/third_party/rust/num_derive/v0_4/BUILD.gn
@@ -0,0 +1,72 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# @generated from third_party/rust/chromium_crates_io/BUILD.gn.hbs by
+# tools/crates/gnrt.
+# Do not edit!
+
+import("//build/rust/cargo_crate.gni")
+
+cargo_crate("lib") {
+  crate_name = "num_derive"
+  epoch = "0.4"
+  crate_type = "proc-macro"
+  crate_root =
+      "//third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/src/lib.rs"
+  sources = [
+    "//third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/src/lib.rs",
+  ]
+  inputs = []
+
+  build_native_rust_unit_tests = false
+  edition = "2021"
+  cargo_pkg_authors = "The Rust Project Developers"
+  cargo_pkg_name = "num-derive"
+  cargo_pkg_description = "Numeric syntax extensions"
+  cargo_pkg_repository = "https://github.com/rust-num/num-derive"
+  cargo_pkg_version = "0.4.2"
+
+  allow_unsafe = false
+
+  deps = [
+    "//third_party/rust/proc_macro2/v1:lib",
+    "//third_party/rust/quote/v1:lib",
+    "//third_party/rust/syn/v2:lib",
+  ]
+
+  # Only for usage from third-party crates. Add the crate to
+  # //third_party/rust/chromium_crates_io/Cargo.toml to use
+  # it from first-party code.
+  visibility = [ "//third_party/rust/*" ]
+
+  #####################################################################
+  # Tweaking which GN `config`s apply to this target.
+
+  # Config changes that apply to all `//third_party/rust` crates.
+  _configs_to_remove = [
+    # We don't need code coverage data for any `chromium_crates_io` crates.
+    "//build/config/coverage:default_coverage",
+
+    # This is third-party code, so remove `chromium_code` config.  We are not
+    # at the same time adding `//build/config/compiler:no_chromium_code`,
+    # because 1) we don't want to pull how warnings are handled by that config
+    # and 2) that config doesn't have any non-warnings-related stuff.
+    "//build/config/compiler:chromium_code",
+  ]
+  _configs_to_add = []
+
+  # Changing (if needed) which configs apply to this specific crate (based on
+  # `extra_kv.configs_to_remove` and `extra_kv.configs_to_add` from
+  # `gnrt_config.toml`).
+  _configs_to_remove += []
+  _configs_to_add += []
+
+  # Applying config changes.
+  library_configs -= _configs_to_remove
+  library_configs += _configs_to_add
+  executable_configs -= _configs_to_remove
+  executable_configs += _configs_to_add
+  proc_macro_configs -= _configs_to_remove
+  proc_macro_configs += _configs_to_add
+}
diff --git a/third_party/rust/num_derive/v0_4/README.chromium b/third_party/rust/num_derive/v0_4/README.chromium
new file mode 100644
index 0000000..da35d216
--- /dev/null
+++ b/third_party/rust/num_derive/v0_4/README.chromium
@@ -0,0 +1,11 @@
+Name: num-derive
+URL: https://crates.io/crates/num-derive
+Version: 0.4.2
+Revision: 7cc33515dd2ae0eb43c5795c50ce49c554e8ba02
+Update Mechanism: Manual (https://crbug.com/449898466)
+License: Apache-2.0
+License File: //third_party/rust/chromium_crates_io/vendor/num-derive-v0_4/LICENSE-APACHE
+Shipped: yes
+Security Critical: yes
+
+Description: Numeric syntax extensions
diff --git a/third_party/rust/num_traits/v0_2/BUILD.gn b/third_party/rust/num_traits/v0_2/BUILD.gn
index 00f46bf..fb6c8c4 100644
--- a/third_party/rust/num_traits/v0_2/BUILD.gn
+++ b/third_party/rust/num_traits/v0_2/BUILD.gn
@@ -48,7 +48,11 @@
   allow_unsafe = true
 
   build_deps = [ "//third_party/rust/autocfg/v1:buildrs_support" ]
-  features = [ "i128" ]
+  features = [
+    "default",
+    "i128",
+    "std",
+  ]
 
   # Only for usage from third-party crates. Add the crate to
   # //third_party/rust/chromium_crates_io/Cargo.toml to use
diff --git a/third_party/rust/proc_macro_error2/v2/BUILD.gn b/third_party/rust/proc_macro_error2/v2/BUILD.gn
new file mode 100644
index 0000000..7b0c834f
--- /dev/null
+++ b/third_party/rust/proc_macro_error2/v2/BUILD.gn
@@ -0,0 +1,82 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# @generated from third_party/rust/chromium_crates_io/BUILD.gn.hbs by
+# tools/crates/gnrt.
+# Do not edit!
+
+import("//build/rust/cargo_crate.gni")
+
+cargo_crate("lib") {
+  crate_name = "proc_macro_error2"
+  epoch = "2"
+  crate_type = "rlib"
+  crate_root = "//third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/lib.rs"
+  sources = [
+    "//third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/diagnostic.rs",
+    "//third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/dummy.rs",
+    "//third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/imp/delegate.rs",
+    "//third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/imp/fallback.rs",
+    "//third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/lib.rs",
+    "//third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/macros.rs",
+    "//third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/src/sealed.rs",
+  ]
+  inputs = []
+
+  build_native_rust_unit_tests = false
+  edition = "2021"
+  cargo_pkg_authors = "CreepySkeleton <creepy-skeleton@yandex.ru>, GnomedDev <david2005thomas@gmail.com>"
+  cargo_pkg_name = "proc-macro-error2"
+  cargo_pkg_description = "Almost drop-in replacement to panics in proc-macros"
+  cargo_pkg_repository = "https://github.com/GnomedDev/proc-macro-error-2"
+  cargo_pkg_version = "2.0.1"
+
+  allow_unsafe = false
+
+  deps = [
+    "//third_party/rust/proc_macro2/v1:lib",
+    "//third_party/rust/proc_macro_error_attr2/v2:lib",
+    "//third_party/rust/quote/v1:lib",
+    "//third_party/rust/syn/v2:lib",
+  ]
+  features = [
+    "default",
+    "syn-error",
+  ]
+
+  # Only for usage from third-party crates. Add the crate to
+  # //third_party/rust/chromium_crates_io/Cargo.toml to use
+  # it from first-party code.
+  visibility = [ "//third_party/rust/*" ]
+
+  #####################################################################
+  # Tweaking which GN `config`s apply to this target.
+
+  # Config changes that apply to all `//third_party/rust` crates.
+  _configs_to_remove = [
+    # We don't need code coverage data for any `chromium_crates_io` crates.
+    "//build/config/coverage:default_coverage",
+
+    # This is third-party code, so remove `chromium_code` config.  We are not
+    # at the same time adding `//build/config/compiler:no_chromium_code`,
+    # because 1) we don't want to pull how warnings are handled by that config
+    # and 2) that config doesn't have any non-warnings-related stuff.
+    "//build/config/compiler:chromium_code",
+  ]
+  _configs_to_add = []
+
+  # Changing (if needed) which configs apply to this specific crate (based on
+  # `extra_kv.configs_to_remove` and `extra_kv.configs_to_add` from
+  # `gnrt_config.toml`).
+  _configs_to_remove += []
+  _configs_to_add += []
+
+  # Applying config changes.
+  library_configs -= _configs_to_remove
+  library_configs += _configs_to_add
+  executable_configs -= _configs_to_remove
+  executable_configs += _configs_to_add
+  proc_macro_configs -= _configs_to_remove
+  proc_macro_configs += _configs_to_add
+}
diff --git a/third_party/rust/proc_macro_error2/v2/README.chromium b/third_party/rust/proc_macro_error2/v2/README.chromium
new file mode 100644
index 0000000..b0c94f5a
--- /dev/null
+++ b/third_party/rust/proc_macro_error2/v2/README.chromium
@@ -0,0 +1,11 @@
+Name: proc-macro-error2
+URL: https://crates.io/crates/proc-macro-error2
+Version: 2.0.1
+Revision: 9b129234ed8f50d3ff8da09041dcbd980b63fc8c
+Update Mechanism: Manual (https://crbug.com/449898466)
+License: Apache-2.0
+License File: //third_party/rust/chromium_crates_io/vendor/proc-macro-error2-v2/LICENSE-APACHE
+Shipped: yes
+Security Critical: yes
+
+Description: Almost drop-in replacement to panics in proc-macros
diff --git a/third_party/rust/proc_macro_error_attr2/v2/BUILD.gn b/third_party/rust/proc_macro_error_attr2/v2/BUILD.gn
new file mode 100644
index 0000000..0b3c6f99
--- /dev/null
+++ b/third_party/rust/proc_macro_error_attr2/v2/BUILD.gn
@@ -0,0 +1,72 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# @generated from third_party/rust/chromium_crates_io/BUILD.gn.hbs by
+# tools/crates/gnrt.
+# Do not edit!
+
+import("//build/rust/cargo_crate.gni")
+
+cargo_crate("lib") {
+  crate_name = "proc_macro_error_attr2"
+  epoch = "2"
+  crate_type = "proc-macro"
+  crate_root = "//third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/src/lib.rs"
+  sources = [
+    "//third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/src/lib.rs",
+    "//third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/src/parse.rs",
+    "//third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/src/settings.rs",
+  ]
+  inputs = []
+
+  build_native_rust_unit_tests = false
+  edition = "2021"
+  cargo_pkg_authors = "CreepySkeleton <creepy-skeleton@yandex.ru>, GnomedDev <david2005thomas@gmail.com>"
+  cargo_pkg_name = "proc-macro-error-attr2"
+  cargo_pkg_description = "Attribute macro for the proc-macro-error2 crate"
+  cargo_pkg_repository = "https://github.com/GnomedDev/proc-macro-error-2"
+  cargo_pkg_version = "2.0.0"
+
+  allow_unsafe = false
+
+  deps = [
+    "//third_party/rust/proc_macro2/v1:lib",
+    "//third_party/rust/quote/v1:lib",
+  ]
+
+  # Only for usage from third-party crates. Add the crate to
+  # //third_party/rust/chromium_crates_io/Cargo.toml to use
+  # it from first-party code.
+  visibility = [ "//third_party/rust/*" ]
+
+  #####################################################################
+  # Tweaking which GN `config`s apply to this target.
+
+  # Config changes that apply to all `//third_party/rust` crates.
+  _configs_to_remove = [
+    # We don't need code coverage data for any `chromium_crates_io` crates.
+    "//build/config/coverage:default_coverage",
+
+    # This is third-party code, so remove `chromium_code` config.  We are not
+    # at the same time adding `//build/config/compiler:no_chromium_code`,
+    # because 1) we don't want to pull how warnings are handled by that config
+    # and 2) that config doesn't have any non-warnings-related stuff.
+    "//build/config/compiler:chromium_code",
+  ]
+  _configs_to_add = []
+
+  # Changing (if needed) which configs apply to this specific crate (based on
+  # `extra_kv.configs_to_remove` and `extra_kv.configs_to_add` from
+  # `gnrt_config.toml`).
+  _configs_to_remove += []
+  _configs_to_add += []
+
+  # Applying config changes.
+  library_configs -= _configs_to_remove
+  library_configs += _configs_to_add
+  executable_configs -= _configs_to_remove
+  executable_configs += _configs_to_add
+  proc_macro_configs -= _configs_to_remove
+  proc_macro_configs += _configs_to_add
+}
diff --git a/third_party/rust/proc_macro_error_attr2/v2/README.chromium b/third_party/rust/proc_macro_error_attr2/v2/README.chromium
new file mode 100644
index 0000000..275b97d
--- /dev/null
+++ b/third_party/rust/proc_macro_error_attr2/v2/README.chromium
@@ -0,0 +1,11 @@
+Name: proc-macro-error-attr2
+URL: https://crates.io/crates/proc-macro-error-attr2
+Version: 2.0.0
+Revision: 4302a1d749def2b2929b1292bf418bd58df04486
+Update Mechanism: Manual (https://crbug.com/449898466)
+License: Apache-2.0
+License File: //third_party/rust/chromium_crates_io/vendor/proc-macro-error-attr2-v2/LICENSE-APACHE
+Shipped: yes
+Security Critical: yes
+
+Description: Attribute macro for the proc-macro-error2 crate
diff --git a/third_party/rust/thiserror/v2/BUILD.gn b/third_party/rust/thiserror/v2/BUILD.gn
new file mode 100644
index 0000000..c27cee6
--- /dev/null
+++ b/third_party/rust/thiserror/v2/BUILD.gn
@@ -0,0 +1,82 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# @generated from third_party/rust/chromium_crates_io/BUILD.gn.hbs by
+# tools/crates/gnrt.
+# Do not edit!
+
+import("//build/rust/cargo_crate.gni")
+
+cargo_crate("lib") {
+  crate_name = "thiserror"
+  epoch = "2"
+  crate_type = "rlib"
+  crate_root =
+      "//third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/lib.rs"
+  sources = [
+    "//third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/aserror.rs",
+    "//third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/display.rs",
+    "//third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/lib.rs",
+    "//third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/private.rs",
+    "//third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/provide.rs",
+    "//third_party/rust/chromium_crates_io/vendor/thiserror-v2/src/var.rs",
+  ]
+  inputs = []
+
+  build_native_rust_unit_tests = false
+  edition = "2021"
+  cargo_pkg_authors = "David Tolnay <dtolnay@gmail.com>"
+  cargo_pkg_name = "thiserror"
+  cargo_pkg_description = "derive(Error)"
+  cargo_pkg_repository = "https://github.com/dtolnay/thiserror"
+  cargo_pkg_version = "2.0.17"
+
+  allow_unsafe = false
+
+  deps = [ "//third_party/rust/thiserror_impl/v2:lib" ]
+  features = [
+    "default",
+    "std",
+  ]
+  build_root =
+      "//third_party/rust/chromium_crates_io/vendor/thiserror-v2/build.rs"
+  build_sources =
+      [ "//third_party/rust/chromium_crates_io/vendor/thiserror-v2/build.rs" ]
+  build_script_outputs = [ "private.rs" ]
+
+  # Only for usage from third-party crates. Add the crate to
+  # //third_party/rust/chromium_crates_io/Cargo.toml to use
+  # it from first-party code.
+  visibility = [ "//third_party/rust/*" ]
+
+  #####################################################################
+  # Tweaking which GN `config`s apply to this target.
+
+  # Config changes that apply to all `//third_party/rust` crates.
+  _configs_to_remove = [
+    # We don't need code coverage data for any `chromium_crates_io` crates.
+    "//build/config/coverage:default_coverage",
+
+    # This is third-party code, so remove `chromium_code` config.  We are not
+    # at the same time adding `//build/config/compiler:no_chromium_code`,
+    # because 1) we don't want to pull how warnings are handled by that config
+    # and 2) that config doesn't have any non-warnings-related stuff.
+    "//build/config/compiler:chromium_code",
+  ]
+  _configs_to_add = []
+
+  # Changing (if needed) which configs apply to this specific crate (based on
+  # `extra_kv.configs_to_remove` and `extra_kv.configs_to_add` from
+  # `gnrt_config.toml`).
+  _configs_to_remove += []
+  _configs_to_add += []
+
+  # Applying config changes.
+  library_configs -= _configs_to_remove
+  library_configs += _configs_to_add
+  executable_configs -= _configs_to_remove
+  executable_configs += _configs_to_add
+  proc_macro_configs -= _configs_to_remove
+  proc_macro_configs += _configs_to_add
+}
diff --git a/third_party/rust/thiserror/v2/README.chromium b/third_party/rust/thiserror/v2/README.chromium
new file mode 100644
index 0000000..88137c6
--- /dev/null
+++ b/third_party/rust/thiserror/v2/README.chromium
@@ -0,0 +1,11 @@
+Name: thiserror
+URL: https://crates.io/crates/thiserror
+Version: 2.0.17
+Revision: 72ae716e6d6a7f7fdabdc394018c745b4d39ca45
+Update Mechanism: Manual (https://crbug.com/449898466)
+License: Apache-2.0
+License File: //third_party/rust/chromium_crates_io/vendor/thiserror-v2/LICENSE-APACHE
+Shipped: yes
+Security Critical: yes
+
+Description: derive(Error)
diff --git a/third_party/rust/thiserror_impl/v2/BUILD.gn b/third_party/rust/thiserror_impl/v2/BUILD.gn
new file mode 100644
index 0000000..7a3d2e1e
--- /dev/null
+++ b/third_party/rust/thiserror_impl/v2/BUILD.gn
@@ -0,0 +1,81 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# @generated from third_party/rust/chromium_crates_io/BUILD.gn.hbs by
+# tools/crates/gnrt.
+# Do not edit!
+
+import("//build/rust/cargo_crate.gni")
+
+cargo_crate("lib") {
+  crate_name = "thiserror_impl"
+  epoch = "2"
+  crate_type = "proc-macro"
+  crate_root = "//third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/lib.rs"
+  sources = [
+    "//third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/ast.rs",
+    "//third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/attr.rs",
+    "//third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/expand.rs",
+    "//third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/fallback.rs",
+    "//third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/fmt.rs",
+    "//third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/generics.rs",
+    "//third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/lib.rs",
+    "//third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/prop.rs",
+    "//third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/scan_expr.rs",
+    "//third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/unraw.rs",
+    "//third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/src/valid.rs",
+  ]
+  inputs = []
+
+  build_native_rust_unit_tests = false
+  edition = "2021"
+  cargo_pkg_authors = "David Tolnay <dtolnay@gmail.com>"
+  cargo_pkg_name = "thiserror-impl"
+  cargo_pkg_description = "Implementation detail of the `thiserror` crate"
+  cargo_pkg_repository = "https://github.com/dtolnay/thiserror"
+  cargo_pkg_version = "2.0.17"
+
+  allow_unsafe = false
+
+  deps = [
+    "//third_party/rust/proc_macro2/v1:lib",
+    "//third_party/rust/quote/v1:lib",
+    "//third_party/rust/syn/v2:lib",
+  ]
+
+  # Only for usage from third-party crates. Add the crate to
+  # //third_party/rust/chromium_crates_io/Cargo.toml to use
+  # it from first-party code.
+  visibility = [ "//third_party/rust/*" ]
+
+  #####################################################################
+  # Tweaking which GN `config`s apply to this target.
+
+  # Config changes that apply to all `//third_party/rust` crates.
+  _configs_to_remove = [
+    # We don't need code coverage data for any `chromium_crates_io` crates.
+    "//build/config/coverage:default_coverage",
+
+    # This is third-party code, so remove `chromium_code` config.  We are not
+    # at the same time adding `//build/config/compiler:no_chromium_code`,
+    # because 1) we don't want to pull how warnings are handled by that config
+    # and 2) that config doesn't have any non-warnings-related stuff.
+    "//build/config/compiler:chromium_code",
+  ]
+  _configs_to_add = []
+
+  # Changing (if needed) which configs apply to this specific crate (based on
+  # `extra_kv.configs_to_remove` and `extra_kv.configs_to_add` from
+  # `gnrt_config.toml`).
+  _configs_to_remove += []
+  _configs_to_add += []
+
+  # Applying config changes.
+  library_configs -= _configs_to_remove
+  library_configs += _configs_to_add
+  executable_configs -= _configs_to_remove
+  executable_configs += _configs_to_add
+  proc_macro_configs -= _configs_to_remove
+  proc_macro_configs += _configs_to_add
+}
diff --git a/third_party/rust/thiserror_impl/v2/README.chromium b/third_party/rust/thiserror_impl/v2/README.chromium
new file mode 100644
index 0000000..43aaaf4
--- /dev/null
+++ b/third_party/rust/thiserror_impl/v2/README.chromium
@@ -0,0 +1,11 @@
+Name: thiserror-impl
+URL: https://crates.io/crates/thiserror-impl
+Version: 2.0.17
+Revision: 72ae716e6d6a7f7fdabdc394018c745b4d39ca45
+Update Mechanism: Manual (https://crbug.com/449898466)
+License: Apache-2.0
+License File: //third_party/rust/chromium_crates_io/vendor/thiserror-impl-v2/LICENSE-APACHE
+Shipped: yes
+Security Critical: yes
+
+Description: Implementation detail of the `thiserror` crate
diff --git a/third_party/skia b/third_party/skia
index 07dc976..82fff05 160000
--- a/third_party/skia
+++ b/third_party/skia
@@ -1 +1 @@
-Subproject commit 07dc97655915230e26ef96cc41ac7193d6dd356c
+Subproject commit 82fff05cc62168683f5e94e65a63c49ec210bf47
diff --git a/extensions/common/api/usb.idl b/tools/json_schema_compiler/test/converted_schemas/usb.idl
similarity index 100%
rename from extensions/common/api/usb.idl
rename to tools/json_schema_compiler/test/converted_schemas/usb.idl
diff --git a/tools/json_schema_compiler/test/converted_schemas/usb.webidl b/tools/json_schema_compiler/test/converted_schemas/usb.webidl
new file mode 100644
index 0000000..fa0764c9
--- /dev/null
+++ b/tools/json_schema_compiler/test/converted_schemas/usb.webidl
@@ -0,0 +1,454 @@
+// 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.
+
+// Direction, Recipient, RequestType, and TransferType all map to their
+// namesakes within the USB specification.
+enum Direction {
+  "in",
+  "out"
+};
+
+enum Recipient {
+  "device",
+  "interface",
+  "endpoint",
+  "other"
+};
+
+enum RequestType {
+  "standard",
+  "class",
+  "vendor",
+  "reserved"
+};
+
+enum TransferType {
+  "control",
+  "interrupt",
+  "isochronous",
+  "bulk"
+};
+
+// For interrupt and isochronous modes, SynchronizationType and UsageType map
+// to their namesakes within the USB specification.
+enum SynchronizationType {
+  "asynchronous",
+  "adaptive",
+  "synchronous"
+};
+
+enum UsageType {
+  "data",
+  "feedback",
+  "explicitFeedback",
+  "periodic",
+  "notification"
+};
+
+dictionary Device {
+  // An opaque ID for the USB device. It remains unchanged until the device is
+  // unplugged.
+  required long device;
+  // The device vendor ID.
+  required long vendorId;
+  // The product ID.
+  required long productId;
+  // The device version (bcdDevice field).
+  required long version;
+  // The iProduct string read from the device, if available.
+  required DOMString productName;
+  // The iManufacturer string read from the device, if available.
+  required DOMString manufacturerName;
+  // The iSerialNumber string read from the device, if available.
+  required DOMString serialNumber;
+};
+
+dictionary ConnectionHandle {
+  // An opaque handle representing this connection to the USB device and all
+  // associated claimed interfaces and pending transfers. A new handle is
+  // created each time the device is opened. The connection handle is
+  // different from $(ref:Device.device).
+  required long handle;
+  // The device vendor ID.
+  required long vendorId;
+  // The product ID.
+  required long productId;
+};
+
+dictionary EndpointDescriptor {
+  // Endpoint address.
+  required long address;
+  // Transfer type.
+  required TransferType type;
+  // Transfer direction.
+  required Direction direction;
+  // Maximum packet size.
+  required long maximumPacketSize;
+  // Transfer synchronization mode (isochronous only).
+  SynchronizationType synchronization;
+  // Endpoint usage hint.
+  UsageType usage;
+  // Polling interval (interrupt and isochronous only).
+  long pollingInterval;
+  // Extra descriptor data associated with this endpoint.
+  required ArrayBuffer extra_data;
+};
+
+dictionary InterfaceDescriptor {
+  // The interface number.
+  required long interfaceNumber;
+  // The interface alternate setting number (defaults to <code>0</code).
+  required long alternateSetting;
+  // The USB interface class.
+  required long interfaceClass;
+  // The USB interface sub-class.
+  required long interfaceSubclass;
+  // The USB interface protocol.
+  required long interfaceProtocol;
+  // Description of the interface.
+  DOMString description;
+  // Available endpoints.
+  required sequence<EndpointDescriptor> endpoints;
+  // Extra descriptor data associated with this interface.
+  required ArrayBuffer extra_data;
+};
+
+dictionary ConfigDescriptor {
+  // Is this the active configuration?
+  required boolean active;
+  // The configuration number.
+  required long configurationValue;
+  // Description of the configuration.
+  DOMString description;
+  // The device is self-powered.
+  required boolean selfPowered;
+  // The device supports remote wakeup.
+  required boolean remoteWakeup;
+  // The maximum power needed by this device in milliamps (mA).
+  required long maxPower;
+  // Available interfaces.
+  required sequence<InterfaceDescriptor> interfaces;
+  // Extra descriptor data associated with this configuration.
+  required ArrayBuffer extra_data;
+};
+
+dictionary ControlTransferInfo {
+  // The transfer direction (<code>"in"</code> or <code>"out"</code>).
+  required Direction direction;
+
+  // The transfer target. The target given by <code>index</code> must be
+  // claimed if <code>"interface"</code> or <code>"endpoint"</code>.
+  required Recipient recipient;
+
+  // The request type.
+  required RequestType requestType;
+
+  // The <code>bRequest</code> field, see <i>Universal Serial Bus
+  // Specification Revision 1.1</i> &sect; 9.3.
+  required long request;
+  // The <code>wValue</code> field, see <i>Ibid</i>.
+  required long value;
+  // The <code>wIndex</code> field, see <i>Ibid</i>.
+  required long index;
+
+  // The maximum number of bytes to receive (required only by input
+  // transfers).
+  long length;
+
+  // The data to transmit (required only by output transfers).
+  ArrayBuffer data;
+
+  // Request timeout (in milliseconds). The default value <code>0</code>
+  // indicates no timeout.
+  long timeout;
+};
+
+dictionary GenericTransferInfo {
+  // The transfer direction (<code>"in"</code> or <code>"out"</code>).
+  required Direction direction;
+
+  // The target endpoint address. The interface containing this endpoint must
+  // be claimed.
+  required long endpoint;
+
+  // The maximum number of bytes to receive (required only by input
+  // transfers).
+  long length;
+
+  // The data to transmit (required only by output transfers).
+  ArrayBuffer data;
+
+  // Request timeout (in milliseconds). The default value <code>0</code>
+  // indicates no timeout.
+  long timeout;
+};
+
+dictionary IsochronousTransferInfo {
+  // Transfer parameters. The transfer length or data buffer specified in this
+  // parameter block is split along <code>packetLength</code> boundaries to
+  // form the individual packets of the transfer.
+  required GenericTransferInfo transferInfo;
+
+  // The total number of packets in this transfer.
+  required long packets;
+
+  // The length of each of the packets in this transfer.
+  required long packetLength;
+};
+
+dictionary TransferResultInfo {
+  // A value of <code>0</code> indicates that the transfer was a success.
+  // Other values indicate failure.
+  long resultCode;
+
+  // The data returned by an input transfer. <code>undefined</code> for output
+  // transfers.
+  ArrayBuffer data;
+};
+
+dictionary DeviceFilter {
+  // Device vendor ID.
+  long vendorId;
+  // Device product ID, checked only if the vendor ID matches.
+  long productId;
+  // USB interface class, matches any interface on the device.
+  long interfaceClass;
+  // USB interface sub-class, checked only if the interface class matches.
+  long interfaceSubclass;
+  // USB interface protocol, checked only if the interface sub-class matches.
+  long interfaceProtocol;
+};
+
+dictionary EnumerateDevicesOptions {
+  [deprecated="Equivalent to setting $(ref:DeviceFilter.vendorId)."]
+  long vendorId;
+  [deprecated="Equivalent to setting $(ref:DeviceFilter.productId)."]
+  long productId;
+  // A device matching any given filter will be returned. An empty filter list
+  // will return all devices the app has permission for.
+  sequence<DeviceFilter> filters;
+};
+
+dictionary EnumerateDevicesAndRequestAccessOptions {
+  // The device vendor ID.
+  required long vendorId;
+  // The product ID.
+  required long productId;
+  // The interface ID to request access to.
+  // Only available on Chrome OS. It has no effect on other platforms.
+  long interfaceId;
+};
+
+dictionary DevicePromptOptions {
+  // Allow the user to select multiple devices.
+  boolean multiple;
+  // Filter the list of devices presented to the user. If multiple filters are
+  // provided devices matching any filter will be displayed.
+  sequence<DeviceFilter> filters;
+};
+
+callback OnDeviceAddedListener = undefined (Device device);
+
+interface OnDeviceAddedEvent : ExtensionEvent {
+  static undefined addListener(OnDeviceAddedListener listener);
+  static undefined removeListener(OnDeviceAddedListener listener);
+  static boolean hasListener(OnDeviceAddedListener listener);
+};
+
+callback OnDeviceRemovedListener = undefined (Device device);
+
+interface OnDeviceRemovedEvent : ExtensionEvent {
+  static undefined addListener(OnDeviceRemovedListener listener);
+  static undefined removeListener(OnDeviceRemovedListener listener);
+  static boolean hasListener(OnDeviceRemovedListener listener);
+};
+
+// Use the <code>chrome.usb</code> API to interact with connected USB
+// devices. This API provides access to USB operations from within the context
+// of an app. Using this API, apps can function as drivers for hardware devices.
+// Errors generated by this API are reported by setting
+// $(ref:runtime.lastError) and executing the function's regular callback. The
+// callback's regular parameters will be undefined in this case.
+interface Usb {
+  // Enumerates connected USB devices.
+  // |options|: The properties to search for on target devices.
+  // |PromiseValue|: devices
+  [requiredCallback] static Promise<sequence<Device>> getDevices(
+      EnumerateDevicesOptions options);
+
+  // Presents a device picker to the user and returns the $(ref:Device)s
+  // selected.
+  // If the user cancels the picker devices will be empty. A user gesture
+  // is required for the dialog to display. Without a user gesture, the
+  // callback will run as though the user cancelled.
+  // |options|: Configuration of the device picker dialog box.
+  // |Returns|: Invoked with a list of chosen $(ref:Device)s.
+  // |PromiseValue|: devices
+  [requiredCallback] static Promise<sequence<Device>> getUserSelectedDevices(
+      DevicePromptOptions options);
+
+  // Returns the full set of device configuration descriptors.
+  // |device|: The $(ref:Device) to fetch descriptors from.
+  // |PromiseValue|: configs
+  [requiredCallback]
+  static Promise<sequence<ConfigDescriptor>> getConfigurations(
+      Device device);
+
+  // Requests access from the permission broker to a device claimed by
+  // Chrome OS if the given interface on the device is not claimed.
+  //
+  // |device|: The $(ref:Device) to request access to.
+  // |interfaceId|: The particular interface requested.
+  // |PromiseValue|: success
+  [deprecated="This function was Chrome OS specific and calling it on other
+    platforms would fail. This operation is now implicitly performed as part of
+    $(ref:openDevice) and this function will return <code>true</code> on all
+    platforms.", requiredCallback]
+  static Promise<boolean> requestAccess(Device device,
+                            long interfaceId);
+
+  // Opens a USB device returned by $(ref:getDevices).
+  // |device|: The $(ref:Device) to open.
+  // |PromiseValue|: handle
+  [requiredCallback] static Promise<ConnectionHandle> openDevice(
+      Device device);
+
+  // Finds USB devices specified by the vendor, product and (optionally)
+  // interface IDs and if permissions allow opens them for use.
+  //
+  // If the access request is rejected or the device fails to be opened a
+  // connection handle will not be created or returned.
+  //
+  // Calling this method is equivalent to calling $(ref:getDevices) followed
+  // by $(ref:openDevice) for each device.
+  //
+  // |options|: The properties to search for on target devices.
+  // |PromiseValue|: handles
+  [requiredCallback] static Promise<sequence<ConnectionHandle>> findDevices(
+      EnumerateDevicesAndRequestAccessOptions options);
+
+  // Closes a connection handle. Invoking operations on a handle after it
+  // has been closed is a safe operation but causes no action to be taken.
+  // |handle|: The $(ref:ConnectionHandle) to close.
+  static Promise<undefined> closeDevice(
+      ConnectionHandle handle);
+
+  // Select a device configuration.
+  //
+  // This function effectively resets the device by selecting one of the
+  // device's available configurations. Only configuration values greater
+  // than <code>0</code> are valid however some buggy devices have a working
+  // configuration <code>0</code> and so this value is allowed.
+  // |handle|: An open connection to the device.
+  [requiredCallback] static Promise<undefined> setConfiguration(
+      ConnectionHandle handle,
+      long configurationValue);
+
+  // Gets the configuration descriptor for the currently selected
+  // configuration.
+  // |handle|: An open connection to the device.
+  // |PromiseValue|: config
+  [requiredCallback] static Promise<ConfigDescriptor> getConfiguration(
+      ConnectionHandle handle);
+
+  // Lists all interfaces on a USB device.
+  // |handle|: An open connection to the device.
+  // |PromiseValue|: descriptors
+  [requiredCallback]
+  static Promise<sequence<InterfaceDescriptor>> listInterfaces(
+      ConnectionHandle handle);
+
+  // Claims an interface on a USB device.
+  // Before data can be transfered to an interface or associated endpoints the
+  // interface must be claimed. Only one connection handle can claim an
+  // interface at any given time. If the interface is already claimed, this
+  // call will fail.
+  //
+  // $(ref:releaseInterface) should be called when the interface is no longer
+  // needed.
+  //
+  // |handle|: An open connection to the device.
+  // |interfaceNumber|: The interface to be claimed.
+  [requiredCallback] static Promise<undefined> claimInterface(
+      ConnectionHandle handle,
+      long interfaceNumber);
+
+  // Releases a claimed interface.
+  // |handle|: An open connection to the device.
+  // |interfaceNumber|: The interface to be released.
+  [requiredCallback] static Promise<undefined> releaseInterface(
+      ConnectionHandle handle,
+      long interfaceNumber);
+
+  // Selects an alternate setting on a previously claimed interface.
+  // |handle|: An open connection to the device where this interface has been
+  //     claimed.
+  // |interfaceNumber|: The interface to configure.
+  // |alternateSetting|: The alternate setting to configure.
+  [requiredCallback] static Promise<undefined> setInterfaceAlternateSetting(
+      ConnectionHandle handle,
+      long interfaceNumber,
+      long alternateSetting);
+
+  // Performs a control transfer on the specified device.
+  //
+  // Control transfers refer to either the device, an interface or an
+  // endpoint. Transfers to an interface or endpoint require the interface to
+  // be claimed.
+  //
+  // |handle|: An open connection to the device.
+  // |PromiseValue|: info
+  [requiredCallback] static Promise<TransferResultInfo> controlTransfer(
+      ConnectionHandle handle,
+      ControlTransferInfo transferInfo);
+
+  // Performs a bulk transfer on the specified device.
+  // |handle|: An open connection to the device.
+  // |transferInfo|: The transfer parameters.
+  // |PromiseValue|: info
+  [requiredCallback] static Promise<TransferResultInfo> bulkTransfer(
+      ConnectionHandle handle,
+      GenericTransferInfo transferInfo);
+
+  // Performs an interrupt transfer on the specified device.
+  // |handle|: An open connection to the device.
+  // |transferInfo|: The transfer parameters.
+  // |PromiseValue|: info
+  [requiredCallback] static Promise<TransferResultInfo> interruptTransfer(
+      ConnectionHandle handle,
+      GenericTransferInfo transferInfo);
+
+  // Performs an isochronous transfer on the specific device.
+  // |handle|: An open connection to the device.
+  // |PromiseValue|: info
+  [requiredCallback] static Promise<TransferResultInfo> isochronousTransfer(
+      ConnectionHandle handle,
+      IsochronousTransferInfo transferInfo);
+
+  // Tries to reset the USB device.
+  // If the reset fails, the given connection handle will be closed and the
+  // USB device will appear to be disconnected then reconnected.
+  // In this case $(ref:getDevices) or $(ref:findDevices) must be called again
+  // to acquire the device.
+  //
+  // |handle|: A connection handle to reset.
+  // |PromiseValue|: success
+  [requiredCallback] static Promise<boolean> resetDevice(
+      ConnectionHandle handle);
+
+  // Event generated when a device is added to the system. Events are only
+  // broadcast to apps and extensions that have permission to access the
+  // device. Permission may have been granted at install time, when the user
+  // accepted an optional permission (see $(ref:permissions.request)), or
+  // through $(ref:getUserSelectedDevices).
+  static attribute OnDeviceAddedEvent onDeviceAdded;
+
+  // Event generated when a device is removed from the system. See
+  // $(ref:onDeviceAdded) for which events are delivered.
+  static attribute OnDeviceRemovedEvent onDeviceRemoved;
+};
+
+partial interface Browser {
+  static attribute Usb usb;
+};
diff --git a/tools/json_schema_compiler/web_idl_diff_tool_test.py b/tools/json_schema_compiler/web_idl_diff_tool_test.py
index b63d30f4..0cd537f 100755
--- a/tools/json_schema_compiler/web_idl_diff_tool_test.py
+++ b/tools/json_schema_compiler/web_idl_diff_tool_test.py
@@ -40,6 +40,7 @@
         ('bluetooth_socket.idl', 'bluetooth_socket.webidl'),
         ('clipboard.idl', 'clipboard.webidl'),
         ('system_display.idl', 'system_display.webidl'),
+        ('usb.idl', 'usb.webidl'),
     ]
     # LoadAndReturnUnifiedDiff expects file paths relative to the repo root.
     converted_schema_path = 'tools/json_schema_compiler/test/converted_schemas/'
diff --git a/tools/metrics/histograms/metadata/ash/histograms.xml b/tools/metrics/histograms/metadata/ash/histograms.xml
index c87c97c..7facc597 100644
--- a/tools/metrics/histograms/metadata/ash/histograms.xml
+++ b/tools/metrics/histograms/metadata/ash/histograms.xml
@@ -7141,7 +7141,7 @@
 </histogram>
 
 <histogram name="Ash.Projector.CreationFlow.{TabletOrClamshellMode}"
-    enum="ProjectorCreationFlow" expires_after="2026-01-15">
+    enum="ProjectorCreationFlow" expires_after="2026-06-15">
   <owner>dorianbrandon@google.com</owner>
   <owner>bzielinski@google.com</owner>
   <owner>cros-projector@google.com</owner>
@@ -7153,7 +7153,7 @@
 </histogram>
 
 <histogram name="Ash.Projector.CreationFlowError.{TabletOrClamshellMode}"
-    enum="ProjectorCreationFlowError" expires_after="2026-01-15">
+    enum="ProjectorCreationFlowError" expires_after="2026-06-15">
   <owner>dorianbrandon@google.com</owner>
   <owner>bzielinski@google.com</owner>
   <owner>cros-projector@google.com</owner>
@@ -7164,7 +7164,7 @@
 </histogram>
 
 <histogram name="Ash.Projector.MarkerColor.{TabletOrClamshellMode}"
-    enum="ProjectorMarkerColor" expires_after="2026-01-15">
+    enum="ProjectorMarkerColor" expires_after="2026-06-15">
   <owner>dorianbrandon@google.com</owner>
   <owner>bzielinski@google.com</owner>
   <owner>cros-projector@google.com</owner>
@@ -7189,7 +7189,7 @@
 </histogram>
 
 <histogram name="Ash.Projector.PendingScreencastBatchIOTaskDuration" units="ms"
-    expires_after="2026-01-15">
+    expires_after="2026-06-15">
   <owner>dorianbrandon@google.com</owner>
   <owner>bzielinski@google.com</owner>
   <owner>cros-projector@google.com</owner>
@@ -7200,7 +7200,7 @@
 </histogram>
 
 <histogram name="Ash.Projector.PendingScreencastChangeInterval" units="ms"
-    expires_after="2026-01-15">
+    expires_after="2026-06-15">
   <owner>dorianbrandon@google.com</owner>
   <owner>bzielinski@google.com</owner>
   <owner>cros-projector@google.com</owner>
@@ -7212,7 +7212,7 @@
 </histogram>
 
 <histogram name="Ash.Projector.SpeechRecognitionEndState.{Location}"
-    enum="SpeechRecognitionEndState" expires_after="2026-03-22">
+    enum="SpeechRecognitionEndState" expires_after="2026-06-15">
   <owner>dorianbrandon@google.com</owner>
   <owner>bzielinski@google.com</owner>
   <owner>cros-projector@google.com</owner>
@@ -7224,7 +7224,7 @@
 </histogram>
 
 <histogram name="Ash.Projector.Toolbar.{TabletOrClamshellMode}"
-    enum="ProjectorToolbar" expires_after="2026-01-15">
+    enum="ProjectorToolbar" expires_after="2026-06-15">
   <owner>dorianbrandon@google.com</owner>
   <owner>bzielinski@google.com</owner>
   <owner>cros-projector@google.com</owner>
@@ -7235,7 +7235,7 @@
 </histogram>
 
 <histogram name="Ash.Projector.TranscriptsCount.{TabletOrClamshellMode}"
-    units="Number of transcripts" expires_after="2026-01-15">
+    units="Number of transcripts" expires_after="2026-06-15">
   <owner>dorianbrandon@google.com</owner>
   <owner>bzielinski@google.com</owner>
   <owner>cros-projector@google.com</owner>
@@ -8435,7 +8435,7 @@
 </histogram>
 
 <histogram name="Ash.SpeechRecognitionSessionLength.{Location}" units="ms"
-    expires_after="2026-01-15">
+    expires_after="2026-06-15">
   <owner>dorianbrandon@google.com</owner>
   <owner>bzielinski@google.com</owner>
   <owner>cros-projector@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/navigation/histograms.xml b/tools/metrics/histograms/metadata/navigation/histograms.xml
index 3d159a6a..c7d0543 100644
--- a/tools/metrics/histograms/metadata/navigation/histograms.xml
+++ b/tools/metrics/histograms/metadata/navigation/histograms.xml
@@ -1723,6 +1723,21 @@
 </histogram>
 
 <histogram
+    name="Navigation.OnBeforeUnloadOverheadTime.BeforeUnloadHandlerRegistered"
+    units="ms" expires_after="2026-12-01">
+  <owner>chikamune@chromium.org</owner>
+  <owner>chrome-loading@google.com</owner>
+  <summary>
+    Overhead time spent handling the OnBeforeUnload event from the browser
+    standpoint. More precisely, it is the total time between dispatch and
+    acknowledgment of the BeforeUnload event on the browser side, minus the
+    actual time spent executing the BeforeUnload handlers on the renderer side.
+    Recorded only when `for_legacy` is false which means there were mojo calls
+    between the browser process and the renderer process.
+  </summary>
+</histogram>
+
+<histogram
     name="Navigation.OnBeforeUnloadOverheadTime.NoBeforeUnloadHandlerRegistered"
     units="ms" expires_after="2026-04-12">
   <owner>hayato@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/safe_browsing/enums.xml b/tools/metrics/histograms/metadata/safe_browsing/enums.xml
index 43842df..eb412d5 100644
--- a/tools/metrics/histograms/metadata/safe_browsing/enums.xml
+++ b/tools/metrics/histograms/metadata/safe_browsing/enums.xml
@@ -119,11 +119,6 @@
   <int value="1" label="Ineligible"/>
 </enum>
 
-<enum name="BooleanIsPrefetch">
-  <int value="0" label="Is not prefetch"/>
-  <int value="1" label="Is prefetch"/>
-</enum>
-
 <enum name="BooleanManagedPref">
   <int value="0" label="Unmanaged Pref"/>
   <int value="1" label="Managed Pref"/>
diff --git a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
index 7ead6a33..21831518 100644
--- a/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
+++ b/tools/metrics/histograms/metadata/safe_browsing/histograms.xml
@@ -475,17 +475,6 @@
   </summary>
 </histogram>
 
-<histogram name="SafeBrowsing.CheckUrl.IsDocumentCheckPrefetch"
-    enum="BooleanIsPrefetch" expires_after="2025-12-14">
-  <owner>thefrog@chromium.org</owner>
-  <owner>chrome-counter-abuse-alerts@google.com</owner>
-  <summary>
-    When a kDocument Safe Browsing URL check completes, logs whether the
-    triggering load flags were net::LOAD_PREFETCH, which corresponds to
-    rel=prefetch.
-  </summary>
-</histogram>
-
 <histogram name="SafeBrowsing.CheckUrl.Timeout" enum="BooleanTimedOut"
     expires_after="2026-05-10">
 <!-- Note to owner: This histogram can be renewed 1 full year if it is still
diff --git a/tools/web_dev_style/eslint.config.mjs b/tools/web_dev_style/eslint.config.mjs
index 148f8bae..c41d0c9 100644
--- a/tools/web_dev_style/eslint.config.mjs
+++ b/tools/web_dev_style/eslint.config.mjs
@@ -223,6 +223,10 @@
     },
 
     rules: {
+      // https://google.github.io/styleguide/tsguide.html#switch-statements
+      'default-case': 'error',
+      'default-case-last': 'error',
+
       'no-unused-vars': 'off',
 
       '@typescript-eslint/no-unused-vars': [
diff --git a/ui/display/mac/screen_utils_mac.mm b/ui/display/mac/screen_utils_mac.mm
index 870abf8..255c74da 100644
--- a/ui/display/mac/screen_utils_mac.mm
+++ b/ui/display/mac/screen_utils_mac.mm
@@ -8,9 +8,14 @@
 
 NSScreen* GetNSScreenFromDisplayID(CGDirectDisplayID display_id) {
   for (NSScreen* screen in NSScreen.screens) {
-    CGDirectDisplayID screen_number =
-        [screen.deviceDescription[@"NSScreenNumber"] unsignedIntValue];
-    if (screen_number == display_id) {
+    CGDirectDisplayID screen_display_id = kCGNullDirectDisplay;
+    if (@available(macOS 26, *)) {
+      screen_display_id = screen.CGDirectDisplayID;
+    } else {
+      screen_display_id =
+          [screen.deviceDescription[@"NSScreenNumber"] unsignedIntValue];
+    }
+    if (screen_display_id == display_id) {
       return screen;
     }
   }
diff --git a/ui/webui/untrusted_web_ui_controller.cc b/ui/webui/untrusted_web_ui_controller.cc
index 0058f3301..91a5845 100644
--- a/ui/webui/untrusted_web_ui_controller.cc
+++ b/ui/webui/untrusted_web_ui_controller.cc
@@ -6,6 +6,7 @@
 
 #include "content/public/browser/web_ui.h"
 #include "content/public/common/bindings_policy.h"
+#include "content/public/common/content_client.h"
 
 namespace ui {
 
@@ -17,4 +18,9 @@
 
 UntrustedWebUIController::~UntrustedWebUIController() = default;
 
+content::WebUIController::TrustPolicy
+UntrustedWebUIController::GetTrustPolicy() {
+  return WebUIController::TrustPolicy::kUntrusted;
+}
+
 }  // namespace ui
diff --git a/ui/webui/untrusted_web_ui_controller.h b/ui/webui/untrusted_web_ui_controller.h
index 85be9837..c44015e 100644
--- a/ui/webui/untrusted_web_ui_controller.h
+++ b/ui/webui/untrusted_web_ui_controller.h
@@ -21,6 +21,8 @@
   ~UntrustedWebUIController() override;
   UntrustedWebUIController(UntrustedWebUIController&) = delete;
   UntrustedWebUIController& operator=(const UntrustedWebUIController&) = delete;
+
+  content::WebUIController::TrustPolicy GetTrustPolicy() override;
 };
 
 }  // namespace ui