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, ¤t_frame()->overlay_list, - ¤t_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 + }, + ¤t_frame()->overlay_list, ¤t_frame()->root_damage_rect, ¤t_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> § 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 > Password Manager > 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 + +[](https://crates.io/crates/array-init) +[](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. + +[](https://github.com/BurntSushi/byteorder/actions) +[](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 ¶m 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, + §ion_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, §ion_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(¤t_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, + ¤t_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, ¢er[1..]); + let p12 = D::F32Vec::load(d, ¢er[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() + "e! {#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 + +[](https://crates.io/crates/num-derive) +[](https://docs.rs/num-derive) +[](https://rust-lang.github.io/rfcs/2495-min-rust-version.html) +[](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 + +[](https://docs.rs/proc-macro-error2) +[](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| ¶m.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}")]` ⟶ `write!("{}", self.var)` + - `#[error("{0}")]` ⟶ `write!("{}", self.0)` + - `#[error("{var:?}")]` ⟶ `write!("{:?}", self.var)` + - `#[error("{0:?}")]` ⟶ `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 — 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) [![crates-io]](https://crates.io/crates/thiserror) [![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}")]` ⟶ `write!("{}", self.var)` +//! - `#[error("{0}")]` ⟶ `write!("{}", self.0)` +//! - `#[error("{var:?}")]` ⟶ `write!("{:?}", self.var)` +//! - `#[error("{0:?}")]` ⟶ `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 — 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> § 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