From e76e895e635f6792e97a5eda81abed06d4be1f8c Mon Sep 17 00:00:00 2001 From: Matthias Schoepfer Date: Mon, 7 Apr 2025 17:34:25 +0200 Subject: [PATCH 1/4] Readme: added section to chromium build for std::bad_alloc (#882) This adds a section to the readme, explaining the solution to a build error discussed in #845. Adding this in the readme makes it easier to be found. Signed-off-by: Matthias Schoepfer --- meta-chromium/README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/meta-chromium/README.md b/meta-chromium/README.md index 41ca133d1..f03e60e82 100644 --- a/meta-chromium/README.md +++ b/meta-chromium/README.md @@ -82,6 +82,36 @@ host. clang-native from the meta-clang layer is used to build those binaries. Additionally, make sure the machine being used to build Chromium is powerful enough: a x86-64 machine with at least 16GB RAM is recommended. +### Troubleshooting Build Error: std::bad_alloc +If you encounter a build error similar to the following: + +``` +terminate called after throwing an instance of 'std::bad_alloc' + what(): std::bad_alloc +terminate called recursively +terminate called recursively +``` +You might be experiencing what has been descibed in +[this issue](https://github.com/OSSystems/meta-browser/issues/845#issuecomment-2664769837). + +You can try to increase the +[vm.max_map_count](https://docs.kernel.org/admin-guide/sysctl/vm.html#max-map-count) +value to allow your system to handle more memory mappings. + +1. Temporarily Set vm.max_map_count: + +``` +# echo 1048576 > /proc/sys/vm/max_map_count +``` +This change will only persist until the system is rebooted. + +2. Permanently Set vm.max_map_count: +To make this change permanent, you need to modify `/etc/sysctl.conf` and add: +```bash +vm.max_map_count=1048576 +``` +A reboot may be required for the new value to get picked up (or run `sysconf -p`). + ### scarthgap-specific requirements The scarthgap OE/Yocto branch is an LTS release, which is often at odds with From a4fce8c7f9bef50e4aba1b167c611cd074062ba5 Mon Sep 17 00:00:00 2001 From: Ariel D'Alessandro Date: Tue, 22 Jul 2025 10:38:18 -0300 Subject: [PATCH 2/4] chromium: Add nodejs v22.11.0 recipes The current nodejs version in scarthgap is v20.18.2, but chromium requires v22.11.0. As scarthgap is LTS release, a major update can't be merged upstream, thus we add the dependency backport here. This commit backports nodejs v22.11.0 from meta-openembedded master branch commit: commit 6652b031d7d4d9cabf16d481f3b82115f7d8e15a Author: J. S. Date: Fri Nov 1 13:18:40 2024 -0400 nodejs: upgrade 20.18.0 -> 22.11.0 This moves us from the previous Long Term Support version codenamed 'Iron' to the newly released Long Term Support version 22.11.0 Codename 'Jod' Changelog: https://github.com/nodejs/node/blob/main/doc/changelogs/CHANGELOG_V22.md#22.11.0 License-Update: Add amaro dependency under MIT License. Add swc dependency under Aapche License Version 2.0. Add simdjson dependency under Apache License Version 2.0. Add on-exit-leak-free under MIT License. Remove ESLint. Remove base64 dependency. Removed patchs: 182d9c05e78.patch - This was a backport to 20.x it is now integrated in 22.x Added patches: Two small patches here to use Bourne Shell instad of BASH. 0001-custom-env.patch 0001-positional-args.patch This patch from https://github.com/nodejs/node/commit/686da19abb that addressed CVE-2024-22017 0001-deps-disable-io_uring-support-in-libuv.patch Other patches were refreshed. Signed-off-by: Jason Schonberg Signed-off-by: Khem Raj Signed-off-by: Ariel D'Alessandro --- .../nodejs/nodejs-oe-cache-22.11/oe-npm-cache | 77 +++++++ .../nodejs/nodejs-oe-cache-native_22.11.bb | 24 ++ ...e-running-gyp-files-for-bundled-deps.patch | 47 ++++ .../nodejs/0001-Using-native-binaries.patch | 94 ++++++++ .../nodejs/nodejs/0001-custom-env.patch | 18 ++ ...ps-disable-io_uring-support-in-libuv.patch | 52 +++++ ...-liftoff-Correct-function-signatures.patch | 69 ++++++ .../nodejs/nodejs/0001-positional-args.patch | 19 ++ ...4-Do-not-use-mminimal-toc-with-clang.patch | 25 ++ .../0004-v8-don-t-override-ARM-CFLAGS.patch | 99 ++++++++ .../nodejs/nodejs/libatomic.patch | 77 +++++++ .../recipes-devtools/nodejs/nodejs/run-ptest | 8 + .../nodejs/nodejs/system-c-ares.patch | 32 +++ .../recipes-devtools/nodejs/nodejs_22.11.0.bb | 214 ++++++++++++++++++ 14 files changed, 855 insertions(+) create mode 100755 meta-chromium/recipes-devtools/nodejs/nodejs-oe-cache-22.11/oe-npm-cache create mode 100644 meta-chromium/recipes-devtools/nodejs/nodejs-oe-cache-native_22.11.bb create mode 100644 meta-chromium/recipes-devtools/nodejs/nodejs/0001-Disable-running-gyp-files-for-bundled-deps.patch create mode 100644 meta-chromium/recipes-devtools/nodejs/nodejs/0001-Using-native-binaries.patch create mode 100644 meta-chromium/recipes-devtools/nodejs/nodejs/0001-custom-env.patch create mode 100644 meta-chromium/recipes-devtools/nodejs/nodejs/0001-deps-disable-io_uring-support-in-libuv.patch create mode 100644 meta-chromium/recipes-devtools/nodejs/nodejs/0001-liftoff-Correct-function-signatures.patch create mode 100644 meta-chromium/recipes-devtools/nodejs/nodejs/0001-positional-args.patch create mode 100644 meta-chromium/recipes-devtools/nodejs/nodejs/0001-ppc64-Do-not-use-mminimal-toc-with-clang.patch create mode 100644 meta-chromium/recipes-devtools/nodejs/nodejs/0004-v8-don-t-override-ARM-CFLAGS.patch create mode 100644 meta-chromium/recipes-devtools/nodejs/nodejs/libatomic.patch create mode 100755 meta-chromium/recipes-devtools/nodejs/nodejs/run-ptest create mode 100644 meta-chromium/recipes-devtools/nodejs/nodejs/system-c-ares.patch create mode 100644 meta-chromium/recipes-devtools/nodejs/nodejs_22.11.0.bb diff --git a/meta-chromium/recipes-devtools/nodejs/nodejs-oe-cache-22.11/oe-npm-cache b/meta-chromium/recipes-devtools/nodejs/nodejs-oe-cache-22.11/oe-npm-cache new file mode 100755 index 000000000..eb0f143ea --- /dev/null +++ b/meta-chromium/recipes-devtools/nodejs/nodejs-oe-cache-22.11/oe-npm-cache @@ -0,0 +1,77 @@ +#!/usr/bin/env node + +/// Usage: oe-npm-cache +/// ... meta - metainformation about package +/// tgz - tarball + +const process = require("node:process"); + +module.paths.unshift("@@libdir@@/node_modules/npm/node_modules"); + +const cacache = require('cacache') +const fs = require('fs') + +// argv[0] is 'node', argv[1] is this script +const cache_dir = process.argv[2] +const type = process.argv[3] +const key = process.argv[4] +const file = process.argv[5] + +const data = fs.readFileSync(file) + +// metadata content is highly nodejs dependent; when cache entries are not +// found, place debug statements in 'make-fetch-happen/lib/cache/policy.js' +// (CachePolicy::satisfies()) +const xlate = { + 'meta': { + 'key_prefix': 'make-fetch-happen:request-cache:', + 'metadata': function() { + return { + time: Date.now(), + url: key, + reqHeaders: { + 'accept': 'application/json', + }, + resHeaders: { + "content-type": "application/json", + "status": 200, + }, + options: { + compress: true, + } + }; + }, + }, + + 'tgz': { + 'key_prefix': 'make-fetch-happen:request-cache:', + 'metadata': function() { + return { + time: Date.now(), + url: key, + reqHeaders: { + 'accept': '*/*', + }, + resHeaders: { + "content-type": "application/octet-stream", + "status": 200, + }, + options: { + compress: true, + }, + }; + }, + }, +}; + +const info = xlate[type]; +let opts = {} + +if (info.metadata) { + opts['metadata'] = info.metadata(); +} + +cacache.put(cache_dir, info.key_prefix + key, data, opts) + .then(integrity => { + console.log(`Saved content of ${key} (${file}).`); +}) diff --git a/meta-chromium/recipes-devtools/nodejs/nodejs-oe-cache-native_22.11.bb b/meta-chromium/recipes-devtools/nodejs/nodejs-oe-cache-native_22.11.bb new file mode 100644 index 000000000..d4b818f96 --- /dev/null +++ b/meta-chromium/recipes-devtools/nodejs/nodejs-oe-cache-native_22.11.bb @@ -0,0 +1,24 @@ +DESCRIPTION = "OE helper for manipulating npm cache" +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10" + +SRC_URI = "\ + file://oe-npm-cache \ +" + +inherit native + +S = "${WORKDIR}/sources" +UNPACKDIR = "${S}" + +B = "${WORKDIR}/build" + +do_configure() { + sed -e 's!@@libdir@@!${libdir}!g' < '${UNPACKDIR}/oe-npm-cache' > '${B}/oe-npm-cache' +} + +do_install() { + install -D -p -m 0755 ${B}/oe-npm-cache ${D}${bindir}/oe-npm-cache +} + +RDEPENDS:${PN} = "nodejs-native" diff --git a/meta-chromium/recipes-devtools/nodejs/nodejs/0001-Disable-running-gyp-files-for-bundled-deps.patch b/meta-chromium/recipes-devtools/nodejs/nodejs/0001-Disable-running-gyp-files-for-bundled-deps.patch new file mode 100644 index 000000000..f692eedd4 --- /dev/null +++ b/meta-chromium/recipes-devtools/nodejs/nodejs/0001-Disable-running-gyp-files-for-bundled-deps.patch @@ -0,0 +1,47 @@ +From 689e098cbde130ecde523ae39df3567456271fda Mon Sep 17 00:00:00 2001 +From: Zuzana Svetlikova +Date: Thu, 27 Apr 2017 14:25:42 +0200 +Subject: [PATCH] Disable running gyp on shared deps + +Upstream-Status: Inappropriate [embedded specific] + +Probably imported from: +https://src.fedoraproject.org/rpms/nodejs/c/41af04f2a3c050fb44628e91ac65fd225b927acb?branch=22609d8c1bfeaa21fe0057645af20b3a2ccc7f53 +which is probably based on dont-run-gyp-files-for-bundled-deps.patch added in: +https://github.com/alpinelinux/aports/commit/6662eb3199902e8451fb20dce82554ad96f796bb + +We also explicitly prune some dependencies from source in the bitbake recipe: + +python prune_sources() { + import shutil + + shutil.rmtree(d.getVar('S') + '/deps/openssl') + if 'ares' in d.getVar('PACKAGECONFIG'): + shutil.rmtree(d.getVar('S') + '/deps/cares') + if 'brotli' in d.getVar('PACKAGECONFIG'): + shutil.rmtree(d.getVar('S') + '/deps/brotli') + if 'libuv' in d.getVar('PACKAGECONFIG'): + shutil.rmtree(d.getVar('S') + '/deps/uv') + if 'nghttp2' in d.getVar('PACKAGECONFIG'): + shutil.rmtree(d.getVar('S') + '/deps/nghttp2') + if 'zlib' in d.getVar('PACKAGECONFIG'): + shutil.rmtree(d.getVar('S') + '/deps/zlib') +} +do_unpack[postfuncs] += "prune_sources" +--- + Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Makefile b/Makefile +index dba16e5e..da4faffc 100644 +--- a/Makefile ++++ b/Makefile +@@ -173,7 +173,7 @@ with-code-cache test-code-cache: + $(warning '$@' target is a noop) + + out/Makefile: config.gypi common.gypi common_node.gypi node.gyp \ +- deps/uv/uv.gyp deps/llhttp/llhttp.gyp deps/zlib/zlib.gyp \ ++ deps/llhttp/llhttp.gyp \ + deps/simdutf/simdutf.gyp deps/ada/ada.gyp deps/nbytes/nbytes.gyp \ + tools/v8_gypfiles/toolchain.gypi \ + tools/v8_gypfiles/features.gypi \ diff --git a/meta-chromium/recipes-devtools/nodejs/nodejs/0001-Using-native-binaries.patch b/meta-chromium/recipes-devtools/nodejs/nodejs/0001-Using-native-binaries.patch new file mode 100644 index 000000000..0178cec77 --- /dev/null +++ b/meta-chromium/recipes-devtools/nodejs/nodejs/0001-Using-native-binaries.patch @@ -0,0 +1,94 @@ +From 6c3ac20477a4bac643088f24df3c042e627fafa9 Mon Sep 17 00:00:00 2001 +From: Guillaume Burel +Date: Fri, 3 Jan 2020 11:25:54 +0100 +Subject: [PATCH] Using native binaries + +Upstream-Status: Inappropriate [embedded specific] + +Originally added in: +https://git.openembedded.org/meta-openembedded/commit/?id=1c8e4a679ae382f953b2e5c7a4966a4646314f3e +later extended and renamed in: +https://git.openembedded.org/meta-openembedded/commit/?id=feeb172d1a8bf010490d22b8df9448b20d9d2aed + +Signed-off-by: Archana Polampalli +--- + node.gyp | 3 + + tools/v8_gypfiles/v8.gyp | 5 +++++ + 2 files changed, 6 insertions(+) + +diff --git a/node.gyp b/node.gyp +index e8e1d9f9..e60ccc10 100644 +--- a/node.gyp ++++ b/node.gyp +@@ -320,6 +320,7 @@ + 'action_name': 'node_mksnapshot', + 'process_outputs_as_sources': 1, + 'inputs': [ ++ '<(PRODUCT_DIR)/v8-qemu-wrapper.sh', + '<(node_mksnapshot_exec)', + '<(node_snapshot_main)', + ], +@@ -935,6 +935,7 @@ + 'action_name': 'node_js2c', + 'process_outputs_as_sources': 1, + 'inputs': [ ++ '<(PRODUCT_DIR)/v8-qemu-wrapper.sh', + '<(node_js2c_exec)', + '<@(library_files)', + '<@(deps_files)', +@@ -944,6 +945,7 @@ + '<(SHARED_INTERMEDIATE_DIR)/node_javascript.cc', + ], + 'action': [ ++ '<(PRODUCT_DIR)/v8-qemu-wrapper.sh', + '<(node_js2c_exec)', + '<@(_outputs)', + 'lib', + +diff --git a/tools/v8_gypfiles/v8.gyp b/tools/v8_gypfiles/v8.gyp +index 42e26cd9..bc721991 100644 +--- a/tools/v8_gypfiles/v8.gyp ++++ b/tools/v8_gypfiles/v8.gyp +@@ -68,6 +68,7 @@ + { + 'action_name': 'run_torque_action', + 'inputs': [ # Order matters. ++ '<(PRODUCT_DIR)/v8-qemu-wrapper.sh', + '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)torque<(EXECUTABLE_SUFFIX)', + '<@(torque_files)', + ], +@@ -99,6 +100,7 @@ + '<@(torque_outputs_inc)', + ], + 'action': [ ++ '<(PRODUCT_DIR)/v8-qemu-wrapper.sh', + '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)torque<(EXECUTABLE_SUFFIX)', + '-o', '<(SHARED_INTERMEDIATE_DIR)/torque-generated', + '-v8-root', '<(V8_ROOT)', +@@ -211,6 +213,7 @@ + { + 'action_name': 'generate_bytecode_builtins_list_action', + 'inputs': [ ++ '<(PRODUCT_DIR)/v8-qemu-wrapper.sh', + '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)bytecode_builtins_list_generator<(EXECUTABLE_SUFFIX)', + ], + 'outputs': [ +@@ -400,6 +403,7 @@ + ], + }, + 'inputs': [ ++ '<(PRODUCT_DIR)/v8-qemu-wrapper.sh', + '<(mksnapshot_exec)', + ], + 'outputs': [ +@@ -1539,6 +1543,7 @@ + { + 'action_name': 'run_gen-regexp-special-case_action', + 'inputs': [ ++ '<(PRODUCT_DIR)/v8-qemu-wrapper.sh', + '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)gen-regexp-special-case<(EXECUTABLE_SUFFIX)', + ], + 'outputs': [ +-- +2.34.1 + diff --git a/meta-chromium/recipes-devtools/nodejs/nodejs/0001-custom-env.patch b/meta-chromium/recipes-devtools/nodejs/nodejs/0001-custom-env.patch new file mode 100644 index 000000000..532d3c5f5 --- /dev/null +++ b/meta-chromium/recipes-devtools/nodejs/nodejs/0001-custom-env.patch @@ -0,0 +1,18 @@ +From 9c1a31afdcf368f794b9f5378cb3fe759570f905 Mon Sep 17 00:00:00 2001 +From: Jason Schonberg +Date: Tue, 30 Apr 2024 21:48:33 -0400 +Subject: [PATCH] Update to nodejs 22.0.0 + +Upstream-Status: Inappropriate [embedded specific] +--- + test/fixtures/run-script/node_modules/.bin/custom-env | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/test/fixtures/run-script/node_modules/.bin/custom-env b/test/fixtures/run-script/node_modules/.bin/custom-env +index e6f291c6..1430f2e9 100755 +--- a/test/fixtures/run-script/node_modules/.bin/custom-env ++++ b/test/fixtures/run-script/node_modules/.bin/custom-env +@@ -1,2 +1,2 @@ +-#!/bin/bash ++#!/bin/sh + echo "$CUSTOM_ENV" diff --git a/meta-chromium/recipes-devtools/nodejs/nodejs/0001-deps-disable-io_uring-support-in-libuv.patch b/meta-chromium/recipes-devtools/nodejs/nodejs/0001-deps-disable-io_uring-support-in-libuv.patch new file mode 100644 index 000000000..04398ac68 --- /dev/null +++ b/meta-chromium/recipes-devtools/nodejs/nodejs/0001-deps-disable-io_uring-support-in-libuv.patch @@ -0,0 +1,52 @@ +From 2bb296f169f86dbb04ee47e9a0dc1e3ee13d4f73 Mon Sep 17 00:00:00 2001 +From: Jason Schonberg +Date: Thu, 7 Mar 2024 12:55:56 -0500 +Subject: [PATCH] Update to nodejs 20.11.1 + +Upstream-Status: Inappropriate [embedded specific] +--- + ...ps-disable-io_uring-support-in-libuv.patch | 35 +++++++++++++++++++ + 1 file changed, 35 insertions(+) + create mode 100644 meta-oe/recipes-devtools/nodejs/nodejs/0001-deps-disable-io_uring-support-in-libuv.patch + +diff --git a/meta-oe/recipes-devtools/nodejs/nodejs/0001-deps-disable-io_uring-support-in-libuv.patch b/meta-oe/recipes-devtools/nodejs/nodejs/0001-deps-disable-io_uring-support-in-libuv.patch +new file mode 100644 +index 00000000..5ac711fb +--- /dev/null ++++ b/meta-oe/recipes-devtools/nodejs/nodejs/0001-deps-disable-io_uring-support-in-libuv.patch +@@ -0,0 +1,35 @@ ++From 9838be9c710ab4249df86726fa390232a3b6a6e7 Mon Sep 17 00:00:00 2001 ++From: Changqing Li ++Date: Fri, 1 Mar 2024 15:46:11 +0800 ++Subject: [PATCH] deps: disable io_uring support in libuv ++ ++Refer [1], Pseudo fails to intercept some of the syscalls when io_uring ++enabled. Refer [2], always disable io_uring support in libuv to fix ++issue in [1]. ++ ++[1] https://git.openembedded.org/meta-openembedded/commit/?id=d08453978c31ee41d28206c6ff198d7d9d701d88 ++[2] https://github.com/nodejs/node/commit/686da19abb ++ ++Upstream-Status: Inappropriate [oe-specific] ++ ++Signed-off-by: Changqing Li ++--- ++ deps/uv/src/unix/linux.c | 2 +- ++ 1 file changed, 1 insertion(+), 1 deletion(-) ++ ++diff --git a/deps/uv/src/unix/linux.c b/deps/uv/src/unix/linux.c ++index 0c997185..7508409d 100644 ++--- a/deps/uv/src/unix/linux.c +++++ b/deps/uv/src/unix/linux.c ++@@ -433,7 +433,7 @@ static int uv__use_io_uring(void) { ++ if (use == 0) { ++ /* Disable io_uring by default due to CVE-2024-22017. */ ++ val = getenv("UV_USE_IO_URING"); ++- use = val != NULL && atoi(val) ? 1 : -1; +++ use = 0; ++ atomic_store_explicit(&use_io_uring, use, memory_order_relaxed); ++ } ++ ++-- ++2.25.1 ++ diff --git a/meta-chromium/recipes-devtools/nodejs/nodejs/0001-liftoff-Correct-function-signatures.patch b/meta-chromium/recipes-devtools/nodejs/nodejs/0001-liftoff-Correct-function-signatures.patch new file mode 100644 index 000000000..5e617e655 --- /dev/null +++ b/meta-chromium/recipes-devtools/nodejs/nodejs/0001-liftoff-Correct-function-signatures.patch @@ -0,0 +1,69 @@ +From 33393507ba8209f0d6b85b391c525b4c70807275 Mon Sep 17 00:00:00 2001 +From: Khem Raj +Date: Mon, 3 Jul 2023 12:33:16 +0000 +Subject: [PATCH] Correct function signatures + +Fixes builds on mips where clang reports an error +../deps/v8/src/wasm/baseline/mips/liftoff-assembler-mips.h:661:5: error: no matching member function for call to 'Move' + Move(tmp, src, type.value_type()); + ^~~~ + +Upstream-Status: Submitted [https://chromium-review.googlesource.com/c/v8/v8/+/3235674] + +Signed-off-by: Archana Polampalli +--- + deps/v8/src/wasm/baseline/liftoff-assembler.h | 6 +++--- + .../src/wasm/baseline/mips64/liftoff-assembler-mips64-inl.h | 2 +- + .../src/wasm/baseline/riscv/liftoff-assembler-riscv64-inl.h | 2 +- + 3 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/deps/v8/src/wasm/baseline/liftoff-assembler.h b/deps/v8/src/wasm/baseline/liftoff-assembler.h +index 7cb2f500..713d16db 100644 +--- a/deps/v8/src/wasm/baseline/liftoff-assembler.h ++++ b/deps/v8/src/wasm/baseline/liftoff-assembler.h +@@ -681,7 +681,7 @@ class LiftoffAssembler : public MacroAssembler { + void FinishCall(const ValueKindSig*, compiler::CallDescriptor*); + + // Move {src} into {dst}. {src} and {dst} must be different. +- void Move(LiftoffRegister dst, LiftoffRegister src, ValueKind); ++ void Move(LiftoffRegister dst, LiftoffRegister src, ValueKind kind); + + // Parallel register move: For a list of tuples , move the + // {src} register of kind {kind} into {dst}. If {src} equals {dst}, ignore +@@ -851,8 +851,8 @@ class LiftoffAssembler : public MacroAssembler { + inline void MoveStackValue(uint32_t dst_offset, uint32_t src_offset, + ValueKind); + +- inline void Move(Register dst, Register src, ValueKind); +- inline void Move(DoubleRegister dst, DoubleRegister src, ValueKind); ++ inline void Move(Register dst, Register src, ValueKind kind); ++ inline void Move(DoubleRegister dst, DoubleRegister src, ValueKind kind); + + inline void Spill(int offset, LiftoffRegister, ValueKind); + inline void Spill(int offset, WasmValue); +diff --git a/deps/v8/src/wasm/baseline/mips64/liftoff-assembler-mips64-inl.h b/deps/v8/src/wasm/baseline/mips64/liftoff-assembler-mips64-inl.h +index bd59f162..56b4d70c 100644 +--- a/deps/v8/src/wasm/baseline/mips64/liftoff-assembler-mips64-inl.h ++++ b/deps/v8/src/wasm/baseline/mips64/liftoff-assembler-mips64-inl.h +@@ -672,7 +672,7 @@ void LiftoffAssembler::Store(Register dst_addr, Register offset_reg, + pinned.set(dst_op.rm()); + LiftoffRegister tmp = kScratchReg2; + // Save original value. +- Move(tmp, src, type.value_type()); ++ Move(tmp, src, type.value_type().kind()); + + src = tmp; + pinned.set(tmp); +diff --git a/deps/v8/src/wasm/baseline/riscv/liftoff-assembler-riscv64-inl.h b/deps/v8/src/wasm/baseline/riscv/liftoff-assembler-riscv64-inl.h +index a3c94af0..456e5334 100644 +--- a/deps/v8/src/wasm/baseline/riscv/liftoff-assembler-riscv64-inl.h ++++ b/deps/v8/src/wasm/baseline/riscv/liftoff-assembler-riscv64-inl.h +@@ -452,7 +452,7 @@ void LiftoffAssembler::Store(Register dst_addr, Register offset_reg, + pinned.set(dst_op.rm()); + LiftoffRegister tmp = GetUnusedRegister(src.reg_class(), pinned); + // Save original value. +- Move(tmp, src, type.value_type()); ++ Move(tmp, src, type.value_type().kind()); + + src = tmp; + pinned.set(tmp); diff --git a/meta-chromium/recipes-devtools/nodejs/nodejs/0001-positional-args.patch b/meta-chromium/recipes-devtools/nodejs/nodejs/0001-positional-args.patch new file mode 100644 index 000000000..5fd6aee35 --- /dev/null +++ b/meta-chromium/recipes-devtools/nodejs/nodejs/0001-positional-args.patch @@ -0,0 +1,19 @@ +From 07ee84863fa4a9e4d5f155632478587b0acbf71a Mon Sep 17 00:00:00 2001 +From: Jason Schonberg +Date: Tue, 30 Apr 2024 21:48:33 -0400 +Subject: [PATCH] Update to nodejs 22.0.0 + +Upstream-Status: Inappropriate [embedded specific] +--- + test/fixtures/run-script/node_modules/.bin/positional-args | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/test/fixtures/run-script/node_modules/.bin/positional-args b/test/fixtures/run-script/node_modules/.bin/positional-args +index 2d809237..3dc5314f 100755 +--- a/test/fixtures/run-script/node_modules/.bin/positional-args ++++ b/test/fixtures/run-script/node_modules/.bin/positional-args +@@ -1,3 +1,3 @@ +-#!/bin/bash ++#!/bin/sh + echo "Arguments: '$@'" + echo "The total number of arguments are: $#" diff --git a/meta-chromium/recipes-devtools/nodejs/nodejs/0001-ppc64-Do-not-use-mminimal-toc-with-clang.patch b/meta-chromium/recipes-devtools/nodejs/nodejs/0001-ppc64-Do-not-use-mminimal-toc-with-clang.patch new file mode 100644 index 000000000..dd9c9015e --- /dev/null +++ b/meta-chromium/recipes-devtools/nodejs/nodejs/0001-ppc64-Do-not-use-mminimal-toc-with-clang.patch @@ -0,0 +1,25 @@ +From 0976af0f3b328436ea44a74a406f311adb2ab211 Mon Sep 17 00:00:00 2001 +From: Khem Raj +Date: Tue, 15 Jun 2021 19:01:31 -0700 +Subject: [PATCH] ppc64: Do not use -mminimal-toc with clang + +clang does not support this option + +Signed-off-by: Khem Raj +--- +Upstream-Status: Pending + + common.gypi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/common.gypi ++++ b/common.gypi +@@ -417,7 +417,7 @@ + 'ldflags': [ '-m32' ], + }], + [ 'target_arch=="ppc64" and OS!="aix"', { +- 'cflags': [ '-m64', '-mminimal-toc' ], ++ 'cflags': [ '-m64' ], + 'ldflags': [ '-m64' ], + }], + [ 'target_arch=="s390x"', { diff --git a/meta-chromium/recipes-devtools/nodejs/nodejs/0004-v8-don-t-override-ARM-CFLAGS.patch b/meta-chromium/recipes-devtools/nodejs/nodejs/0004-v8-don-t-override-ARM-CFLAGS.patch new file mode 100644 index 000000000..cc920118a --- /dev/null +++ b/meta-chromium/recipes-devtools/nodejs/nodejs/0004-v8-don-t-override-ARM-CFLAGS.patch @@ -0,0 +1,99 @@ +From afc085af7b6b935a5e14fc3f40db47df02ca3af2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Andr=C3=A9=20Draszik?= +Date: Sat, 9 Nov 2019 14:45:30 +0000 +Subject: [PATCH] v8: don't override ARM CFLAGS +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This overrides yocto-provided build flags with its own, e.g we get + arm-poky-linux-musleabi-g++ -mthumb -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a7 \ + ... \ + -march=armv7-a -mfpu=neon -mfloat-abi=hard -marm + +Causing the latter to override the former, and compiler warnings: + cc1plus: warning: switch '-mcpu=cortex-a7' conflicts with '-march=armv7-a' switch + +Patch this out, so that yocto-provided flags take precedence. +Note that in reality the same should probably be done for all the other +supported architectures, too. + +Note that this also switches to Thumb(2) mode (in my case). No obvious +problems have been noted during compilation or runtime. + +Upstream-Status: Inappropriate [oe-specific] +Signed-off-by: André Draszik +--- + tools/v8_gypfiles/toolchain.gypi | 52 ++------------------------------ + 1 file changed, 2 insertions(+), 50 deletions(-) + +diff --git a/tools/v8_gypfiles/toolchain.gypi b/tools/v8_gypfiles/toolchain.gypi +index 9d1b0987..4df15e60 100644 +--- a/tools/v8_gypfiles/toolchain.gypi ++++ b/tools/v8_gypfiles/toolchain.gypi +@@ -203,31 +203,7 @@ + 'target_conditions': [ + ['_toolset=="host"', { + 'conditions': [ +- ['v8_target_arch==host_arch', { +- # Host built with an Arm CXX compiler. +- 'conditions': [ +- [ 'arm_version==7', { +- 'cflags': ['-march=armv7-a',], +- }], +- [ 'arm_version==7 or arm_version=="default"', { +- 'conditions': [ +- [ 'arm_fpu!="default"', { +- 'cflags': ['-mfpu=<(arm_fpu)',], +- }], +- ], +- }], +- [ 'arm_float_abi!="default"', { +- 'cflags': ['-mfloat-abi=<(arm_float_abi)',], +- }], +- [ 'arm_thumb==1', { +- 'cflags': ['-mthumb',], +- }], +- [ 'arm_thumb==0', { +- 'cflags': ['-marm',], +- }], +- ], +- }, { +- # 'v8_target_arch!=host_arch' ++ ['v8_target_arch!=host_arch', { + # Host not built with an Arm CXX compiler (simulator build). + 'conditions': [ + [ 'arm_float_abi=="hard"', { +@@ -246,31 +222,7 @@ + }], # _toolset=="host" + ['_toolset=="target"', { + 'conditions': [ +- ['v8_target_arch==target_arch', { +- # Target built with an Arm CXX compiler. +- 'conditions': [ +- [ 'arm_version==7', { +- 'cflags': ['-march=armv7-a',], +- }], +- [ 'arm_version==7 or arm_version=="default"', { +- 'conditions': [ +- [ 'arm_fpu!="default"', { +- 'cflags': ['-mfpu=<(arm_fpu)',], +- }], +- ], +- }], +- [ 'arm_float_abi!="default"', { +- 'cflags': ['-mfloat-abi=<(arm_float_abi)',], +- }], +- [ 'arm_thumb==1', { +- 'cflags': ['-mthumb',], +- }], +- [ 'arm_thumb==0', { +- 'cflags': ['-marm',], +- }], +- ], +- }, { +- # 'v8_target_arch!=target_arch' ++ ['v8_target_arch!=target_arch', { + # Target not built with an Arm CXX compiler (simulator build). + 'conditions': [ + [ 'arm_float_abi=="hard"', { diff --git a/meta-chromium/recipes-devtools/nodejs/nodejs/libatomic.patch b/meta-chromium/recipes-devtools/nodejs/nodejs/libatomic.patch new file mode 100644 index 000000000..d987ac50b --- /dev/null +++ b/meta-chromium/recipes-devtools/nodejs/nodejs/libatomic.patch @@ -0,0 +1,77 @@ +From 15e751e4b79475fb34e4b32a3ca54119b20c564a Mon Sep 17 00:00:00 2001 +From: Hongxu Jia +Date: Sat, 17 Aug 2024 21:33:18 +0800 +Subject: [PATCH] link libatomic for clang conditionally + +Clang emits atomic builtin, explicitly link libatomic conditionally: +- For target build, always link -latomic for clang as usual +- For host build, if host and target have same bit width, cross compiling + is enabled, and host toolchain is gcc which does not link -latomic; + if host and target have different bit width, no cross compiling, + host build is the same with target build that requires to link + -latomic; + +Fix: +|tmp-glibc/work/core2-64-wrs-linux/nodejs/20.13.0/node-v20.13.0/out/Release/node_js2c: error while loading shared libraries: libatomic.so.1: cannot open shared object file: No such file or directory + +Upstream-Status: Inappropriate [OE specific] + +Signed-off-by: Hongxu Jia +--- + node.gyp | 13 ++++++++++++- + tools/v8_gypfiles/v8.gyp | 15 ++++++++++++--- + 2 files changed, 24 insertions(+), 4 deletions(-) + +diff --git a/node.gyp b/node.gyp +index b425f443..f296f35c 100644 +--- a/node.gyp ++++ b/node.gyp +@@ -487,7 +487,18 @@ + ], + }], + ['OS=="linux" and clang==1', { +- 'libraries': ['-latomic'], ++ 'target_conditions': [ ++ ['_toolset=="host"', { ++ 'conditions': [ ++ ['" +Date: Mon, 4 Mar 2024 11:05:25 -0500 +Subject: [PATCH] keep nodejs compatible with c-ares 1.17.1 + +Upstream-Status: Inappropriate [c-ares specific] +Signed-off-by: Khem Raj +--- + src/cares_wrap.h | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/src/cares_wrap.h b/src/cares_wrap.h +index 021ef1c9..820c5d88 100644 +--- a/src/cares_wrap.h ++++ b/src/cares_wrap.h +@@ -23,7 +23,15 @@ + # include + #endif // __POSIX__ + +-# include ++#if defined(__ANDROID__) || \ ++ defined(__MINGW32__) || \ ++ defined(__OpenBSD__) || \ ++ defined(_MSC_VER) ++ ++# include ++#else ++# include ++#endif + + namespace node { + namespace cares_wrap { diff --git a/meta-chromium/recipes-devtools/nodejs/nodejs_22.11.0.bb b/meta-chromium/recipes-devtools/nodejs/nodejs_22.11.0.bb new file mode 100644 index 000000000..49a5f350d --- /dev/null +++ b/meta-chromium/recipes-devtools/nodejs/nodejs_22.11.0.bb @@ -0,0 +1,214 @@ +DESCRIPTION = "nodeJS Evented I/O for V8 JavaScript" +HOMEPAGE = "http://nodejs.org" +LICENSE = "MIT & ISC & BSD-2-Clause & BSD-3-Clause & Artistic-2.0 & Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=25e89142a2f4b075904a9986c45fbdb2" + +CVE_PRODUCT = "nodejs node.js" + +DEPENDS = "openssl openssl-native file-replacement-native python3-packaging-native" +DEPENDS:append:class-target = " qemu-native" +DEPENDS:append:class-native = " c-ares-native" + +inherit pkgconfig python3native qemu ptest siteinfo + +COMPATIBLE_MACHINE:armv4 = "(!.*armv4).*" +COMPATIBLE_MACHINE:armv5 = "(!.*armv5).*" +COMPATIBLE_MACHINE:mips64 = "(!.*mips64).*" + +COMPATIBLE_HOST:riscv64 = "null" +COMPATIBLE_HOST:riscv32 = "null" +COMPATIBLE_HOST:powerpc = "null" + +SRC_URI = "http://nodejs.org/dist/v${PV}/node-v${PV}.tar.xz \ + file://0001-Disable-running-gyp-files-for-bundled-deps.patch \ + file://0004-v8-don-t-override-ARM-CFLAGS.patch \ + file://system-c-ares.patch \ + file://0001-liftoff-Correct-function-signatures.patch \ + file://libatomic.patch \ + file://0001-deps-disable-io_uring-support-in-libuv.patch \ + file://0001-positional-args.patch \ + file://0001-custom-env.patch \ + file://run-ptest \ + " +SRC_URI:append:class-target = " \ + file://0001-Using-native-binaries.patch \ + " +SRC_URI:append:toolchain-clang:powerpc64le = " \ + file://0001-ppc64-Do-not-use-mminimal-toc-with-clang.patch \ + " +SRC_URI[sha256sum] = "bbf0297761d53aefda9d7855c57c7d2c272b83a7b5bad4fea9cb29006d8e1d35" + +S = "${WORKDIR}/node-v${PV}" + +CVE_PRODUCT += "node.js" + +# v8 errors out if you have set CCACHE +CCACHE = "" + +def map_nodejs_arch(a, d): + import re + + if re.match('i.86$', a): return 'ia32' + elif re.match('x86_64$', a): return 'x64' + elif re.match('aarch64$', a): return 'arm64' + elif re.match('(powerpc64|powerpc64le|ppc64le)$', a): return 'ppc64' + elif re.match('powerpc$', a): return 'ppc' + return a + +ARCHFLAGS:arm = "${@bb.utils.contains('TUNE_FEATURES', 'callconvention-hard', '--with-arm-float-abi=hard', '--with-arm-float-abi=softfp', d)} \ + ${@bb.utils.contains('TUNE_FEATURES', 'neon', '--with-arm-fpu=neon', \ + bb.utils.contains('TUNE_FEATURES', 'vfpv3d16', '--with-arm-fpu=vfpv3-d16', \ + bb.utils.contains('TUNE_FEATURES', 'vfpv3', '--with-arm-fpu=vfpv3', \ + '--with-arm-fpu=vfp', d), d), d)}" +ARCHFLAGS:append:mips = " --v8-lite-mode" +ARCHFLAGS:append:mipsel = " --v8-lite-mode" +ARCHFLAGS ?= "" + +PACKAGECONFIG ??= "ares brotli icu zlib" + +PACKAGECONFIG[ares] = "--shared-cares,,c-ares c-ares-native" +PACKAGECONFIG[brotli] = "--shared-brotli,,brotli brotli-native" +PACKAGECONFIG[icu] = "--with-intl=system-icu,--without-intl,icu icu-native" +PACKAGECONFIG[libuv] = "--shared-libuv,,libuv" +PACKAGECONFIG[nghttp2] = "--shared-nghttp2,,nghttp2" +PACKAGECONFIG[shared] = "--shared" +PACKAGECONFIG[zlib] = "--shared-zlib,,zlib" + +EXTRANATIVEPATH += "file-native" + +python prune_sources() { + import shutil + + shutil.rmtree(d.getVar('S') + '/deps/openssl') + if 'ares' in d.getVar('PACKAGECONFIG'): + shutil.rmtree(d.getVar('S') + '/deps/cares') + if 'brotli' in d.getVar('PACKAGECONFIG'): + shutil.rmtree(d.getVar('S') + '/deps/brotli') + if 'libuv' in d.getVar('PACKAGECONFIG'): + shutil.rmtree(d.getVar('S') + '/deps/uv') + if 'nghttp2' in d.getVar('PACKAGECONFIG'): + shutil.rmtree(d.getVar('S') + '/deps/nghttp2') + if 'zlib' in d.getVar('PACKAGECONFIG'): + shutil.rmtree(d.getVar('S') + '/deps/zlib') +} +do_unpack[postfuncs] += "prune_sources" + +# V8's JIT infrastructure requires binaries such as mksnapshot and +# mkpeephole to be run in the host during the build. However, these +# binaries must have the same bit-width as the target (e.g. a x86_64 +# host targeting ARMv6 needs to produce a 32-bit binary). +# 1. If host and target have the different bit width, run those +# binaries for the target and run them on the host with QEMU. +# 2. If host and target have the same bit width, enable upstream +# cross compile support and no QEMU +python do_create_v8_qemu_wrapper () { + """Creates a small wrapper that invokes QEMU to run some target V8 binaries + on the host.""" + qemu_libdirs = [d.expand('${STAGING_DIR_HOST}${libdir}'), + d.expand('${STAGING_DIR_HOST}${base_libdir}')] + qemu_cmd = qemu_wrapper_cmdline(d, d.getVar('STAGING_DIR_HOST'), + qemu_libdirs) + + if d.getVar("HOST_AND_TARGET_SAME_WIDTH") == "1": + qemu_cmd = "" + + wrapper_path = d.expand('${B}/v8-qemu-wrapper.sh') + with open(wrapper_path, 'w') as wrapper_file: + wrapper_file.write("""#!/bin/sh + +# This file has been generated automatically. +# It invokes QEMU to run binaries built for the target in the host during the +# build process. + +%s "$@" +""" % qemu_cmd) + os.chmod(wrapper_path, 0o755) +} + +do_create_v8_qemu_wrapper[dirs] = "${B}" +addtask create_v8_qemu_wrapper after do_configure before do_compile + +LDFLAGS:append:x86 = " -latomic" + +export CC_host +export CFLAGS_host +export CXX_host +export CXXFLAGS_host +export LDFLAGS_host +export AR_host +export HOST_AND_TARGET_SAME_WIDTH + +CROSS_FLAGS = "--cross-compiling" +CROSS_FLAGS:class-native = "--no-cross-compiling" + +# Node is way too cool to use proper autotools, so we install two wrappers to forcefully inject proper arch cflags to workaround gypi +do_configure () { + GYP_DEFINES="${GYP_DEFINES}" export GYP_DEFINES + # $TARGET_ARCH settings don't match --dest-cpu settings + python3 configure.py --verbose --prefix=${prefix} \ + --shared-openssl \ + --dest-cpu="${@map_nodejs_arch(d.getVar('TARGET_ARCH'), d)}" \ + --dest-os=linux \ + --libdir=${baselib} \ + ${CROSS_FLAGS} \ + ${ARCHFLAGS} \ + ${PACKAGECONFIG_CONFARGS} +} + +do_compile () { + install -D ${RECIPE_SYSROOT_NATIVE}/etc/ssl/openssl.cnf ${B}/deps/openssl/nodejs-openssl.cnf + install -D ${B}/v8-qemu-wrapper.sh ${B}/out/Release/v8-qemu-wrapper.sh + oe_runmake BUILDTYPE=Release +} + +do_install () { + oe_runmake install DESTDIR=${D} +} + +do_install_ptest () { + cp -r ${B}/out/Release/cctest ${D}${PTEST_PATH}/ + cp -r ${B}/test ${D}${PTEST_PATH} + chown -R root:root ${D}${PTEST_PATH} +} + +PACKAGES =+ "${PN}-npm" +FILES:${PN}-npm = "${nonarch_libdir}/node_modules ${bindir}/npm ${bindir}/npx ${bindir}/corepack" +RDEPENDS:${PN}-npm = "bash python3-core python3-shell python3-datetime \ + python3-misc python3-multiprocessing" + +PACKAGES =+ "${PN}-systemtap" +FILES:${PN}-systemtap = "${datadir}/systemtap" + +do_configure[prefuncs] += "set_gyp_variables" +do_compile[prefuncs] += "set_gyp_variables" +do_install[prefuncs] += "set_gyp_variables" +python set_gyp_variables () { + if d.getVar("HOST_AND_TARGET_SAME_WIDTH") == "0": + # We don't want to cross-compile during target compile, + # and we need to use the right flags during host compile, + # too. + d.setVar("CC_host", d.getVar("CC") + " -pie -fPIE") + d.setVar("CFLAGS_host", d.getVar("CFLAGS")) + d.setVar("CXX_host", d.getVar("CXX") + " -pie -fPIE") + d.setVar("CXXFLAGS_host", d.getVar("CXXFLAGS")) + d.setVar("LDFLAGS_host", d.getVar("LDFLAGS")) + d.setVar("AR_host", d.getVar("AR")) + elif d.getVar("HOST_AND_TARGET_SAME_WIDTH") == "1": + # Enable upstream cross compile support + d.setVar("CC_host", d.getVar("BUILD_CC")) + d.setVar("CFLAGS_host", d.getVar("BUILD_CFLAGS")) + d.setVar("CXX_host", d.getVar("BUILD_CXX")) + d.setVar("CXXFLAGS_host", d.getVar("BUILD_CXXFLAGS")) + d.setVar("LDFLAGS_host", d.getVar("BUILD_LDFLAGS")) + d.setVar("AR_host", d.getVar("BUILD_AR")) +} + +python __anonymous () { + # 32 bit target and 64 bit host (x86-64 or aarch64) have different bit width + if d.getVar("SITEINFO_BITS") == "32" and "64" in d.getVar("BUILD_ARCH"): + d.setVar("HOST_AND_TARGET_SAME_WIDTH", "0") + else: + d.setVar("HOST_AND_TARGET_SAME_WIDTH", "1") +} + +BBCLASSEXTEND = "native" From a0c4965836e4aa021d20cb4113da4fa1d48f8b30 Mon Sep 17 00:00:00 2001 From: Ariel D'Alessandro Date: Fri, 25 Apr 2025 12:44:49 -0300 Subject: [PATCH 3/4] chromium: Update to 136.0.7103.113 Release notes: https://chromereleases.googleblog.com/2025/05/stable-channel-update-for-desktop_14.html Build and patch changes: ------------------------ Added patches: * 0014-Revert-Remove-libavif-based-AVIF-decoder.patch * 0015-Revert-Remove-third_party-libavif.patch * 0017-rust-Use-adler-instead-of-adler2.patch Updated patches: * 0016-Disable-crabbyavif-to-fix-build-errors.patch * Rebased remaining patches. Removed patches: * 0015-Revert-Connect-the-Rust-log-crate-to-the-base-loggin.patch License changes: ---------------- Added licenses: * TBD Removed licenses: * TBD Updated licenses: * TBD Test-built: ----------- * chromium-ozone-wayland * master, clang, MACHINE=qemux86-64, qemuarm, qemuarm64 * chromium-x11 * master, clang, MACHINE=qemux86-64, qemuarm, qemuarm64 Signed-off-by: Ariel D'Alessandro --- meta-chromium/README.md | 11 +- .../recipes-browser/chromium/chromium-gn.inc | 27 +- ... chromium-ozone-wayland_136.0.7103.113.bb} | 0 ...4.83.bb => chromium-x11_136.0.7103.113.bb} | 0 .../recipes-browser/chromium/chromium.inc | 286 +- ...ompiler-settings-conflicting-with-OE.patch | 16 +- .../chromium/files/0002-v8-qemu-wrapper.patch | 28 +- .../files/0003-wrapper-extra-flags.patch | 2 +- ...options-not-available-in-release-ver.patch | 15 +- ...ink-latomic-failure-on-CentOS-8-host.patch | 6 +- ...0006-Don-t-pass-unknown-LLVM-options.patch | 6 +- ...riable-must-be-initialized-by-a-cons.patch | 12 +- ...rrect-path-to-libclang_rt.builtins.a.patch | 10 +- ...9-Adjust-the-Rust-build-to-our-needs.patch | 34 +- ...use-std-hardware_destructive_interf.patch} | 12 +- ...ymbol-visibility-to-hidden-when-C-s.patch} | 0 ...g-PDFiumAPIStringBufferAdapter-temp.patch} | 0 ...rt-Remove-libavif-based-AVIF-decoder.patch | 3744 +++++++++++++++++ ...he-Rust-log-crate-to-the-base-loggin.patch | 488 --- ...15-Revert-Remove-third_party-libavif.patch | 333 ++ ...able-crabbyavif-to-fix-build-errors.patch} | 0 ...017-rust-Use-adler-instead-of-adler2.patch | 38 + ...6834.83.bb => gn-native_136.0.7103.113.bb} | 0 23 files changed, 4433 insertions(+), 635 deletions(-) rename meta-chromium/recipes-browser/chromium/{chromium-ozone-wayland_132.0.6834.83.bb => chromium-ozone-wayland_136.0.7103.113.bb} (100%) rename meta-chromium/recipes-browser/chromium/{chromium-x11_132.0.6834.83.bb => chromium-x11_136.0.7103.113.bb} (100%) rename meta-chromium/recipes-browser/chromium/files/{0012-Revert-Allow-and-use-std-hardware_destructive_interf.patch => 0011-Revert-Allow-and-use-std-hardware_destructive_interf.patch} (92%) rename meta-chromium/recipes-browser/chromium/files/{0013-Revert-Set-Rust-symbol-visibility-to-hidden-when-C-s.patch => 0012-Revert-Set-Rust-symbol-visibility-to-hidden-when-C-s.patch} (100%) rename meta-chromium/recipes-browser/chromium/files/{0014-pdfium-Fix-missing-PDFiumAPIStringBufferAdapter-temp.patch => 0013-pdfium-Fix-missing-PDFiumAPIStringBufferAdapter-temp.patch} (100%) create mode 100644 meta-chromium/recipes-browser/chromium/files/0014-Revert-Remove-libavif-based-AVIF-decoder.patch delete mode 100644 meta-chromium/recipes-browser/chromium/files/0015-Revert-Connect-the-Rust-log-crate-to-the-base-loggin.patch create mode 100644 meta-chromium/recipes-browser/chromium/files/0015-Revert-Remove-third_party-libavif.patch rename meta-chromium/recipes-browser/chromium/files/{0011-Disable-crabbyavif-to-fix-build-errors.patch => 0016-Disable-crabbyavif-to-fix-build-errors.patch} (100%) create mode 100644 meta-chromium/recipes-browser/chromium/files/0017-rust-Use-adler-instead-of-adler2.patch rename meta-chromium/recipes-browser/chromium/{gn-native_132.0.6834.83.bb => gn-native_136.0.7103.113.bb} (100%) diff --git a/meta-chromium/README.md b/meta-chromium/README.md index f03e60e82..dd98d57e9 100644 --- a/meta-chromium/README.md +++ b/meta-chromium/README.md @@ -15,7 +15,7 @@ This layer depends on: - revision: HEAD * URI: git://github.com/kraj/meta-clang - - branch: master + - branch: scarthgap-clang20 - revision: HEAD ## Contributing @@ -119,13 +119,12 @@ Chromium's release model because it often requires recent versions of certain recipes to build correctly. This is particularly a problem for the toolchain (i.e. LLVM/clang and Rust). -Chromium needs a more recent version of Rust than OE Core provides for + +* Chromium needs a more recent version of Rust than OE Core provides for scarthgap, which is why we depend on meta-lts-mixins' `scarthgap/rust` branch. -**Side note: For now, clang 18 provided by meta-clang is recent enough, but at -some point during scarthgap's LTS lifetime Chromium won't be compilable with -that version, and we'll have to create e.g. a scarthgap-clang20 branch for -meta-clang and use that.** +* Clang 18 provided by meta-clang is no longer compatible with the current +Chromium release, thus we depend on meta-clang's `scarthgap-clang20` branch. ## PACKAGECONFIG knobs diff --git a/meta-chromium/recipes-browser/chromium/chromium-gn.inc b/meta-chromium/recipes-browser/chromium/chromium-gn.inc index 98716ad3a..e8cee463f 100644 --- a/meta-chromium/recipes-browser/chromium/chromium-gn.inc +++ b/meta-chromium/recipes-browser/chromium/chromium-gn.inc @@ -25,12 +25,23 @@ SRC_URI += "\ file://0008-Use-the-correct-path-to-libclang_rt.builtins.a.patch \ file://0009-Adjust-the-Rust-build-to-our-needs.patch \ file://0010-Don-t-require-profiler_builtins.rlib.patch \ - file://0011-Disable-crabbyavif-to-fix-build-errors.patch \ - file://0012-Revert-Allow-and-use-std-hardware_destructive_interf.patch \ - file://0013-Revert-Set-Rust-symbol-visibility-to-hidden-when-C-s.patch \ - file://0014-pdfium-Fix-missing-PDFiumAPIStringBufferAdapter-temp.patch \ - file://0015-Revert-Connect-the-Rust-log-crate-to-the-base-loggin.patch \ + file://0011-Revert-Allow-and-use-std-hardware_destructive_interf.patch \ + file://0012-Revert-Set-Rust-symbol-visibility-to-hidden-when-C-s.patch \ + file://0013-pdfium-Fix-missing-PDFiumAPIStringBufferAdapter-temp.patch \ + file://0014-Revert-Remove-libavif-based-AVIF-decoder.patch \ + file://0015-Revert-Remove-third_party-libavif.patch \ + file://0016-Disable-crabbyavif-to-fix-build-errors.patch \ + file://0017-rust-Use-adler-instead-of-adler2.patch \ " + +# Missing third_party sources. +SRC_URI += "\ + git://chromium.googlesource.com/external/github.com/AOMediaCodec/libavif;protocol=https;branch=main;name=libavif;destsuffix=third_party/libavif/src \ +" + +SRCREV_FORMAT .= "_libavif" +SRCREV_libavif = "e7b34a1f5e9f7024d08311c7bae156061b889882" + # ARM/AArch64-specific patches. SRC_URI:append:aarch64 = "${@bb.utils.contains('TUNE_FEATURES', 'crypto', '', ' file://arm/0001-Fix-AES-crypto-SIGILL-on-rpi4-64.patch', d)}" @@ -475,6 +486,12 @@ do_copy_target_rustlibs () { } addtask copy_target_rustlibs after do_configure before do_compile +do_copy_missing_third_party_sources () { + rm -rf ${S}/third_party/libavif/src + cp -r ${WORKDIR}/third_party/libavif/src/ ${S}/third_party/libavif/ +} +addtask copy_missing_third_party_sources after do_patch before do_configure + do_configure() { cd ${S} python3 ./build/linux/unbundle/replace_gn_files.py --system-libraries ${GN_UNBUNDLE_LIBS} diff --git a/meta-chromium/recipes-browser/chromium/chromium-ozone-wayland_132.0.6834.83.bb b/meta-chromium/recipes-browser/chromium/chromium-ozone-wayland_136.0.7103.113.bb similarity index 100% rename from meta-chromium/recipes-browser/chromium/chromium-ozone-wayland_132.0.6834.83.bb rename to meta-chromium/recipes-browser/chromium/chromium-ozone-wayland_136.0.7103.113.bb diff --git a/meta-chromium/recipes-browser/chromium/chromium-x11_132.0.6834.83.bb b/meta-chromium/recipes-browser/chromium/chromium-x11_136.0.7103.113.bb similarity index 100% rename from meta-chromium/recipes-browser/chromium/chromium-x11_132.0.6834.83.bb rename to meta-chromium/recipes-browser/chromium/chromium-x11_136.0.7103.113.bb diff --git a/meta-chromium/recipes-browser/chromium/chromium.inc b/meta-chromium/recipes-browser/chromium/chromium.inc index 4b003cd4a..e2a4f585f 100644 --- a/meta-chromium/recipes-browser/chromium/chromium.inc +++ b/meta-chromium/recipes-browser/chromium/chromium.inc @@ -4,7 +4,7 @@ HOMEPAGE = "https://www.chromium.org/Home" CVE_PRODUCT = "chromium:chromium google:chrome" SRC_URI = "https://commondatastorage.googleapis.com/chromium-browser-official/chromium-${PV}.tar.xz" -SRC_URI[sha256sum] = "f98315eacbf3be106feca37f8243d8c4092d4fd832c918aa36dc229eb6ab39e0" +SRC_URI[sha256sum] = "7c765bd13df842a28bb52279b8d711411ac6082151473e07bd70b9a482c0a0ac" S = "${WORKDIR}/chromium-${PV}" @@ -70,14 +70,13 @@ LIC_FILES_CHKSUM = "\ file://${S}/base/third_party/superfasthash/LICENSE;md5=c66981f8ad23c9f279a5b9e07385128c \ file://${S}/base/third_party/symbolize/LICENSE;md5=17ae3b22fe8fa438966625593e2eea85 \ file://${S}/base/third_party/xdg_user_dirs/LICENSE;md5=d998f250c491c329a8254dd1ca62c647 \ - file://${S}/chrome/browser/resources/chromeos/accessibility/chromevox/third_party/tamachiyomi/LICENSE;md5=15772cfcf7016e701ce54554516c0688 \ + file://${S}/chrome/browser/resources/chromeos/accessibility/chromevox/mv2/third_party/tamachiyomi/LICENSE;md5=15772cfcf7016e701ce54554516c0688 \ file://${S}/chrome/installer/mac/third_party/bsdiff/LICENSE;md5=0dbe7a50f028269750631fcbded3846a \ file://${S}/chrome/installer/mac/third_party/xz/LICENSE;md5=84982e6bf3ed99ef2647e48626ffa984 \ file://${S}/chrome/third_party/mozilla_security_manager/LICENSE;md5=0c259b853bbf067b361100ce560adce7 \ file://${S}/ios/third_party/blink/LICENSE;md5=9fdb47308c4e0a2b6d07c5af39e5da1a \ file://${S}/ios/third_party/lottie/LICENSE;md5=1e714768add1e7fdb1288bac703bad06 \ file://${S}/ios/third_party/material_components_ios/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ - file://${S}/ios/third_party/material_font_disk_loader_ios/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/ios/third_party/material_internationalization_ios/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/ios/third_party/material_roboto_font_loader_ios/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/ios/third_party/material_sprited_animation_view_ios/LICENSE;md5=175792518e4ac015ab6696d16c4f607e \ @@ -86,97 +85,236 @@ LIC_FILES_CHKSUM = "\ file://${S}/ios/third_party/motion_interchange_objc/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/ios/third_party/motion_transitioning_objc/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/native_client_sdk/src/libraries/third_party/newlib-extras/README;md5=e944d73ca3817b7ca8656eafb9497fed \ + file://${S}/net/third_party/mozilla_security_manager/LICENSE;md5=f19cdef64a433efe7fd2ddbfc3a19313 \ file://${S}/net/third_party/mozilla_win/LICENSE;md5=9b13a17f35cae227ee726ee0108d72a2 \ file://${S}/net/third_party/nss/LICENSE;md5=3b1e88e1b9c0b5a4b2881d46cce06a18 \ file://${S}/net/third_party/quiche/src/LICENSE;md5=0fca02217a5d49a14dfe2d11837bb34d \ file://${S}/net/third_party/uri_template/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/abseil-cpp/LICENSE;md5=df52c6edb7adc22e533b2bacc3bd3915 \ - file://${S}/third_party/accessibility-audit/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_auth/LICENSE;md5=e207fc5a134660990a7068d5a02c7ea8 \ + file://${S}/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_auth_api_phone/LICENSE;md5=e5a8d882f7945961271786002e6a581d \ + file://${S}/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_auth_base/LICENSE;md5=8b3fee5c5451b70decc3ea70f7bc0024 \ + file://${S}/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_auth_blockstore/LICENSE;md5=fff98c651a1ae8a04462a12f8ea1f7a4 \ + file://${S}/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_base/LICENSE;md5=e5a8d882f7945961271786002e6a581d \ + file://${S}/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_basement/LICENSE;md5=4a37c94d22ef29d62102bef4fc7bd8b0 \ + file://${S}/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_fido/LICENSE;md5=ff76e1f91bd64c4593743be9d83a4c5f \ + file://${S}/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_identity_credentials/LICENSE;md5=4a37c94d22ef29d62102bef4fc7bd8b0 \ + file://${S}/third_party/android_deps/autorolled/committed/libs/com_google_android_gms_play_services_tasks/LICENSE;md5=e5a8d882f7945961271786002e6a581d \ + file://${S}/third_party/android_deps/autorolled/committed/libs/com_google_android_libraries_identity_googleid_googleid/LICENSE;md5=498e555b4ebef5399d944fb662c61913 \ + file://${S}/third_party/android_deps/autorolled/committed/libs/com_google_auto_service_auto_service_annotations/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/android_deps/autorolled/committed/libs/com_google_code_findbugs_jsr305/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/android_deps/autorolled/committed/libs/com_google_errorprone_error_prone_annotations/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/android_deps/autorolled/committed/libs/com_google_guava_failureaccess/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/android_deps/autorolled/committed/libs/com_google_j2objc_j2objc_annotations/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/android_deps/autorolled/committed/libs/com_squareup_okio_okio_jvm/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/android_deps/autorolled/committed/libs/javax_inject_javax_inject/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/android_deps/autorolled/committed/libs/org_checkerframework_checker_qual/LICENSE;md5=f32f668c1f4eea36fb53fc4cc7d96385 \ + file://${S}/third_party/android_deps/autorolled/committed/libs/org_jetbrains_kotlinx_kotlinx_coroutines_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/android_deps/autorolled/committed/libs/org_jetbrains_kotlinx_kotlinx_coroutines_core_jvm/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/android_deps/autorolled/committed/libs/org_jetbrains_kotlinx_kotlinx_serialization_core_jvm/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/android_deps/autorolled/committed/libs/org_jspecify_jspecify/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/android_deps/libs/com_android_support_support_annotations/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ - file://${S}/third_party/android_deps/libs/com_google_android_annotations/LICENSE;md5=7f7d74108ee1b7a743cca7d9a86784d6 \ file://${S}/third_party/android_deps/libs/com_google_android_datatransport_transport_api/LICENSE;md5=7f7d74108ee1b7a743cca7d9a86784d6 \ - file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_auth/LICENSE;md5=c342c84a7fac9459603b5f30a5a93723 \ - file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_auth_api_phone/LICENSE;md5=e5a8d882f7945961271786002e6a581d \ - file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_auth_base/LICENSE;md5=d1680c9b9927e21a8e831e443964c3ff \ - file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_auth_blockstore/LICENSE;md5=fff98c651a1ae8a04462a12f8ea1f7a4 \ - file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_base/LICENSE;md5=e5a8d882f7945961271786002e6a581d \ - file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_basement/LICENSE;md5=e5a8d882f7945961271786002e6a581d \ - file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_cast/LICENSE;md5=1e61529f08860f8fa1c90bf8af8007ff \ - file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework/LICENSE;md5=6688c3d596b2e35dd1928d1ffdf5a9e2 \ + file://${S}/third_party/android_deps/libs/com_google_android_datatransport_transport_backend_cct/LICENSE;md5=7f7d74108ee1b7a743cca7d9a86784d6 \ + file://${S}/third_party/android_deps/libs/com_google_android_datatransport_transport_runtime/LICENSE;md5=54d2f6e66dae1f9e4dbf3cb3cc197631 \ + file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_cast/LICENSE;md5=d4ace05266b66c1c0ccdeba11bbe745e \ + file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_cast_framework/LICENSE;md5=98aafe35230de6fc18e977f2feda5671 \ file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_clearcut/LICENSE;md5=32c019d8c1f8222a8aad9c3e1f1d2d10 \ - file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_cloud_messaging/LICENSE;md5=fb1c3d71ca3681654ec1604b10fc1ace \ - file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_fido/LICENSE;md5=ff76e1f91bd64c4593743be9d83a4c5f \ - file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_flags/LICENSE;md5=92b728c587a67a1b9577e9ca141ca520 \ + file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_cloud_messaging/LICENSE;md5=fff98c651a1ae8a04462a12f8ea1f7a4 \ + file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_flags/LICENSE;md5=5c9317538bd492b4fd01eec9d6972640 \ file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_gcm/LICENSE;md5=92b728c587a67a1b9577e9ca141ca520 \ - file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_identity_credentials/LICENSE;md5=fff98c651a1ae8a04462a12f8ea1f7a4 \ file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_iid/LICENSE;md5=05fc50851d6d550ef2bb400b326353f0 \ file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_instantapps/LICENSE;md5=cd033bdb088af16ecdbcd95bd5562a30 \ - file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_location/LICENSE;md5=6a7afdc2d1780ac0a9bd21bd59640cdf \ + file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_location/LICENSE;md5=18ad89b4a01838496ae844c2b9bd2a7f \ file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_phenotype/LICENSE;md5=32c019d8c1f8222a8aad9c3e1f1d2d10 \ - file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_stats/LICENSE;md5=92b728c587a67a1b9577e9ca141ca520 \ - file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_tasks/LICENSE;md5=e5a8d882f7945961271786002e6a581d \ + file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_stats/LICENSE;md5=5c9317538bd492b4fd01eec9d6972640 \ file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_vision/LICENSE;md5=d332b0f8bf5e67cef70541572ba69b61 \ file://${S}/third_party/android_deps/libs/com_google_android_gms_play_services_vision_common/LICENSE;md5=d332b0f8bf5e67cef70541572ba69b61 \ - file://${S}/third_party/android_deps/libs/com_google_android_libraries_identity_googleid_googleid/LICENSE;md5=498e555b4ebef5399d944fb662c61913 \ file://${S}/third_party/android_deps/libs/com_google_android_material_material/LICENSE;md5=7f7d74108ee1b7a743cca7d9a86784d6 \ - file://${S}/third_party/android_deps/libs/com_google_android_play_core_common/LICENSE;md5=8194dd288cb886b87752b09da8cd9287 \ - file://${S}/third_party/android_deps/libs/com_google_android_play_feature_delivery/LICENSE;md5=f2f92822aef2474358b9e1d21514e278 \ - file://${S}/third_party/android_deps/libs/com_google_auto_service_auto_service_annotations/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ - file://${S}/third_party/android_deps/libs/com_google_code_findbugs_jsr305/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ - file://${S}/third_party/android_deps/libs/com_google_code_gson_gson/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/android_deps/libs/com_google_android_play_core_common/LICENSE;md5=73c6700ef062ad41c3d27cab65d0c1e2 \ + file://${S}/third_party/android_deps/libs/com_google_android_play_feature_delivery/LICENSE;md5=014a1ef6f09b1a5ac887d86d5f18918d \ + file://${S}/third_party/android_deps/libs/com_google_ar_impress/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/android_deps/libs/com_google_dagger_dagger/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ - file://${S}/third_party/android_deps/libs/com_google_dagger_hilt_core/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ - file://${S}/third_party/android_deps/libs/com_google_errorprone_error_prone_annotations/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/android_deps/libs/com_google_firebase_firebase_annotations/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/android_deps/libs/com_google_firebase_firebase_common/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/android_deps/libs/com_google_firebase_firebase_common_ktx/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/android_deps/libs/com_google_firebase_firebase_components/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/android_deps/libs/com_google_firebase_firebase_datatransport/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/android_deps/libs/com_google_firebase_firebase_encoders/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/android_deps/libs/com_google_firebase_firebase_encoders_json/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ - file://${S}/third_party/android_deps/libs/com_google_firebase_firebase_iid/LICENSE;md5=18b56b380e9331ebdf0247a0b10bbaf0 \ - file://${S}/third_party/android_deps/libs/com_google_firebase_firebase_iid_interop/LICENSE;md5=a5923809e496d46d8842ab7d8a52621f \ + file://${S}/third_party/android_deps/libs/com_google_firebase_firebase_encoders_proto/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/android_deps/libs/com_google_firebase_firebase_iid/LICENSE;md5=57214b126e4e648c9066e6e23d43be77 \ + file://${S}/third_party/android_deps/libs/com_google_firebase_firebase_iid_interop/LICENSE;md5=5c9317538bd492b4fd01eec9d6972640 \ file://${S}/third_party/android_deps/libs/com_google_firebase_firebase_installations/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/android_deps/libs/com_google_firebase_firebase_installations_interop/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ - file://${S}/third_party/android_deps/libs/com_google_firebase_firebase_measurement_connector/LICENSE;md5=a5923809e496d46d8842ab7d8a52621f \ - file://${S}/third_party/android_deps/libs/com_google_firebase_firebase_messaging/LICENSE;md5=6287e01249a45d9de9bc62ca9163c913 \ - file://${S}/third_party/android_deps/libs/com_google_guava_failureaccess/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/android_deps/libs/com_google_firebase_firebase_measurement_connector/LICENSE;md5=298bd2a9dc20becb6693cfdccd58001a \ + file://${S}/third_party/android_deps/libs/com_google_firebase_firebase_messaging/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/android_deps/libs/com_google_guava_guava_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ - file://${S}/third_party/android_deps/libs/com_google_j2objc_j2objc_annotations/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/android_deps/libs/com_google_protobuf_protobuf_javalite/LICENSE;md5=37b5762e07f0af8c74ce80a8bda4266b \ - file://${S}/third_party/android_deps/libs/com_squareup_okio_okio_jvm/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ - file://${S}/third_party/android_deps/libs/io_grpc_grpc_api/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ - file://${S}/third_party/android_deps/libs/io_grpc_grpc_binder/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ - file://${S}/third_party/android_deps/libs/io_grpc_grpc_context/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ - file://${S}/third_party/android_deps/libs/io_grpc_grpc_core/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ - file://${S}/third_party/android_deps/libs/io_grpc_grpc_protobuf_lite/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ - file://${S}/third_party/android_deps/libs/io_grpc_grpc_stub/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ - file://${S}/third_party/android_deps/libs/io_perfmark_perfmark_api/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/android_deps/libs/jakarta_inject_jakarta_inject_api/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ - file://${S}/third_party/android_deps/libs/javax_inject_javax_inject/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ - file://${S}/third_party/android_deps/libs/org_checkerframework_checker_compat_qual/LICENSE;md5=f32f668c1f4eea36fb53fc4cc7d96385 \ - file://${S}/third_party/android_deps/libs/org_checkerframework_checker_qual/LICENSE;md5=f32f668c1f4eea36fb53fc4cc7d96385 \ file://${S}/third_party/android_deps/libs/org_checkerframework_checker_util/LICENSE;md5=87abbc18e66acb445c00810347051776 \ file://${S}/third_party/android_deps/libs/org_codehaus_mojo_animal_sniffer_annotations/LICENSE;md5=a5dd953e661e22a77f7b8062ae790f6a \ file://${S}/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_android_extensions_runtime/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/android_deps/libs/org_jetbrains_kotlin_kotlin_parcelize_runtime/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/android_deps/libs/org_jetbrains_kotlinx_atomicfu_jvm/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ - file://${S}/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ - file://${S}/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_core_jvm/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_guava/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ - file://${S}/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_serialization_core_jvm/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ - file://${S}/third_party/android_deps/libs/org_jspecify_jspecify/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/android_deps/libs/org_jetbrains_kotlinx_kotlinx_coroutines_play_services/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/android_media/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/android_opengl/LICENSE;md5=d10e92761a860d4113a7a525c78daf13 \ file://${S}/third_party/android_provider/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/android_sdk/LICENSE;md5=a9559ed17808a8b10eec6672f993ce75 \ file://${S}/third_party/android_swipe_refresh/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/android_toolchain/NOTICE;md5=350d21a23b5ad67f48caa7a8e55d32c0 \ + file://${S}/third_party/androidx/committed/libs/androidx_activity_activity/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_activity_activity_compose/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_activity_activity_ktx/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_annotation_annotation_experimental/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_annotation_annotation_jvm/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_appcompat_appcompat/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_appcompat_appcompat_resources/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_appsearch_appsearch/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_appsearch_appsearch_builtin_types/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_appsearch_appsearch_platform_storage/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_arch_core_core_common/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_arch_core_core_runtime/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_asynclayoutinflater_asynclayoutinflater/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_asynclayoutinflater_asynclayoutinflater_appcompat/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_autofill_autofill/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_biometric_biometric/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_browser_browser/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_cardview_cardview/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_collection_collection_jvm/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_collection_collection_ktx/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_compose_animation_animation_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_compose_animation_animation_core_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_compose_foundation_foundation_layout_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_compose_material3_material3_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_compose_material_material_ripple_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_annotation_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_compose_runtime_runtime_saveable_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_compose_ui_ui_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_compose_ui_ui_geometry_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_compose_ui_ui_graphics_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_compose_ui_ui_text_google_fonts/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_compose_ui_ui_unit_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_compose_ui_ui_util_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_concurrent_concurrent_futures/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_concurrent_concurrent_futures_ktx/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_constraintlayout_constraintlayout_core/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_coordinatorlayout_coordinatorlayout/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_core_core/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_core_core_animation/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_core_core_ktx/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_core_core_viewtree/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_credentials_credentials/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_credentials_credentials_play_services_auth/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_credentials_registry_registry_provider_play_services/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_cursoradapter_cursoradapter/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_customview_customview/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_customview_customview_poolingcontainer/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_datastore_datastore_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_datastore_datastore_core_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_datastore_datastore_core_okio_jvm/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_documentfile_documentfile/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_drawerlayout_drawerlayout/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_dynamicanimation_dynamicanimation/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_emoji2_emoji2/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_emoji2_emoji2_views_helper/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_emoji_emoji/LICENSE;md5=7773bd2f52bfeaf2c4f9eac7cb9227e6 \ + file://${S}/third_party/androidx/committed/libs/androidx_exifinterface_exifinterface/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_fragment_fragment/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_fragment_fragment_compose/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_fragment_fragment_ktx/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_graphics_graphics_path/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_graphics_graphics_shapes_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_gridlayout_gridlayout/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_interpolator_interpolator/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_leanback_leanback/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_leanback_leanback_grid/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_leanback_leanback_preference/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_legacy_legacy_support_core_ui/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_legacy_legacy_support_core_utils/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_legacy_legacy_support_v4/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_java8/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_common_jvm/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_livedata_core_ktx/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_process/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_compose_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_runtime_ktx_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_service/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_compose_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_ktx/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_lifecycle_lifecycle_viewmodel_savedstate_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_loader_loader/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_localbroadcastmanager_localbroadcastmanager/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_media3_media3_common/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_media3_media3_container/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_media3_media3_database/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_media3_media3_datasource/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_media3_media3_decoder/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_media3_media3_exoplayer/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_media3_media3_extractor/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_media3_media3_session/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_media3_media3_ui/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_media_media/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_mediarouter_mediarouter/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_multidex_multidex/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_navigation_navigation_common_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_navigation_navigation_compose_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_navigation_navigation_runtime_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_palette_palette/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_pdf_pdf_document_service/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_pdf_pdf_viewer_fragment/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_preference_preference/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_print_print/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_privacysandbox_ads_ads_adservices/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_privacysandbox_ads_ads_adservices_java/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_profileinstaller_profileinstaller/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_recyclerview_recyclerview/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_resourceinspection_resourceinspection_annotation/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_room_room_common_jvm/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_room_room_runtime_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_savedstate_savedstate_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_savedstate_savedstate_compose_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_savedstate_savedstate_ktx/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_slidingpanelayout_slidingpanelayout/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_sqlite_sqlite_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_sqlite_sqlite_framework_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_startup_startup_runtime/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_swiperefreshlayout_swiperefreshlayout/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_tracing_tracing_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_transition_transition/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_tvprovider_tvprovider/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_vectordrawable_vectordrawable/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_vectordrawable_vectordrawable_animated/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_versionedparcelable_versionedparcelable/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_viewpager2_viewpager2/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_viewpager_viewpager/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_webkit_webkit/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_window_extensions_extensions/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_window_sidecar_sidecar/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_window_window/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_window_window_core_android/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_xr_arcore_arcore/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_xr_runtime_runtime/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_xr_runtime_runtime_openxr/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/androidx/committed/libs/androidx_xr_scenecore_scenecore/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/angle/LICENSE;md5=7abdb66a6948f39c2f469140db5184e2 \ file://${S}/third_party/angle/src/common/third_party/xxhash/LICENSE;md5=cb91c07001f1ca6fd50b6bd4f042946a \ file://${S}/third_party/angle/src/libANGLE/renderer/vulkan/shaders/src/third_party/etc_decoder/LICENSE;md5=100356b560682b0ae7739e09db42f319 \ file://${S}/third_party/angle/src/libANGLE/renderer/vulkan/shaders/src/third_party/ffx_spd/LICENSE;md5=64356ee6f79c94525e102a3264a62653 \ file://${S}/third_party/angle/src/third_party/libXNVCtrl/LICENSE;md5=9e6c209899aa4986d090320bbca2fc76 \ file://${S}/third_party/angle/src/third_party/volk/LICENSE.md;md5=af213f738e88117b90238ef76ad25ae6 \ - file://${S}/third_party/angle/third_party/android_system_sdk/LICENSE;md5=cbb64e76df0f98fc138b1918c089417e \ file://${S}/third_party/angle/third_party/flatbuffers/LICENSE;md5=a873c5645c184d51e0f9b34e1d7cf559 \ file://${S}/third_party/angle/third_party/spirv-headers/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/angle/third_party/spirv-tools/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ @@ -192,26 +330,29 @@ LIC_FILES_CHKSUM = "\ file://${S}/third_party/bidimapper/licenses/LICENSE.mitt;md5=4ed316158806c1e39b6b6e457c85b10f \ file://${S}/third_party/bidimapper/licenses/LICENSE.zod;md5=7aa01d261c2ac4ca667875e22474c798 \ file://${S}/third_party/blink/LICENSE_FOR_ABOUT_CREDITS;md5=11e90d553b211de885f245900c4ccf89 \ - file://${S}/third_party/boringssl/src/LICENSE;md5=2ca501bc96ce9ed0814e2c592c3f9593 \ - file://${S}/third_party/boringssl/src/third_party/fiat/LICENSE;md5=8eb8c1cdeb53faab99e4673182bed9f7 \ + file://${S}/third_party/boringssl/src/LICENSE;md5=bfca80950e49496c340e3327990eb7e7 \ + file://${S}/third_party/boringssl/src/third_party/fiat/LICENSE;md5=7a7086e01a29257a15f3b0c9a42a12ff \ file://${S}/third_party/brotli/LICENSE;md5=941ee9cd1609382f946352712a319b4b \ file://${S}/third_party/bspatch/LICENSE;md5=3e837ede9697ce4c789c3ca32aabe003 \ file://${S}/third_party/cardboard/LICENSE;md5=3446ed11f63049b8f1e60e833dcdc5b7 \ file://${S}/third_party/cast_core/LICENSE;md5=175792518e4ac015ab6696d16c4f607e \ file://${S}/third_party/catapult/experimental/trace_on_tap/third_party/pako/LICENSE;md5=6b8c8aad0a85200097ec8f989636baf0 \ file://${S}/third_party/catapult/third_party/apiclient/LICENSE;md5=94023d14f6b58272fd885e4e3f2f08b3 \ + file://${S}/third_party/catapult/third_party/beautifulsoup4/COPYING.txt;md5=83e365dc17176bd72ba7d08ca0555efa \ file://${S}/third_party/catapult/third_party/cachetools/LICENSE;md5=27f7518eb6f7dc686d0f953b2f28dae5 \ - file://${S}/third_party/catapult/third_party/chardet/LICENSE;md5=a6f89e2100d9b6cdffcea4f398e37343 \ file://${S}/third_party/catapult/third_party/cloudstorage/COPYING;md5=dcbf253b3d6d09ae7e64cb34b4d0ec33 \ file://${S}/third_party/catapult/third_party/coverage/LICENSE.txt;md5=2ee41112a44fe7014dce33e26468ba93 \ file://${S}/third_party/catapult/third_party/flot/LICENSE.txt;md5=5bc600a435aadbd7dcde045ccb3208bf \ file://${S}/third_party/catapult/third_party/google-auth/LICENSE;md5=86d3f3a95c324c9479bd8986968f4327 \ + file://${S}/third_party/catapult/third_party/graphy/LICENSE;md5=86d3f3a95c324c9479bd8986968f4327 \ file://${S}/third_party/catapult/third_party/gsutil/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/catapult/third_party/idna/LICENSE.rst;md5=782775b32f96098512e283fb5d4546cd \ file://${S}/third_party/catapult/third_party/ijson/LICENSE.txt;md5=2809bd5857eee6be054555222fd89712 \ - file://${S}/third_party/catapult/third_party/oauth2client/LICENSE;md5=88f599f710b9d48dad0929ebd090fc1a \ + file://${S}/third_party/catapult/third_party/jquery/LICENSE.txt;md5=18d9b3a646e7608b8951c4f6aa1bbf25 \ + file://${S}/third_party/catapult/third_party/mapreduce/LICENSE;md5=175792518e4ac015ab6696d16c4f607e \ file://${S}/third_party/catapult/third_party/pipeline/LICENSE;md5=8f7bb094c7232b058c7e9f2e431f389c \ file://${S}/third_party/catapult/third_party/polymer/LICENSE.polymer;md5=324f45ce459ffd97e41d175a4e95a4be \ - file://${S}/third_party/catapult/third_party/polymer3/LICENSE.polymer;md5=a798ede8c314cbc7a31b41bce0008d57 \ + file://${S}/third_party/catapult/third_party/pyasn1_modules/LICENSE.txt;md5=a14482d15c2249de3b6f0e8a47e021fd \ file://${S}/third_party/catapult/third_party/pyfakefs/COPYING;md5=34400b68072d710fecd0a2940a0d1658 \ file://${S}/third_party/catapult/third_party/pyparsing/LICENSE;md5=657a566233888513e1f07ba13e2f47f1 \ file://${S}/third_party/catapult/third_party/python_gflags/COPYING;md5=c80d1a3b623f72bb85a4c75b556551df \ @@ -223,6 +364,7 @@ LIC_FILES_CHKSUM = "\ file://${S}/third_party/catapult/third_party/vinn/third_party/v8/LICENSE.v8;md5=1ea35644f0ec0d9767897115667e901f \ file://${S}/third_party/catapult/third_party/vinn/third_party/v8/LICENSE.valgrind;md5=df3b3d49700e781f7508895abd114277 \ file://${S}/third_party/catapult/third_party/webapp2/LICENSE;md5=40b32c2af961e8ca20e66cdea65bcb36 \ + file://${S}/third_party/catapult/third_party/webtest/license.rst;md5=64f013a9d7a2a8ffc8d016a2d4214bcd \ file://${S}/third_party/catapult/tracing/third_party/jpeg-js/LICENSE;md5=11ed819ab28c14377693b9c990511293 \ file://${S}/third_party/catapult/tracing/third_party/oboe/LICENCE;md5=a50188ab5dc0b5b3963791e0c5f43c6b \ file://${S}/third_party/catapult/tracing/third_party/pako/LICENSE;md5=a4f08d6b2d1bf3f3a1bc296a6109a25b \ @@ -232,6 +374,7 @@ LIC_FILES_CHKSUM = "\ file://${S}/third_party/chromevox/third_party/sre/LICENSE;md5=2ee41112a44fe7014dce33e26468ba93 \ file://${S}/third_party/cld_3/LICENSE;md5=d8b32ba83f8b11e4badd979f4319e706 \ file://${S}/third_party/cldr/LICENSE;md5=fe2500bb52e825476d4b93d6f1458232 \ + file://${S}/third_party/compiler-rt/src/LICENSE.TXT;md5=d846d1d65baf322d4c485d6ee54e877a \ file://${S}/third_party/content_analysis_sdk/LICENSE;md5=ee5fc272be9139e1816c73ce09611ca5 \ file://${S}/third_party/coremltools/mlmodel/format/LICENSE;md5=646b3097f3a7222ada5b4561c39d52e8 \ file://${S}/third_party/cpu_features/src/LICENSE;md5=31a8379f6fe09baf921e654832ac5700 \ @@ -259,6 +402,7 @@ LIC_FILES_CHKSUM = "\ file://${S}/third_party/devtools-frontend/src/front_end/third_party/i18n/LICENSE;md5=a873c5645c184d51e0f9b34e1d7cf559 \ file://${S}/third_party/devtools-frontend/src/front_end/third_party/intl-messageformat/LICENSE;md5=913015c0e75ff89ef9461fadca555f65 \ file://${S}/third_party/devtools-frontend/src/front_end/third_party/json5/LICENSE;md5=d80f2808a405d641840b50a06f80e93c \ + file://${S}/third_party/devtools-frontend/src/front_end/third_party/legacy-javascript/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/devtools-frontend/src/front_end/third_party/lighthouse/LICENSE;md5=a873c5645c184d51e0f9b34e1d7cf559 \ file://${S}/third_party/devtools-frontend/src/front_end/third_party/lit/LICENSE;md5=4b390b7b932ca7872d1de2c834797cad \ file://${S}/third_party/devtools-frontend/src/front_end/third_party/marked/LICENSE;md5=449f8b1cf0bfef1e5ec7824a4179ac6f \ @@ -295,14 +439,12 @@ LIC_FILES_CHKSUM = "\ file://${S}/third_party/google_input_tools/LICENSE;md5=ff0b0f0202337c9d4ae2d869797049d3 \ file://${S}/third_party/google_input_tools/third_party/closure_library/LICENSE;md5=24a5bad64ae7d51b99ecb8864af80e84 \ file://${S}/third_party/google_toolbox_for_mac/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ - file://${S}/third_party/google_trust_services/src/LICENSE;md5=cfaf8febfe7b4f3e07a08dd4d0db1914 \ - file://${S}/third_party/grpc/src/LICENSE;md5=731e401b36f8077ae0c134b59be5c906 \ + file://${S}/third_party/grpc/source/LICENSE;md5=731e401b36f8077ae0c134b59be5c906 \ file://${S}/third_party/harfbuzz-ng/src/COPYING;md5=b98429b8e8e3c2a67cfef01e99e4893d \ file://${S}/third_party/highway/LICENSE;md5=2b42edef8fa55315f34f2370b4715ca9 \ file://${S}/third_party/hunspell/COPYING.MPL;md5=bfe1f75d606912a4111c90743d6c7325 \ file://${S}/third_party/hyphenation-patterns/LICENSE;md5=23d9bd4878e6f3669ed39b2095b01c13 \ file://${S}/third_party/iaccessible2/LICENSE;md5=43bbd0bfb581347ec10def720000a645 \ - file://${S}/third_party/iccjpeg/LICENSE;md5=26834d132689a03abf860f4572705494 \ file://${S}/third_party/icu/LICENSE;md5=08dc3852df8fffa807301902ad899ff8 \ file://${S}/third_party/ink/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/ink_stroke_modeler/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ @@ -311,23 +453,21 @@ LIC_FILES_CHKSUM = "\ file://${S}/third_party/isimpledom/LICENSE;md5=822502c0e010ccdbb6a3e681dd47888e \ file://${S}/third_party/jni_zero/LICENSE;md5=70dc659673a50c63e07b2287222230e6 \ file://${S}/third_party/jsoncpp/LICENSE;md5=c56ee55c03a55f8105b969d8270632ce \ - file://${S}/third_party/jstemplate/COPYING;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/jszip/LICENSE;md5=401d270383d75b05d76fc13fc1750765 \ file://${S}/third_party/khronos/LICENSE;md5=1d2ef853a9ae7ace4e16fda0d48f597b \ file://${S}/third_party/lens_server_proto/LICENSE;md5=57b69a83c4a9b2401aa4de147cb22bd4 \ file://${S}/third_party/leveldatabase/src/LICENSE;md5=92d1b128950b11ba8495b64938fc164d \ file://${S}/third_party/libaddressinput/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/libaom/source/libaom/LICENSE;md5=6ea91368c1bbdf877159435572b931f5 \ - file://${S}/third_party/libavif/LICENSE;md5=15744a27d810133340dc64ad411ec4cd \ + file://${S}/third_party/libaom/source/libaom/PATENTS;md5=a111d47497d3bb49e04eef71377eb8ba \ file://${S}/third_party/libbrlapi/LICENSE;md5=fad9b3332be894bab9bc501572864b29 \ file://${S}/third_party/libc++/src/LICENSE.TXT;md5=55d89dd7eec8d3b4204b680e27da3953 \ file://${S}/third_party/libc++abi/src/LICENSE.TXT;md5=7b9334635b542c56868400a46b272b1e \ file://${S}/third_party/libei/LICENSE;md5=a98fa76460f96f41696611d6f07e8d49 \ - file://${S}/third_party/libevent/LICENSE;md5=a2b0302a710150293fb85d2bfabd3de6 \ file://${S}/third_party/libgav1/src/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/libipp/LICENSE;md5=af9e58383a1b2b17c75c6c9ff561ca9d \ file://${S}/third_party/libjingle_xmpp/LICENSE;md5=ad296492125bc71530d06234d9bfebe0 \ - file://${S}/third_party/libjpeg_turbo/LICENSE.md;md5=2a8e0d8226a102f07ab63ed7fd6ce155 \ + file://${S}/third_party/libjpeg_turbo/LICENSE.md;md5=023c2e8942020502d6ea709e2a5453f7 \ file://${S}/third_party/liblouis/LICENSE;md5=8ab69863de0d3a0e00c4f97a4d78dd4a \ file://${S}/third_party/libphonenumber/LICENSE;md5=e23fadd6ceef8c618fc1c65191d846fa \ file://${S}/third_party/libpng/LICENSE;md5=b0085051bf265bac2bfc38bc89f50000 \ @@ -341,8 +481,11 @@ LIC_FILES_CHKSUM = "\ file://${S}/third_party/libusb/src/COPYING;md5=fbc093901857fcd118f065f900982c24 \ file://${S}/third_party/libva_protected_content/LICENSE;md5=2e48940f94acb0af582e5ef03537800f \ file://${S}/third_party/libvpx/source/libvpx/LICENSE;md5=d5b04755015be901744a78cc30d390d4 \ + file://${S}/third_party/libvpx/source/libvpx/PATENTS;md5=c6926d0cb07d296f886ab6e0cc5a85b7 \ file://${S}/third_party/libwebm/source/LICENSE.TXT;md5=6e8dee932c26f2dab503abf70c96d8bb \ - file://${S}/third_party/libwebp/LICENSE;md5=72dceabd78c6f435bb304047aff1745a \ + file://${S}/third_party/libwebm/source/PATENTS.TXT;md5=c6926d0cb07d296f886ab6e0cc5a85b7 \ + file://${S}/third_party/libwebp/src/COPYING;md5=6e8dee932c26f2dab503abf70c96d8bb \ + file://${S}/third_party/libwebp/src/PATENTS;md5=c6926d0cb07d296f886ab6e0cc5a85b7 \ file://${S}/third_party/libx11/LICENSE;md5=28a27b3e1a66e95206d5645b787dad69 \ file://${S}/third_party/libxcb-keysyms/LICENSE;md5=5b0382211c6a98f8e4861daa0f3f4322 \ file://${S}/third_party/libxml/src/Copyright;md5=f437ed9058e8e5135e47c01e973376ba \ @@ -352,7 +495,7 @@ LIC_FILES_CHKSUM = "\ file://${S}/third_party/lit/LICENSE;md5=4b390b7b932ca7872d1de2c834797cad \ file://${S}/third_party/llvm-libc/src/LICENSE.TXT;md5=ff42885ed2ab98f1ecb8c1fc41205343 \ file://${S}/third_party/lottie/LICENSE;md5=827837648055a0bfb7782b91ab42eed1 \ - file://${S}/third_party/lss/LICENSE;md5=dcd794613f580ae04e9633662024c7a2 \ + file://${S}/third_party/lss/LICENSE;md5=31b650551268648966d774a3ecc710cf \ file://${S}/third_party/lzma_sdk/LICENSE;md5=eceed1d308734c8051664bc3d1ca175e \ file://${S}/third_party/material_color_utilities/LICENSE;md5=175792518e4ac015ab6696d16c4f607e \ file://${S}/third_party/material_design_icons/LICENSE;md5=175792518e4ac015ab6696d16c4f607e \ @@ -365,7 +508,9 @@ LIC_FILES_CHKSUM = "\ file://${S}/third_party/modp_b64/LICENSE;md5=eb7e2e0af1d4971360553aedadee8d86 \ file://${S}/third_party/nearby/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/neon_2_sse/LICENSE;md5=53abad1ded16f44100126962f4bbef6c \ - file://${S}/third_party/node/LICENSE;md5=f08301c3b31b4f85e464f95ce1d8bf81 \ + file://${S}/third_party/node/Apache-LICENSE-2.0.txt;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/node/node_modules/@azure/msal-browser/LICENSE;md5=4f9c2c296f77b3096b6c11a16fa7c66e \ + file://${S}/third_party/node/node_modules/lit/LICENSE;md5=4b390b7b932ca7872d1de2c834797cad \ file://${S}/third_party/omnibox_proto/LICENSE;md5=9956e3ce49f0eea45461cec47a5f96b0 \ file://${S}/third_party/one_euro_filter/LICENSE;md5=5b4d092181a412ae42c63e7fc1e53366 \ file://${S}/third_party/openh264/src/LICENSE;md5=bb6d3771da6a07d33fd50d4d9aa73bcf \ @@ -378,6 +523,8 @@ LIC_FILES_CHKSUM = "\ file://${S}/third_party/pdfium/third_party/agg23/copying;md5=d501f87982fe576fa1bfdf4f0ae741af \ file://${S}/third_party/pdfium/third_party/fp16/LICENSE;md5=855dd24c28c76c916c5c2301b1958728 \ file://${S}/third_party/pdfium/third_party/freetype/FTL.TXT;md5=d479e83797f699fe873b38dadd0fcd4c \ + file://${S}/third_party/pdfium/third_party/highway/LICENSE;md5=86d3f3a95c324c9479bd8986968f4327 \ + file://${S}/third_party/pdfium/third_party/lcms/LICENSE;md5=e9ce323c4b71c943a785db90142b228a \ file://${S}/third_party/pdfium/third_party/libopenjpeg/LICENSE;md5=c648878b4840d7babaade1303e7f108c \ file://${S}/third_party/pdfium/third_party/libtiff/LICENSE.md;md5=a3e32d664d6db1386b4689c8121531c3 \ file://${S}/third_party/perfetto/LICENSE;md5=65fc11c16d093b463bafae828ec00d41 \ @@ -389,17 +536,18 @@ LIC_FILES_CHKSUM = "\ file://${S}/third_party/protobuf/LICENSE;md5=37b5762e07f0af8c74ce80a8bda4266b \ file://${S}/third_party/pthreadpool/src/LICENSE;md5=1609499688b503850848d795dce4da2d \ file://${S}/third_party/puffin/LICENSE;md5=b1ed361f9fc790c1054d81a7ef041a34 \ - file://${S}/third_party/qcms/src/COPYING;md5=65636fa951328d3be95f6047ec3936ce \ file://${S}/third_party/re2/LICENSE;md5=3b5c31eb512bdf3cb11ffd5713963760 \ file://${S}/third_party/rjsmin/LICENSE;md5=34f8c1142fd6208a8be89399cb521df9 \ file://${S}/third_party/rnnoise/COPYING;md5=1890bf89a18f8339491894a0b45428bf \ file://${S}/third_party/ruy/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ + file://${S}/third_party/screen-ai/THIRD_PARTY_LICENSES;md5=c1060306f371a5ac9a35cfba2d55f902 \ file://${S}/third_party/securemessage/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/selenium-atoms/LICENSE;md5=5cd827bdaf8605a596a7ac9dcf808ea1 \ file://${S}/third_party/selenium-atoms/LICENSE.sizzle;md5=7a9495742f21b7624515e120b720cc65 \ file://${S}/third_party/selenium-atoms/LICENSE.wgxpath;md5=73a4131394317651a4370c0507a9ccb5 \ file://${S}/third_party/sentencepiece/LICENSE;md5=5cb9ee2840d20280145e929f30f32060 \ file://${S}/third_party/shell-encryption/src/LICENSE;md5=c96a2157133614bf8a135bd27cd230d6 \ + file://${S}/third_party/simdutf/LICENSE;md5=44b8879887e312bc332a205805fb41d1 \ file://${S}/third_party/simplejson/LICENSE.txt;md5=8a9f8dcfcd28c34daa443e5b1d29813b \ file://${S}/third_party/skia/LICENSE;md5=822f02cc7736281816581cd064afbb1c \ file://${S}/third_party/smhasher/LICENSE;md5=0d948322ab524e2b74f55eb8ef57c74a \ @@ -430,6 +578,7 @@ LIC_FILES_CHKSUM = "\ file://${S}/third_party/vulkan-headers/LICENSE.txt;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/third_party/vulkan-loader/src/LICENSE.txt;md5=7dbefed23242760aa3475ee42801c5ac \ file://${S}/third_party/vulkan_memory_allocator/LICENSE.txt;md5=6eed3e06ed116324029b9de40eaf0ee5 \ + file://${S}/third_party/wasm_tts_engine/EIGEN_LICENSE;md5=fb0a45fc2d5c3c92cf3e5c8e19e0e758 \ file://${S}/third_party/wayland-protocols/gtk/COPYING;md5=5f30f0716dfdd0d91eb439ebec522ec2 \ file://${S}/third_party/wayland-protocols/kde/COPYING.LIB;md5=2d5025d4aa3495befef8f17206a5b0a1 \ file://${S}/third_party/wayland-protocols/src/COPYING;md5=c7b12b6702da38ca028ace54aae3d484 \ @@ -437,6 +586,9 @@ LIC_FILES_CHKSUM = "\ file://${S}/third_party/webrtc/LICENSE;md5=ad296492125bc71530d06234d9bfebe0 \ file://${S}/third_party/webrtc/common_audio/third_party/ooura/LICENSE;md5=08458468f7a32acf1657071c5396f0c7 \ file://${S}/third_party/webrtc/common_audio/third_party/spl_sqrt_floor/LICENSE;md5=aa45275d6069f8d96c1f99741f72ea3f \ + file://${S}/third_party/webrtc/modules/third_party/fft/LICENSE;md5=0d4cd8529c0756f037fe890b12d1f6f8 \ + file://${S}/third_party/webrtc/modules/third_party/g711/LICENSE;md5=b36ce10e2d3d47fd5e3a465cbc9626da \ + file://${S}/third_party/webrtc/modules/third_party/g722/LICENSE;md5=b6ec8735a974f440bc0cd4d93929336e \ file://${S}/third_party/webrtc/modules/third_party/portaudio/LICENSE;md5=9f48147ba9bd3e7ca9a2392d2a3099c1 \ file://${S}/third_party/webrtc/rtc_base/third_party/sigslot/LICENSE;md5=d31e106d9b0e980d8b5773f151e33ec7 \ file://${S}/third_party/woff2/LICENSE;md5=027c71da9e4664fdf192e6ec615f4d18 \ @@ -450,5 +602,5 @@ LIC_FILES_CHKSUM = "\ file://${S}/third_party/zxcvbn-cpp/LICENSE.txt;md5=50f9303d0b3adb4952217b0d8c00d83f \ file://${S}/tools/mac/power/protos/third_party/pprof/LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ file://${S}/url/third_party/mozilla/LICENSE.txt;md5=437ced1e9b232651b0912a9594da43b2 \ - file://${S}/v8/LICENSE;md5=f38a2942edcfe4abb45e9a83a1ad2f82 \ + file://${S}/v8/LICENSE;md5=3f722db07a0a940a6c859c5c9c2c78fd \ " diff --git a/meta-chromium/recipes-browser/chromium/files/0001-Drop-GN-compiler-settings-conflicting-with-OE.patch b/meta-chromium/recipes-browser/chromium/files/0001-Drop-GN-compiler-settings-conflicting-with-OE.patch index ea996acef..ed58c3371 100644 --- a/meta-chromium/recipes-browser/chromium/files/0001-Drop-GN-compiler-settings-conflicting-with-OE.patch +++ b/meta-chromium/recipes-browser/chromium/files/0001-Drop-GN-compiler-settings-conflicting-with-OE.patch @@ -1,4 +1,4 @@ -From 2e867ac9e97b5ae2090b4de212d9c0e50eee653b Mon Sep 17 00:00:00 2001 +From feb3b8299f312e4074fc76fe7b6dfa236a5823d8 Mon Sep 17 00:00:00 2001 From: Max Ihlenfeldt Date: Tue, 25 Jun 2024 11:06:19 +0000 Subject: [PATCH] Drop GN compiler settings conflicting with OE @@ -19,10 +19,10 @@ Signed-off-by: Max Ihlenfeldt 1 file changed, 46 deletions(-) diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn -index f58320b88f..309c3078a2 100644 +index e7a60d56b5..b0e9e04bf3 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn -@@ -1240,26 +1240,6 @@ config("compiler_cpu_abi") { +@@ -1211,26 +1211,6 @@ config("compiler_cpu_abi") { "-msse3", ] } @@ -49,7 +49,7 @@ index f58320b88f..309c3078a2 100644 } else if (current_cpu == "mipsel" && !is_nacl) { ldflags += [ "-Wl,--hash-style=sysv" ] if (custom_toolchain == "") { -@@ -1267,9 +1247,6 @@ config("compiler_cpu_abi") { +@@ -1238,9 +1218,6 @@ config("compiler_cpu_abi") { if (is_android) { cflags += [ "--target=mipsel-linux-android" ] ldflags += [ "--target=mipsel-linux-android" ] @@ -59,7 +59,7 @@ index f58320b88f..309c3078a2 100644 } } else { cflags += [ "-EL" ] -@@ -1349,8 +1326,6 @@ config("compiler_cpu_abi") { +@@ -1320,8 +1297,6 @@ config("compiler_cpu_abi") { ldflags += [ "-Wl,--hash-style=sysv" ] if (custom_toolchain == "") { if (is_clang) { @@ -68,7 +68,7 @@ index f58320b88f..309c3078a2 100644 } else { cflags += [ "-EB" ] ldflags += [ "-EB" ] -@@ -1399,8 +1374,6 @@ config("compiler_cpu_abi") { +@@ -1370,8 +1345,6 @@ config("compiler_cpu_abi") { cflags += [ "--target=mips64el-linux-android" ] ldflags += [ "--target=mips64el-linux-android" ] } else { @@ -77,7 +77,7 @@ index f58320b88f..309c3078a2 100644 } } else { cflags += [ -@@ -1458,8 +1431,6 @@ config("compiler_cpu_abi") { +@@ -1429,8 +1402,6 @@ config("compiler_cpu_abi") { ldflags += [ "-Wl,--hash-style=sysv" ] if (custom_toolchain == "") { if (is_clang) { @@ -86,7 +86,7 @@ index f58320b88f..309c3078a2 100644 } else { cflags += [ "-EB", -@@ -1628,23 +1599,6 @@ config("compiler_deterministic") { +@@ -1599,23 +1570,6 @@ config("compiler_deterministic") { } } } diff --git a/meta-chromium/recipes-browser/chromium/files/0002-v8-qemu-wrapper.patch b/meta-chromium/recipes-browser/chromium/files/0002-v8-qemu-wrapper.patch index 080de6e16..9261b47c1 100644 --- a/meta-chromium/recipes-browser/chromium/files/0002-v8-qemu-wrapper.patch +++ b/meta-chromium/recipes-browser/chromium/files/0002-v8-qemu-wrapper.patch @@ -1,4 +1,4 @@ -From 60233d0570b4c9c9a9827616b224c9c93cbf6254 Mon Sep 17 00:00:00 2001 +From d326bbe195c6853c600d01b9d438b5ee430b55c2 Mon Sep 17 00:00:00 2001 From: Raphael Kubo da Costa Date: Tue, 7 Nov 2017 15:24:32 +0100 Subject: [PATCH] v8: qemu wrapper @@ -17,22 +17,22 @@ Signed-off-by: Maksim Sisov 2 files changed, 5 insertions(+) diff --git a/tools/v8_context_snapshot/BUILD.gn b/tools/v8_context_snapshot/BUILD.gn -index f46bec2eb5..54383655c0 100644 +index 70c32b2fc9..88497d1436 100644 --- a/tools/v8_context_snapshot/BUILD.gn +++ b/tools/v8_context_snapshot/BUILD.gn -@@ -45,6 +45,7 @@ if (use_v8_context_snapshot) { - output_path = rebase_path(output_file, root_build_dir) +@@ -49,6 +49,7 @@ if (use_v8_context_snapshot) { + output_path = rebase_path(output_file, root_build_dir) - args = [ -+ "./v8-qemu-wrapper.sh", - "./" + rebase_path(get_label_info(":v8_context_snapshot_generator", - "root_out_dir") + - "/v8_context_snapshot_generator", + args = [ ++ "./v8-qemu-wrapper.sh", + "./" + rebase_path( + get_label_info( + ":v8_context_snapshot_generator($v8_snapshot_toolchain)", diff --git a/v8/BUILD.gn b/v8/BUILD.gn -index 0c559713ea..c8c95eb3a9 100644 +index 9a2b2cdd94..8c217b57c9 100644 --- a/v8/BUILD.gn +++ b/v8/BUILD.gn -@@ -2274,6 +2274,7 @@ template("run_torque") { +@@ -2228,6 +2228,7 @@ template("run_torque") { } args = [ @@ -40,7 +40,7 @@ index 0c559713ea..c8c95eb3a9 100644 "./" + rebase_path( get_label_info(":torque($toolchain)", "root_out_dir") + "/torque", root_build_dir), -@@ -2437,6 +2438,7 @@ action("generate_bytecode_builtins_list") { +@@ -2391,6 +2392,7 @@ action("generate_bytecode_builtins_list") { outputs = [ "$target_gen_dir/builtins-generated/bytecodes-builtins-list.h" ] deps = [ ":bytecode_builtins_list_generator($v8_generator_toolchain)" ] args = [ @@ -48,7 +48,7 @@ index 0c559713ea..c8c95eb3a9 100644 "./" + rebase_path( get_label_info( ":bytecode_builtins_list_generator($v8_generator_toolchain)", -@@ -2509,6 +2511,7 @@ template("run_mksnapshot") { +@@ -2470,6 +2472,7 @@ template("run_mksnapshot") { } args += [ @@ -56,7 +56,7 @@ index 0c559713ea..c8c95eb3a9 100644 "./" + rebase_path(get_label_info(":mksnapshot($v8_snapshot_toolchain)", "root_out_dir") + "/mksnapshot", root_build_dir), -@@ -7451,6 +7454,7 @@ if (v8_enable_i18n_support) { +@@ -7427,6 +7430,7 @@ if (v8_enable_i18n_support) { outputs = [ output_file ] args = [ diff --git a/meta-chromium/recipes-browser/chromium/files/0003-wrapper-extra-flags.patch b/meta-chromium/recipes-browser/chromium/files/0003-wrapper-extra-flags.patch index 56493bbc4..5f012500a 100644 --- a/meta-chromium/recipes-browser/chromium/files/0003-wrapper-extra-flags.patch +++ b/meta-chromium/recipes-browser/chromium/files/0003-wrapper-extra-flags.patch @@ -1,4 +1,4 @@ -From 71eca88e5d42d4732dfe53ea8fadf2199db519a2 Mon Sep 17 00:00:00 2001 +From a8c669d57bd409ba07255bd52fe3c9f0817de2ac Mon Sep 17 00:00:00 2001 From: Raphael Kubo da Costa Date: Wed, 8 Nov 2017 16:43:47 +0100 Subject: [PATCH] wrapper: extra flags diff --git a/meta-chromium/recipes-browser/chromium/files/0004-Delete-compiler-options-not-available-in-release-ver.patch b/meta-chromium/recipes-browser/chromium/files/0004-Delete-compiler-options-not-available-in-release-ver.patch index 1b3e23dcb..55401d2f2 100644 --- a/meta-chromium/recipes-browser/chromium/files/0004-Delete-compiler-options-not-available-in-release-ver.patch +++ b/meta-chromium/recipes-browser/chromium/files/0004-Delete-compiler-options-not-available-in-release-ver.patch @@ -1,4 +1,4 @@ -From fc3a1af7d8d6ed6bc54d096e72cbf3d35ff4fa97 Mon Sep 17 00:00:00 2001 +From 0a052a88bf96542e0bb7585ccbfd39e681a32e3d Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Wed, 4 Dec 2019 19:06:54 -0800 Subject: [PATCH] Delete compiler options not available in release versions of @@ -17,29 +17,28 @@ Signed-off-by: Randy MacLeod Signed-off-by: Ariel D'Alessandro --- - build/config/compiler/BUILD.gn | 13 +++++-------- - 1 file changed, 5 insertions(+), 8 deletions(-) + build/config/compiler/BUILD.gn | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn -index 309c3078a2647..5eeb241fc9038 100644 +index b0e9e04bf3..46ed84d73c 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn -@@ -615,14 +615,6 @@ config("compiler") { +@@ -614,13 +614,6 @@ config("compiler") { } else { cflags += [ "-ffp-contract=off" ] } - - # Enable ELF CREL (see crbug.com/357878242) for all platforms that use ELF - # (excluding toolchains that use an older version of LLVM). -- # TODO(crbug.com/376278218): This causes segfault on Linux ARM builds. -- if (is_linux && !llvm_android_mainline && current_cpu != "arm" && +- if (is_linux && !llvm_android_mainline && - default_toolchain != "//build/toolchain/cros:target") { - cflags += [ "-Wa,--crel,--allow-experimental-crel" ] - } } # C11/C++11 compiler flags setup. -@@ -1924,6 +1916,11 @@ config("default_warnings") { +@@ -1934,6 +1927,11 @@ config("default_warnings") { } cflags += [ diff --git a/meta-chromium/recipes-browser/chromium/files/0005-avoid-link-latomic-failure-on-CentOS-8-host.patch b/meta-chromium/recipes-browser/chromium/files/0005-avoid-link-latomic-failure-on-CentOS-8-host.patch index 9a4359307..ff4660210 100644 --- a/meta-chromium/recipes-browser/chromium/files/0005-avoid-link-latomic-failure-on-CentOS-8-host.patch +++ b/meta-chromium/recipes-browser/chromium/files/0005-avoid-link-latomic-failure-on-CentOS-8-host.patch @@ -1,4 +1,4 @@ -From c68f4f68490005e1576ca2339b1124dca5f83867 Mon Sep 17 00:00:00 2001 +From be9a610454f3a90e2610443a424efcb34b4903e5 Mon Sep 17 00:00:00 2001 From: Hongxu Jia Date: Fri, 22 Jan 2021 00:02:25 +0800 Subject: [PATCH] avoid link latomic failure on CentOS 8 host @@ -18,10 +18,10 @@ Signed-off-by: Randy MacLeod 2 files changed, 4 insertions(+) diff --git a/base/BUILD.gn b/base/BUILD.gn -index 5dee8a9226..bc3e57164a 100644 +index 57a6af0061..2703e81421 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn -@@ -1077,7 +1077,9 @@ component("base") { +@@ -1104,7 +1104,9 @@ component("base") { # Needed for if using newer C++ library than sysroot, except if # building inside the cros_sdk environment - use host_toolchain as a # more robust check for this. diff --git a/meta-chromium/recipes-browser/chromium/files/0006-Don-t-pass-unknown-LLVM-options.patch b/meta-chromium/recipes-browser/chromium/files/0006-Don-t-pass-unknown-LLVM-options.patch index 4c9bf722a..de6266158 100644 --- a/meta-chromium/recipes-browser/chromium/files/0006-Don-t-pass-unknown-LLVM-options.patch +++ b/meta-chromium/recipes-browser/chromium/files/0006-Don-t-pass-unknown-LLVM-options.patch @@ -1,4 +1,4 @@ -From 651736ea42939ae67169d3429489ae9f304eae3c Mon Sep 17 00:00:00 2001 +From 8e9bf93215630604eed49476d6e848ad3ec3bdba Mon Sep 17 00:00:00 2001 From: Max Ihlenfeldt Date: Fri, 8 Dec 2023 11:47:43 +0000 Subject: [PATCH] Don't pass unknown LLVM options @@ -17,10 +17,10 @@ Signed-off-by: Max Ihlenfeldt 1 file changed, 18 deletions(-) diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn -index 8951f6006c..cc300e7122 100644 +index 46ed84d73c..5f7cfb69e9 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn -@@ -591,24 +591,6 @@ config("compiler") { +@@ -590,24 +590,6 @@ config("compiler") { } } diff --git a/meta-chromium/recipes-browser/chromium/files/0007-Fix-constexpr-variable-must-be-initialized-by-a-cons.patch b/meta-chromium/recipes-browser/chromium/files/0007-Fix-constexpr-variable-must-be-initialized-by-a-cons.patch index 46aec8a3d..c0dcffa6c 100644 --- a/meta-chromium/recipes-browser/chromium/files/0007-Fix-constexpr-variable-must-be-initialized-by-a-cons.patch +++ b/meta-chromium/recipes-browser/chromium/files/0007-Fix-constexpr-variable-must-be-initialized-by-a-cons.patch @@ -1,4 +1,4 @@ -From 5a28cb783a33391476839a5b904f0eab7fb9b13d Mon Sep 17 00:00:00 2001 +From 713169dbbcb3081744ea103749597885bb1b97a2 Mon Sep 17 00:00:00 2001 From: Max Ihlenfeldt Date: Fri, 22 Mar 2024 10:43:47 +0000 Subject: [PATCH] Fix "constexpr variable must be initialized by a constant @@ -10,13 +10,13 @@ change the problematic expressions to be const instead. Upstream-Status: Inappropriate [specific to older versions of clang] Signed-off-by: Max Ihlenfeldt --- - .../autofill/core/browser/data_model/autofill_i18n_api.h | 4 ++-- + .../core/browser/data_model/addresses/autofill_i18n_api.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) -diff --git a/components/autofill/core/browser/data_model/autofill_i18n_api.h b/components/autofill/core/browser/data_model/autofill_i18n_api.h -index fa1a06bdad..8e1fe01bfc 100644 ---- a/components/autofill/core/browser/data_model/autofill_i18n_api.h -+++ b/components/autofill/core/browser/data_model/autofill_i18n_api.h +diff --git a/components/autofill/core/browser/data_model/addresses/autofill_i18n_api.h b/components/autofill/core/browser/data_model/addresses/autofill_i18n_api.h +index e926bdca5b..799c4b3f80 100644 +--- a/components/autofill/core/browser/data_model/addresses/autofill_i18n_api.h ++++ b/components/autofill/core/browser/data_model/addresses/autofill_i18n_api.h @@ -16,8 +16,8 @@ namespace autofill::i18n_model_definition { // Country code that represents autofill's legacy address hierarchy model as // stored `kAutofillModelRules`. As a workaround for GCC we declare the diff --git a/meta-chromium/recipes-browser/chromium/files/0008-Use-the-correct-path-to-libclang_rt.builtins.a.patch b/meta-chromium/recipes-browser/chromium/files/0008-Use-the-correct-path-to-libclang_rt.builtins.a.patch index 421758343..465bc5412 100644 --- a/meta-chromium/recipes-browser/chromium/files/0008-Use-the-correct-path-to-libclang_rt.builtins.a.patch +++ b/meta-chromium/recipes-browser/chromium/files/0008-Use-the-correct-path-to-libclang_rt.builtins.a.patch @@ -1,4 +1,4 @@ -From b9b4dffd99fd57dc3acbce7304284c26a10e695e Mon Sep 17 00:00:00 2001 +From 6fcf4a20eef34ad3577505b8c36cd2ecd5e97676 Mon Sep 17 00:00:00 2001 From: Max Ihlenfeldt Date: Tue, 19 Dec 2023 12:14:05 +0000 Subject: [PATCH] Use the correct path to libclang_rt.builtins.a @@ -21,12 +21,12 @@ Signed-off-by: Max Ihlenfeldt 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/build/config/clang/BUILD.gn b/build/config/clang/BUILD.gn -index 44bd202d2b..6789beccdc 100644 +index 0d648fa310..4652cb5127 100644 --- a/build/config/clang/BUILD.gn +++ b/build/config/clang/BUILD.gn -@@ -166,14 +166,15 @@ template("clang_lib") { - } else if (is_apple) { - _dir = "darwin" +@@ -199,14 +199,15 @@ template("clang_lib") { + assert(false) # Unhandled cpu type + } } else if (is_linux || is_chromeos) { + _dir = "linux" if (current_cpu == "x64") { diff --git a/meta-chromium/recipes-browser/chromium/files/0009-Adjust-the-Rust-build-to-our-needs.patch b/meta-chromium/recipes-browser/chromium/files/0009-Adjust-the-Rust-build-to-our-needs.patch index 495a56ada..d25447620 100644 --- a/meta-chromium/recipes-browser/chromium/files/0009-Adjust-the-Rust-build-to-our-needs.patch +++ b/meta-chromium/recipes-browser/chromium/files/0009-Adjust-the-Rust-build-to-our-needs.patch @@ -1,4 +1,4 @@ -From f4f50a5de596d13d18f1f9b80f83e446936a4afb Mon Sep 17 00:00:00 2001 +From 394ff496602bf9695c7f815f5f73c0027ab4ddc7 Mon Sep 17 00:00:00 2001 From: Max Ihlenfeldt Date: Tue, 16 Jan 2024 12:29:30 +0000 Subject: [PATCH] Adjust the Rust build to our needs @@ -16,14 +16,14 @@ Subject: [PATCH] Adjust the Rust build to our needs Upstream-Status: Inappropriate [specific to our build setup] Signed-off-by: Max Ihlenfeldt --- - build/config/rust.gni | 26 +++++++++++++++++++------- + build/config/rust.gni | 28 ++++++++++++++++++++-------- build/rust/rustc_wrapper.py | 1 + build/rust/std/BUILD.gn | 28 +++++++++++++++++++++------- build/rust/std/find_std_rlibs.py | 16 +++++++++++----- - 4 files changed, 52 insertions(+), 19 deletions(-) + 4 files changed, 53 insertions(+), 20 deletions(-) diff --git a/build/config/rust.gni b/build/config/rust.gni -index 60856e609d..4baeaecb9c 100644 +index 74b3b9ced5..5affd0b445 100644 --- a/build/config/rust.gni +++ b/build/config/rust.gni @@ -102,6 +102,11 @@ declare_args() { @@ -63,12 +63,16 @@ index 60856e609d..4baeaecb9c 100644 cargo_target_abi = "" } else if (current_cpu == "arm") { if (arm_float_abi == "hard") { -@@ -191,18 +203,18 @@ if (is_linux || is_chromeos) { - } - if (arm_arch == "armv7-a" || arm_arch == "armv7") { - # No way to inform Rust about the -a suffix. -- rust_abi_target = "armv7-unknown-linux-gnueabi" + float_suffix -+ rust_abi_target = "armv7" + vendor + "-linux-gnueabi" + float_suffix +@@ -201,21 +213,21 @@ if (is_linux || is_chromeos) { + # targets in fact target Thumb, see: + # https://github.com/rust-lang/rust/issues/44722 + if (arm_use_neon) { +- rust_abi_target = "thumbv7neon-unknown-linux-gnueabi" + float_suffix ++ rust_abi_target = "thumbv7neon" + vendor + "-linux-gnueabi" + float_suffix + } else { +- rust_abi_target = "armv7-unknown-linux-gnueabi" + float_suffix ++ rust_abi_target = "armv7" + vendor + "-linux-gnueabi" + float_suffix + } cargo_target_abi = "eabi" + float_suffix } else { - rust_abi_target = "arm-unknown-linux-gnueabi" + float_suffix @@ -99,10 +103,10 @@ index 8f2096dfe5..de43d44eed 100755 abs_build_root = os.getcwd().replace('\\', '/') + '/' is_windows = sys.platform == 'win32' or args.target_windows diff --git a/build/rust/std/BUILD.gn b/build/rust/std/BUILD.gn -index b5f5291283..9619dccc45 100644 +index 6b996aa1fe..146f6633ce 100644 --- a/build/rust/std/BUILD.gn +++ b/build/rust/std/BUILD.gn -@@ -191,7 +191,8 @@ if (toolchain_has_rust) { +@@ -207,7 +207,8 @@ if (toolchain_has_rust) { # our locally-built std. Both reside in root_out_dir: we must only have one of # each per GN toolchain anyway. @@ -112,7 +116,7 @@ index b5f5291283..9619dccc45 100644 if (!rust_prebuilt_stdlib) { local_rustc_sysroot = "$root_out_dir/local_rustc_sysroot" -@@ -320,12 +321,12 @@ if (toolchain_has_rust) { +@@ -336,12 +337,12 @@ if (toolchain_has_rust) { rust_abi_target, ] @@ -128,7 +132,7 @@ index b5f5291283..9619dccc45 100644 } visibility = [ ":*" ] -@@ -338,8 +339,18 @@ if (toolchain_has_rust) { +@@ -354,8 +355,18 @@ if (toolchain_has_rust) { "enable_rust=false") deps = [ ":find_stdlib" ] sources = get_target_outputs(":find_stdlib") @@ -149,7 +153,7 @@ index b5f5291283..9619dccc45 100644 visibility = [ ":*" ] } -@@ -379,7 +390,10 @@ if (toolchain_has_rust) { +@@ -395,7 +406,10 @@ if (toolchain_has_rust) { ":prebuilt_stdlib_libs", ":stdlib_public_dependent_libs", ] diff --git a/meta-chromium/recipes-browser/chromium/files/0012-Revert-Allow-and-use-std-hardware_destructive_interf.patch b/meta-chromium/recipes-browser/chromium/files/0011-Revert-Allow-and-use-std-hardware_destructive_interf.patch similarity index 92% rename from meta-chromium/recipes-browser/chromium/files/0012-Revert-Allow-and-use-std-hardware_destructive_interf.patch rename to meta-chromium/recipes-browser/chromium/files/0011-Revert-Allow-and-use-std-hardware_destructive_interf.patch index c9a94ffd5..0dca0b54d 100644 --- a/meta-chromium/recipes-browser/chromium/files/0012-Revert-Allow-and-use-std-hardware_destructive_interf.patch +++ b/meta-chromium/recipes-browser/chromium/files/0011-Revert-Allow-and-use-std-hardware_destructive_interf.patch @@ -21,7 +21,7 @@ Signed-off-by: Max Ihlenfeldt 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/components/media_router/common/providers/cast/channel/enum_table.h b/components/media_router/common/providers/cast/channel/enum_table.h -index fba9c05770..9cd7596443 100644 +index fdf8941c32..9340ba2857 100644 --- a/components/media_router/common/providers/cast/channel/enum_table.h +++ b/components/media_router/common/providers/cast/channel/enum_table.h @@ -12,7 +12,6 @@ @@ -32,7 +32,7 @@ index fba9c05770..9cd7596443 100644 #include #include #include -@@ -366,7 +365,8 @@ class EnumTable { +@@ -368,7 +367,8 @@ class EnumTable { private: #ifdef ARCH_CPU_64_BITS @@ -43,10 +43,10 @@ index fba9c05770..9cd7596443 100644 std::initializer_list data_; bool is_sorted_; diff --git a/styleguide/c++/c++-features.md b/styleguide/c++/c++-features.md -index 8bde1b84da..a9222082f6 100644 +index fec5e73654..ffaf71fd54 100644 --- a/styleguide/c++/c++-features.md +++ b/styleguide/c++/c++-features.md -@@ -574,6 +574,35 @@ Overlaps with utilities in `base/strings/string_number_conversions.h`, which are +@@ -587,6 +587,35 @@ Overlaps with utilities in `base/strings/string_number_conversions.h`, which are easier to use correctly. *** @@ -79,10 +79,10 @@ index 8bde1b84da..a9222082f6 100644 +[Discussion thread](https://groups.google.com/a/chromium.org/g/cxx/c/cwktrFxxUY4) +*** + - ### std::in_place{_type,_index}[_t] [banned] + ### std::{pmr::memory_resource,polymorphic_allocator} [banned] ```c++ -@@ -1200,31 +1229,6 @@ avoiding the need to use the `erase(remove(...` paradigm. +@@ -1170,31 +1199,6 @@ avoiding the need to use the `erase(remove(...` paradigm. [Migration bug](https://crbug.com/1414639) *** diff --git a/meta-chromium/recipes-browser/chromium/files/0013-Revert-Set-Rust-symbol-visibility-to-hidden-when-C-s.patch b/meta-chromium/recipes-browser/chromium/files/0012-Revert-Set-Rust-symbol-visibility-to-hidden-when-C-s.patch similarity index 100% rename from meta-chromium/recipes-browser/chromium/files/0013-Revert-Set-Rust-symbol-visibility-to-hidden-when-C-s.patch rename to meta-chromium/recipes-browser/chromium/files/0012-Revert-Set-Rust-symbol-visibility-to-hidden-when-C-s.patch diff --git a/meta-chromium/recipes-browser/chromium/files/0014-pdfium-Fix-missing-PDFiumAPIStringBufferAdapter-temp.patch b/meta-chromium/recipes-browser/chromium/files/0013-pdfium-Fix-missing-PDFiumAPIStringBufferAdapter-temp.patch similarity index 100% rename from meta-chromium/recipes-browser/chromium/files/0014-pdfium-Fix-missing-PDFiumAPIStringBufferAdapter-temp.patch rename to meta-chromium/recipes-browser/chromium/files/0013-pdfium-Fix-missing-PDFiumAPIStringBufferAdapter-temp.patch diff --git a/meta-chromium/recipes-browser/chromium/files/0014-Revert-Remove-libavif-based-AVIF-decoder.patch b/meta-chromium/recipes-browser/chromium/files/0014-Revert-Remove-libavif-based-AVIF-decoder.patch new file mode 100644 index 000000000..d7f2d2abf --- /dev/null +++ b/meta-chromium/recipes-browser/chromium/files/0014-Revert-Remove-libavif-based-AVIF-decoder.patch @@ -0,0 +1,3744 @@ +From 75e1653ce9bf360e4c1cb5b86872ebff0b67a35b Mon Sep 17 00:00:00 2001 +From: Ariel D'Alessandro +Date: Thu, 17 Jul 2025 12:51:22 -0300 +Subject: [PATCH] Revert "Remove libavif based AVIF decoder" + +This reverts commit ce78002f97a433e53ab16805e16b895f9b52ea24. + +In order to disable crabbyavif to fix build errors, re-enable libavif so +it can be used in replacement. + +Upstream-Status: Inappropriate [upstream ticket https://crbug.com/357017325] +Signed-off-by: Ariel D'Alessandro +--- + .../common/ProductionSupportedFlagList.java | 3 + + chrome/browser/about_flags.cc | 4 + + chrome/browser/flag-metadata.json | 5 + + chrome/browser/flag_descriptions.cc | 5 + + chrome/browser/flag_descriptions.h | 3 + + third_party/blink/common/features.cc | 2 + + third_party/blink/public/common/features.h | 3 + + third_party/blink/renderer/platform/BUILD.gn | 13 + + .../renderer/platform/image-decoders/BUILD.gn | 12 +- + .../image-decoders/avif/avif_image_decoder.cc | 1295 ++++++++++++ + .../image-decoders/avif/avif_image_decoder.h | 191 ++ + .../avif/avif_image_decoder_fuzzer.cc | 30 + + .../avif/avif_image_decoder_test.cc | 1758 +++++++++++++++++ + .../avif/gen_crabbyavif_wrapper.py | 164 ++ + .../platform/image-decoders/image_decoder.cc | 17 +- + .../image_decoder_fuzzer_utils.cc | 8 + + .../image_decoder_fuzzer_utils.h | 1 + + 17 files changed, 3508 insertions(+), 6 deletions(-) + create mode 100644 third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.cc + create mode 100644 third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h + create mode 100644 third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder_fuzzer.cc + create mode 100644 third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder_test.cc + create mode 100644 third_party/blink/renderer/platform/image-decoders/avif/gen_crabbyavif_wrapper.py + +diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java +index def02f59887c1..3bfa4dc335cb1 100644 +--- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java ++++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java +@@ -434,6 +434,9 @@ public final class ProductionSupportedFlagList { + Flag.baseFeature( + BaseFeatures.RUN_TASKS_BY_BATCHES, + "Run tasks in queue for 8ms before before sending a system message."), ++ Flag.baseFeature( ++ BlinkFeatures.CRABBY_AVIF, ++ "If enabled, CrabbyAvif will be used instead of libavif for decoding AVIF images."), + Flag.baseFeature( + NetworkServiceFeatures.DEPRECATE_UNLOAD, + "If false prevents the gradual deprecation of the unload event."), +diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc +index 5156e5d3f2c74..1a0e2039bda1d 100644 +--- a/chrome/browser/about_flags.cc ++++ b/chrome/browser/about_flags.cc +@@ -7780,6 +7780,10 @@ const FeatureEntry kFeatureEntries[] = { + flag_descriptions::kAvifGainmapHdrImagesDescription, kOsAll, + FEATURE_VALUE_TYPE(blink::features::kAvifGainmapHdrImages)}, + ++ {"crabbyavif", flag_descriptions::kCrabbyAvifName, ++ flag_descriptions::kCrabbyAvifDescription, kOsAll, ++ FEATURE_VALUE_TYPE(blink::features::kCrabbyAvif)}, ++ + {"file-handling-icons", flag_descriptions::kFileHandlingIconsName, + flag_descriptions::kFileHandlingIconsDescription, kOsDesktop, + FEATURE_VALUE_TYPE(blink::features::kFileHandlingIcons)}, +diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json +index d6851e527feb1..bd09150e90221 100644 +--- a/chrome/browser/flag-metadata.json ++++ b/chrome/browser/flag-metadata.json +@@ -1658,6 +1658,11 @@ + "owners": ["sebsg@chromium.org", "bling-transactions-eng@google.com"], + "expiry_milestone": 135 + }, ++ { ++ "name": "crabbyavif", ++ "owners": [ "vigneshv@google.com", "image-codecs-eng@google.com" ], ++ "expiry_milestone": 133 ++ }, + { + "name": "cras-processor-wav-dump", + "owners": ["aaronyu@google.com", "chromeos-audio@google.com" ], +diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc +index c06c6c65b1398..1050fe6c31ca1 100644 +--- a/chrome/browser/flag_descriptions.cc ++++ b/chrome/browser/flag_descriptions.cc +@@ -446,6 +446,11 @@ const char kAvifGainmapHdrImagesDescription[] = + "If enabled, Chrome uses the gainmap (if present) in AVIF images to render " + "the HDR version on HDR displays and the SDR version on SDR displays."; + ++const char kCrabbyAvifName[] = "CrabbyAvif for decoding AVIF images"; ++const char kCrabbyAvifDescription[] = ++ "If enabled, CrabbyAvif will be used instead of libavif for decoding AVIF " ++ "images"; ++ + const char kTangibleSyncName[] = "Tangible Sync"; + const char kTangibleSyncDescription[] = + "Enables the tangible sync when a user starts the sync consent flow"; +diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h +index be3f7a6e96f05..0e4e01f106ba8 100644 +--- a/chrome/browser/flag_descriptions.h ++++ b/chrome/browser/flag_descriptions.h +@@ -312,6 +312,9 @@ extern const char kForestFeatureDescription[]; + extern const char kAvifGainmapHdrImagesName[]; + extern const char kAvifGainmapHdrImagesDescription[]; + ++extern const char kCrabbyAvifName[]; ++extern const char kCrabbyAvifDescription[]; ++ + extern const char kTangibleSyncName[]; + extern const char kTangibleSyncDescription[]; + +diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc +index 720c38313bd13..e4d60ff6ade3e 100644 +--- a/third_party/blink/common/features.cc ++++ b/third_party/blink/common/features.cc +@@ -510,6 +510,8 @@ BASE_FEATURE(kCorrectFloatExtensionTestForWebGL, + "CorrectFloatExtensionTestForWebGL", + base::FEATURE_ENABLED_BY_DEFAULT); + ++BASE_FEATURE(kCrabbyAvif, "CrabbyAvif", base::FEATURE_ENABLED_BY_DEFAULT); ++ + // When enabled, add a new option, {imageOrientation: 'none'}, to + // createImageBitmap, which ignores the image orientation metadata of the source + // and renders the image as encoded. +diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h +index 9970347ef0ccb..220f447a0725e 100644 +--- a/third_party/blink/public/common/features.h ++++ b/third_party/blink/public/common/features.h +@@ -366,6 +366,9 @@ BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE_PARAM( + // See http://crbug.com/40788570. + BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kDevToolsImprovedNetworkError); + ++// Enables the use of CrabbyAvif for decoding AVIF images. ++BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kCrabbyAvif); ++ + // Enables input IPC to directly target the renderer's compositor thread without + // hopping through the IO thread first. + BLINK_COMMON_EXPORT BASE_DECLARE_FEATURE(kDirectCompositorThreadIpc); +diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn +index 291676c658372..57505f9d2622c 100644 +--- a/third_party/blink/renderer/platform/BUILD.gn ++++ b/third_party/blink/renderer/platform/BUILD.gn +@@ -2786,6 +2786,19 @@ fuzzer_test("web_icon_sizes_fuzzer") { + additional_configs = [ "//third_party/blink/renderer:inside_blink" ] + } + ++# Fuzzer for blink::AVIFImageDecoder ++fuzzer_test("blink_avif_decoder_fuzzer") { ++ sources = [ "image-decoders/avif/avif_image_decoder_fuzzer.cc" ] ++ deps = [ ++ ":blink_fuzzer_test_support", ++ ":blink_image_decoder_fuzzer_test_support", ++ ":platform", ++ ] ++ seed_corpuses = [ "//third_party/blink/web_tests/images/resources/avif" ] ++ libfuzzer_options = [ "rss_limit_mb=8192" ] ++ additional_configs = [ "//third_party/blink/renderer:inside_blink" ] ++} ++ + # Fuzzer for blink::CrabbyAVIFImageDecoder + fuzzer_test("blink_crabbyavif_decoder_fuzzer") { + sources = [ "image-decoders/avif/crabbyavif_image_decoder_fuzzer.cc" ] +diff --git a/third_party/blink/renderer/platform/image-decoders/BUILD.gn b/third_party/blink/renderer/platform/image-decoders/BUILD.gn +index 870c7e8537249..e638c6bfcd93a 100644 +--- a/third_party/blink/renderer/platform/image-decoders/BUILD.gn ++++ b/third_party/blink/renderer/platform/image-decoders/BUILD.gn +@@ -79,11 +79,16 @@ component("image_decoders") { + + if (enable_av1_decoder) { + sources += [ ++ "avif/avif_image_decoder.cc", ++ "avif/avif_image_decoder.h", + "avif/crabbyavif_image_decoder.cc", + "avif/crabbyavif_image_decoder.h", + ] + +- deps += [ "//third_party/crabbyavif" ] ++ deps += [ ++ "//third_party/crabbyavif", ++ "//third_party/libavif", ++ ] + } + + if (enable_rust_png) { +@@ -130,6 +135,9 @@ source_set("unit_tests") { + } + + if (enable_av1_decoder) { +- sources += [ "avif/crabbyavif_image_decoder_test.cc" ] ++ sources += [ ++ "avif/avif_image_decoder_test.cc", ++ "avif/crabbyavif_image_decoder_test.cc", ++ ] + } + } +diff --git a/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.cc b/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.cc +new file mode 100644 +index 0000000000000..eb9448d06d30a +--- /dev/null ++++ b/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.cc +@@ -0,0 +1,1295 @@ ++// Copyright 2020 The Chromium Authors ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#ifdef UNSAFE_BUFFERS_BUILD ++// TODO(crbug.com/351564777): Remove this and convert code to safer constructs. ++#pragma allow_unsafe_buffers ++#endif ++ ++#include "third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h" ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "base/bits.h" ++#include "base/containers/adapters.h" ++#include "base/feature_list.h" ++#include "base/functional/bind.h" ++#include "base/logging.h" ++#include "base/memory/scoped_refptr.h" ++#include "base/metrics/histogram_functions.h" ++#include "base/numerics/safe_conversions.h" ++#include "base/timer/elapsed_timer.h" ++#include "build/build_config.h" ++#include "cc/base/math_util.h" ++#include "media/base/video_color_space.h" ++#include "skia/ext/cicp.h" ++#include "third_party/blink/public/common/features.h" ++#include "third_party/blink/renderer/platform/image-decoders/fast_shared_buffer_reader.h" ++#include "third_party/blink/renderer/platform/image-decoders/image_animation.h" ++#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h" ++#include "third_party/blink/renderer/platform/image-decoders/rw_buffer.h" ++#include "third_party/libavif/src/include/avif/avif.h" ++#include "third_party/libyuv/include/libyuv.h" ++#include "third_party/skia/include/core/SkColorSpace.h" ++#include "third_party/skia/include/core/SkTypes.h" ++#include "third_party/skia/include/private/SkXmp.h" ++#include "ui/gfx/color_space.h" ++#include "ui/gfx/icc_profile.h" ++ ++#if defined(ARCH_CPU_BIG_ENDIAN) ++#error Blink assumes a little-endian target. ++#endif ++ ++namespace blink { ++ ++namespace { ++ ++// The maximum AVIF file size we are willing to decode. This helps libavif ++// detect invalid sizes and offsets in an AVIF file before the file size is ++// known. ++constexpr uint64_t kMaxAvifFileSize = 0x10000000; // 256 MB ++ ++const char* AvifDecoderErrorMessage(const avifDecoder* decoder) { ++ // decoder->diag.error is a char array that stores a null-terminated C string. ++ return *decoder->diag.error != '\0' ? decoder->diag.error ++ : "(no error message)"; ++} ++ ++// Builds a gfx::ColorSpace from the ITU-T H.273 (CICP) color description. ++gfx::ColorSpace GetColorSpace( ++ avifColorPrimaries color_primaries, ++ avifTransferCharacteristics transfer_characteristics, ++ avifMatrixCoefficients matrix_coefficients, ++ avifRange yuv_range, ++ bool grayscale) { ++ // (As of ISO/IEC 23000-22:2019 Amendment 2) MIAF Section 7.3.6.4 says: ++ // If a coded image has no associated colour property, the default property ++ // is defined as having colour_type equal to 'nclx' with properties as ++ // follows: ++ // – colour_primaries equal to 1, ++ // - transfer_characteristics equal to 13, ++ // - matrix_coefficients equal to 5 or 6 (which are functionally identical), ++ // and ++ // - full_range_flag equal to 1. ++ // ... ++ // These values correspond to AVIF_COLOR_PRIMARIES_BT709, ++ // AVIF_TRANSFER_CHARACTERISTICS_SRGB, and AVIF_MATRIX_COEFFICIENTS_BT601, ++ // respectively. ++ // ++ // Note that this only specifies the default color property when the color ++ // property is absent. It does not really specify the default values for ++ // colour_primaries, transfer_characteristics, and matrix_coefficients when ++ // they are equal to 2 (unspecified). But we will interpret it as specifying ++ // the default values for these variables because we must choose some defaults ++ // and these are the most reasonable defaults to choose. We also advocate that ++ // all AVIF decoders choose these defaults: ++ // https://github.com/AOMediaCodec/av1-avif/issues/84 ++ const auto primaries = color_primaries == AVIF_COLOR_PRIMARIES_UNSPECIFIED ++ ? AVIF_COLOR_PRIMARIES_BT709 ++ : color_primaries; ++ const auto transfer = ++ transfer_characteristics == AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED ++ ? AVIF_TRANSFER_CHARACTERISTICS_SRGB ++ : transfer_characteristics; ++ const auto matrix = ++ (grayscale || matrix_coefficients == AVIF_MATRIX_COEFFICIENTS_UNSPECIFIED) ++ ? AVIF_MATRIX_COEFFICIENTS_BT601 ++ : matrix_coefficients; ++ const auto range = yuv_range == AVIF_RANGE_FULL ++ ? gfx::ColorSpace::RangeID::FULL ++ : gfx::ColorSpace::RangeID::LIMITED; ++ media::VideoColorSpace color_space(primaries, transfer, matrix, range); ++ if (color_space.IsSpecified()) { ++ return color_space.ToGfxColorSpace(); ++ } ++ // media::VideoColorSpace and gfx::ColorSpace do not support CICP ++ // MatrixCoefficients 12, 13, 14. ++ DCHECK_GE(matrix, 12); ++ DCHECK_LE(matrix, 14); ++ if (yuv_range == AVIF_RANGE_FULL) { ++ return gfx::ColorSpace::CreateJpeg(); ++ } ++ return gfx::ColorSpace::CreateREC709(); ++} ++ ++// Builds a gfx::ColorSpace from the ITU-T H.273 (CICP) color description in the ++// image. ++gfx::ColorSpace GetColorSpace(const avifImage* image) { ++ const bool grayscale = image->yuvFormat == AVIF_PIXEL_FORMAT_YUV400; ++ return GetColorSpace(image->colorPrimaries, image->transferCharacteristics, ++ image->matrixCoefficients, image->yuvRange, grayscale); ++} ++ ++// |y_size| is the width or height of the Y plane. Returns the width or height ++// of the U and V planes. |chroma_shift| represents the subsampling of the ++// chroma (U and V) planes in the x (for width) or y (for height) direction. ++int UVSize(int y_size, int chroma_shift) { ++ DCHECK(chroma_shift == 0 || chroma_shift == 1); ++ return (y_size + chroma_shift) >> chroma_shift; ++} ++ ++float FractionToFloat(auto numerator, uint32_t denominator) { ++ // First cast to double and not float because uint32_t->float conversion can ++ // cause precision loss. ++ return static_cast(numerator) / denominator; ++} ++ ++// If the image has a gain map, returns the alternate image's color space, if ++// it's different from the base image's and can be converted to a SkColorSpace. ++// If the alternate image color space is the same as the base image, there is no ++// need to specify it in SkGainmapInfo, and using the base image's color space ++// may be more accurate if the profile cannot be exactly represented as a ++// SkColorSpace object. ++sk_sp GetAltImageColorSpace(const avifImage& image) { ++ const avifGainMap* gain_map = image.gainMap; ++ if (!gain_map) { ++ return nullptr; ++ } ++ sk_sp color_space; ++ if (gain_map->altICC.size) { ++ if (image.icc.size == gain_map->altICC.size && ++ memcmp(gain_map->altICC.data, image.icc.data, gain_map->altICC.size) == ++ 0) { ++ // Same ICC as the base image, no need to specify it. ++ return nullptr; ++ } ++ std::unique_ptr profile = ColorProfile::Create( ++ base::span(gain_map->altICC.data, gain_map->altICC.size)); ++ if (!profile) { ++ DVLOG(1) << "Failed to parse gain map ICC profile"; ++ return nullptr; ++ } ++ const skcms_ICCProfile* icc_profile = profile->GetProfile(); ++ if (icc_profile->has_CICP) { ++ color_space = ++ skia::CICPGetSkColorSpace(icc_profile->CICP.color_primaries, ++ icc_profile->CICP.transfer_characteristics, ++ icc_profile->CICP.matrix_coefficients, ++ icc_profile->CICP.video_full_range_flag, ++ /*prefer_srgb_trfn=*/true); ++ } else if (icc_profile->has_toXYZD50) { ++ // The transfer function is irrelevant for gain map tone mapping, ++ // set it to something standard in case it's not set or not ++ // supported. ++ skcms_ICCProfile with_srgb = *icc_profile; ++ skcms_SetTransferFunction(&with_srgb, skcms_sRGB_TransferFunction()); ++ color_space = SkColorSpace::Make(with_srgb); ++ } ++ } else if (gain_map->altColorPrimaries != AVIF_COLOR_PRIMARIES_UNSPECIFIED) { ++ if (image.icc.size == 0 && ++ image.colorPrimaries == gain_map->altColorPrimaries) { ++ // Same as base image, no need to specify it. ++ return nullptr; ++ } ++ const bool grayscale = (gain_map->altPlaneCount == 1); ++ const gfx::ColorSpace alt_color_space = GetColorSpace( ++ gain_map->altColorPrimaries, gain_map->altTransferCharacteristics, ++ gain_map->altMatrixCoefficients, gain_map->altYUVRange, grayscale); ++ color_space = alt_color_space.GetAsFullRangeRGB().ToSkColorSpace(); ++ } ++ ++ if (!color_space) { ++ DVLOG(1) << "Gain map image contains an unsupported color space"; ++ } ++ ++ return color_space; ++} ++ ++} // namespace ++ ++AVIFImageDecoder::AVIFImageDecoder(AlphaOption alpha_option, ++ HighBitDepthDecodingOption hbd_option, ++ ColorBehavior color_behavior, ++ cc::AuxImage aux_image, ++ wtf_size_t max_decoded_bytes, ++ AnimationOption animation_option) ++ : ImageDecoder(alpha_option, ++ hbd_option, ++ color_behavior, ++ aux_image, ++ max_decoded_bytes), ++ animation_option_(animation_option) {} ++ ++AVIFImageDecoder::~AVIFImageDecoder() = default; ++ ++String AVIFImageDecoder::FilenameExtension() const { ++ return "avif"; ++} ++ ++const AtomicString& AVIFImageDecoder::MimeType() const { ++ DEFINE_STATIC_LOCAL(const AtomicString, avif_mime_type, ("image/avif")); ++ return avif_mime_type; ++} ++ ++bool AVIFImageDecoder::ImageIsHighBitDepth() { ++ return bit_depth_ > 8; ++} ++ ++void AVIFImageDecoder::OnSetData(scoped_refptr data) { ++ have_parsed_current_data_ = false; ++ const bool all_data_received = IsAllDataReceived(); ++ avif_io_data_.reader = data_; ++ avif_io_data_.all_data_received = all_data_received; ++ avif_io_.sizeHint = all_data_received ? data_->size() : kMaxAvifFileSize; ++ ++ // ImageFrameGenerator::GetYUVAInfo() and ImageFrameGenerator::DecodeToYUV() ++ // assume that allow_decode_to_yuv_ and other image metadata are available ++ // after calling ImageDecoder::Create() with data_complete=true. ++ if (all_data_received) { ++ ParseMetadata(); ++ } ++} ++ ++cc::YUVSubsampling AVIFImageDecoder::GetYUVSubsampling() const { ++ switch (avif_yuv_format_) { ++ case AVIF_PIXEL_FORMAT_YUV420: ++ return cc::YUVSubsampling::k420; ++ case AVIF_PIXEL_FORMAT_YUV422: ++ return cc::YUVSubsampling::k422; ++ case AVIF_PIXEL_FORMAT_YUV444: ++ return cc::YUVSubsampling::k444; ++ case AVIF_PIXEL_FORMAT_YUV400: ++ return cc::YUVSubsampling::kUnknown; ++ case AVIF_PIXEL_FORMAT_NONE: ++ // avif_yuv_format_ is initialized to AVIF_PIXEL_FORMAT_NONE in the ++ // constructor. If we have called SetSize() successfully at the end ++ // of UpdateDemuxer(), avif_yuv_format_ cannot possibly be ++ // AVIF_PIXEL_FORMAT_NONE. ++ CHECK(!IsDecodedSizeAvailable()); ++ return cc::YUVSubsampling::kUnknown; ++ default: ++ break; ++ } ++ NOTREACHED() << "Invalid YUV format: " << avif_yuv_format_; ++} ++ ++gfx::Size AVIFImageDecoder::DecodedYUVSize(cc::YUVIndex index) const { ++ DCHECK(IsDecodedSizeAvailable()); ++ if (index == cc::YUVIndex::kU || index == cc::YUVIndex::kV) { ++ return gfx::Size(UVSize(Size().width(), chroma_shift_x_), ++ UVSize(Size().height(), chroma_shift_y_)); ++ } ++ return Size(); ++} ++ ++wtf_size_t AVIFImageDecoder::DecodedYUVWidthBytes(cc::YUVIndex index) const { ++ DCHECK(IsDecodedSizeAvailable()); ++ // Try to return the same width bytes as used by the dav1d library. This will ++ // allow DecodeToYUV() to copy each plane with a single memcpy() call. ++ // ++ // The comments for Dav1dPicAllocator in dav1d/picture.h require the pixel ++ // width be padded to a multiple of 128 pixels. ++ wtf_size_t aligned_width = static_cast( ++ base::bits::AlignUpDeprecatedDoNotUse(Size().width(), 128)); ++ if (index == cc::YUVIndex::kU || index == cc::YUVIndex::kV) { ++ aligned_width >>= chroma_shift_x_; ++ } ++ // When the stride is a multiple of 1024, dav1d_default_picture_alloc() ++ // slightly pads the stride to avoid a reduction in cache hit rate in most ++ // L1/L2 cache implementations. Match that trick here. (Note that this padding ++ // is not documented in dav1d/picture.h.) ++ if ((aligned_width & 1023) == 0) { ++ aligned_width += 64; ++ } ++ ++ // High bit depth YUV is stored as a uint16_t, double the number of bytes. ++ if (bit_depth_ > 8) { ++ DCHECK_LE(bit_depth_, 16); ++ aligned_width *= 2; ++ } ++ ++ return aligned_width; ++} ++ ++SkYUVColorSpace AVIFImageDecoder::GetYUVColorSpace() const { ++ DCHECK(CanDecodeToYUV()); ++ DCHECK_NE(yuv_color_space_, SkYUVColorSpace::kIdentity_SkYUVColorSpace); ++ return yuv_color_space_; ++} ++ ++uint8_t AVIFImageDecoder::GetYUVBitDepth() const { ++ DCHECK(CanDecodeToYUV()); ++ return bit_depth_; ++} ++ ++std::optional AVIFImageDecoder::GetHDRMetadata() const { ++ return hdr_metadata_; ++} ++ ++void AVIFImageDecoder::DecodeToYUV() { ++ DCHECK(image_planes_); ++ DCHECK(CanDecodeToYUV()); ++ ++ if (Failed()) { ++ return; ++ } ++ ++ DCHECK(decoder_); ++ DCHECK_EQ(decoded_frame_count_, 1u); // Not animation. ++ ++ // If the image is decoded progressively, just render the highest progressive ++ // frame in image_planes_ because the callers of DecodeToYUV() assume that a ++ // complete scan will not be updated. ++ const int frame_index = progressive_ ? (decoder_->imageCount - 1) : 0; ++ // TODO(crbug.com/943519): Implement YUV incremental decoding as in Decode(). ++ decoder_->allowIncremental = AVIF_FALSE; ++ ++ // libavif cannot decode to an external buffer. So we need to copy from ++ // libavif's internal buffer to |image_planes_|. ++ // TODO(crbug.com/1099825): Enhance libavif to decode to an external buffer. ++ auto ret = DecodeImage(frame_index); ++ if (ret != AVIF_RESULT_OK) { ++ if (ret != AVIF_RESULT_WAITING_ON_IO) { ++ SetFailed(); ++ } ++ return; ++ } ++ const avifImage* image = decoded_image_; ++ ++ DCHECK(!image->alphaPlane); ++ static_assert(cc::YUVIndex::kY == static_cast(AVIF_CHAN_Y), ""); ++ static_assert(cc::YUVIndex::kU == static_cast(AVIF_CHAN_U), ""); ++ static_assert(cc::YUVIndex::kV == static_cast(AVIF_CHAN_V), ""); ++ ++ // Disable subnormal floats which can occur when converting to half float. ++ std::unique_ptr disable_subnormals; ++ const bool is_f16 = image_planes_->color_type() == kA16_float_SkColorType; ++ if (is_f16) { ++ disable_subnormals = std::make_unique(); ++ } ++ const float kHighBitDepthMultiplier = ++ (is_f16 ? 1.0f : 65535.0f) / ((1 << bit_depth_) - 1); ++ ++ // Initialize |width| and |height| to the width and height of the luma plane. ++ uint32_t width = image->width; ++ uint32_t height = image->height; ++ ++ for (wtf_size_t plane_index = 0; plane_index < cc::kNumYUVPlanes; ++ ++plane_index) { ++ const cc::YUVIndex plane = static_cast(plane_index); ++ const wtf_size_t src_row_bytes = ++ base::strict_cast(image->yuvRowBytes[plane_index]); ++ const wtf_size_t dst_row_bytes = image_planes_->RowBytes(plane); ++ ++ if (bit_depth_ == 8) { ++ DCHECK_EQ(image_planes_->color_type(), kGray_8_SkColorType); ++ const uint8_t* src = image->yuvPlanes[plane_index]; ++ uint8_t* dst = static_cast(image_planes_->Plane(plane)); ++ libyuv::CopyPlane(src, src_row_bytes, dst, dst_row_bytes, width, height); ++ } else { ++ DCHECK_GT(bit_depth_, 8u); ++ DCHECK_LE(bit_depth_, 16u); ++ const uint16_t* src = ++ reinterpret_cast(image->yuvPlanes[plane_index]); ++ uint16_t* dst = static_cast(image_planes_->Plane(plane)); ++ if (image_planes_->color_type() == kA16_unorm_SkColorType) { ++ const wtf_size_t src_stride = src_row_bytes / 2; ++ const wtf_size_t dst_stride = dst_row_bytes / 2; ++ for (uint32_t j = 0; j < height; ++j) { ++ for (uint32_t i = 0; i < width; ++i) { ++ dst[j * dst_stride + i] = ++ src[j * src_stride + i] * kHighBitDepthMultiplier + 0.5f; ++ } ++ } ++ } else if (image_planes_->color_type() == kA16_float_SkColorType) { ++ // Note: Unlike CopyPlane_16, HalfFloatPlane wants the stride in bytes. ++ libyuv::HalfFloatPlane(src, src_row_bytes, dst, dst_row_bytes, ++ kHighBitDepthMultiplier, width, height); ++ } else { ++ NOTREACHED() << "Unsupported color type: " ++ << static_cast(image_planes_->color_type()); ++ } ++ } ++ if (plane == cc::YUVIndex::kY) { ++ // Having processed the luma plane, change |width| and |height| to the ++ // width and height of the chroma planes. ++ width = UVSize(width, chroma_shift_x_); ++ height = UVSize(height, chroma_shift_y_); ++ } ++ } ++ image_planes_->SetHasCompleteScan(); ++} ++ ++int AVIFImageDecoder::RepetitionCount() const { ++ if (decoded_frame_count_ > 1) { ++ switch (decoder_->repetitionCount) { ++ case AVIF_REPETITION_COUNT_INFINITE: ++ return kAnimationLoopInfinite; ++ case AVIF_REPETITION_COUNT_UNKNOWN: ++ // The AVIF file does not have repetitions specified using an EditList ++ // box. Loop infinitely for backward compatibility with older versions ++ // of Chrome. ++ return kAnimationLoopInfinite; ++ default: ++ return decoder_->repetitionCount; ++ } ++ } ++ return kAnimationNone; ++} ++ ++bool AVIFImageDecoder::FrameIsReceivedAtIndex(wtf_size_t index) const { ++ if (!IsDecodedSizeAvailable()) { ++ return false; ++ } ++ if (decoded_frame_count_ == 1) { ++ return ImageDecoder::FrameIsReceivedAtIndex(index); ++ } ++ if (index >= frame_buffer_cache_.size()) { ++ return false; ++ } ++ if (IsAllDataReceived()) { ++ return true; ++ } ++ avifExtent data_extent; ++ if (avifDecoderNthImageMaxExtent(decoder_.get(), index, &data_extent) != ++ AVIF_RESULT_OK) { ++ return false; ++ } ++ return data_extent.size == 0 || ++ data_extent.offset + data_extent.size <= data_->size(); ++} ++ ++std::optional AVIFImageDecoder::FrameTimestampAtIndex( ++ wtf_size_t index) const { ++ return index < frame_buffer_cache_.size() ++ ? frame_buffer_cache_[index].Timestamp() ++ : std::nullopt; ++} ++ ++base::TimeDelta AVIFImageDecoder::FrameDurationAtIndex(wtf_size_t index) const { ++ return index < frame_buffer_cache_.size() ++ ? frame_buffer_cache_[index].Duration() ++ : base::TimeDelta(); ++} ++ ++bool AVIFImageDecoder::ImageHasBothStillAndAnimatedSubImages() const { ++ // Per MIAF, all animated AVIF files must have a still image, even if it's ++ // just a pointer to the first frame of the animation. ++ return decoder_ && decoder_->imageSequenceTrackPresent; ++} ++ ++// static ++bool AVIFImageDecoder::MatchesAVIFSignature( ++ const FastSharedBufferReader& fast_reader) { ++ // avifPeekCompatibleFileType() clamps compatible brands at 32 when reading in ++ // the ftyp box in ISO BMFF for the 'avif' or 'avis' brand. So the maximum ++ // number of bytes read is 144 bytes (size 4 bytes, type 4 bytes, major brand ++ // 4 bytes, minor version 4 bytes, and 4 bytes * 32 compatible brands). ++ char buffer[144]; ++ avifROData input; ++ input.size = std::min(sizeof(buffer), fast_reader.size()); ++ input.data = reinterpret_cast( ++ fast_reader.GetConsecutiveData(0, input.size, buffer)); ++ return avifPeekCompatibleFileType(&input); ++} ++ ++gfx::ColorSpace AVIFImageDecoder::GetColorSpaceForTesting() const { ++ const auto* image = GetDecoderImage(); ++ CHECK(image); ++ return GetColorSpace(image); ++} ++ ++void AVIFImageDecoder::ParseMetadata() { ++ if (!UpdateDemuxer()) { ++ SetFailed(); ++ } ++} ++ ++void AVIFImageDecoder::DecodeSize() { ++ ParseMetadata(); ++} ++ ++wtf_size_t AVIFImageDecoder::DecodeFrameCount() { ++ if (!Failed()) { ++ ParseMetadata(); ++ } ++ return IsDecodedSizeAvailable() ? decoded_frame_count_ ++ : frame_buffer_cache_.size(); ++} ++ ++void AVIFImageDecoder::InitializeNewFrame(wtf_size_t index) { ++ auto& buffer = frame_buffer_cache_[index]; ++ if (decode_to_half_float_) { ++ buffer.SetPixelFormat(ImageFrame::PixelFormat::kRGBA_F16); ++ } ++ ++ // For AVIFs, the frame always fills the entire image. ++ buffer.SetOriginalFrameRect(gfx::Rect(Size())); ++ ++ avifImageTiming timing; ++ auto ret = avifDecoderNthImageTiming(decoder_.get(), index, &timing); ++ DCHECK_EQ(ret, AVIF_RESULT_OK); ++ buffer.SetTimestamp(base::Seconds(timing.pts)); ++ buffer.SetDuration(base::Seconds(timing.duration)); ++} ++ ++void AVIFImageDecoder::Decode(wtf_size_t index) { ++ if (Failed()) { ++ return; ++ } ++ ++ UpdateAggressivePurging(index); ++ ++ int frame_index = index; ++ // If the image is decoded progressively, find the highest progressive ++ // frame that we have received and decode from that frame index. Internally ++ // decoder_ still decodes the lower progressive frames, but they are only used ++ // as reference frames and not rendered. ++ if (progressive_) { ++ DCHECK_EQ(index, 0u); ++ // decoder_->imageIndex is the current image index. decoder_->imageIndex is ++ // initialized to -1. decoder_->imageIndex + 1 is the next image index. ++ DCHECK_LT(decoder_->imageIndex + 1, decoder_->imageCount); ++ for (frame_index = decoder_->imageIndex + 1; ++ frame_index + 1 < decoder_->imageCount; ++frame_index) { ++ avifExtent data_extent; ++ auto rv = avifDecoderNthImageMaxExtent(decoder_.get(), frame_index + 1, ++ &data_extent); ++ if (rv != AVIF_RESULT_OK) { ++ DVLOG(1) << "avifDecoderNthImageMaxExtent(" << frame_index + 1 ++ << ") failed: " << avifResultToString(rv) << ": " ++ << AvifDecoderErrorMessage(decoder_.get()); ++ SetFailed(); ++ return; ++ } ++ if (data_extent.size != 0 && ++ data_extent.offset + data_extent.size > data_->size()) { ++ break; ++ } ++ } ++ } ++ ++ // Allow AVIF frames to be partially decoded before all data is received. ++ // Only enabled for non-progressive still images because animations look ++ // better without incremental decoding and because progressive decoding makes ++ // incremental decoding unnecessary. ++ decoder_->allowIncremental = (decoder_->imageCount == 1); ++ ++ auto ret = DecodeImage(frame_index); ++ if (ret != AVIF_RESULT_OK && ret != AVIF_RESULT_WAITING_ON_IO) { ++ SetFailed(); ++ return; ++ } ++ const avifImage* image = decoded_image_; ++ ++ // ImageDecoder::SizeCalculationMayOverflow(), called by UpdateDemuxer() ++ // before being here, made sure the image height fits in an int. ++ int displayable_height = ++ static_cast(avifDecoderDecodedRowCount(decoder_.get())); ++ if (image == cropped_image_.get()) { ++ displayable_height -= clap_origin_.y(); ++ displayable_height = ++ std::clamp(displayable_height, 0, static_cast(image->height)); ++ } ++ ++ if (displayable_height == 0) { ++ return; // There is nothing to display. ++ } ++ ++ ImageFrame& buffer = frame_buffer_cache_[index]; ++ DCHECK_NE(buffer.GetStatus(), ImageFrame::kFrameComplete); ++ ++ if (buffer.GetStatus() == ImageFrame::kFrameEmpty) { ++ if (!InitFrameBuffer(index)) { ++ DVLOG(1) << "Failed to create frame buffer..."; ++ SetFailed(); ++ return; ++ } ++ DCHECK_EQ(buffer.GetStatus(), ImageFrame::kFramePartial); ++ // The buffer is transparent outside the decoded area while the image is ++ // loading. The correct alpha value for the frame will be set when it is ++ // fully decoded. ++ buffer.SetHasAlpha(true); ++ if (decoder_->allowIncremental) { ++ // In case of buffer disposal after decoding. ++ incrementally_displayed_height_ = 0; ++ } ++ } ++ ++ const int last_displayed_height = ++ decoder_->allowIncremental ? incrementally_displayed_height_ : 0; ++ if (displayable_height == last_displayed_height) { ++ return; // There is no new row to display. ++ } ++ DCHECK_GT(displayable_height, last_displayed_height); ++ ++ // Only render the newly decoded rows. ++ if (!RenderImage(image, last_displayed_height, &displayable_height, ++ &buffer)) { ++ SetFailed(); ++ return; ++ } ++ if (displayable_height == last_displayed_height) { ++ return; // There is no new row to display. ++ } ++ DCHECK_GT(displayable_height, last_displayed_height); ++ ColorCorrectImage(last_displayed_height, displayable_height, &buffer); ++ buffer.SetPixelsChanged(true); ++ if (decoder_->allowIncremental) { ++ incrementally_displayed_height_ = displayable_height; ++ } ++ ++ if (static_cast(displayable_height) == image->height && ++ (!progressive_ || frame_index + 1 == decoder_->imageCount)) { ++ buffer.SetHasAlpha(!!image->alphaPlane); ++ buffer.SetStatus(ImageFrame::kFrameComplete); ++ PostDecodeProcessing(index); ++ } ++} ++ ++bool AVIFImageDecoder::CanReusePreviousFrameBuffer(wtf_size_t index) const { ++ // (a) Technically we can reuse the bitmap of the previous frame because the ++ // AVIF decoder handles frame dependence internally and we never need to ++ // preserve previous frames to decode later ones, and (b) since this function ++ // will not currently be called, this is really more for the reader than any ++ // functional purpose. ++ return true; ++} ++ ++// static ++avifResult AVIFImageDecoder::ReadFromSegmentReader(avifIO* io, ++ uint32_t read_flags, ++ uint64_t offset, ++ size_t size, ++ avifROData* out) { ++ if (read_flags != 0) { ++ // Unsupported read_flags ++ return AVIF_RESULT_IO_ERROR; ++ } ++ ++ AvifIOData* io_data = static_cast(io->data); ++ ++ // Sanitize/clamp incoming request ++ if (offset > io_data->reader->size()) { ++ // The offset is past the end of the buffer or available data. ++ return io_data->all_data_received ? AVIF_RESULT_IO_ERROR ++ : AVIF_RESULT_WAITING_ON_IO; ++ } ++ ++ // It is more convenient to work with a variable of the size_t type. Since ++ // offset <= io_data->reader->size() <= SIZE_MAX, this cast is safe. ++ size_t position = static_cast(offset); ++ const size_t available_size = io_data->reader->size() - position; ++ if (size > available_size) { ++ if (!io_data->all_data_received) { ++ return AVIF_RESULT_WAITING_ON_IO; ++ } ++ size = available_size; ++ } ++ ++ out->size = size; ++ ++ base::span data = io_data->reader->GetSomeData(position); ++ if (data.size() >= size) { ++ out->data = data.data(); ++ return AVIF_RESULT_OK; ++ } ++ ++ io_data->buffer.clear(); ++ io_data->buffer.reserve(size); ++ ++ while (size != 0) { ++ data = io_data->reader->GetSomeData(position); ++ size_t copy_size = std::min(data.size(), size); ++ io_data->buffer.insert(io_data->buffer.end(), data.begin(), data.end()); ++ position += copy_size; ++ size -= copy_size; ++ } ++ ++ out->data = io_data->buffer.data(); ++ return AVIF_RESULT_OK; ++} ++ ++bool AVIFImageDecoder::UpdateDemuxer() { ++ DCHECK(!Failed()); ++ if (IsDecodedSizeAvailable()) { ++ return true; ++ } ++ ++ if (have_parsed_current_data_) { ++ return true; ++ } ++ have_parsed_current_data_ = true; ++ ++ if (!decoder_) { ++ decoder_.reset(avifDecoderCreate()); ++ if (!decoder_) { ++ return false; ++ } ++ ++ // For simplicity, use a hardcoded maxThreads of 2, independent of the image ++ // size and processor count. Note: even if we want maxThreads to depend on ++ // the image size, it is impossible to do so because maxThreads is passed to ++ // dav1d_open() inside avifDecoderParse(), but the image size is not known ++ // until avifDecoderParse() returns successfully. See ++ // https://github.com/AOMediaCodec/libavif/issues/636. ++ decoder_->maxThreads = 2; ++ ++ if (animation_option_ != AnimationOption::kUnspecified && ++ avifDecoderSetSource( ++ decoder_.get(), ++ animation_option_ == AnimationOption::kPreferAnimation ++ ? AVIF_DECODER_SOURCE_TRACKS ++ : AVIF_DECODER_SOURCE_PRIMARY_ITEM) != AVIF_RESULT_OK) { ++ return false; ++ } ++ ++ // Chrome doesn't use XMP and Exif metadata. Ignoring XMP and Exif will ++ // ensure avifDecoderParse() isn't waiting for some tiny Exif payload hiding ++ // at the end of a file. ++ decoder_->ignoreXMP = AVIF_TRUE; ++ decoder_->ignoreExif = AVIF_TRUE; ++ ++ // Turn off libavif's 'clap' (clean aperture) property validation. We ++ // validate 'clap' ourselves and ignore invalid 'clap' properties. ++ decoder_->strictFlags &= ~AVIF_STRICT_CLAP_VALID; ++ // Allow the PixelInformationProperty ('pixi') to be missing in AV1 image ++ // items. libheif v1.11.0 or older does not add the 'pixi' item property to ++ // AV1 image items. (This issue has been corrected in libheif v1.12.0.) See ++ // crbug.com/1198455. ++ decoder_->strictFlags &= ~AVIF_STRICT_PIXI_REQUIRED; ++ ++ if (base::FeatureList::IsEnabled(features::kAvifGainmapHdrImages) && ++ aux_image_ == cc::AuxImage::kGainmap) { ++ decoder_->imageContentToDecode = AVIF_IMAGE_CONTENT_GAIN_MAP; ++ } ++ ++ avif_io_.destroy = nullptr; ++ avif_io_.read = ReadFromSegmentReader; ++ avif_io_.write = nullptr; ++ avif_io_.persistent = AVIF_FALSE; ++ avif_io_.data = &avif_io_data_; ++ avifDecoderSetIO(decoder_.get(), &avif_io_); ++ } ++ ++ // If all data is received, there is no point in decoding progressively. ++ decoder_->allowProgressive = !IsAllDataReceived(); ++ ++ auto ret = avifDecoderParse(decoder_.get()); ++ if (ret == AVIF_RESULT_WAITING_ON_IO) { ++ return true; ++ } ++ if (ret != AVIF_RESULT_OK) { ++ DVLOG(1) << "avifDecoderParse failed: " << avifResultToString(ret) << ". " ++ << decoder_->diag.error; ++ return false; ++ } ++ ++ // Image metadata is available in decoder_->image after avifDecoderParse() ++ // even though decoder_->imageIndex is invalid (-1). ++ DCHECK_EQ(decoder_->imageIndex, -1); ++ // This variable is named |container| to emphasize the fact that the current ++ // contents of decoder_->image come from the container, not any frame. ++ const auto* container = GetDecoderImage(); ++ if (!container) { ++ return false; ++ } ++ ++ // The container width and container height are read from either the tkhd ++ // (track header) box of a track or the ispe (image spatial extents) property ++ // of an image item, both of which are mandatory in the spec. ++ if (container->width == 0 || container->height == 0) { ++ DVLOG(1) << "Container width and height must be present"; ++ return false; ++ } ++ ++ // The container depth is read from either the av1C box of a track or the av1C ++ // property of an image item, both of which are mandatory in the spec. ++ if (container->depth == 0) { ++ DVLOG(1) << "Container depth must be present"; ++ return false; ++ } ++ ++ DCHECK_GT(decoder_->imageCount, 0); ++ progressive_ = decoder_->progressiveState == AVIF_PROGRESSIVE_STATE_ACTIVE; ++ // If the image is progressive, decoder_->imageCount is the number of ++ // progressive frames, but there is only one still image. ++ decoded_frame_count_ = progressive_ ? 1 : decoder_->imageCount; ++ container_width_ = container->width; ++ container_height_ = container->height; ++ bit_depth_ = container->depth; ++ decode_to_half_float_ = ++ ImageIsHighBitDepth() && ++ high_bit_depth_decoding_option_ == kHighBitDepthToHalfFloat; ++ ++ // Verify that AVIF_PIXEL_FORMAT_{YUV444,YUV422,YUV420,YUV400} are ++ // consecutive. ++ static_assert(AVIF_PIXEL_FORMAT_YUV422 == AVIF_PIXEL_FORMAT_YUV444 + 1); ++ static_assert(AVIF_PIXEL_FORMAT_YUV420 == AVIF_PIXEL_FORMAT_YUV422 + 1); ++ static_assert(AVIF_PIXEL_FORMAT_YUV400 == AVIF_PIXEL_FORMAT_YUV420 + 1); ++ // Assert that after avifDecoderParse() returns AVIF_RESULT_OK, ++ // decoder_->image->yuvFormat (the same as container->yuvFormat) is one of the ++ // four YUV formats in AV1. ++ CHECK(container->yuvFormat >= AVIF_PIXEL_FORMAT_YUV444 && ++ container->yuvFormat <= AVIF_PIXEL_FORMAT_YUV400) ++ << "Invalid YUV format: " << container->yuvFormat; ++ avif_yuv_format_ = container->yuvFormat; ++ avifPixelFormatInfo format_info; ++ avifGetPixelFormatInfo(container->yuvFormat, &format_info); ++ chroma_shift_x_ = format_info.chromaShiftX; ++ chroma_shift_y_ = format_info.chromaShiftY; ++ ++ if (container->clli.maxCLL || container->clli.maxPALL) { ++ hdr_metadata_ = gfx::HDRMetadata(); ++ hdr_metadata_->cta_861_3 = gfx::HdrMetadataCta861_3( ++ container->clli.maxCLL, container->clli.maxPALL); ++ } ++ ++ // SetEmbeddedColorProfile() must be called before IsSizeAvailable() becomes ++ // true. So call SetEmbeddedColorProfile() before calling SetSize(). The color ++ // profile is either an ICC profile or the CICP color description. ++ ++ if (!IgnoresColorSpace()) { ++ // The CICP color description is always present because we can always get it ++ // from the AV1 sequence header for the frames. If an ICC profile is ++ // present, use it instead of the CICP color description. ++ if (container->icc.size) { ++ std::unique_ptr profile = ColorProfile::Create( ++ base::span(container->icc.data, container->icc.size)); ++ if (!profile) { ++ DVLOG(1) << "Failed to parse image ICC profile"; ++ return false; ++ } ++ uint32_t data_color_space = profile->GetProfile()->data_color_space; ++ const bool is_mono = container->yuvFormat == AVIF_PIXEL_FORMAT_YUV400; ++ if (is_mono) { ++ if (data_color_space != skcms_Signature_Gray && ++ data_color_space != skcms_Signature_RGB) { ++ profile = nullptr; ++ } ++ } else { ++ if (data_color_space != skcms_Signature_RGB) { ++ profile = nullptr; ++ } ++ } ++ if (!profile) { ++ DVLOG(1) ++ << "Image contains ICC profile that does not match its color space"; ++ return false; ++ } ++ SetEmbeddedColorProfile(std::move(profile)); ++ } else if (container->colorPrimaries != AVIF_COLOR_PRIMARIES_UNSPECIFIED || ++ container->transferCharacteristics != ++ AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED) { ++ gfx::ColorSpace frame_cs = GetColorSpace(container); ++ ++ sk_sp sk_color_space = ++ frame_cs.GetAsFullRangeRGB().ToSkColorSpace(); ++ if (!sk_color_space) { ++ DVLOG(1) << "Image contains an unsupported color space"; ++ return false; ++ } ++ ++ skcms_ICCProfile profile; ++ sk_color_space->toProfile(&profile); ++ SetEmbeddedColorProfile(std::make_unique(profile)); ++ } ++ } ++ ++ // |angle| * 90 specifies the angle of anti-clockwise rotation in degrees. ++ // Legal values: [0-3]. ++ int angle = 0; ++ if (container->transformFlags & AVIF_TRANSFORM_IROT) { ++ angle = container->irot.angle; ++ CHECK_LT(angle, 4); ++ } ++ // |axis| specifies how the mirroring is performed. ++ // -1: No mirroring. ++ // 0: The top and bottom parts of the image are exchanged. ++ // 1: The left and right parts of the image are exchanged. ++ int axis = -1; ++ if (container->transformFlags & AVIF_TRANSFORM_IMIR) { ++ axis = container->imir.axis; ++ CHECK_LT(axis, 2); ++ } ++ // MIAF Section 7.3.6.7 (Clean aperture, rotation and mirror) says: ++ // These properties, if used, shall be indicated to be applied in the ++ // following order: clean aperture first, then rotation, then mirror. ++ // ++ // In the kAxisAngleToOrientation array, the first dimension is axis (with an ++ // offset of 1). The second dimension is angle. ++ constexpr std::array, 3> ++ kAxisAngleToOrientation = {{ ++ // No mirroring. ++ {ImageOrientationEnum::kOriginTopLeft, ++ ImageOrientationEnum::kOriginLeftBottom, ++ ImageOrientationEnum::kOriginBottomRight, ++ ImageOrientationEnum::kOriginRightTop}, ++ // Top-to-bottom mirroring. Change Top<->Bottom in the first row. ++ {ImageOrientationEnum::kOriginBottomLeft, ++ ImageOrientationEnum::kOriginLeftTop, ++ ImageOrientationEnum::kOriginTopRight, ++ ImageOrientationEnum::kOriginRightBottom}, ++ // Left-to-right mirroring. Change Left<->Right in the first row. ++ {ImageOrientationEnum::kOriginTopRight, ++ ImageOrientationEnum::kOriginRightBottom, ++ ImageOrientationEnum::kOriginBottomLeft, ++ ImageOrientationEnum::kOriginLeftTop}, ++ }}; ++ orientation_ = kAxisAngleToOrientation[axis + 1][angle]; ++ ++ // Determine whether the image can be decoded to YUV. ++ // * Alpha channel is not supported. ++ // * Multi-frame images (animations) are not supported. (The DecodeToYUV() ++ // method does not have an 'index' parameter.) ++ allow_decode_to_yuv_ = ++ avif_yuv_format_ != AVIF_PIXEL_FORMAT_YUV400 && !decoder_->alphaPresent && ++ decoded_frame_count_ == 1 && ++ GetColorSpace(container).ToSkYUVColorSpace(container->depth, ++ &yuv_color_space_) && ++ // TODO(crbug.com/911246): Support color space transforms for YUV decodes. ++ !ColorTransform(); ++ ++ // Record bpp information only for 8-bit, color, still images that do not have ++ // alpha. ++ if (container->depth == 8 && avif_yuv_format_ != AVIF_PIXEL_FORMAT_YUV400 && ++ !decoder_->alphaPresent && decoded_frame_count_ == 1) { ++ static constexpr char kType[] = "Avif"; ++ update_bpp_histogram_callback_ = base::BindOnce(&UpdateBppHistogram); ++ } ++ ++ unsigned width = container->width; ++ unsigned height = container->height; ++ // If the image is cropped, pass the size of the cropped image (the clean ++ // aperture) to SetSize(). ++ if (container->transformFlags & AVIF_TRANSFORM_CLAP) { ++ AVIFCleanApertureType clap_type; ++ avifCropRect crop_rect; ++ avifDiagnostics diag; ++ avifBool valid_clap = avifCropRectConvertCleanApertureBox( ++ &crop_rect, &container->clap, container->width, container->height, ++ container->yuvFormat, &diag); ++ if (!valid_clap) { ++ DVLOG(1) << "Invalid 'clap' property: " << diag.error ++ << "; showing the full image."; ++ clap_type = AVIFCleanApertureType::kInvalid; ++ ignore_clap_ = true; ++ } else if (crop_rect.x != 0 || crop_rect.y != 0) { ++ // To help discourage the creation of files with privacy risks, also ++ // consider 'clap' properties whose origins are not at (0, 0) as invalid. ++ // See https://github.com/AOMediaCodec/av1-avif/issues/188 and ++ // https://github.com/AOMediaCodec/av1-avif/issues/189. ++ DVLOG(1) << "Origin of 'clap' property anchored to (" << crop_rect.x ++ << ", " << crop_rect.y << "); showing the full image."; ++ clap_type = AVIFCleanApertureType::kNonzeroOrigin; ++ ignore_clap_ = true; ++ } else { ++ clap_type = AVIFCleanApertureType::kZeroOrigin; ++ clap_origin_.SetPoint(crop_rect.x, crop_rect.y); ++ width = crop_rect.width; ++ height = crop_rect.height; ++ } ++ clap_type_ = clap_type; ++ } ++ return SetSize(width, height); ++} ++ ++avifResult AVIFImageDecoder::DecodeImage(wtf_size_t index) { ++ const auto ret = avifDecoderNthImage(decoder_.get(), index); ++ // |index| should be less than what DecodeFrameCount() returns, so we should ++ // not get the AVIF_RESULT_NO_IMAGES_REMAINING error. ++ DCHECK_NE(ret, AVIF_RESULT_NO_IMAGES_REMAINING); ++ if (ret != AVIF_RESULT_OK && ret != AVIF_RESULT_WAITING_ON_IO) { ++ DVLOG(1) << "avifDecoderNthImage(" << index ++ << ") failed: " << avifResultToString(ret) << ": " ++ << AvifDecoderErrorMessage(decoder_.get()); ++ return ret; ++ } ++ ++ const auto* image = GetDecoderImage(); ++ CHECK(image); ++ // Frame size must be equal to container size. ++ if (image->width != container_width_ || image->height != container_height_) { ++ DVLOG(1) << "Frame size " << image->width << "x" << image->height ++ << " differs from container size " << container_width_ << "x" ++ << container_height_; ++ return AVIF_RESULT_UNKNOWN_ERROR; ++ } ++ // Frame bit depth must be equal to container bit depth. ++ if (image->depth != bit_depth_) { ++ DVLOG(1) << "Frame bit depth must be equal to container bit depth"; ++ return AVIF_RESULT_UNKNOWN_ERROR; ++ } ++ // Frame YUV format must be equal to container YUV format. ++ if (image->yuvFormat != avif_yuv_format_) { ++ DVLOG(1) << "Frame YUV format must be equal to container YUV format"; ++ return AVIF_RESULT_UNKNOWN_ERROR; ++ } ++ ++ decoded_image_ = image; ++ if ((image->transformFlags & AVIF_TRANSFORM_CLAP) && !ignore_clap_) { ++ CropDecodedImage(); ++ } ++ ++ if (ret == AVIF_RESULT_OK) { ++ if (IsAllDataReceived() && update_bpp_histogram_callback_) { ++ std::move(update_bpp_histogram_callback_).Run(Size(), data_->size()); ++ } ++ ++ if (clap_type_.has_value()) { ++ base::UmaHistogramEnumeration("Blink.ImageDecoders.Avif.CleanAperture", ++ clap_type_.value()); ++ clap_type_.reset(); ++ } ++ } ++ return ret; ++} ++ ++void AVIFImageDecoder::CropDecodedImage() { ++ DCHECK_NE(decoded_image_, cropped_image_.get()); ++ if (!cropped_image_) { ++ cropped_image_.reset(avifImageCreateEmpty()); ++ } ++ avifCropRect rect; ++ rect.x = clap_origin_.x(); ++ rect.y = clap_origin_.y(); ++ rect.width = Size().width(); ++ rect.height = Size().height(); ++ const avifResult result = ++ avifImageSetViewRect(cropped_image_.get(), decoded_image_, &rect); ++ CHECK_EQ(result, AVIF_RESULT_OK); ++ decoded_image_ = cropped_image_.get(); ++} ++ ++bool AVIFImageDecoder::RenderImage(const avifImage* image, ++ int from_row, ++ int* to_row, ++ ImageFrame* buffer) { ++ DCHECK_LT(from_row, *to_row); ++ ++ // libavif uses libyuv for the YUV 4:2:0 to RGB upsampling and/or conversion ++ // as follows: ++ // - convert the top RGB row 0, ++ // - convert the RGB rows 1 and 2, then RGB rows 3 and 4 etc., ++ // - convert the bottom (odd) RGB row if there is an even number of RGB rows. ++ // ++ // Unfortunately this cannot be applied incrementally as is. The RGB values ++ // would differ because the first and last RGB rows have a formula using only ++ // one UV row, while the other RGB rows use two UV rows as input each. ++ // See https://crbug.com/libyuv/934. ++ // ++ // The workaround is a backup of the last converted even RGB row, called top ++ // row, located right before |from_row|. The conversion is then called ++ // starting at this top row, overwriting it with invalid values. The remaining ++ // pairs of rows are correctly aligned and their freshly converted values are ++ // valid. Then the backed up row is put back, fixing the issue. ++ // The bottom row is postponed if the other half of the pair it belongs to is ++ // not yet decoded. ++ // ++ // UV rows | Y/RGB rows ++ // | all | first decoding | second decoding ++ // ____ 0 ____ 0 (from_row) ++ // 0 ---- ____ 1 ____ 1 ++ // ____ 2 ____ 2 ____ 2 (backed up) ++ // 1 ---- ____ 3 ____ 3 (postponed) ____ 3 (from_row) ++ // ____ 4 4 (*to_row) ____ 4 ++ // 2 ---- ____ 5 ____ 5 ++ // 6 (*to_row) ++ ++ const bool use_libyuv_bilinear_upsampling = ++ !decode_to_half_float_ && image->yuvFormat == AVIF_PIXEL_FORMAT_YUV420; ++ const bool save_top_row = use_libyuv_bilinear_upsampling && from_row > 0; ++ const bool postpone_bottom_row = ++ use_libyuv_bilinear_upsampling && ++ static_cast(*to_row) < image->height; ++ if (postpone_bottom_row) { ++ // libavif outputs an even number of rows because 4:2:0 samples are decoded ++ // in pairs. ++ DCHECK(!(*to_row & 1)); ++ --*to_row; ++ if (from_row == *to_row) { ++ return true; // Nothing to do. ++ } ++ } ++ if (save_top_row) { ++ // |from_row| is odd because it is equal to the output value of |*to_row| ++ // from the previous RenderImage() call, and |*to_row| was even and then ++ // decremented at that time. ++ DCHECK(from_row & 1); ++ --from_row; ++ } ++ ++ // Focus |image| on rows [from_row, *to_row). ++ std::unique_ptr view( ++ nullptr, avifImageDestroy); ++ if (from_row > 0 || static_cast(*to_row) < image->height) { ++ const avifCropRect rect = {0, static_cast(from_row), image->width, ++ static_cast(*to_row - from_row)}; ++ view.reset(avifImageCreateEmpty()); ++ const avifResult result = avifImageSetViewRect(view.get(), image, &rect); ++ CHECK_EQ(result, AVIF_RESULT_OK); ++ image = view.get(); ++ } ++ ++ avifRGBImage rgb_image; ++ avifRGBImageSetDefaults(&rgb_image, image); ++ ++ if (decode_to_half_float_) { ++ rgb_image.depth = 16; ++ rgb_image.isFloat = AVIF_TRUE; ++ rgb_image.pixels = ++ reinterpret_cast(buffer->GetAddrF16(0, from_row)); ++ rgb_image.rowBytes = image->width * sizeof(uint64_t); ++ // When decoding to half float, the pixel ordering is always RGBA on all ++ // platforms. ++ rgb_image.format = AVIF_RGB_FORMAT_RGBA; ++ } else { ++ rgb_image.depth = 8; ++ rgb_image.pixels = reinterpret_cast(buffer->GetAddr(0, from_row)); ++ rgb_image.rowBytes = image->width * sizeof(uint32_t); ++ // When decoding to 8-bit, Android uses little-endian RGBA pixels. All other ++ // platforms use BGRA pixels. ++ static_assert(SK_B32_SHIFT == 16 - SK_R32_SHIFT); ++ static_assert(SK_G32_SHIFT == 8); ++ static_assert(SK_A32_SHIFT == 24); ++#if SK_B32_SHIFT ++ rgb_image.format = AVIF_RGB_FORMAT_RGBA; ++#else ++ rgb_image.format = AVIF_RGB_FORMAT_BGRA; ++#endif ++ } ++ rgb_image.alphaPremultiplied = buffer->PremultiplyAlpha(); ++ rgb_image.maxThreads = decoder_->maxThreads; ++ ++ if (save_top_row) { ++ previous_last_decoded_row_.resize(rgb_image.rowBytes); ++ memcpy(previous_last_decoded_row_.data(), rgb_image.pixels, ++ rgb_image.rowBytes); ++ } ++ const avifResult result = avifImageYUVToRGB(image, &rgb_image); ++ if (save_top_row) { ++ memcpy(rgb_image.pixels, previous_last_decoded_row_.data(), ++ rgb_image.rowBytes); ++ } ++ return result == AVIF_RESULT_OK; ++} ++ ++void AVIFImageDecoder::ColorCorrectImage(int from_row, ++ int to_row, ++ ImageFrame* buffer) { ++ // Postprocess the image data according to the profile. ++ const ColorProfileTransform* const transform = ColorTransform(); ++ if (!transform) { ++ return; ++ } ++ const auto alpha_format = (buffer->HasAlpha() && buffer->PremultiplyAlpha()) ++ ? skcms_AlphaFormat_PremulAsEncoded ++ : skcms_AlphaFormat_Unpremul; ++ if (decode_to_half_float_) { ++ const skcms_PixelFormat color_format = skcms_PixelFormat_RGBA_hhhh; ++ for (int y = from_row; y < to_row; ++y) { ++ ImageFrame::PixelDataF16* const row = buffer->GetAddrF16(0, y); ++ const bool success = skcms_Transform( ++ row, color_format, alpha_format, transform->SrcProfile(), row, ++ color_format, alpha_format, transform->DstProfile(), Size().width()); ++ DCHECK(success); ++ } ++ } else { ++ const skcms_PixelFormat color_format = XformColorFormat(); ++ for (int y = from_row; y < to_row; ++y) { ++ ImageFrame::PixelData* const row = buffer->GetAddr(0, y); ++ const bool success = skcms_Transform( ++ row, color_format, alpha_format, transform->SrcProfile(), row, ++ color_format, alpha_format, transform->DstProfile(), Size().width()); ++ DCHECK(success); ++ } ++ } ++} ++ ++bool AVIFImageDecoder::GetGainmapInfoAndData( ++ SkGainmapInfo& out_gainmap_info, ++ scoped_refptr& out_gainmap_data) const { ++ if (!base::FeatureList::IsEnabled(features::kAvifGainmapHdrImages)) { ++ return false; ++ } ++ // Ensure that parsing succeeded. ++ if (!IsDecodedSizeAvailable()) { ++ return false; ++ } ++ if (!decoder_->image->gainMap) { ++ return false; ++ } ++ const avifGainMap& gain_map = *decoder_->image->gainMap; ++ if (gain_map.baseHdrHeadroom.d == 0 || gain_map.alternateHdrHeadroom.d == 0) { ++ DVLOG(1) << "Invalid gainmap metadata: a denominator value is zero"; ++ return false; ++ } ++ const float base_headroom = std::exp2( ++ FractionToFloat(gain_map.baseHdrHeadroom.n, gain_map.baseHdrHeadroom.d)); ++ const float alternate_headroom = std::exp2(FractionToFloat( ++ gain_map.alternateHdrHeadroom.n, gain_map.alternateHdrHeadroom.d)); ++ const bool base_is_hdr = base_headroom > alternate_headroom; ++ out_gainmap_info.fDisplayRatioSdr = ++ base_is_hdr ? alternate_headroom : base_headroom; ++ out_gainmap_info.fDisplayRatioHdr = ++ base_is_hdr ? base_headroom : alternate_headroom; ++ out_gainmap_info.fBaseImageType = base_is_hdr ++ ? SkGainmapInfo::BaseImageType::kHDR ++ : SkGainmapInfo::BaseImageType::kSDR; ++ if (!gain_map.useBaseColorSpace) { ++ // Try to use the alternate image's color space. ++ out_gainmap_info.fGainmapMathColorSpace = ++ GetAltImageColorSpace(*decoder_->image); ++ } ++ for (int i = 0; i < 3; ++i) { ++ if (gain_map.gainMapMin[i].d == 0 || gain_map.gainMapMax[i].d == 0 || ++ gain_map.gainMapGamma[i].d == 0 || gain_map.baseOffset[i].d == 0 || ++ gain_map.alternateOffset[i].d == 0) { ++ DVLOG(1) << "Invalid gainmap metadata: a denominator value is zero"; ++ return false; ++ } ++ if (gain_map.gainMapGamma[i].n == 0) { ++ DVLOG(1) << "Invalid gainmap metadata: gamma is zero"; ++ return false; ++ } ++ ++ const float min_log2 = ++ FractionToFloat(gain_map.gainMapMin[i].n, gain_map.gainMapMin[i].d); ++ const float max_log2 = ++ FractionToFloat(gain_map.gainMapMax[i].n, gain_map.gainMapMax[i].d); ++ out_gainmap_info.fGainmapRatioMin[i] = std::exp2(min_log2); ++ out_gainmap_info.fGainmapRatioMax[i] = std::exp2(max_log2); ++ ++ // Numerator and denominator intentionally swapped to get 1.0/gamma. ++ out_gainmap_info.fGainmapGamma[i] = ++ FractionToFloat(gain_map.gainMapGamma[i].d, gain_map.gainMapGamma[i].n); ++ const float base_offset = ++ FractionToFloat(gain_map.baseOffset[i].n, gain_map.baseOffset[i].d); ++ const float alternate_offset = FractionToFloat( ++ gain_map.alternateOffset[i].n, gain_map.alternateOffset[i].d); ++ out_gainmap_info.fEpsilonSdr[i] = ++ base_is_hdr ? alternate_offset : base_offset; ++ out_gainmap_info.fEpsilonHdr[i] = ++ base_is_hdr ? base_offset : alternate_offset; ++ } ++ out_gainmap_data = data_; ++ return true; ++} ++ ++avifImage* AVIFImageDecoder::GetDecoderImage() const { ++ if (aux_image_ == cc::AuxImage::kGainmap) { ++ if (!decoder_->image->gainMap) { ++ DVLOG(1) << "Attempted to access gain map image, but gainMap is nullptr"; ++ return nullptr; ++ } ++ return decoder_->image->gainMap->image; ++ } ++ return decoder_->image; ++} ++ ++AVIFImageDecoder::AvifIOData::AvifIOData() = default; ++AVIFImageDecoder::AvifIOData::AvifIOData( ++ scoped_refptr reader, ++ bool all_data_received) ++ : reader(std::move(reader)), all_data_received(all_data_received) {} ++AVIFImageDecoder::AvifIOData::~AvifIOData() = default; ++ ++} // namespace blink +diff --git a/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h b/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h +new file mode 100644 +index 0000000000000..75247663ef158 +--- /dev/null ++++ b/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h +@@ -0,0 +1,191 @@ ++// Copyright 2020 The Chromium Authors ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_IMAGE_DECODERS_AVIF_AVIF_IMAGE_DECODER_H_ ++#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_IMAGE_DECODERS_AVIF_AVIF_IMAGE_DECODER_H_ ++ ++#include ++#include ++ ++#include "base/functional/callback.h" ++#include "third_party/blink/renderer/platform/allow_discouraged_type.h" ++#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h" ++#include "third_party/blink/renderer/platform/wtf/vector.h" ++#include "third_party/libavif/src/include/avif/avif.h" ++#include "third_party/skia/include/core/SkImageInfo.h" ++#include "ui/gfx/color_space.h" ++#include "ui/gfx/geometry/point.h" ++ ++namespace blink { ++ ++class FastSharedBufferReader; ++ ++class PLATFORM_EXPORT AVIFImageDecoder final : public ImageDecoder { ++ public: ++ AVIFImageDecoder(AlphaOption, ++ HighBitDepthDecodingOption, ++ ColorBehavior, ++ cc::AuxImage, ++ wtf_size_t max_decoded_bytes, ++ AnimationOption); ++ AVIFImageDecoder(const AVIFImageDecoder&) = delete; ++ AVIFImageDecoder& operator=(const AVIFImageDecoder&) = delete; ++ ~AVIFImageDecoder() override; ++ ++ // ImageDecoder: ++ String FilenameExtension() const override; ++ const AtomicString& MimeType() const override; ++ bool ImageIsHighBitDepth() override; ++ void OnSetData(scoped_refptr data) override; ++ bool GetGainmapInfoAndData( ++ SkGainmapInfo& out_gainmap_info, ++ scoped_refptr& out_gainmap_data) const override; ++ cc::YUVSubsampling GetYUVSubsampling() const override; ++ gfx::Size DecodedYUVSize(cc::YUVIndex) const override; ++ wtf_size_t DecodedYUVWidthBytes(cc::YUVIndex) const override; ++ SkYUVColorSpace GetYUVColorSpace() const override; ++ uint8_t GetYUVBitDepth() const override; ++ std::optional GetHDRMetadata() const override; ++ void DecodeToYUV() override; ++ int RepetitionCount() const override; ++ bool FrameIsReceivedAtIndex(wtf_size_t) const override; ++ std::optional FrameTimestampAtIndex( ++ wtf_size_t) const override; ++ base::TimeDelta FrameDurationAtIndex(wtf_size_t) const override; ++ bool ImageHasBothStillAndAnimatedSubImages() const override; ++ ++ // Returns true if the data in fast_reader begins with a valid FileTypeBox ++ // (ftyp) that supports the brand 'avif' or 'avis'. ++ static bool MatchesAVIFSignature(const FastSharedBufferReader& fast_reader); ++ ++ gfx::ColorSpace GetColorSpaceForTesting() const; ++ ++ private: ++ // If the AVIF image has a clean aperture ('clap') property, what kind of ++ // clean aperture it is. Values synced with 'AVIFCleanApertureType' in ++ // src/tools/metrics/histograms/enums.xml. ++ // ++ // These values are persisted to logs. Entries should not be renumbered and ++ // numeric values should never be reused. ++ enum class AVIFCleanApertureType { ++ kInvalid = 0, // The clean aperture property is invalid. ++ kNonzeroOrigin = 1, // The origin of the clean aperture is not (0, 0). ++ kZeroOrigin = 2, // The origin of the clean aperture is (0, 0). ++ kMaxValue = kZeroOrigin, ++ }; ++ ++ struct AvifIOData { ++ AvifIOData(); ++ AvifIOData(scoped_refptr reader, ++ bool all_data_received); ++ ~AvifIOData(); ++ ++ scoped_refptr reader; ++ std::vector buffer ALLOW_DISCOURAGED_TYPE("Required by libavif"); ++ bool all_data_received = false; ++ }; ++ ++ void ParseMetadata(); ++ ++ // ImageDecoder: ++ void DecodeSize() override; ++ wtf_size_t DecodeFrameCount() override; ++ void InitializeNewFrame(wtf_size_t) override; ++ void Decode(wtf_size_t) override; ++ bool CanReusePreviousFrameBuffer(wtf_size_t) const override; ++ ++ // Implements avifIOReadFunc, the |read| function in the avifIO struct. ++ static avifResult ReadFromSegmentReader(avifIO* io, ++ uint32_t read_flags, ++ uint64_t offset, ++ size_t size, ++ avifROData* out); ++ ++ // Creates |decoder_| if not yet created and decodes the size and frame count. ++ bool UpdateDemuxer(); ++ ++ // Decodes the frame at index |index| and checks if the frame's size, bit ++ // depth, and YUV format matches those reported by the container. The decoded ++ // frame is available in decoded_image_. ++ avifResult DecodeImage(wtf_size_t index); ++ ++ // Crops |decoded_image_|. ++ void CropDecodedImage(); ++ ++ // Renders the rows [from_row, *to_row) of |image| to |buffer|. Returns ++ // whether |image| was rendered successfully. On return, the in/out argument ++ // |*to_row| may be decremented in case of subsampled chroma needing more ++ // data. ++ bool RenderImage(const avifImage* image, ++ int from_row, ++ int* to_row, ++ ImageFrame* buffer); ++ ++ // Applies color profile correction to the rows [from_row, to_row) of ++ // |buffer|, if desired. ++ void ColorCorrectImage(int from_row, int to_row, ImageFrame* buffer); ++ ++ // Returns decoder_->image or decoder_->image->gainMap->image depending on ++ // aux_image_. May be nullptr if requesting the gain map image ++ // (cc::AuxImage::kGainmap) but no gain map is present. ++ avifImage* GetDecoderImage() const; ++ ++ bool have_parsed_current_data_ = false; ++ // The image width and height (before cropping, if any) from the container. ++ // ++ // Note: container_width_, container_height_, decoder_->image->width, and ++ // decoder_->image->height are the width and height of the full image. Size() ++ // returns the size of the cropped image (the clean aperture). ++ uint32_t container_width_ = 0; ++ uint32_t container_height_ = 0; ++ // The bit depth from the container. ++ uint8_t bit_depth_ = 0; ++ bool decode_to_half_float_ = false; ++ uint8_t chroma_shift_x_ = 0; ++ uint8_t chroma_shift_y_ = 0; ++ std::optional hdr_metadata_; ++ bool progressive_ = false; ++ // Number of displayed rows for a non-progressive still image. ++ int incrementally_displayed_height_ = 0; ++ // The YUV format from the container. ++ avifPixelFormat avif_yuv_format_ = AVIF_PIXEL_FORMAT_NONE; ++ wtf_size_t decoded_frame_count_ = 0; ++ SkYUVColorSpace yuv_color_space_ = SkYUVColorSpace::kIdentity_SkYUVColorSpace; ++ // Used to call UpdateBppHistogram<"Avif">() at most once to record the ++ // bits-per-pixel value of the image when the image is successfully decoded. ++ base::OnceCallback update_bpp_histogram_callback_; ++ std::optional clap_type_; ++ // Whether the 'clap' (clean aperture) property should be ignored, e.g. ++ // because the 'clap' property is invalid or unsupported. ++ bool ignore_clap_ = false; ++ // The origin (top left corner) of the clean aperture. Used only when the ++ // image has a valid 'clap' (clean aperture) property. ++ gfx::Point clap_origin_; ++ // A copy of decoder_->image with the width, height, and plane buffers ++ // adjusted to those of the clean aperture. Used only when the image has a ++ // 'clap' (clean aperture) property. ++ std::unique_ptr cropped_image_{ ++ nullptr, avifImageDestroy}; ++ // Set by a successful DecodeImage() call to either decoder_->image or ++ // cropped_image_.get() depending on whether the image has a 'clap' (clean ++ // aperture) property. ++ raw_ptr decoded_image_ = nullptr; ++ // The declaration order of the next three fields is important. decoder_ ++ // points to avif_io_, and avif_io_ points to avif_io_data_. The destructor ++ // must destroy them in that order. ++ AvifIOData avif_io_data_; ++ avifIO avif_io_ = {}; ++ std::unique_ptr decoder_{ ++ nullptr, avifDecoderDestroy}; ++ ++ const AnimationOption animation_option_; ++ ++ // Used temporarily for incremental decoding and for some YUV to RGB color ++ // conversions. ++ Vector previous_last_decoded_row_; ++}; ++ ++} // namespace blink ++ ++#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_IMAGE_DECODERS_AVIF_AVIF_IMAGE_DECODER_H_ +diff --git a/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder_fuzzer.cc b/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder_fuzzer.cc +new file mode 100644 +index 0000000000000..f337ad075244a +--- /dev/null ++++ b/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder_fuzzer.cc +@@ -0,0 +1,30 @@ ++// 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. ++ ++#include "third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h" ++ ++#include ++#include ++#include ++ ++#include ++ ++#include "third_party/blink/renderer/platform/graphics/color_behavior.h" ++#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h" ++#include "third_party/blink/renderer/platform/image-decoders/image_decoder_fuzzer_utils.h" ++#include "third_party/blink/renderer/platform/testing/blink_fuzzer_test_support.h" ++#include "third_party/blink/renderer/platform/testing/task_environment.h" ++#include "third_party/blink/renderer/platform/wtf/shared_buffer.h" ++#include "third_party/blink/renderer/platform/wtf/wtf_size_t.h" ++ ++namespace blink { ++ ++extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { ++ static BlinkFuzzerTestSupport test_support; ++ FuzzedDataProvider fdp(data, size); ++ FuzzDecoder(DecoderType::kAvifDecoder, fdp); ++ return 0; ++} ++ ++} // namespace blink +diff --git a/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder_test.cc b/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder_test.cc +new file mode 100644 +index 0000000000000..9ec2b420bdf7d +--- /dev/null ++++ b/third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder_test.cc +@@ -0,0 +1,1758 @@ ++// Copyright 2020 The Chromium Authors ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#ifdef UNSAFE_BUFFERS_BUILD ++// TODO(crbug.com/351564777): Remove this and convert code to safer constructs. ++#pragma allow_unsafe_buffers ++#endif ++ ++#include "third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "base/barrier_closure.h" ++#include "base/bit_cast.h" ++#include "base/functional/bind.h" ++#include "base/strings/stringprintf.h" ++#include "base/synchronization/waitable_event.h" ++#include "base/task/thread_pool.h" ++#include "base/test/metrics/histogram_tester.h" ++#include "base/test/scoped_feature_list.h" ++#include "base/test/task_environment.h" ++#include "testing/gtest/include/gtest/gtest.h" ++#include "third_party/blink/public/common/features.h" ++#include "third_party/blink/public/platform/platform.h" ++#include "third_party/blink/renderer/platform/image-decoders/image_decoder_test_helpers.h" ++#include "third_party/blink/renderer/platform/wtf/shared_buffer.h" ++#include "ui/gfx/color_space.h" ++#include "ui/gfx/color_transform.h" ++ ++#define FIXME_SUPPORT_ICC_PROFILE_NO_TRANSFORM 0 ++#define FIXME_SUPPORT_ICC_PROFILE_TRANSFORM 0 ++#define FIXME_DISTINGUISH_LOSSY_OR_LOSSLESS 0 ++ ++namespace blink { ++ ++namespace { ++ ++std::unique_ptr CreateAVIFDecoderWithOptions( ++ ImageDecoder::AlphaOption alpha_option, ++ ImageDecoder::HighBitDepthDecodingOption high_bit_depth_option, ++ ColorBehavior color_behavior, ++ cc::AuxImage aux_image, ++ ImageDecoder::AnimationOption animation_option) { ++ return std::make_unique( ++ alpha_option, high_bit_depth_option, color_behavior, aux_image, ++ ImageDecoder::kNoDecodedImageByteLimit, animation_option); ++} ++ ++std::unique_ptr CreateAVIFDecoder() { ++ return CreateAVIFDecoderWithOptions( ++ ImageDecoder::kAlphaNotPremultiplied, ImageDecoder::kDefaultBitDepth, ++ ColorBehavior::kTag, cc::AuxImage::kDefault, ++ ImageDecoder::AnimationOption::kUnspecified); ++} ++ ++std::unique_ptr CreateGainMapAVIFDecoder() { ++ return CreateAVIFDecoderWithOptions( ++ ImageDecoder::kAlphaNotPremultiplied, ImageDecoder::kDefaultBitDepth, ++ ColorBehavior::kTag, cc::AuxImage::kGainmap, ++ ImageDecoder::AnimationOption::kUnspecified); ++} ++ ++struct ExpectedColor { ++ gfx::Point point; ++ SkColor color; ++}; ++ ++enum class ColorType { ++ kRgb, ++ kRgbA, ++ kMono, ++ kMonoA, ++}; ++ ++struct StaticColorCheckParam { ++ const char* path; ++ int bit_depth; ++ ColorType color_type; ++ ImageDecoder::CompressionFormat compression_format; ++ ImageDecoder::AlphaOption alpha_option; ++ ColorBehavior color_behavior; ++ ImageOrientationEnum orientation = ImageOrientationEnum::kDefault; ++ int color_threshold; ++ std::vector colors; ++}; ++ ++std::ostream& operator<<(std::ostream& os, const StaticColorCheckParam& param) { ++ const char* color_type; ++ switch (param.color_type) { ++ case ColorType::kRgb: ++ color_type = "kRgb"; ++ break; ++ case ColorType::kRgbA: ++ color_type = "kRgbA"; ++ break; ++ case ColorType::kMono: ++ color_type = "kMono"; ++ break; ++ case ColorType::kMonoA: ++ color_type = "kMonoA"; ++ break; ++ } ++ const char* alpha_option = ++ (param.alpha_option == ImageDecoder::kAlphaPremultiplied ++ ? "kAlphaPremultiplied" ++ : "kAlphaNotPremultiplied"); ++ const char* color_behavior; ++ if (param.color_behavior == ColorBehavior::kIgnore) { ++ color_behavior = "Ignore"; ++ } else if (param.color_behavior == ColorBehavior::kTag) { ++ color_behavior = "Tag"; ++ } else { ++ DCHECK(param.color_behavior == ColorBehavior::kTransformToSRGB); ++ color_behavior = "TransformToSRGB"; ++ } ++ const char* orientation; ++ switch (param.orientation) { ++ case ImageOrientationEnum::kOriginTopLeft: ++ orientation = "kOriginTopLeft"; ++ break; ++ case ImageOrientationEnum::kOriginTopRight: ++ orientation = "kOriginTopRight"; ++ break; ++ case ImageOrientationEnum::kOriginBottomRight: ++ orientation = "kOriginBottomRight"; ++ break; ++ case ImageOrientationEnum::kOriginBottomLeft: ++ orientation = "kOriginBottomLeft"; ++ break; ++ case ImageOrientationEnum::kOriginLeftTop: ++ orientation = "kOriginLeftTop"; ++ break; ++ case ImageOrientationEnum::kOriginRightTop: ++ orientation = "kOriginRightTop"; ++ break; ++ case ImageOrientationEnum::kOriginRightBottom: ++ orientation = "kOriginRightBottom"; ++ break; ++ case ImageOrientationEnum::kOriginLeftBottom: ++ orientation = "kOriginLeftBottom"; ++ break; ++ } ++ return os << "\nStaticColorCheckParam {\n path: \"" << param.path ++ << "\",\n bit_depth: " << param.bit_depth ++ << ",\n color_type: " << color_type ++ << ",\n alpha_option: " << alpha_option ++ << ",\n color_behavior: " << color_behavior ++ << ",\n orientation: " << orientation << "\n}"; ++} ++ ++StaticColorCheckParam kTestParams[] = { ++ { ++ "/images/resources/avif/red-at-12-oclock-with-color-profile-lossy.avif", ++ 8, ++ ColorType::kRgb, ++ ImageDecoder::kLossyFormat, ++ ImageDecoder::kAlphaNotPremultiplied, // q=60(lossy) ++ ColorBehavior::kTag, ++ ImageOrientationEnum::kOriginTopLeft, ++ 0, ++ {}, // we just check that this image is lossy. ++ }, ++ { ++ "/images/resources/avif/red-at-12-oclock-with-color-profile-lossy.avif", ++ 8, ++ ColorType::kRgb, ++ ImageDecoder::kLossyFormat, ++ ImageDecoder::kAlphaNotPremultiplied, // q=60(lossy) ++ ColorBehavior::kIgnore, ++ ImageOrientationEnum::kOriginTopLeft, ++ 0, ++ {}, // we just check that the decoder won't crash when ++ // ColorBehavior::kIgnore is used. ++ }, ++ {"/images/resources/avif/red-with-alpha-8bpc.avif", ++ 8, ++ ColorType::kRgbA, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTag, ++ ImageOrientationEnum::kOriginTopLeft, ++ 3, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(0, 255, 0, 0)}, ++ {gfx::Point(1, 1), SkColorSetARGB(127, 255, 0, 0)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 0, 0)}, ++ }}, ++ {"/images/resources/avif/red-full-range-420-8bpc.avif", ++ 8, ++ ColorType::kRgb, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTag, ++ ImageOrientationEnum::kOriginTopLeft, ++ 1, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(255, 255, 0, 0)}, ++ {gfx::Point(1, 1), SkColorSetARGB(255, 255, 0, 0)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 0, 0)}, ++ }}, ++ {"/images/resources/avif/red-full-range-unspecified-420-8bpc.avif", ++ 8, ++ ColorType::kRgb, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTag, ++ ImageOrientationEnum::kOriginTopLeft, ++ 0, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(255, 255, 0, 0)}, ++ {gfx::Point(1, 1), SkColorSetARGB(255, 255, 0, 0)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 0, 0)}, ++ }}, ++ {"/images/resources/avif/silver-full-range-srgb-420-8bpc.avif", ++ 8, ++ ColorType::kRgb, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTag, ++ ImageOrientationEnum::kOriginTopLeft, ++ 0, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(255, 192, 192, 192)}, ++ {gfx::Point(1, 1), SkColorSetARGB(255, 192, 192, 192)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 192, 192, 192)}, ++ }}, ++ {"/images/resources/avif/silver-400-matrix-6.avif", ++ 8, ++ ColorType::kRgb, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTag, ++ ImageOrientationEnum::kOriginTopLeft, ++ 0, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(255, 192, 192, 192)}, ++ {gfx::Point(1, 1), SkColorSetARGB(255, 192, 192, 192)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 192, 192, 192)}, ++ }}, ++ {"/images/resources/avif/silver-400-matrix-0.avif", ++ 8, ++ ColorType::kRgb, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTag, ++ ImageOrientationEnum::kOriginTopLeft, ++ 0, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(255, 192, 192, 192)}, ++ {gfx::Point(1, 1), SkColorSetARGB(255, 192, 192, 192)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 192, 192, 192)}, ++ }}, ++ {"/images/resources/avif/alpha-mask-limited-range-8bpc.avif", ++ 8, ++ ColorType::kMono, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTag, ++ ImageOrientationEnum::kOriginTopLeft, ++ 1, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(255, 0, 0, 0)}, ++ {gfx::Point(1, 1), SkColorSetARGB(255, 128, 128, 128)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 255, 255)}, ++ }}, ++ {"/images/resources/avif/alpha-mask-full-range-8bpc.avif", ++ 8, ++ ColorType::kMono, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTag, ++ ImageOrientationEnum::kOriginTopLeft, ++ 1, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(255, 0, 0, 0)}, ++ {gfx::Point(1, 1), SkColorSetARGB(255, 128, 128, 128)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 255, 255)}, ++ }}, ++ {"/images/resources/avif/red-with-alpha-8bpc.avif", ++ 8, ++ ColorType::kRgbA, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaPremultiplied, ++ ColorBehavior::kTransformToSRGB, ++ ImageOrientationEnum::kOriginTopLeft, ++ 4, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(0, 0, 0, 0)}, ++ {gfx::Point(1, 1), SkColorSetARGB(127, 255, 0, 0)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 0, 0)}, ++ }}, ++#if FIXME_SUPPORT_ICC_PROFILE_NO_TRANSFORM ++ {"/images/resources/avif/red-with-profile-8bpc.avif", ++ 8, ++ ColorType::kRgb, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kIgnore, ++ ImageOrientationEnum::kOriginTopLeft, ++ 1, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(255, 0, 0, 255)}, ++ {gfx::Point(1, 1), SkColorSetARGB(255, 0, 0, 255)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 0, 0, 255)}, ++ }}, ++#endif ++#if FIXME_SUPPORT_ICC_PROFILE_TRANSFORM ++ {"/images/resources/avif/red-with-profile-8bpc.avif", ++ 8, ++ ColorType::kRgb, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTransformToSRGB, ++ ImageOrientationEnum::kOriginTopLeft, ++ 1, ++ { ++ /* ++ * "Color Spin" ICC profile, embedded in this image, ++ * changes blue to red. ++ */ ++ {gfx::Point(0, 0), SkColorSetARGB(255, 255, 0, 0)}, ++ {gfx::Point(1, 1), SkColorSetARGB(255, 255, 0, 0)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 0, 0)}, ++ }}, ++#endif ++ {"/images/resources/avif/red-with-alpha-10bpc.avif", ++ 10, ++ ColorType::kRgbA, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTag, ++ ImageOrientationEnum::kOriginTopLeft, ++ 2, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(0, 255, 0, 0)}, ++ {gfx::Point(1, 1), SkColorSetARGB(128, 255, 0, 0)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 0, 0)}, ++ }}, ++ {"/images/resources/avif/red-with-alpha-10bpc.avif", ++ 10, ++ ColorType::kRgbA, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaPremultiplied, ++ ColorBehavior::kTransformToSRGB, ++ ImageOrientationEnum::kOriginTopLeft, ++ 2, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(0, 0, 0, 0)}, ++ {gfx::Point(1, 1), SkColorSetARGB(128, 255, 0, 0)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 0, 0)}, ++ }}, ++ {"/images/resources/avif/red-full-range-420-10bpc.avif", ++ 10, ++ ColorType::kRgb, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTag, ++ ImageOrientationEnum::kOriginTopLeft, ++ 0, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(255, 255, 0, 0)}, ++ {gfx::Point(1, 1), SkColorSetARGB(255, 255, 0, 0)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 0, 0)}, ++ }}, ++ {"/images/resources/avif/alpha-mask-limited-range-10bpc.avif", ++ 10, ++ ColorType::kMono, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTag, ++ ImageOrientationEnum::kOriginTopLeft, ++ 1, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(255, 0, 0, 0)}, ++ {gfx::Point(1, 1), SkColorSetARGB(255, 128, 128, 128)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 255, 255)}, ++ }}, ++ {"/images/resources/avif/alpha-mask-full-range-10bpc.avif", ++ 10, ++ ColorType::kMono, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTag, ++ ImageOrientationEnum::kOriginTopLeft, ++ 1, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(255, 0, 0, 0)}, ++ {gfx::Point(1, 1), SkColorSetARGB(255, 128, 128, 128)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 255, 255)}, ++ }}, ++#if FIXME_SUPPORT_ICC_PROFILE_NO_TRANSFORM ++ {"/images/resources/avif/red-with-profile-10bpc.avif", ++ 10, ++ ColorType::kRgb, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kIgnore, ++ ImageOrientationEnum::kOriginTopLeft, ++ 1, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(255, 0, 0, 255)}, ++ {gfx::Point(1, 1), SkColorSetARGB(255, 0, 0, 255)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 0, 0, 255)}, ++ }}, ++#endif ++#if FIXME_SUPPORT_ICC_PROFILE_TRANSFORM ++ {"/images/resources/avif/red-with-profile-10bpc.avif", ++ 10, ++ ColorType::kRgb, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTransformToSRGB, ++ ImageOrientationEnum::kOriginTopLeft, ++ 1, ++ { ++ /* ++ * "Color Spin" ICC profile, embedded in this image, ++ * changes blue to red. ++ */ ++ {gfx::Point(0, 0), SkColorSetARGB(255, 255, 0, 0)}, ++ {gfx::Point(1, 1), SkColorSetARGB(255, 255, 0, 0)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 0, 0)}, ++ }}, ++#endif ++ {"/images/resources/avif/red-with-alpha-12bpc.avif", ++ 12, ++ ColorType::kRgbA, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTag, ++ ImageOrientationEnum::kOriginTopLeft, ++ 2, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(0, 255, 0, 0)}, ++ {gfx::Point(1, 1), SkColorSetARGB(128, 255, 0, 0)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 0, 0)}, ++ }}, ++ {"/images/resources/avif/red-with-alpha-12bpc.avif", ++ 12, ++ ColorType::kRgbA, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaPremultiplied, ++ ColorBehavior::kTransformToSRGB, ++ ImageOrientationEnum::kOriginTopLeft, ++ 2, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(0, 0, 0, 0)}, ++ {gfx::Point(1, 1), SkColorSetARGB(128, 255, 0, 0)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 0, 0)}, ++ }}, ++ {"/images/resources/avif/red-full-range-420-12bpc.avif", ++ 12, ++ ColorType::kRgb, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTag, ++ ImageOrientationEnum::kOriginTopLeft, ++ 0, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(255, 255, 0, 0)}, ++ {gfx::Point(1, 1), SkColorSetARGB(255, 255, 0, 0)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 0, 0)}, ++ }}, ++ {"/images/resources/avif/alpha-mask-limited-range-12bpc.avif", ++ 12, ++ ColorType::kMono, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTag, ++ ImageOrientationEnum::kOriginTopLeft, ++ 1, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(255, 0, 0, 0)}, ++ {gfx::Point(1, 1), SkColorSetARGB(255, 128, 128, 128)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 255, 255)}, ++ }}, ++ {"/images/resources/avif/alpha-mask-full-range-12bpc.avif", ++ 12, ++ ColorType::kMono, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTag, ++ ImageOrientationEnum::kOriginTopLeft, ++ 1, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(255, 0, 0, 0)}, ++ {gfx::Point(1, 1), SkColorSetARGB(255, 128, 128, 128)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 255, 255)}, ++ }}, ++#if FIXME_SUPPORT_ICC_PROFILE_NO_TRANSFORM ++ {"/images/resources/avif/red-with-profile-12bpc.avif", ++ 12, ++ ColorType::kRgb, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kIgnore, ++ ImageOrientationEnum::kOriginTopLeft, ++ 1, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(255, 0, 0, 255)}, ++ {gfx::Point(1, 1), SkColorSetARGB(255, 0, 0, 255)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 0, 0, 255)}, ++ }}, ++#endif ++#if FIXME_SUPPORT_ICC_PROFILE_TRANSFORM ++ {"/images/resources/avif/red-with-profile-12bpc.avif", ++ 12, ++ ColorType::kRgb, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTransformToSRGB, ++ ImageOrientationEnum::kOriginTopLeft, ++ 1, ++ { ++ /* ++ * "Color Spin" ICC profile, embedded in this image, ++ * changes blue to red. ++ */ ++ {gfx::Point(0, 0), SkColorSetARGB(255, 255, 0, 0)}, ++ {gfx::Point(1, 1), SkColorSetARGB(255, 255, 0, 0)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 0, 0)}, ++ }}, ++#endif ++ {"/images/resources/avif/red-and-purple-crop.avif", ++ 8, ++ ColorType::kRgbA, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTag, ++ ImageOrientationEnum::kOriginTopLeft, ++ 0, ++ { ++ // The clean aperture's size is 200x50. The left half is red and the ++ // right half is purple. Alpha values in the clean aperture are 255. ++ // (Alpha values to the right of the clean aperture are 128.) ++ {gfx::Point(0, 0), SkColorSetARGB(255, 255, 0, 0)}, // red ++ {gfx::Point(99, 24), SkColorSetARGB(255, 255, 0, 0)}, // red ++ {gfx::Point(100, 25), SkColorSetARGB(255, 127, 0, 128)}, // purple ++ {gfx::Point(199, 49), SkColorSetARGB(255, 127, 0, 128)}, // purple ++ }}, ++ {"/images/resources/avif/red-full-range-angle-1-420-8bpc.avif", ++ 8, ++ ColorType::kRgb, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTag, ++ ImageOrientationEnum::kOriginLeftBottom, ++ 0, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(255, 255, 0, 0)}, ++ {gfx::Point(1, 1), SkColorSetARGB(255, 255, 0, 0)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 0, 0)}, ++ }}, ++ {"/images/resources/avif/red-full-range-mode-0-420-8bpc.avif", ++ 8, ++ ColorType::kRgb, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTag, ++ ImageOrientationEnum::kOriginBottomLeft, ++ 0, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(255, 255, 0, 0)}, ++ {gfx::Point(1, 1), SkColorSetARGB(255, 255, 0, 0)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 0, 0)}, ++ }}, ++ {"/images/resources/avif/red-full-range-mode-1-420-8bpc.avif", ++ 8, ++ ColorType::kRgb, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTag, ++ ImageOrientationEnum::kOriginTopRight, ++ 0, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(255, 255, 0, 0)}, ++ {gfx::Point(1, 1), SkColorSetARGB(255, 255, 0, 0)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 0, 0)}, ++ }}, ++ {"/images/resources/avif/red-full-range-angle-2-mode-0-420-8bpc.avif", ++ 8, ++ ColorType::kRgb, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTag, ++ ImageOrientationEnum::kOriginTopRight, ++ 0, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(255, 255, 0, 0)}, ++ {gfx::Point(1, 1), SkColorSetARGB(255, 255, 0, 0)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 0, 0)}, ++ }}, ++ {"/images/resources/avif/red-full-range-angle-3-mode-1-420-8bpc.avif", ++ 8, ++ ColorType::kRgb, ++ ImageDecoder::kLosslessFormat, ++ ImageDecoder::kAlphaNotPremultiplied, ++ ColorBehavior::kTag, ++ ImageOrientationEnum::kOriginLeftTop, ++ 0, ++ { ++ {gfx::Point(0, 0), SkColorSetARGB(255, 255, 0, 0)}, ++ {gfx::Point(1, 1), SkColorSetARGB(255, 255, 0, 0)}, ++ {gfx::Point(2, 2), SkColorSetARGB(255, 255, 0, 0)}, ++ }}, ++ // TODO(ryoh): Add other color profile images, such as BT2020CL, ++ // SMPTE 274M ++ // TODO(ryoh): Add images with different combinations of ColorPrimaries, ++ // TransferFunction and MatrixCoefficients, ++ // such as: ++ // sRGB ColorPrimaries, BT.2020 TransferFunction and ++ // BT.709 MatrixCoefficients ++ // TODO(ryoh): Add Mono + Alpha Images. ++}; ++ ++enum class ErrorPhase { kParse, kDecode }; ++ ++// If 'error_phase' is ErrorPhase::kParse, error is expected during parse ++// (SetData() call); else error is expected during decode ++// (DecodeFrameBufferAtIndex() call). ++void TestInvalidStaticImage(const char* avif_file, ErrorPhase error_phase) { ++ std::unique_ptr decoder = CreateAVIFDecoder(); ++ ++ scoped_refptr data = ReadFileToSharedBuffer(avif_file); ++ ASSERT_TRUE(data.get()); ++ decoder->SetData(std::move(data), true); ++ ++ if (error_phase == ErrorPhase::kParse) { ++ EXPECT_FALSE(decoder->IsSizeAvailable()); ++ EXPECT_TRUE(decoder->Failed()); ++ EXPECT_EQ(0u, decoder->FrameCount()); ++ EXPECT_FALSE(decoder->DecodeFrameBufferAtIndex(0)); ++ } else { ++ EXPECT_TRUE(decoder->IsSizeAvailable()); ++ EXPECT_FALSE(decoder->Failed()); ++ EXPECT_GT(decoder->FrameCount(), 0u); ++ ImageFrame* frame = decoder->DecodeFrameBufferAtIndex(0); ++ ASSERT_TRUE(frame); ++ EXPECT_NE(ImageFrame::kFrameComplete, frame->GetStatus()); ++ EXPECT_TRUE(decoder->Failed()); ++ } ++} ++ ++float HalfFloatToUnorm(uint16_t h) { ++ const uint32_t f = ((h & 0x8000) << 16) | (((h & 0x7c00) + 0x1c000) << 13) | ++ ((h & 0x03ff) << 13); ++ return base::bit_cast(f); ++} ++ ++void ReadYUV(const char* file_name, ++ const gfx::Size& expected_y_size, ++ const gfx::Size& expected_uv_size, ++ SkColorType color_type, ++ int bit_depth, ++ gfx::Point3F* rgb_pixel = nullptr) { ++ scoped_refptr data = ++ ReadFileToSharedBuffer("web_tests/images/resources/avif/", file_name); ++ ASSERT_TRUE(data); ++ ++ auto decoder = CreateAVIFDecoder(); ++ decoder->SetData(std::move(data), true); ++ ++ ASSERT_TRUE(decoder->IsDecodedSizeAvailable()); ++ ASSERT_TRUE(decoder->CanDecodeToYUV()); ++ EXPECT_NE(decoder->GetYUVSubsampling(), cc::YUVSubsampling::kUnknown); ++ EXPECT_NE(decoder->GetYUVColorSpace(), ++ SkYUVColorSpace::kIdentity_SkYUVColorSpace); ++ EXPECT_EQ(decoder->GetYUVBitDepth(), bit_depth); ++ ++ gfx::Size size = decoder->DecodedSize(); ++ gfx::Size y_size = decoder->DecodedYUVSize(cc::YUVIndex::kY); ++ gfx::Size u_size = decoder->DecodedYUVSize(cc::YUVIndex::kU); ++ gfx::Size v_size = decoder->DecodedYUVSize(cc::YUVIndex::kV); ++ ++ EXPECT_EQ(size, y_size); ++ EXPECT_EQ(u_size, v_size); ++ ++ EXPECT_EQ(expected_y_size, y_size); ++ EXPECT_EQ(expected_uv_size, u_size); ++ ++ wtf_size_t row_bytes[3]; ++ row_bytes[0] = decoder->DecodedYUVWidthBytes(cc::YUVIndex::kY); ++ row_bytes[1] = decoder->DecodedYUVWidthBytes(cc::YUVIndex::kU); ++ row_bytes[2] = decoder->DecodedYUVWidthBytes(cc::YUVIndex::kV); ++ ++ size_t planes_data_size = row_bytes[0] * y_size.height() + ++ row_bytes[1] * u_size.height() + ++ row_bytes[2] * v_size.height(); ++ auto planes_data = std::make_unique(planes_data_size); ++ ++ void* planes[3]; ++ planes[0] = planes_data.get(); ++ planes[1] = static_cast(planes[0]) + row_bytes[0] * y_size.height(); ++ planes[2] = static_cast(planes[1]) + row_bytes[1] * u_size.height(); ++ ++ decoder->SetImagePlanes( ++ std::make_unique(planes, row_bytes, color_type)); ++ ++ decoder->DecodeToYUV(); ++ EXPECT_FALSE(decoder->Failed()); ++ EXPECT_TRUE(decoder->HasDisplayableYUVData()); ++ ++ auto metadata = decoder->MakeMetadataForDecodeAcceleration(); ++ EXPECT_EQ(cc::ImageType::kAVIF, metadata.image_type); ++ EXPECT_EQ(size, metadata.image_size); ++ if (expected_y_size == expected_uv_size) { ++ EXPECT_EQ(cc::YUVSubsampling::k444, metadata.yuv_subsampling); ++ } else if (expected_y_size.height() == expected_uv_size.height()) { ++ EXPECT_EQ(cc::YUVSubsampling::k422, metadata.yuv_subsampling); ++ } else { ++ EXPECT_EQ(cc::YUVSubsampling::k420, metadata.yuv_subsampling); ++ } ++ ++ if (!rgb_pixel) { ++ return; ++ } ++ ++ if (bit_depth > 8) { ++ rgb_pixel->set_x(reinterpret_cast(planes[0])[0]); ++ rgb_pixel->set_y(reinterpret_cast(planes[1])[0]); ++ rgb_pixel->set_z(reinterpret_cast(planes[2])[0]); ++ } else { ++ rgb_pixel->set_x(reinterpret_cast(planes[0])[0]); ++ rgb_pixel->set_y(reinterpret_cast(planes[1])[0]); ++ rgb_pixel->set_z(reinterpret_cast(planes[2])[0]); ++ } ++ ++ if (color_type == kGray_8_SkColorType) { ++ const float max_channel = (1 << bit_depth) - 1; ++ rgb_pixel->set_x(rgb_pixel->x() / max_channel); ++ rgb_pixel->set_y(rgb_pixel->y() / max_channel); ++ rgb_pixel->set_z(rgb_pixel->z() / max_channel); ++ } else if (color_type == kA16_unorm_SkColorType) { ++ constexpr float kR16MaxChannel = 65535.0f; ++ rgb_pixel->set_x(rgb_pixel->x() / kR16MaxChannel); ++ rgb_pixel->set_y(rgb_pixel->y() / kR16MaxChannel); ++ rgb_pixel->set_z(rgb_pixel->z() / kR16MaxChannel); ++ } else { ++ DCHECK_EQ(color_type, kA16_float_SkColorType); ++ rgb_pixel->set_x(HalfFloatToUnorm(rgb_pixel->x())); ++ rgb_pixel->set_y(HalfFloatToUnorm(rgb_pixel->y())); ++ rgb_pixel->set_z(HalfFloatToUnorm(rgb_pixel->z())); ++ } ++ ++ // Convert our YUV pixel to RGB to avoid an excessive amounts of test ++ // expectations. We otherwise need bit_depth * yuv_sampling * color_type. ++ gfx::ColorTransform::Options options; ++ options.src_bit_depth = bit_depth; ++ options.dst_bit_depth = bit_depth; ++ auto transform = gfx::ColorTransform::NewColorTransform( ++ reinterpret_cast(decoder.get()) ++ ->GetColorSpaceForTesting(), ++ gfx::ColorSpace(), options); ++ transform->Transform(rgb_pixel, 1); ++} ++ ++void TestYUVRed(const char* file_name, ++ const gfx::Size& expected_uv_size, ++ SkColorType color_type = kGray_8_SkColorType, ++ int bit_depth = 8) { ++ SCOPED_TRACE(base::StringPrintf("file_name=%s, color_type=%d", file_name, ++ int{color_type})); ++ ++ constexpr gfx::Size kRedYSize(3, 3); ++ ++ gfx::Point3F decoded_pixel; ++ ASSERT_NO_FATAL_FAILURE(ReadYUV(file_name, kRedYSize, expected_uv_size, ++ color_type, bit_depth, &decoded_pixel)); ++ ++ // Allow the RGB value to be off by one step. 1/max_value is the minimum ++ // amount of error possible if error exists for integer sources. ++ // ++ // For half float values we have additional error from precision limitations, ++ // which gets worse at the extents of [-0.5, 1] -- which is the case for our R ++ // channel since we're using a pure red source. ++ // ++ // https://en.wikipedia.org/wiki/Half-precision_floating-point_format#Precision_limitations_on_decimal_values_in_[0,_1] ++ const double kMinError = 1.0 / ((1 << bit_depth) - 1); ++ const double kError = color_type == kA16_float_SkColorType ++ ? kMinError + std::pow(2, -11) ++ : kMinError; ++ EXPECT_NEAR(decoded_pixel.x(), 1, kError); // R ++ EXPECT_NEAR(decoded_pixel.y(), 0, kMinError); // G ++ EXPECT_NEAR(decoded_pixel.z(), 0, kMinError); // B ++} ++ ++void DecodeTask(const Vector* data, base::RepeatingClosure* done) { ++ std::unique_ptr decoder = CreateAVIFDecoder(); ++ ++ scoped_refptr data_copy = SharedBuffer::Create(); ++ data_copy->Append(*data); ++ decoder->SetData(std::move(data_copy), true); ++ ++ EXPECT_TRUE(decoder->IsSizeAvailable()); ++ EXPECT_FALSE(decoder->Failed()); ++ EXPECT_EQ(decoder->FrameCount(), 1u); ++ ImageFrame* frame = decoder->DecodeFrameBufferAtIndex(0); ++ ASSERT_TRUE(frame); ++ EXPECT_EQ(ImageFrame::kFrameComplete, frame->GetStatus()); ++ EXPECT_FALSE(decoder->Failed()); ++ ++ done->Run(); ++} ++ ++void InspectImage( ++ const StaticColorCheckParam& param, ++ ImageDecoder::HighBitDepthDecodingOption high_bit_depth_option) { ++ std::unique_ptr decoder = CreateAVIFDecoderWithOptions( ++ param.alpha_option, high_bit_depth_option, param.color_behavior, ++ cc::AuxImage::kDefault, ImageDecoder::AnimationOption::kUnspecified); ++ scoped_refptr data = ReadFileToSharedBuffer(param.path); ++ ASSERT_TRUE(data.get()); ++#if FIXME_DISTINGUISH_LOSSY_OR_LOSSLESS ++ EXPECT_EQ(param.compression_format, ++ ImageDecoder::GetCompressionFormat(data, "image/avif")); ++#endif ++ decoder->SetData(std::move(data), true); ++ EXPECT_EQ(1u, decoder->FrameCount()); ++ EXPECT_EQ(kAnimationNone, decoder->RepetitionCount()); ++ EXPECT_EQ(param.bit_depth > 8, decoder->ImageIsHighBitDepth()); ++ auto metadata = decoder->MakeMetadataForDecodeAcceleration(); ++ EXPECT_EQ(cc::ImageType::kAVIF, metadata.image_type); ++ // TODO(wtc): Check metadata.yuv_subsampling. ++ ImageFrame* frame = decoder->DecodeFrameBufferAtIndex(0); ++ ASSERT_TRUE(frame); ++ EXPECT_EQ(ImageFrame::kFrameComplete, frame->GetStatus()); ++ EXPECT_FALSE(decoder->Failed()); ++ EXPECT_EQ(param.orientation, decoder->Orientation()); ++ EXPECT_EQ(param.color_type == ColorType::kRgbA || ++ param.color_type == ColorType::kMonoA, ++ frame->HasAlpha()); ++ auto get_color_channel = [](SkColorChannel channel, SkColor color) { ++ switch (channel) { ++ case SkColorChannel::kR: ++ return SkColorGetR(color); ++ case SkColorChannel::kG: ++ return SkColorGetG(color); ++ case SkColorChannel::kB: ++ return SkColorGetB(color); ++ case SkColorChannel::kA: ++ return SkColorGetA(color); ++ } ++ }; ++ auto color_difference = [get_color_channel](SkColorChannel channel, ++ SkColor color1, ++ SkColor color2) -> int { ++ return std::abs(static_cast(get_color_channel(channel, color1)) - ++ static_cast(get_color_channel(channel, color2))); ++ }; ++ for (const auto& expected : param.colors) { ++ const SkBitmap& bitmap = frame->Bitmap(); ++ SkColor frame_color = ++ bitmap.getColor(expected.point.x(), expected.point.y()); ++ ++ EXPECT_LE(color_difference(SkColorChannel::kR, frame_color, expected.color), ++ param.color_threshold); ++ EXPECT_LE(color_difference(SkColorChannel::kG, frame_color, expected.color), ++ param.color_threshold); ++ EXPECT_LE(color_difference(SkColorChannel::kB, frame_color, expected.color), ++ param.color_threshold); ++ // TODO(ryoh): Create alpha_threshold field for alpha channels. ++ EXPECT_LE(color_difference(SkColorChannel::kA, frame_color, expected.color), ++ param.color_threshold); ++ if (param.color_type == ColorType::kMono || ++ param.color_type == ColorType::kMonoA) { ++ EXPECT_EQ(SkColorGetR(frame_color), SkColorGetG(frame_color)); ++ EXPECT_EQ(SkColorGetR(frame_color), SkColorGetB(frame_color)); ++ } ++ } ++} ++ ++void TestAvifBppHistogram(const char* image_name, ++ const char* histogram_name = nullptr, ++ base::HistogramBase::Sample32 sample = 0) { ++ TestBppHistogram(CreateAVIFDecoder, "Avif", image_name, histogram_name, ++ sample); ++} ++ ++struct AVIFImageParam { ++ const char* path; ++ size_t expected_frame_count; ++ int expected_repetition_count; ++}; ++ ++constexpr AVIFImageParam kAnimatedTestParams[] = { ++ // star-animated-8bpc.avif, star-animated-10bpc.avif, and ++ // star-animated-12bpc.avif contain an EditListBox whose `flags` field is ++ // equal to 0, meaning the edit list is not repeated. Therefore their ++ // `expected_repetition_count` is 0. ++ {"/images/resources/avif/star-animated-8bpc.avif", 5u, 0}, ++ {"/images/resources/avif/star-animated-8bpc-with-alpha.avif", 5u, ++ kAnimationLoopInfinite}, ++ {"/images/resources/avif/star-animated-10bpc.avif", 5u, 0}, ++ {"/images/resources/avif/star-animated-10bpc-with-alpha.avif", 5u, ++ kAnimationLoopInfinite}, ++ {"/images/resources/avif/star-animated-12bpc.avif", 5u, 0}, ++ {"/images/resources/avif/star-animated-12bpc-with-alpha.avif", 5u, ++ kAnimationLoopInfinite}, ++ {"/images/resources/avif/star-animated-8bpc-1-repetition.avif", 5u, 1}, ++ {"/images/resources/avif/star-animated-8bpc-10-repetition.avif", 5u, 10}, ++ {"/images/resources/avif/star-animated-8bpc-infinite-repetition.avif", 5u, ++ kAnimationLoopInfinite}, ++}; ++ ++constexpr AVIFImageParam kStaticTestParams[] = { ++ {"/images/resources/avif/red-at-12-oclock-with-color-profile-lossy.avif", 1, ++ kAnimationNone}, ++ {"/images/resources/avif/red-at-12-oclock-with-color-profile-8bpc.avif", 1, ++ kAnimationNone}, ++ {"/images/resources/avif/red-at-12-oclock-with-color-profile-10bpc.avif", 1, ++ kAnimationNone}, ++ {"/images/resources/avif/red-at-12-oclock-with-color-profile-12bpc.avif", 1, ++ kAnimationNone}, ++ {"/images/resources/avif/tiger_3layer_1res.avif", 1, kAnimationNone}, ++ {"/images/resources/avif/tiger_3layer_3res.avif", 1, kAnimationNone}, ++ {"/images/resources/avif/tiger_420_8b_grid1x13.avif", 1, kAnimationNone}, ++ {"/images/resources/avif/dice_444_10b_grid4x3.avif", 1, kAnimationNone}, ++ {"/images/resources/avif/gracehopper_422_12b_grid2x4.avif", 1, ++ kAnimationNone}, ++ {"/images/resources/avif/small-with-gainmap-iso.avif", 1, kAnimationNone}, ++}; ++ ++using AVIFValidImagesTest = ::testing::TestWithParam; ++ ++INSTANTIATE_TEST_SUITE_P(AnimatedAVIF, ++ AVIFValidImagesTest, ++ ::testing::ValuesIn(kAnimatedTestParams)); ++ ++INSTANTIATE_TEST_SUITE_P(StaticAVIF, ++ AVIFValidImagesTest, ++ ::testing::ValuesIn(kStaticTestParams)); ++ ++TEST_P(AVIFValidImagesTest, ByteByByteDecode) { ++ TestByteByByteDecode(&CreateAVIFDecoder, GetParam().path, ++ GetParam().expected_frame_count, ++ GetParam().expected_repetition_count); ++} ++ ++TEST(AnimatedAVIFTests, HasMultipleSubImages) { ++ std::unique_ptr decoder = CreateAVIFDecoder(); ++ decoder->SetData( ++ ReadFileToSharedBuffer("/images/resources/avif/star-animated-8bpc.avif"), ++ true); ++ EXPECT_TRUE(decoder->ImageHasBothStillAndAnimatedSubImages()); ++} ++ ++TEST(StaticAVIFTests, DoesNotHaveMultipleSubImages) { ++ std::unique_ptr decoder = CreateAVIFDecoder(); ++ decoder->SetData( ++ ReadFileToSharedBuffer("/images/resources/avif/" ++ "red-at-12-oclock-with-color-profile-8bpc.avif"), ++ true); ++ EXPECT_FALSE(decoder->ImageHasBothStillAndAnimatedSubImages()); ++} ++ ++TEST(StaticAVIFTests, HasTimingInformation) { ++ std::unique_ptr decoder = CreateAVIFDecoder(); ++ decoder->SetData( ++ ReadFileToSharedBuffer("/images/resources/avif/" ++ "red-at-12-oclock-with-color-profile-8bpc.avif"), ++ true); ++ EXPECT_TRUE(!!decoder->DecodeFrameBufferAtIndex(0)); ++ ++ // libavif has placeholder values for timestamp and duration on still images, ++ // so any duration value is valid, but the timestamp should be zero. ++ EXPECT_EQ(base::TimeDelta(), decoder->FrameTimestampAtIndex(0)); ++} ++ ++TEST(AnimatedAVIFTests, HasTimingInformation) { ++ std::unique_ptr decoder = CreateAVIFDecoder(); ++ decoder->SetData( ++ ReadFileToSharedBuffer("/images/resources/avif/star-animated-8bpc.avif"), ++ true); ++ ++ constexpr auto kDuration = base::Milliseconds(100); ++ ++ EXPECT_TRUE(!!decoder->DecodeFrameBufferAtIndex(0)); ++ EXPECT_EQ(base::TimeDelta(), decoder->FrameTimestampAtIndex(0)); ++ EXPECT_EQ(kDuration, decoder->FrameDurationAtIndex(0)); ++ ++ EXPECT_TRUE(!!decoder->DecodeFrameBufferAtIndex(1)); ++ EXPECT_EQ(kDuration, decoder->FrameTimestampAtIndex(1)); ++ EXPECT_EQ(kDuration, decoder->FrameDurationAtIndex(1)); ++} ++ ++TEST(StaticAVIFTests, NoCrashWhenCheckingForMultipleSubImages) { ++ std::unique_ptr decoder = CreateAVIFDecoder(); ++ constexpr char kHeader[] = {0x00, 0x00, 0x00, 0x20, 0x66, 0x74, 0x79, 0x70}; ++ auto buffer = SharedBuffer::Create(); ++ buffer->Append(kHeader); ++ decoder->SetData(std::move(buffer), false); ++ EXPECT_FALSE(decoder->ImageHasBothStillAndAnimatedSubImages()); ++} ++ ++// TODO(ryoh): Add corrupted video tests. ++ ++TEST(StaticAVIFTests, invalidImages) { ++ // Image data is truncated. ++ TestInvalidStaticImage( ++ "/images/resources/avif/" ++ "red-at-12-oclock-with-color-profile-truncated.avif", ++ ErrorPhase::kParse); ++ // Chunk size in AV1 frame header doesn't match the file size. ++ TestInvalidStaticImage( ++ "/images/resources/avif/" ++ "red-at-12-oclock-with-color-profile-with-wrong-frame-header.avif", ++ ErrorPhase::kDecode); ++} ++ ++TEST(StaticAVIFTests, GetIsoGainmapInfoAndData) { ++ base::test::ScopedFeatureList scoped_feature_list; ++ scoped_feature_list.InitWithFeatures( ++ /*enabled_features=*/{features::kAvifGainmapHdrImages}, ++ /*disabled_features=*/{}); ++ ++ scoped_refptr data = ReadFileToSharedBuffer( ++ "/images/resources/avif/small-with-gainmap-iso.avif"); ++ std::unique_ptr decoder = CreateAVIFDecoder(); ++ decoder->SetData(data, true); ++ EXPECT_FALSE(decoder->Failed()); ++ EXPECT_EQ(decoder->Size(), gfx::Size(134, 100)); ++ SkGainmapInfo gainmap_info; ++ scoped_refptr gainmap_data; ++ const bool has_gainmap = ++ decoder->GetGainmapInfoAndData(gainmap_info, gainmap_data); ++ ASSERT_TRUE(has_gainmap); ++ ++ // Check gainmap metadata. ++ constexpr double kEpsilon = 0.00001; ++ EXPECT_NEAR(gainmap_info.fGainmapRatioMin[0], 1.0, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fGainmapRatioMin[1], 1.0, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fGainmapRatioMin[2], 1.0, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fGainmapRatioMin[3], 1.0, kEpsilon); ++ ++ EXPECT_NEAR(gainmap_info.fGainmapRatioMax[0], std::exp2(1.4427), kEpsilon); ++ EXPECT_NEAR(gainmap_info.fGainmapRatioMax[1], std::exp2(1.4427), kEpsilon); ++ EXPECT_NEAR(gainmap_info.fGainmapRatioMax[2], std::exp2(1.4427), kEpsilon); ++ EXPECT_NEAR(gainmap_info.fGainmapRatioMax[3], 1., kEpsilon); ++ ++ EXPECT_NEAR(gainmap_info.fGainmapGamma[0], 1.0, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fGainmapGamma[1], 1.0, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fGainmapGamma[2], 1.0, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fGainmapGamma[3], 1.0, kEpsilon); ++ ++ EXPECT_NEAR(gainmap_info.fEpsilonSdr[0], 0.015625, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fEpsilonSdr[1], 0.015625, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fEpsilonSdr[2], 0.015625, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fEpsilonSdr[3], 1.0, kEpsilon); ++ ++ EXPECT_NEAR(gainmap_info.fEpsilonHdr[0], 0.015625, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fEpsilonHdr[1], 0.015625, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fEpsilonHdr[2], 0.015625, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fEpsilonHdr[3], 1.0, kEpsilon); ++ ++ EXPECT_NEAR(gainmap_info.fDisplayRatioSdr, 1.0, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fDisplayRatioHdr, std::exp2(1.4427), kEpsilon); ++ ++ EXPECT_EQ(gainmap_info.fBaseImageType, SkGainmapInfo::BaseImageType::kSDR); ++ ++ EXPECT_EQ(gainmap_info.fGainmapMathColorSpace, nullptr); ++ ++ // Check that the gainmap can be decoded. ++ std::unique_ptr gainmap_decoder = CreateGainMapAVIFDecoder(); ++ gainmap_decoder->SetData(gainmap_data, true); ++ EXPECT_FALSE(decoder->Failed()); ++ EXPECT_EQ(gainmap_decoder->Size(), gfx::Size(33, 25)); ++ ImageFrame* gainmap_frame = gainmap_decoder->DecodeFrameBufferAtIndex(0); ++ EXPECT_TRUE(gainmap_frame); ++} ++ ++TEST(StaticAVIFTests, GetIsoGainmapInfoAndDataHdrToSdr) { ++ base::test::ScopedFeatureList scoped_feature_list; ++ scoped_feature_list.InitWithFeatures( ++ /*enabled_features=*/{features::kAvifGainmapHdrImages}, ++ /*disabled_features=*/{}); ++ ++ scoped_refptr data = ReadFileToSharedBuffer( ++ "/images/resources/avif/small-with-gainmap-iso-hdrbase.avif"); ++ std::unique_ptr decoder = CreateAVIFDecoder(); ++ decoder->SetData(data, true); ++ EXPECT_FALSE(decoder->Failed()); ++ EXPECT_EQ(decoder->Size(), gfx::Size(134, 100)); ++ SkGainmapInfo gainmap_info; ++ scoped_refptr gainmap_data; ++ const bool has_gainmap = ++ decoder->GetGainmapInfoAndData(gainmap_info, gainmap_data); ++ ASSERT_TRUE(has_gainmap); ++ ++ // Check gainmap metadata. ++ constexpr double kEpsilon = 0.00001; ++ EXPECT_NEAR(gainmap_info.fGainmapRatioMin[0], 1.0, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fGainmapRatioMin[1], 1.0, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fGainmapRatioMin[2], 1.0, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fGainmapRatioMin[3], 1.0, kEpsilon); ++ ++ EXPECT_NEAR(gainmap_info.fGainmapRatioMax[0], std::exp2(1.4427), kEpsilon); ++ EXPECT_NEAR(gainmap_info.fGainmapRatioMax[1], std::exp2(1.4427), kEpsilon); ++ EXPECT_NEAR(gainmap_info.fGainmapRatioMax[2], std::exp2(1.4427), kEpsilon); ++ EXPECT_NEAR(gainmap_info.fGainmapRatioMax[3], 1.0, kEpsilon); ++ ++ EXPECT_NEAR(gainmap_info.fGainmapGamma[0], 1.0, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fGainmapGamma[1], 1.0, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fGainmapGamma[2], 1.0, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fGainmapGamma[3], 1.0, kEpsilon); ++ ++ EXPECT_NEAR(gainmap_info.fEpsilonSdr[0], 0.015625, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fEpsilonSdr[1], 0.015625, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fEpsilonSdr[2], 0.015625, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fEpsilonSdr[3], 1.0, kEpsilon); ++ ++ EXPECT_NEAR(gainmap_info.fEpsilonHdr[0], 0.015625, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fEpsilonHdr[1], 0.015625, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fEpsilonHdr[2], 0.015625, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fEpsilonHdr[3], 1.0, kEpsilon); ++ ++ EXPECT_NEAR(gainmap_info.fDisplayRatioSdr, 1.0, kEpsilon); ++ EXPECT_NEAR(gainmap_info.fDisplayRatioHdr, std::exp2(1.4427), kEpsilon); ++ ++ EXPECT_EQ(gainmap_info.fBaseImageType, SkGainmapInfo::BaseImageType::kHDR); ++ ++ // Check that the gainmap can be decoded. ++ std::unique_ptr gainmap_decoder = CreateGainMapAVIFDecoder(); ++ gainmap_decoder->SetData(gainmap_data, true); ++ EXPECT_FALSE(decoder->Failed()); ++ EXPECT_EQ(gainmap_decoder->Size(), gfx::Size(33, 25)); ++ ImageFrame* gainmap_frame = gainmap_decoder->DecodeFrameBufferAtIndex(0); ++ EXPECT_TRUE(gainmap_frame); ++} ++ ++TEST(StaticAVIFTests, GetIsoGainmapColorSpaceSameICC) { ++ base::test::ScopedFeatureList scoped_feature_list; ++ scoped_feature_list.InitWithFeatures( ++ /*enabled_features=*/{features::kAvifGainmapHdrImages}, ++ /*disabled_features=*/{}); ++ ++ // The image has use_base_color_space set to false (i.e. use the alternate ++ // image's color space), and the base and alternate image ICC profiles are the ++ // same, so the alternate image color space should be ignored. ++ scoped_refptr data = ReadFileToSharedBuffer( ++ "/images/resources/avif/small-with-gainmap-iso-usealtcolorspace.avif"); ++ std::unique_ptr decoder = CreateAVIFDecoder(); ++ decoder->SetData(data, true); ++ SkGainmapInfo gainmap_info; ++ scoped_refptr gainmap_data; ++ const bool has_gainmap = ++ decoder->GetGainmapInfoAndData(gainmap_info, gainmap_data); ++ ASSERT_TRUE(has_gainmap); ++ ++ EXPECT_EQ(gainmap_info.fGainmapMathColorSpace, nullptr); ++} ++ ++void ExpectMatrixNear(const skcms_Matrix3x3& lhs, ++ const skcms_Matrix3x3& rhs, ++ float epsilon) { ++ for (int r = 0; r < 3; r++) { ++ for (int c = 0; c < 3; c++) { ++ EXPECT_NEAR(lhs.vals[r][c], rhs.vals[r][c], epsilon); ++ } ++ } ++} ++ ++TEST(StaticAVIFTests, GetIsoGainmapColorSpaceDifferentICC) { ++ base::test::ScopedFeatureList scoped_feature_list; ++ scoped_feature_list.InitWithFeatures( ++ /*enabled_features=*/{features::kAvifGainmapHdrImages}, ++ /*disabled_features=*/{}); ++ ++ // The image has use_base_color_space set to false (i.e. use the alternate ++ // image's color space), and the base and alternate image ICC profiles are ++ // different, so the alternate ICC profile should be set as ++ // fGainmapMathColorSpace. ++ // Base is sRGB, alternate is P3. ++ scoped_refptr data = ReadFileToSharedBuffer( ++ "/images/resources/avif/" ++ "small-with-gainmap-iso-usealtcolorspace-differenticc.avif"); ++ std::unique_ptr decoder = CreateAVIFDecoder(); ++ decoder->SetData(data, true); ++ SkGainmapInfo gainmap_info; ++ scoped_refptr gainmap_data; ++ const bool has_gainmap = ++ decoder->GetGainmapInfoAndData(gainmap_info, gainmap_data); ++ ASSERT_TRUE(has_gainmap); ++ ++ // Check that the gain map color space is specified. ++ EXPECT_NE(gainmap_info.fGainmapMathColorSpace, nullptr); ++ // Only compare the color primaries, the transfer function is irrelevant. ++ skcms_Matrix3x3 matrix; ++ ASSERT_TRUE(gainmap_info.fGainmapMathColorSpace->toXYZD50(&matrix)); ++ ExpectMatrixNear(matrix, SkNamedGamut::kDisplayP3, 0.001); ++} ++ ++TEST(StaticAVIFTests, GetIsoGainmapColorSpaceDifferentCICP) { ++ base::test::ScopedFeatureList scoped_feature_list; ++ scoped_feature_list.InitWithFeatures( ++ /*enabled_features=*/{features::kAvifGainmapHdrImages}, ++ /*disabled_features=*/{}); ++ ++ // The image has use_base_color_space set to false (i.e. use the alternate ++ // image's color space), and the base and alternate images don't have ICC ++ // but CICP values instead. The alternate image's CICP values should be used. ++ // Base is sRGB, alternate is Rec 2020. ++ scoped_refptr data = ReadFileToSharedBuffer( ++ "/images/resources/avif/gainmap-sdr-srgb-to-hdr-wcg-rec2020.avif"); ++ std::unique_ptr decoder = CreateAVIFDecoder(); ++ decoder->SetData(data, true); ++ SkGainmapInfo gainmap_info; ++ scoped_refptr gainmap_data; ++ const bool has_gainmap = ++ decoder->GetGainmapInfoAndData(gainmap_info, gainmap_data); ++ ASSERT_TRUE(has_gainmap); ++ ++ // Check that the gain map color space is specified. ++ EXPECT_NE(gainmap_info.fGainmapMathColorSpace, nullptr); ++ // Only compare the color primaries, the transfer function is irrelevant. ++ skcms_Matrix3x3 matrix; ++ ASSERT_TRUE(gainmap_info.fGainmapMathColorSpace->toXYZD50(&matrix)); ++ ExpectMatrixNear(matrix, SkNamedGamut::kRec2020, 0.0001); ++} ++ ++TEST(StaticAVIFTests, GetGainmapInfoAndDataWithFeatureDisabled) { ++ base::test::ScopedFeatureList scoped_feature_list; ++ scoped_feature_list.InitWithFeatures( ++ /*enabled_features=*/{}, ++ /*disabled_features=*/{features::kAvifGainmapHdrImages}); ++ ++ const std::string image = "small-with-gainmap-iso.avif"; ++ scoped_refptr data = ++ ReadFileToSharedBuffer("web_tests/images/resources/avif", image.c_str()); ++ std::unique_ptr decoder = CreateAVIFDecoder(); ++ decoder->SetData(data, true); ++ SkGainmapInfo gainmap_info; ++ scoped_refptr gainmap_data; ++ const bool has_gainmap = ++ decoder->GetGainmapInfoAndData(gainmap_info, gainmap_data); ++ ASSERT_FALSE(has_gainmap); ++ ++ // Check that we get an error if we try decoding the gain map. ++ std::unique_ptr gainmap_decoder = CreateGainMapAVIFDecoder(); ++ gainmap_decoder->SetData(data, true); ++ EXPECT_FALSE(gainmap_decoder->IsSizeAvailable()); ++ EXPECT_TRUE(gainmap_decoder->Failed()); ++ EXPECT_EQ(gainmap_decoder->FrameCount(), 0u); ++ EXPECT_FALSE(gainmap_decoder->DecodeFrameBufferAtIndex(0)); ++} ++ ++TEST(StaticAVIFTests, GetGainmapInfoAndDataWithTruncatedData) { ++ base::test::ScopedFeatureList scoped_feature_list; ++ scoped_feature_list.InitWithFeatures( ++ /*enabled_features=*/{features::kAvifGainmapHdrImages}, ++ /*disabled_features=*/{}); ++ ++ const std::string image = "small-with-gainmap-iso.avif"; ++ const Vector data_vector = ++ ReadFile("web_tests/images/resources/avif", image.c_str()); ++ scoped_refptr half_data = SharedBuffer::Create( ++ base::span(data_vector).first(data_vector.size() / 2)); ++ ++ std::unique_ptr decoder = CreateAVIFDecoder(); ++ decoder->SetData(half_data, true); ++ SkGainmapInfo gainmap_info; ++ scoped_refptr gainmap_data; ++ const bool has_gainmap = ++ decoder->GetGainmapInfoAndData(gainmap_info, gainmap_data); ++ ASSERT_FALSE(has_gainmap); ++} ++ ++TEST(StaticAVIFTests, GetGainmapWithGammaZero) { ++ base::test::ScopedFeatureList scoped_feature_list; ++ scoped_feature_list.InitWithFeatures( ++ /*enabled_features=*/{features::kAvifGainmapHdrImages}, ++ /*disabled_features=*/{}); ++ ++ const std::string image = "small-with-gainmap-iso-gammazero.avif"; ++ scoped_refptr data = ++ ReadFileToSharedBuffer("web_tests/images/resources/avif", image.c_str()); ++ std::unique_ptr decoder = CreateAVIFDecoder(); ++ decoder->SetData(data, true); ++ SkGainmapInfo gainmap_info; ++ scoped_refptr gainmap_data; ++ const bool has_gainmap = ++ decoder->GetGainmapInfoAndData(gainmap_info, gainmap_data); ++ ASSERT_FALSE(has_gainmap); ++} ++ ++TEST(StaticAVIFTests, YUV) { ++ // 3x3, YUV 4:2:0 ++ constexpr gfx::Size kUVSize420(2, 2); ++ TestYUVRed("red-limited-range-420-8bpc.avif", kUVSize420); ++ TestYUVRed("red-full-range-420-8bpc.avif", kUVSize420); ++ ++ // 3x3, YUV 4:2:2 ++ constexpr gfx::Size kUVSize422(2, 3); ++ TestYUVRed("red-limited-range-422-8bpc.avif", kUVSize422); ++ ++ // 3x3, YUV 4:4:4 ++ constexpr gfx::Size kUVSize444(3, 3); ++ TestYUVRed("red-limited-range-444-8bpc.avif", kUVSize444); ++ ++ // Full range BT709 color space is uncommon, but should be supported. ++ TestYUVRed("red-full-range-bt709-444-8bpc.avif", kUVSize444); ++ ++ for (const auto ct : {kA16_unorm_SkColorType, kA16_float_SkColorType}) { ++ // 3x3, YUV 4:2:0, 10bpc ++ TestYUVRed("red-limited-range-420-10bpc.avif", kUVSize420, ct, 10); ++ ++ // 3x3, YUV 4:2:2, 10bpc ++ TestYUVRed("red-limited-range-422-10bpc.avif", kUVSize422, ct, 10); ++ ++ // 3x3, YUV 4:4:4, 10bpc ++ TestYUVRed("red-limited-range-444-10bpc.avif", kUVSize444, ct, 10); ++ ++ // 3x3, YUV 4:2:0, 12bpc ++ TestYUVRed("red-limited-range-420-12bpc.avif", kUVSize420, ct, 12); ++ ++ // 3x3, YUV 4:2:2, 12bpc ++ TestYUVRed("red-limited-range-422-12bpc.avif", kUVSize422, ct, 12); ++ ++ // 3x3, YUV 4:4:4, 12bpc ++ TestYUVRed("red-limited-range-444-12bpc.avif", kUVSize444, ct, 12); ++ ++ // Various common color spaces should be supported. ++ TestYUVRed("red-full-range-bt2020-pq-444-10bpc.avif", kUVSize444, ct, 10); ++ TestYUVRed("red-full-range-bt2020-pq-444-12bpc.avif", kUVSize444, ct, 12); ++ TestYUVRed("red-full-range-bt2020-hlg-444-10bpc.avif", kUVSize444, ct, 10); ++ TestYUVRed("red-full-range-bt2020-hlg-444-12bpc.avif", kUVSize444, ct, 12); ++ } ++} ++ ++TEST(StaticAVIFTests, SizeAvailableBeforeAllDataReceived) { ++ scoped_refptr stream_buffer = WTF::SharedBuffer::Create(); ++ scoped_refptr segment_reader = ++ SegmentReader::CreateFromSharedBuffer(stream_buffer); ++ std::unique_ptr decoder = ImageDecoder::CreateByMimeType( ++ "image/avif", segment_reader, /*data_complete=*/false, ++ ImageDecoder::kAlphaPremultiplied, ImageDecoder::kDefaultBitDepth, ++ ColorBehavior::kTag, cc::AuxImage::kDefault, ++ Platform::GetMaxDecodedImageBytes(), SkISize::MakeEmpty(), ++ ImageDecoder::AnimationOption::kUnspecified); ++ EXPECT_FALSE(decoder->IsSizeAvailable()); ++ ++ Vector data = ++ ReadFile("/images/resources/avif/red-limited-range-420-8bpc.avif"); ++ stream_buffer->Append(data); ++ EXPECT_EQ(stream_buffer->size(), 318u); ++ decoder->SetData(stream_buffer, /*all_data_received=*/false); ++ // All bytes are appended so we should have size, even though we pass ++ // all_data_received=false. ++ EXPECT_TRUE(decoder->IsSizeAvailable()); ++ ++ decoder->SetData(stream_buffer, /*all_data_received=*/true); ++ EXPECT_TRUE(decoder->IsSizeAvailable()); ++} ++ ++TEST(StaticAVIFTests, ProgressiveDecoding) { ++ base::HistogramTester histogram_tester; ++ scoped_refptr stream_buffer = WTF::SharedBuffer::Create(); ++ scoped_refptr segment_reader = ++ SegmentReader::CreateFromSharedBuffer(stream_buffer); ++ std::unique_ptr decoder = ImageDecoder::CreateByMimeType( ++ "image/avif", segment_reader, /*data_complete=*/false, ++ ImageDecoder::kAlphaPremultiplied, ImageDecoder::kDefaultBitDepth, ++ ColorBehavior::kTag, cc::AuxImage::kDefault, ++ Platform::GetMaxDecodedImageBytes(), SkISize::MakeEmpty(), ++ ImageDecoder::AnimationOption::kUnspecified); ++ ++ Vector data = ReadFile("/images/resources/avif/tiger_3layer_1res.avif"); ++ ASSERT_EQ(data.size(), 70944u); ++ ++ // This image has three layers. The first layer is 8299 bytes. Because of ++ // image headers and other overhead, if we pass exactly 8299 bytes to the ++ // decoder, the decoder does not have enough data to decode the first layer. ++ stream_buffer->Append(base::span(data).first(8299u)); ++ decoder->SetData(stream_buffer, /*all_data_received=*/false); ++ EXPECT_TRUE(decoder->IsSizeAvailable()); ++ EXPECT_FALSE(decoder->Failed()); ++ EXPECT_EQ(decoder->FrameCount(), 1u); ++ histogram_tester.ExpectTotalCount("Blink.DecodedImage.AvifDensity.Count.02MP", ++ 0); ++ ImageFrame* frame = decoder->DecodeFrameBufferAtIndex(0); ++ ASSERT_TRUE(frame); ++ EXPECT_EQ(frame->GetStatus(), ImageFrame::kFrameEmpty); ++ EXPECT_FALSE(decoder->Failed()); ++ ++ // An additional 301 bytes are enough data for the decoder to decode the first ++ // layer. With progressive decoding, the frame buffer status will transition ++ // to ImageFrame::kFramePartial. ++ stream_buffer->Append(base::span(data).subspan(8299u, 301u)); ++ decoder->SetData(stream_buffer, /*all_data_received=*/false); ++ EXPECT_FALSE(decoder->Failed()); ++ frame = decoder->DecodeFrameBufferAtIndex(0); ++ ASSERT_TRUE(frame); ++ EXPECT_EQ(frame->GetStatus(), ImageFrame::kFramePartial); ++ EXPECT_FALSE(decoder->Failed()); ++ ++ base::HistogramTester::CountsMap expected_counts; ++ EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix( ++ "Blink.DecodedImage.AvifDensity.Count."), ++ testing::ContainerEq(expected_counts)); ++ ++ // Now send the rest of the data. ++ stream_buffer->Append(base::span(data).subspan(8299u + 301u, 62344u)); ++ decoder->SetData(stream_buffer, /*all_data_received=*/true); ++ EXPECT_FALSE(decoder->Failed()); ++ frame = decoder->DecodeFrameBufferAtIndex(0); ++ ASSERT_TRUE(frame); ++ EXPECT_EQ(frame->GetStatus(), ImageFrame::kFrameComplete); ++ EXPECT_FALSE(decoder->Failed()); ++ ++ constexpr int kImageArea = 1216 * 832; // = 1011712 ++ constexpr int kFileSize = 70944; ++ constexpr int kSample = ++ (kFileSize * 100 * 8 + kImageArea / 2) / kImageArea; // = 56 ++ histogram_tester.ExpectUniqueSample( ++ "Blink.DecodedImage.AvifDensity.Count.02MP", kSample, 1); ++ expected_counts["Blink.DecodedImage.AvifDensity.Count.02MP"] = 1; ++ EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix( ++ "Blink.DecodedImage.AvifDensity.Count."), ++ testing::ContainerEq(expected_counts)); ++} ++ ++TEST(StaticAVIFTests, IncrementalDecoding) { ++ base::HistogramTester histogram_tester; ++ scoped_refptr stream_buffer = WTF::SharedBuffer::Create(); ++ scoped_refptr segment_reader = ++ SegmentReader::CreateFromSharedBuffer(stream_buffer); ++ std::unique_ptr decoder = ImageDecoder::CreateByMimeType( ++ "image/avif", segment_reader, /*data_complete=*/false, ++ ImageDecoder::kAlphaPremultiplied, ImageDecoder::kDefaultBitDepth, ++ ColorBehavior::kTag, cc::AuxImage::kDefault, ++ Platform::GetMaxDecodedImageBytes(), SkISize::MakeEmpty(), ++ ImageDecoder::AnimationOption::kUnspecified); ++ ++ Vector data = ++ ReadFile("/images/resources/avif/tiger_420_8b_grid1x13.avif"); ++ ++ constexpr int kImageArea = 1216 * 832; // = 1011712 ++ constexpr int kFileSize = 72257; ++ constexpr int kSample = ++ (kFileSize * 100 * 8 + kImageArea / 2) / kImageArea; // = 57 ++ ++ struct Step { ++ size_t size; // In bytes. ++ ImageFrame::Status status; ++ int num_decoded_rows; // In pixels. ++ }; ++ // There are 13 tiles. Tiles are as wide as the image and 64 pixels tall. ++ // |num_decoded_rows| may be odd due to an output pixel row missing the ++ // following upsampled decoded chroma row (belonging to the next tile). ++ const Step steps[] = { ++ {2000, ImageFrame::kFrameEmpty, 0}, ++ // Decoding half of the bytes gives 6 tile rows. ++ {data.size() / 2, ImageFrame::kFramePartial, 6 * 64 - 1}, ++ // Decoding all bytes but one gives 12 tile rows. ++ {data.size() - 1, ImageFrame::kFramePartial, 12 * 64 - 1}, ++ // Decoding all bytes gives all 13 tile rows. ++ {data.size(), ImageFrame::kFrameComplete, 13 * 64}}; ++ size_t previous_size = 0; ++ auto data_span = base::span(data); ++ for (const Step& step : steps) { ++ stream_buffer->Append( ++ data_span.subspan(previous_size, step.size - previous_size)); ++ decoder->SetData(stream_buffer, step.status == ImageFrame::kFrameComplete); ++ ++ EXPECT_EQ(decoder->FrameCount(), 1u); ++ ImageFrame* frame = decoder->DecodeFrameBufferAtIndex(0); ++ ASSERT_TRUE(frame); ++ ASSERT_FALSE(decoder->Failed()); ++ EXPECT_EQ(frame->GetStatus(), step.status); ++ ++ const SkBitmap& bitmap = frame->Bitmap(); ++ for (int y = 0; y < bitmap.height(); ++y) { ++ const uint32_t* row = bitmap.getAddr32(0, y); ++ const bool is_row_decoded = y < step.num_decoded_rows; ++ for (int x = 0; x < bitmap.width(); ++x) { ++ // The input image is opaque. Pixels outside the decoded area are fully ++ // transparent black pixels, with each channel value being 0. ++ const bool is_pixel_decoded = row[x] != 0x00000000u; ++ ASSERT_EQ(is_pixel_decoded, is_row_decoded); ++ } ++ } ++ previous_size = step.size; ++ ++ base::HistogramTester::CountsMap expected_counts; ++ if (step.status == ImageFrame::kFrameComplete) { ++ histogram_tester.ExpectUniqueSample( ++ "Blink.DecodedImage.AvifDensity.Count.02MP", kSample, 1); ++ expected_counts["Blink.DecodedImage.AvifDensity.Count.02MP"] = 1; ++ } ++ EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix( ++ "Blink.DecodedImage.AvifDensity.Count."), ++ testing::ContainerEq(expected_counts)); ++ } ++} ++ ++// Reproduces crbug.com/1402841. Decodes a large AVIF image 104 times in ++// parallel from base::ThreadPool. Should not cause temporary deadlock of ++// base::ThreadPool. ++TEST(StaticAVIFTests, ParallelDecoding) { ++ // The base::test::TaskEnvironment constructor creates a base::ThreadPool ++ // instance with 4 foreground threads. The number 4 comes from the ++ // test::TaskEnvironment::kNumForegroundThreadPoolThreads constant. ++ base::test::TaskEnvironment task_environment; ++ ++ // This test image is fast to decode (all neutral gray pixels) and its ++ // allocation size is large enough to cause ++ // media::PaintCanvasVideoRenderer::ConvertVideoFrameToRGBPixels() to pick ++ // n_tasks > 1 if AVIFImageDecoder did not pass disable_threading=true to it. ++ Vector data = ReadFile("/images/resources/avif/gray1024x704.avif"); ++ ++ // Task timeout in tests is 30 seconds (see https://crrev.com/c/1949028). ++ // Four blocking tasks cause a temporary deadlock (1.2 seconds) of ++ // base::ThreadPool, so we need at least 30 / 1.2 * 4 = 100 decodes for the ++ // test to time out without the bug fix. We add a margin of 4 decodes, i.e., ++ // (30 / 1.2 + 1) * 4 = 104. ++ const size_t n_decodes = 104; ++ base::WaitableEvent event; ++ base::RepeatingClosure barrier = base::BarrierClosure( ++ n_decodes, ++ base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(&event))); ++ ++ for (size_t i = 0; i < n_decodes; ++i) { ++ base::ThreadPool::PostTask( ++ FROM_HERE, ++ base::BindOnce(DecodeTask, base::Unretained(&data), &barrier)); ++ } ++ ++ event.Wait(); ++} ++ ++TEST(StaticAVIFTests, AlphaHasNoIspeProperty) { ++ std::unique_ptr decoder = CreateAVIFDecoder(); ++ decoder->SetData( ++ ReadFileToSharedBuffer("/images/resources/avif/green-no-alpha-ispe.avif"), ++ true); ++ EXPECT_FALSE(decoder->IsSizeAvailable()); ++ EXPECT_TRUE(decoder->Failed()); ++} ++ ++TEST(StaticAVIFTests, UnsupportedTransferFunctionInColrProperty) { ++ std::unique_ptr decoder = CreateAVIFDecoder(); ++ decoder->SetData(ReadFileToSharedBuffer( ++ "/images/resources/avif/red-unsupported-transfer.avif"), ++ true); ++ EXPECT_FALSE(decoder->IsSizeAvailable()); ++ EXPECT_TRUE(decoder->Failed()); ++} ++ ++TEST(StaticAVIFTests, ClapPropertyZeroOrigin) { ++ constexpr int kClapWidth = 200; ++ constexpr int kClapHeight = 50; ++ std::unique_ptr decoder1 = CreateAVIFDecoder(); ++ decoder1->SetData( ++ ReadFileToSharedBuffer("/images/resources/avif/red-and-purple-crop.avif"), ++ true); ++ ASSERT_TRUE(decoder1->IsSizeAvailable()); ++ gfx::Size size1 = decoder1->Size(); ++ ASSERT_EQ(size1.width(), kClapWidth); ++ ASSERT_EQ(size1.height(), kClapHeight); ++ ImageFrame* frame1 = decoder1->DecodeFrameBufferAtIndex(0); ++ ASSERT_TRUE(frame1); ++ EXPECT_EQ(ImageFrame::kFrameComplete, frame1->GetStatus()); ++ EXPECT_FALSE(decoder1->Failed()); ++ const SkBitmap& bitmap1 = frame1->Bitmap(); ++ ++ // The second image is the uncropped version of the first image. ++ std::unique_ptr decoder2 = CreateAVIFDecoder(); ++ decoder2->SetData(ReadFileToSharedBuffer( ++ "/images/resources/avif/red-and-purple-and-blue.avif"), ++ true); ++ ASSERT_TRUE(decoder2->IsSizeAvailable()); ++ gfx::Size size2 = decoder2->Size(); ++ ASSERT_EQ(size2.width(), 300); ++ ASSERT_EQ(size2.height(), 100); ++ ImageFrame* frame2 = decoder2->DecodeFrameBufferAtIndex(0); ++ ASSERT_TRUE(frame2); ++ EXPECT_EQ(ImageFrame::kFrameComplete, frame2->GetStatus()); ++ EXPECT_FALSE(decoder2->Failed()); ++ const SkBitmap& bitmap2 = frame2->Bitmap(); ++ ++ // Compare pixel data. ++ for (int row = 0; row < kClapHeight; ++row) { ++ for (int col = 0; col < kClapWidth; ++col) { ++ EXPECT_EQ(bitmap1.getColor(/*x=*/col, /*y=*/row), ++ bitmap2.getColor(/*x=*/col, /*y=*/row)); ++ } ++ } ++} ++ ++// Verifies that an invalid 'clap' (clean aperture) image property is handled by ++// ignoring the 'clap' property and showing the full image. ++TEST(StaticAVIFTests, InvalidClapPropertyHandling) { ++ // The first image has a valid 'clap' property. The full image has size ++ // 320x280. The clean aperture has size 180x100, located at (40, 80) of the ++ // full image. ++ // ++ // Since the origin of the clean aperture is not located at (0, 0), we treat ++ // the 'clap' property as invalid. So the full image is shown. ++ std::unique_ptr decoder1 = CreateAVIFDecoder(); ++ decoder1->SetData(ReadFileToSharedBuffer( ++ "/images/resources/avif/blue-and-magenta-crop.avif"), ++ true); ++ ASSERT_TRUE(decoder1->IsSizeAvailable()); ++ gfx::Size size1 = decoder1->Size(); ++ ASSERT_EQ(size1.width(), 320); ++ ASSERT_EQ(size1.height(), 280); ++ ImageFrame* frame1 = decoder1->DecodeFrameBufferAtIndex(0); ++ ASSERT_TRUE(frame1); ++ EXPECT_EQ(ImageFrame::kFrameComplete, frame1->GetStatus()); ++ EXPECT_FALSE(decoder1->Failed()); ++ const SkBitmap& bitmap1 = frame1->Bitmap(); ++ ++ // The second image is the same as the first image except that the 'clap' ++ // property is invalid. In this case the full image is shown. ++ std::unique_ptr decoder2 = CreateAVIFDecoder(); ++ decoder2->SetData( ++ ReadFileToSharedBuffer( ++ "/images/resources/avif/blue-and-magenta-crop-invalid.avif"), ++ true); ++ ASSERT_TRUE(decoder2->IsSizeAvailable()); ++ gfx::Size size2 = decoder2->Size(); ++ ASSERT_EQ(size2.width(), 320); ++ ASSERT_EQ(size2.height(), 280); ++ ImageFrame* frame2 = decoder2->DecodeFrameBufferAtIndex(0); ++ ASSERT_TRUE(frame2); ++ EXPECT_EQ(ImageFrame::kFrameComplete, frame2->GetStatus()); ++ EXPECT_FALSE(decoder2->Failed()); ++ const SkBitmap& bitmap2 = frame2->Bitmap(); ++ ++ // Compare pixel data. ++ for (int row = 0; row < size1.height(); ++row) { ++ for (int col = 0; col < size1.width(); ++col) { ++ EXPECT_EQ(bitmap1.getColor(/*x=*/col, /*y=*/row), ++ bitmap2.getColor(/*x=*/col, /*y=*/row)); ++ } ++ } ++} ++ ++TEST(StaticAVIFTests, BppHistogramSmall) { ++ constexpr int kImageArea = 768 * 512; // = 393216 ++ constexpr int kFileSize = 25724; ++ constexpr int kSample = ++ (kFileSize * 100 * 8 + kImageArea / 2) / kImageArea; // = 52 ++ TestAvifBppHistogram("/images/resources/avif/kodim03.avif", ++ "Blink.DecodedImage.AvifDensity.Count.0.4MP", kSample); ++} ++ ++TEST(StaticAVIFTests, BppHistogramSmall3x3) { ++ // The centi bpp = 318 * 100 * 8 / (3 * 3) ~= 28267, which is greater than the ++ // histogram's max value (1000), so this sample goes into the overflow bucket. ++ constexpr int kSample = 1000; ++ TestAvifBppHistogram("/images/resources/avif/red-full-range-420-8bpc.avif", ++ "Blink.DecodedImage.AvifDensity.Count.0.1MP", kSample); ++} ++ ++TEST(StaticAVIFTests, BppHistogramSmall900000) { ++ constexpr int kImageArea = 1200 * 750; // = 900000 ++ constexpr int kFileSize = 8144; ++ constexpr int kSample = ++ (kFileSize * 100 * 8 + kImageArea / 2) / kImageArea; // = 7 ++ TestAvifBppHistogram("/images/resources/avif/peach_900000.avif", ++ "Blink.DecodedImage.AvifDensity.Count.0.9MP", kSample); ++} ++ ++TEST(StaticAVIFTests, BppHistogramBig) { ++ constexpr int kImageArea = 4032 * 3024; // = 12192768 ++ constexpr int kFileSize = 88692; ++ constexpr int kSample = ++ (kFileSize * 100 * 8 + kImageArea / 2) / kImageArea; // = 6 ++ TestAvifBppHistogram("/images/resources/avif/bee.avif", ++ "Blink.DecodedImage.AvifDensity.Count.13MP", kSample); ++} ++ ++TEST(StaticAVIFTests, BppHistogramBig13000000) { ++ constexpr int kImageArea = 4000 * 3250; // = 13000000 ++ constexpr int kFileSize = 16725; ++ constexpr int kSample = ++ (kFileSize * 100 * 8 + kImageArea / 2) / kImageArea; // = 1 ++ TestAvifBppHistogram("/images/resources/avif/peach_13000000.avif", ++ "Blink.DecodedImage.AvifDensity.Count.13MP", kSample); ++} ++ ++TEST(StaticAVIFTests, BppHistogramHuge) { ++ constexpr int kImageArea = 4624 * 3472; // = 16054528 ++ constexpr int kFileSize = 20095; ++ constexpr int kSample = ++ (kFileSize * 100 * 8 + kImageArea / 2) / kImageArea; // = 1 ++ TestAvifBppHistogram("/images/resources/avif/peach.avif", ++ "Blink.DecodedImage.AvifDensity.Count.14+MP", kSample); ++} ++ ++TEST(StaticAVIFTests, BppHistogramHuge13000002) { ++ constexpr int kImageArea = 3961 * 3282; // = 13000002 ++ constexpr int kFileSize = 16379; ++ constexpr int kSample = ++ (kFileSize * 100 * 8 + kImageArea / 2) / kImageArea; // = 1 ++ TestAvifBppHistogram("/images/resources/avif/peach_13000002.avif", ++ "Blink.DecodedImage.AvifDensity.Count.14+MP", kSample); ++} ++ ++TEST(StaticAVIFTests, BppHistogramInvalid) { ++ base::HistogramTester histogram_tester; ++ std::unique_ptr decoder = CreateAVIFDecoder(); ++ decoder->SetData( ++ ReadFileToSharedBuffer( ++ "/images/resources/avif/" ++ "red-at-12-oclock-with-color-profile-with-wrong-frame-header.avif"), ++ true); ++ ASSERT_TRUE(decoder->IsSizeAvailable()); ++ EXPECT_FALSE(decoder->Failed()); ++ EXPECT_EQ(decoder->FrameCount(), 1u); ++ ImageFrame* frame = decoder->DecodeFrameBufferAtIndex(0); ++ ASSERT_TRUE(frame); ++ EXPECT_NE(ImageFrame::kFrameComplete, frame->GetStatus()); ++ EXPECT_TRUE(decoder->Failed()); ++ const base::HistogramTester::CountsMap empty_counts; ++ EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix( ++ "Blink.DecodedImage.AvifDensity.Count."), ++ testing::ContainerEq(empty_counts)); ++} ++ ++TEST(StaticAVIFTests, BppHistogram10bit) { ++ TestAvifBppHistogram("/images/resources/avif/red-full-range-420-10bpc.avif"); ++} ++ ++TEST(StaticAVIFTests, BppHistogramMonochrome) { ++ TestAvifBppHistogram("/images/resources/avif/silver-400-matrix-6.avif"); ++} ++ ++TEST(StaticAVIFTests, BppHistogramAlpha) { ++ TestAvifBppHistogram("/images/resources/avif/red-with-alpha-8bpc.avif"); ++} ++ ++TEST(StaticAVIFTests, BppHistogramAnimated) { ++ TestAvifBppHistogram("/images/resources/avif/star-animated-8bpc.avif"); ++} ++ ++using StaticAVIFColorTests = ::testing::TestWithParam; ++ ++INSTANTIATE_TEST_SUITE_P(Parameterized, ++ StaticAVIFColorTests, ++ ::testing::ValuesIn(kTestParams)); ++ ++TEST_P(StaticAVIFColorTests, InspectImage) { ++ InspectImage(GetParam(), ImageDecoder::kDefaultBitDepth); ++} ++ ++TEST_P(StaticAVIFColorTests, InspectImageHalfFloat) { ++ InspectImage(GetParam(), ImageDecoder::kHighBitDepthToHalfFloat); ++} ++ ++} // namespace ++ ++} // namespace blink +diff --git a/third_party/blink/renderer/platform/image-decoders/avif/gen_crabbyavif_wrapper.py b/third_party/blink/renderer/platform/image-decoders/avif/gen_crabbyavif_wrapper.py +new file mode 100644 +index 0000000000000..82f1c0c3df73a +--- /dev/null ++++ b/third_party/blink/renderer/platform/image-decoders/avif/gen_crabbyavif_wrapper.py +@@ -0,0 +1,164 @@ ++# 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. ++"""Script to generate crabbyavif wrapper using the libavif wrapper as the base. ++ ++When the libavif wrapper files (any of avif_image_decoder*) are changed, this ++script must be run to update the crabbyavif wrappers ++(crabbyavif_image_decoder*). ++""" ++ ++import os ++import re ++ ++ ++def _read_file(filename): ++ with open(filename) as file: ++ return file.read() ++ ++ ++def _write_file(filename, contents): ++ with open(filename, "w") as file: ++ file.write(contents) ++ ++ ++def _apply_replacements(contents, replacements): ++ for find, replace in replacements: ++ contents = re.sub(find, replace, contents) ++ return contents ++ ++ ++_COMMON_REPLACEMENTS = ( ++ (r"Copyright 2020", "Copyright 2024"), ++ (r"third_party/libavif/src", "third_party/crabbyavif/src"), ++ (r"avif_image_decoder.h", "crabbyavif_image_decoder.h"), ++ (r"AVIFImageDecoder", "CrabbyAVIFImageDecoder"), ++ (r"AVIF_TRUE", "CRABBY_AVIF_TRUE"), ++ (r"AVIF_FALSE", "CRABBY_AVIF_FALSE"), ++ (r"AVIF_REPETITION_COUNT_", "CRABBY_AVIF_REPETITION_COUNT_"), ++) ++ ++_NOTICE = """// WARNING: Auto-generated by gen_crabbyavif_wrapper.py. ++// Do not modify manually. ++""" ++ ++ ++def _generate_crabbyavif_file(source_file, replacements): ++ contents = _read_file(source_file) ++ contents = _apply_replacements(contents, _COMMON_REPLACEMENTS) ++ contents = _apply_replacements(contents, replacements) ++ contents = contents.split("\n") ++ # Copyright notice is 3 lines, insert the notice as the 4th line. ++ contents.insert(3, _NOTICE) ++ contents = "\n".join(contents) ++ crabby_source_file = "crabby%(source_file)s" % locals() ++ _write_file(crabby_source_file, contents) ++ os.system("clang-format -style chromium -i %(crabby_source_file)s" % ++ locals()) ++ ++ ++_HEADER_REPLACEMENTS = ( ++ (r"AVIF_AVIF_IMAGE_DECODER_H_", "AVIF_CRABBYAVIF_IMAGE_DECODER_H_"), ++ (r"AVIF_PIXEL_FORMAT_NONE", "crabbyavif::AVIF_PIXEL_FORMAT_NONE"), ++ # Functions ++ (r"avifDecoderDestroy", "crabbyavif::crabby_avifDecoderDestroy"), ++ (r"avifImageDestroy", "crabbyavif::crabby_avifImageDestroy"), ++ # Types ++ (r"avifIO", "crabbyavif::avifIO"), ++ (r"avifPixelFormat", "crabbyavif::avifPixelFormat"), ++ (r"avifROData", "crabbyavif::avifROData"), ++ (r"avifResult", "crabbyavif::avifResult"), ++ (r"\bavifDecoder\b", "crabbyavif::avifDecoder"), ++ (r"\bavifImage\b", "crabbyavif::avifImage"), ++) ++ ++_CC_REPLACEMENTS = ( ++ # Functions (to be namespaced and prefixed with "crabby_") ++ ( ++ r"\bavifCropRectConvertCleanApertureBox\b", ++ "crabbyavif::crabby_avifCropRectConvertCleanApertureBox", ++ ), ++ (r"\bavifDecoderCreate\b", "crabbyavif::crabby_avifDecoderCreate"), ++ ( ++ r"\bavifDecoderDecodedRowCount\b", ++ "crabbyavif::crabby_avifDecoderDecodedRowCount", ++ ), ++ (r"\bavifDecoderDestroy\b", "crabbyavif::crabby_avifDecoderDestroy"), ++ (r"\bavifDecoderNthImage\b", "crabbyavif::crabby_avifDecoderNthImage"), ++ ( ++ r"\bavifDecoderNthImageMaxExtent\b", ++ "crabbyavif::crabby_avifDecoderNthImageMaxExtent", ++ ), ++ ( ++ r"\bavifDecoderNthImageMaxExtent\b", ++ "crabbyavif::crabby_avifDecoderNthImageMaxExtent", ++ ), ++ ( ++ r"\bavifDecoderNthImageTiming\b", ++ "crabbyavif::crabby_avifDecoderNthImageTiming", ++ ), ++ (r"\bavifDecoderParse\b", "crabbyavif::crabby_avifDecoderParse"), ++ (r"\bavifDecoderSetIO\b", "crabbyavif::crabby_avifDecoderSetIO"), ++ (r"\bavifDecoderSetSource\b", "crabbyavif::crabby_avifDecoderSetSource"), ++ ( ++ r"\bavifGetPixelFormatInfo\b", ++ "crabbyavif::crabby_avifGetPixelFormatInfo", ++ ), ++ (r"\bavifImageCreateEmpty\b", "crabbyavif::crabby_avifImageCreateEmpty"), ++ (r"\bavifImageDestroy\b", "crabbyavif::crabby_avifImageDestroy"), ++ (r"\bavifImageSetViewRect\b", "crabbyavif::crabby_avifImageSetViewRect"), ++ (r"\bavifImageYUVToRGB\b", "crabbyavif::crabby_avifImageYUVToRGB"), ++ ( ++ r"\bavifPeekCompatibleFileType\b", ++ "crabbyavif::crabby_avifPeekCompatibleFileType", ++ ), ++ ( ++ r"\bavifRGBImageSetDefaults\b", ++ "crabbyavif::crabby_avifRGBImageSetDefaults", ++ ), ++ (r"\bavifResultToString\b", "crabbyavif::crabby_avifResultToString"), ++ # Symbols (to be namespaced). ++ (r"avifBool\b", "crabbyavif::avifBool"), ++ (r"avifColorPrimaries\b", "crabbyavif::avifColorPrimaries"), ++ (r"avifCropRect\b", "crabbyavif::avifCropRect"), ++ (r"avifDecoder\b", "crabbyavif::avifDecoder"), ++ (r"avifDiagnostics\b", "crabbyavif::avifDiagnostics"), ++ (r"avifExtent\b", "crabbyavif::avifExtent"), ++ (r"avifGainMap\b", "crabbyavif::avifGainMap"), ++ (r"avifGainMapMetadata\b", "crabbyavif::avifGainMapMetadata"), ++ (r"avifIO\b", "crabbyavif::avifIO"), ++ (r"avifImage\b", "crabbyavif::avifImage"), ++ (r"avifImageTiming\b", "crabbyavif::avifImageTiming"), ++ (r"avifMatrixCoefficients\b", "crabbyavif::avifMatrixCoefficients"), ++ (r"avifPixelFormatInfo\b", "crabbyavif::avifPixelFormatInfo"), ++ (r"avifRGBImage\b", "crabbyavif::avifRGBImage"), ++ (r"avifROData\b", "crabbyavif::avifROData"), ++ (r"avifRange\b", "crabbyavif::avifRange"), ++ (r"avifResult\b", "crabbyavif::avifResult"), ++ ( ++ r"avifTransferCharacteristics\b", ++ "crabbyavif::avifTransferCharacteristics", ++ ), ++ (r"\bAVIF_", "crabbyavif::AVIF_"), ++ (r"\bCRABBY_AVIF_", "crabbyavif::CRABBY_AVIF_"), ++) ++ ++_TEST_REPLACEMENTS = ( ++ (r"\bAVIFValidImagesTest\b", "CrabbyAVIFValidImagesTest"), ++ (r"\bAnimatedAVIFTests\b", "CrabbyAnimatedAVIFTests"), ++ (r"\bStaticAVIFColorTests\b", "CrabbyStaticAVIFColorTests"), ++ (r"\bStaticAVIFTests\b", "CrabbyStaticAVIFTests"), ++) ++ ++_FUZZER_REPLACEMENTS = ((r"kAvifDecoder", "kCrabbyAvifDecoder"), ) ++ ++def main(): ++ _generate_crabbyavif_file("avif_image_decoder.h", _HEADER_REPLACEMENTS) ++ _generate_crabbyavif_file("avif_image_decoder.cc", _CC_REPLACEMENTS) ++ _generate_crabbyavif_file("avif_image_decoder_test.cc", _TEST_REPLACEMENTS) ++ _generate_crabbyavif_file("avif_image_decoder_fuzzer.cc", ++ _FUZZER_REPLACEMENTS) ++ ++ ++if __name__ == "__main__": ++ main() +diff --git a/third_party/blink/renderer/platform/image-decoders/image_decoder.cc b/third_party/blink/renderer/platform/image-decoders/image_decoder.cc +index 0cc5dfa276964..0523ccbd18509 100644 +--- a/third_party/blink/renderer/platform/image-decoders/image_decoder.cc ++++ b/third_party/blink/renderer/platform/image-decoders/image_decoder.cc +@@ -52,6 +52,7 @@ + #include "ui/gfx/geometry/size_conversions.h" + + #if BUILDFLAG(ENABLE_AV1_DECODER) ++#include "third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h" + #include "third_party/blink/renderer/platform/image-decoders/avif/crabbyavif_image_decoder.h" + #endif + +@@ -197,7 +198,9 @@ String SniffMimeTypeInternal(scoped_refptr reader) { + return "image/bmp"; + } + #if BUILDFLAG(ENABLE_AV1_DECODER) +- if (CrabbyAVIFImageDecoder::MatchesAVIFSignature(fast_reader)) { ++ if (base::FeatureList::IsEnabled(blink::features::kCrabbyAvif) ++ ? CrabbyAVIFImageDecoder::MatchesAVIFSignature(fast_reader) ++ : AVIFImageDecoder::MatchesAVIFSignature(fast_reader)) { + return "image/avif"; + } + #endif +@@ -307,9 +310,15 @@ std::unique_ptr ImageDecoder::CreateByMimeType( + max_decoded_bytes); + #if BUILDFLAG(ENABLE_AV1_DECODER) + } else if (mime_type == "image/avif") { +- decoder = std::make_unique( +- alpha_option, high_bit_depth_decoding_option, color_behavior, aux_image, +- max_decoded_bytes, animation_option); ++ if (base::FeatureList::IsEnabled(blink::features::kCrabbyAvif)) { ++ decoder = std::make_unique( ++ alpha_option, high_bit_depth_decoding_option, color_behavior, ++ aux_image, max_decoded_bytes, animation_option); ++ } else { ++ decoder = std::make_unique( ++ alpha_option, high_bit_depth_decoding_option, color_behavior, ++ aux_image, max_decoded_bytes, animation_option); ++ } + #endif + } + +diff --git a/third_party/blink/renderer/platform/image-decoders/image_decoder_fuzzer_utils.cc b/third_party/blink/renderer/platform/image-decoders/image_decoder_fuzzer_utils.cc +index 93805eafce9fd..d07cbcd599f15 100644 +--- a/third_party/blink/renderer/platform/image-decoders/image_decoder_fuzzer_utils.cc ++++ b/third_party/blink/renderer/platform/image-decoders/image_decoder_fuzzer_utils.cc +@@ -5,6 +5,7 @@ + #include "third_party/blink/renderer/platform/image-decoders/image_decoder_fuzzer_utils.h" + + #include "third_party/blink/renderer/platform/graphics/color_behavior.h" ++#include "third_party/blink/renderer/platform/image-decoders/avif/avif_image_decoder.h" + #include "third_party/blink/renderer/platform/image-decoders/avif/crabbyavif_image_decoder.h" + #include "third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_decoder.h" + #include "third_party/blink/renderer/platform/image-decoders/image_decoder.h" +@@ -72,6 +73,13 @@ std::unique_ptr CreateImageDecoder(DecoderType decoder_type, + /*max_decoded_bytes=*/fdp.ConsumeIntegral(), + /*offset=*/fdp.ConsumeIntegral()); + } ++ case DecoderType::kAvifDecoder: { ++ return std::make_unique( ++ GetAlphaOption(fdp), GetHbdOption(fdp), GetColorBehavior(fdp), ++ GetAuxImageType(fdp), ++ /*max_decoded_bytes=*/fdp.ConsumeIntegral(), ++ GetAnimationOption(fdp)); ++ } + case DecoderType::kCrabbyAvifDecoder: { + return std::make_unique( + GetAlphaOption(fdp), GetHbdOption(fdp), GetColorBehavior(fdp), +diff --git a/third_party/blink/renderer/platform/image-decoders/image_decoder_fuzzer_utils.h b/third_party/blink/renderer/platform/image-decoders/image_decoder_fuzzer_utils.h +index f6ad7fe6b4c52..d1227387a9145 100644 +--- a/third_party/blink/renderer/platform/image-decoders/image_decoder_fuzzer_utils.h ++++ b/third_party/blink/renderer/platform/image-decoders/image_decoder_fuzzer_utils.h +@@ -15,6 +15,7 @@ enum class DecoderType { + kBmpDecoder, + kJpegDecoder, + kPngDecoder, ++ kAvifDecoder, + kCrabbyAvifDecoder, + }; + diff --git a/meta-chromium/recipes-browser/chromium/files/0015-Revert-Connect-the-Rust-log-crate-to-the-base-loggin.patch b/meta-chromium/recipes-browser/chromium/files/0015-Revert-Connect-the-Rust-log-crate-to-the-base-loggin.patch deleted file mode 100644 index 637bbad0e..000000000 --- a/meta-chromium/recipes-browser/chromium/files/0015-Revert-Connect-the-Rust-log-crate-to-the-base-loggin.patch +++ /dev/null @@ -1,488 +0,0 @@ -From a8d282ffd65a8de353a446485d730b27ccd5cd67 Mon Sep 17 00:00:00 2001 -From: Ariel D'Alessandro -Date: Fri, 1 Nov 2024 08:48:02 -0300 -Subject: [PATCH] Revert "Connect the Rust log crate to the //base logging - implementation" - -This reverts chromium commit 7ea0a5e831dd5 ("Connect the Rust log crate -to the //base logging implementation". - -The above commit enabled bindgen for the Rust logger. Similar to patch -0011-Disable-crabbyavif-to-fix-build-errors.patch added in commit [0], -this fixes a build error that's most likely because the way upstream -configures bindgen makes it incompatible with our cross-architecture -builds. - -``` -| FAILED: gen/base/logging_rust_log_integration_bindgen_generator/bindings.rs -| [...] -| panicked at bindgen-cli/main.rs:52:36: -| Unable to generate bindings: ClangDiagnostic("error: unsupported option '-mbranch-protection=' for target 'x86_64-unknown-linux-gnu'\n") -``` - -[0] meta-browser commit fd347dc ("chromium: Update to 127.0.6533.99") - -Upstream-Status: Inappropriate [specific to our build setup] -Signed-off-by: Ariel D'Alessandro ---- - base/BUILD.gn | 42 ---------- - base/logging.cc | 9 --- - base/logging/rust_log_integration.cc | 24 ------ - base/logging/rust_log_integration.h | 29 ------- - base/logging/rust_log_integration_unittest.cc | 76 ------------------- - base/logging/rust_logger.rs | 74 ------------------ - base/test/BUILD.gn | 13 ---- - .../test/logging/test_rust_logger_consumer.rs | 41 ---------- - .../rust/chromium_crates_io/gnrt_config.toml | 1 + - third_party/rust/log/v0_4/BUILD.gn | 2 + - 10 files changed, 3 insertions(+), 308 deletions(-) - delete mode 100644 base/logging/rust_log_integration.cc - delete mode 100644 base/logging/rust_log_integration.h - delete mode 100644 base/logging/rust_log_integration_unittest.cc - delete mode 100644 base/logging/rust_logger.rs - delete mode 100644 base/test/logging/test_rust_logger_consumer.rs - -diff --git a/base/BUILD.gn b/base/BUILD.gn -index bc3e57164a010..ba0a6cad17477 100644 ---- a/base/BUILD.gn -+++ b/base/BUILD.gn -@@ -38,8 +38,6 @@ import("//build/config/sanitizers/sanitizers.gni") - import("//build/config/sysroot.gni") - import("//build/config/ui.gni") - import("//build/nocompile.gni") --import("//build/rust/rust_bindgen.gni") --import("//build/rust/rust_static_library.gni") - import("//build/timestamp.gni") - import("//build/util/process_version.gni") - import("//build_overrides/build.gni") -@@ -1022,9 +1020,7 @@ component("base") { - # Used by metrics/crc32, except on NaCl builds. - deps += [ "//third_party/zlib" ] - -- # NaCl does not support Rust. - deps += [ -- ":rust_logger", - "//third_party/rust/serde_json_lenient/v0_2/wrapper", - ] - } -@@ -1545,8 +1541,6 @@ component("base") { - "files/scoped_temp_file.h", - "json/json_file_value_serializer.cc", - "json/json_file_value_serializer.h", -- "logging/rust_log_integration.cc", -- "logging/rust_log_integration.h", - "memory/discardable_memory.cc", - "memory/discardable_memory.h", - "memory/discardable_memory_allocator.cc", -@@ -2449,41 +2443,6 @@ component("base") { - } - } - --rust_bindgen("logging_log_severity_bindgen") { -- # TODO(danakj): Maybe combine all base bindgen targets, or all base/logging -- # ones even) into a single GN target? But the GN rule needs to handle multiple -- # headers then. -- header = "logging/log_severity.h" -- cpp = true -- visibility = [ ":*" ] -- -- # Transitive generated header dependency. -- deps = [ ":debugging_buildflags" ] --} -- --rust_bindgen("logging_rust_log_integration_bindgen") { -- header = "logging/rust_log_integration.h" -- cpp = true -- visibility = [ ":*" ] -- -- # Transitive generated header dependency. -- deps = [ ":debugging_buildflags" ] --} -- --rust_static_library("rust_logger") { -- allow_unsafe = true # Unsafe needed for FFI. -- deps = [ -- ":logging_log_severity_bindgen", -- ":logging_rust_log_integration_bindgen", -- "//third_party/rust/log/v0_4:lib", -- ] -- visibility = [ ":base" ] -- sources = [ "logging/rust_logger.rs" ] -- crate_root = "logging/rust_logger.rs" -- -- cxx_bindings = [ "logging/rust_logger.rs" ] --} -- - if (is_linux || is_chromeos) { - # Split out as a separate target for two reasons: - # - the line number reader is 2x slower in debug builds if not optimized, -@@ -3287,7 +3246,6 @@ test("base_unittests") { - "json/string_escape_unittest.cc", - "json/values_util_unittest.cc", - "lazy_instance_unittest.cc", -- "logging/rust_log_integration_unittest.cc", - "logging_unittest.cc", - "memory/aligned_memory_unittest.cc", - "memory/discardable_memory_backing_field_trial_unittest.cc", -diff --git a/base/logging.cc b/base/logging.cc -index 508ce135131aa..d296b81fa6d36 100644 ---- a/base/logging.cc -+++ b/base/logging.cc -@@ -126,10 +126,6 @@ typedef FILE* FileHandle; - #include "base/fuchsia/scoped_fx_logger.h" - #endif - --#if !BUILDFLAG(IS_NACL) --#include "base/logging/rust_logger.rs.h" --#endif -- - namespace logging { - - namespace { -@@ -526,11 +522,6 @@ bool BaseInitLoggingImpl(const LoggingSettings& settings) { - } - #endif - --#if !BUILDFLAG(IS_NACL) -- // Connects Rust logging with the //base logging functionality. -- internal::init_rust_log_crate(); --#endif -- - // Ignore file options unless logging to file is set. - if ((g_logging_destination & LOG_TO_FILE) == 0) - return true; -diff --git a/base/logging/rust_log_integration.cc b/base/logging/rust_log_integration.cc -deleted file mode 100644 -index 1dba55d18a64a..0000000000000 ---- a/base/logging/rust_log_integration.cc -+++ /dev/null -@@ -1,24 +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. -- --#include "base/logging/rust_log_integration.h" -- --#include "base/logging.h" --#include "base/logging/log_severity.h" -- --namespace logging { --namespace internal { -- --BASE_EXPORT void print_rust_log(const char* msg, -- const char* file, -- int line, -- LogSeverity severity, -- bool verbose) { -- // TODO(danakj): If `verbose` make the log equivalent to VLOG instead of LOG. -- logging::LogMessage log_message(file, line, severity); -- log_message.stream() << msg; --} -- --} // namespace internal --} // namespace logging -diff --git a/base/logging/rust_log_integration.h b/base/logging/rust_log_integration.h -deleted file mode 100644 -index 1795950e18557..0000000000000 ---- a/base/logging/rust_log_integration.h -+++ /dev/null -@@ -1,29 +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 BASE_LOGGING_RUST_LOG_INTEGRATION_H_ --#define BASE_LOGGING_RUST_LOG_INTEGRATION_H_ -- --#include "base/base_export.h" --#include "base/logging/log_severity.h" -- --namespace logging { --namespace internal { -- --// Receives a log line from Rust and forwards it to base logging, because --// logging::LogMessage is not accessible from Rust yet with our current interop --// tools. --// --// TODO(danakj): Should this helper function be replaced with C-like apis next --// to logging::LogMessage that Rust uses more directly? --void BASE_EXPORT print_rust_log(const char* msg, -- const char* file, -- int line, -- LogSeverity severity, -- bool verbose); -- --} // namespace internal --} // namespace logging -- --#endif // BASE_LOGGING_RUST_LOG_INTEGRATION_H_ -diff --git a/base/logging/rust_log_integration_unittest.cc b/base/logging/rust_log_integration_unittest.cc -deleted file mode 100644 -index 8fc0fec7e1350..0000000000000 ---- a/base/logging/rust_log_integration_unittest.cc -+++ /dev/null -@@ -1,76 +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. -- --#include "base/logging.h" --#include "base/test/logging/test_rust_logger_consumer.rs.h" --#include "base/test/mock_log.h" -- --using testing::_; -- --namespace logging { --namespace { -- --class RustLogIntegrationTest : public testing::Test { -- public: -- void SetUp() override { log_.StartCapturingLogs(); } -- -- void TearDown() override { log_.StopCapturingLogs(); } -- -- base::test::MockLog log_; --}; -- --// TODO(crbug.com/374023535): Logging does not work in component builds. --#if defined(COMPONENT_BUILD) --#define MAYBE_CheckAllSeverity DISABLED_CheckAllSeverity --#else --#define MAYBE_CheckAllSeverity CheckAllSeverity --#endif --TEST_F(RustLogIntegrationTest, MAYBE_CheckAllSeverity) { --#if DCHECK_IS_ON() -- // Debug and Trace logs from Rust are discarded when DCHECK_IS_ON() is false; -- // otherwise, they are logged as info. -- EXPECT_CALL(log_, -- Log(LOGGING_INFO, _, _, _, testing::HasSubstr("test trace log"))) -- .WillOnce(testing::Return(true)); -- -- EXPECT_CALL(log_, -- Log(LOGGING_INFO, _, _, _, testing::HasSubstr("test debug log"))) -- .WillOnce(testing::Return(true)); --#endif -- -- EXPECT_CALL(log_, -- Log(LOGGING_INFO, _, _, _, testing::HasSubstr("test info log"))) -- .WillOnce(testing::Return(true)); -- -- EXPECT_CALL(log_, Log(LOGGING_WARNING, _, _, _, -- testing::HasSubstr("test warning log"))) -- .WillOnce(testing::Return(true)); -- -- EXPECT_CALL(log_, -- Log(LOGGING_ERROR, _, _, _, testing::HasSubstr("test error log"))) -- .WillOnce(testing::Return(true)); -- -- base::test::print_test_trace_log(); -- base::test::print_test_debug_log(); -- base::test::print_test_info_log(); -- base::test::print_test_warning_log(); -- base::test::print_test_error_log(); --} -- --// TODO(crbug.com/374023535): Logging does not work in component builds. --#if defined(COMPONENT_BUILD) --#define MAYBE_Placeholders DISABLED_Placeholders --#else --#define MAYBE_Placeholders Placeholders --#endif --TEST_F(RustLogIntegrationTest, MAYBE_Placeholders) { -- EXPECT_CALL(log_, Log(LOGGING_ERROR, _, _, _, -- testing::HasSubstr("test log with placeholder 2"))) -- .WillOnce(testing::Return(true)); -- -- base::test::print_test_error_log_with_placeholder(2); --} -- --} // namespace --} // namespace logging -diff --git a/base/logging/rust_logger.rs b/base/logging/rust_logger.rs -deleted file mode 100644 -index 918c1ce0f58bd..0000000000000 ---- a/base/logging/rust_logger.rs -+++ /dev/null -@@ -1,74 +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. -- --chromium::import! { -- "//base:logging_log_severity_bindgen" as log_severity; -- "//base:logging_rust_log_integration_bindgen" as rust_log_integration; --} -- --use log::Level::{Debug, Error, Info, Trace, Warn}; --use log::{LevelFilter, Metadata, Record}; --use log_severity::logging::{LOGGING_ERROR, LOGGING_INFO, LOGGING_WARNING}; --use rust_log_integration::logging::internal::print_rust_log; --use std::ffi::CString; -- --struct RustLogger; -- --impl log::Log for RustLogger { -- fn enabled(&self, _metadata: &Metadata) -> bool { -- // Always enabled, as it's controlled by command line flags managed by the C++ -- // implementation. -- true -- } -- -- fn log(&self, record: &Record) { -- // TODO(thiruak1024@gmail.com): Rather than using heap allocation to pass |msg| -- // and |file|, we should return a pointer and size object to leverage the -- // string_view object in C++. https://crbug.com/371112531 -- let msg = match record.args().as_str() { -- Some(s) => CString::new(s), -- None => CString::new(&*record.args().to_string()), -- } -- .expect("CString::new failed to create the log message!"); -- let file = CString::new(record.file().unwrap()) -- .expect("CString::new failed to create the log file name!"); -- unsafe { -- print_rust_log( -- msg.as_ptr(), -- file.as_ptr(), -- record.line().unwrap() as i32, -- match record.metadata().level() { -- Error => LOGGING_ERROR, -- Warn => LOGGING_WARNING, -- Info => LOGGING_INFO, -- // Note that Debug and Trace level logs are dropped at -- // compile time at the macro call-site when DCHECK_IS_ON() -- // is false. This is done through a Cargo feature. -- Debug | Trace => LOGGING_INFO, -- }, -- record.metadata().level() == Trace, -- ) -- } -- } -- fn flush(&self) {} --} -- --static RUST_LOGGER: RustLogger = RustLogger; -- --#[cxx::bridge(namespace = "logging::internal")] --mod ffi { -- extern "Rust" { -- fn init_rust_log_crate(); -- } --} -- --pub fn init_rust_log_crate() { -- // An error may occur if set_logger has already been called, which can happen -- // during unit tests. In that case, return from the method without executing the -- // subsequent code. -- if let Err(_) = log::set_logger(&RUST_LOGGER) { -- return; -- }; -- log::set_max_level(LevelFilter::Trace); --} -diff --git a/base/test/BUILD.gn b/base/test/BUILD.gn -index ddf58b1d496e0..77b571c31a31c 100644 ---- a/base/test/BUILD.gn -+++ b/base/test/BUILD.gn -@@ -7,7 +7,6 @@ import("//build/config/chromeos/ui_mode.gni") - import("//build/config/features.gni") - import("//build/config/nacl/config.gni") - import("//build/config/ui.gni") --import("//build/rust/rust_static_library.gni") - import("//build_overrides/build.gni") - import("//third_party/protobuf/proto_library.gni") - -@@ -39,17 +38,6 @@ static_library("test_config") { - ] - } - --rust_static_library("test_rust_logger_consumer") { -- allow_unsafe = true # Unsafe needed for FFI -- testonly = true -- deps = [ "//third_party/rust/log/v0_4:lib" ] -- sources = [ "logging/test_rust_logger_consumer.rs" ] -- -- crate_root = "logging/test_rust_logger_consumer.rs" -- -- cxx_bindings = [ "logging/test_rust_logger_consumer.rs" ] --} -- - static_library("test_support") { - testonly = true - sources = [ -@@ -189,7 +177,6 @@ static_library("test_support") { - - public_deps = [ - ":test_config", -- ":test_rust_logger_consumer", - "//base", - "//base:base_static", - "//base:i18n", -diff --git a/base/test/logging/test_rust_logger_consumer.rs b/base/test/logging/test_rust_logger_consumer.rs -deleted file mode 100644 -index dc8adc6b85f22..0000000000000 ---- a/base/test/logging/test_rust_logger_consumer.rs -+++ /dev/null -@@ -1,41 +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. -- --use log::{debug, error, info, trace, warn}; -- --#[cxx::bridge(namespace = "base::test")] --mod ffi { -- extern "Rust" { -- fn print_test_info_log(); -- fn print_test_warning_log(); -- fn print_test_error_log(); -- fn print_test_debug_log(); -- fn print_test_trace_log(); -- fn print_test_error_log_with_placeholder(i: i32); -- } --} -- --pub fn print_test_info_log() { -- info!("test info log"); --} -- --pub fn print_test_warning_log() { -- warn!("test warning log"); --} -- --pub fn print_test_error_log() { -- error!("test error log"); --} -- --pub fn print_test_debug_log() { -- debug!("test debug log"); --} -- --pub fn print_test_trace_log() { -- trace!("test trace log"); --} -- --fn print_test_error_log_with_placeholder(i: i32) { -- error!("test log with placeholder {}", i); --} -diff --git a/third_party/rust/chromium_crates_io/gnrt_config.toml b/third_party/rust/chromium_crates_io/gnrt_config.toml -index 9f36dd0efc3d3..828786f06ff8c 100644 ---- a/third_party/rust/chromium_crates_io/gnrt_config.toml -+++ b/third_party/rust/chromium_crates_io/gnrt_config.toml -@@ -163,6 +163,7 @@ ban_features = [ - ] - - [crate.log] -+group = 'test' - - [crate.nom] - remove_deps = ['minimal-lexical'] -diff --git a/third_party/rust/log/v0_4/BUILD.gn b/third_party/rust/log/v0_4/BUILD.gn -index 6db643f2c446b..6e871e1b71808 100644 ---- a/third_party/rust/log/v0_4/BUILD.gn -+++ b/third_party/rust/log/v0_4/BUILD.gn -@@ -43,4 +43,6 @@ cargo_crate("lib") { - "release_max_level_info", - "std", - ] -+ -+ testonly = true - } diff --git a/meta-chromium/recipes-browser/chromium/files/0015-Revert-Remove-third_party-libavif.patch b/meta-chromium/recipes-browser/chromium/files/0015-Revert-Remove-third_party-libavif.patch new file mode 100644 index 000000000..f0991eb71 --- /dev/null +++ b/meta-chromium/recipes-browser/chromium/files/0015-Revert-Remove-third_party-libavif.patch @@ -0,0 +1,333 @@ +From d71a0fc5b00c20492fbfd15a561548c2e40ae2d4 Mon Sep 17 00:00:00 2001 +From: Ariel D'Alessandro +Date: Thu, 17 Jul 2025 13:11:35 -0300 +Subject: [PATCH] Revert "Remove third_party/libavif" + +This reverts commit 16708cb7341629a2793a6a06a370e2b846313e56. + +In order to disable crabbyavif to fix build errors, re-enable libavif so +it can be used in replacement. + +Upstream-Status: Inappropriate [upstream ticket https://crbug.com/357017325] +Signed-off-by: Ariel D'Alessandro +--- + DEPS | 7 + + third_party/libavif/BUILD.gn | 172 +++++++++++++++++++ + third_party/libavif/DIR_METADATA | 6 + + third_party/libavif/OWNERS | 2 + + third_party/libavif/README.chromium | 13 ++ + third_party/libavif/avif_apps_shared_stubs.c | 50 ++++++ + third_party/libavif/src | 1 + + 7 files changed, 251 insertions(+) + create mode 100644 third_party/libavif/BUILD.gn + create mode 100644 third_party/libavif/DIR_METADATA + create mode 100644 third_party/libavif/OWNERS + create mode 100644 third_party/libavif/README.chromium + create mode 100644 third_party/libavif/avif_apps_shared_stubs.c + create mode 160000 third_party/libavif/src + +diff --git a/DEPS b/DEPS +index f527d6b0d4b78..3b31fee5d5d3a 100644 +--- a/DEPS ++++ b/DEPS +@@ -445,6 +445,10 @@ vars = { + # and whatever else without interference from each other. + 'wuffs_revision': 'e3f919ccfe3ef542cfc983a82146070258fb57f8', + # Three lines of non-changing comments so that ++ # the commit queue can handle CLs rolling libavif ++ # and whatever else without interference from each other. ++ 'libavif_revision': 'e7b34a1f5e9f7024d08311c7bae156061b889882', ++ # Three lines of non-changing comments so that + # the commit queue can handle CLs rolling crabbyavif + # and whatever else without interference from each other. + 'crabbyavif_revision': '02d0fad2c512380b7270d6e704c86521075d7d54', +@@ -2268,6 +2272,9 @@ deps = { + 'src/third_party/libaom/source/libaom': + Var('aomedia_git') + '/aom.git' + '@' + '9680f2b1781fb33b9eeb52409b75c679c8a954be', + ++ 'src/third_party/libavif/src': ++ Var('chromium_git') + '/external/github.com/AOMediaCodec/libavif.git' + '@' + Var('libavif_revision'), ++ + 'src/third_party/crabbyavif/src': + Var('chromium_git') + '/external/github.com/webmproject/CrabbyAvif.git' + '@' + Var('crabbyavif_revision'), + +diff --git a/third_party/libavif/BUILD.gn b/third_party/libavif/BUILD.gn +new file mode 100644 +index 0000000000000..c2cc9e2d9fd87 +--- /dev/null ++++ b/third_party/libavif/BUILD.gn +@@ -0,0 +1,172 @@ ++# Copyright 2020 The Chromium Authors ++# Use of this source code is governed by a BSD-style license that can be ++# found in the LICENSE file. ++ ++import("//media/media_options.gni") ++import("//testing/libfuzzer/fuzzer_test.gni") ++ ++# Public configuration exported to users of the libavif target. ++config("avif_public_config") { ++ if (is_component_build) { ++ defines = [ "AVIF_DLL" ] ++ } ++} ++ ++# Private configuration used in building libavif. ++config("avif_config") { ++ include_dirs = [ "src/include/" ] ++ defines = [ "AVIF_LIBYUV_ENABLED" ] ++ if (is_component_build) { ++ defines += [ "AVIF_BUILDING_SHARED_LIBS" ] ++ } ++ ++ if (enable_dav1d_decoder) { ++ include_dirs += [ "../dav1d/libdav1d/include/" ] ++ defines += [ "AVIF_CODEC_DAV1D" ] ++ } ++} ++ ++libavif_decoder_sources = [ ++ "src/include/avif/internal.h", ++ "src/src/alpha.c", ++ "src/src/avif.c", ++ "src/src/colr.c", ++ "src/src/colrconvert.c", ++ "src/src/diag.c", ++ "src/src/exif.c", ++ "src/src/gainmap.c", ++ "src/src/io.c", ++ "src/src/mem.c", ++ "src/src/obu.c", ++ "src/src/properties.c", ++ "src/src/rawdata.c", ++ "src/src/read.c", ++ "src/src/reformat.c", ++ "src/src/reformat_libsharpyuv.c", ++ "src/src/reformat_libyuv.c", ++ "src/src/scale.c", ++ "src/src/stream.c", ++ "src/src/utils.c", ++] ++ ++component("libavif") { ++ public = [ "src/include/avif/avif.h" ] ++ public_configs = [ ":avif_public_config" ] ++ ++ sources = libavif_decoder_sources ++ ++ configs += [ ":avif_config" ] ++ ++ deps = [ "//third_party/libyuv" ] ++ ++ if (enable_dav1d_decoder) { ++ sources += [ "src/src/codec_dav1d.c" ] ++ deps += [ "//third_party/dav1d" ] ++ } ++} ++ ++# Note only the decoder fuzzers are enabled as only the decoder is being used ++# in Chrome. avif_fuzztest_read_image is not enabled due to libpng not having ++# PNG_READ_iTXt_SUPPORTED enabled. ++config("avif_fuzztest_config") { ++ include_dirs = [ ++ "src/include", ++ "src/apps/shared", ++ ] ++} ++ ++# This is used to satisfy dependencies in avif_fuzztest_helpers. The encoder ++# functions are not used. ++component("libavif_enc") { ++ public = [ "src/include/avif/avif.h" ] ++ public_configs = [ ":avif_public_config" ] ++ ++ sources = libavif_decoder_sources + [ ++ "src/src/write.c", ++ ] ++ testonly = true ++ ++ configs += [ ":avif_config" ] ++ ++ deps = [ ++ "//third_party/libwebp:libwebp_sharpyuv", ++ "//third_party/libyuv", ++ ] ++ defines = [ "AVIF_LIBSHARPYUV_ENABLED" ] ++ ++ if (enable_dav1d_decoder) { ++ sources += [ "src/src/codec_dav1d.c" ] ++ deps += [ "//third_party/dav1d" ] ++ } ++} ++ ++source_set("avif_apps_shared") { ++ sources = [ ++ "avif_apps_shared_stubs.c", ++ "src/apps/shared/avifexif.c", ++ "src/apps/shared/avifexif.h", ++ "src/apps/shared/avifjpeg.h", ++ "src/apps/shared/avifpng.h", ++ "src/apps/shared/avifutil.c", ++ "src/apps/shared/avifutil.h", ++ "src/apps/shared/y4m.c", ++ "src/apps/shared/y4m.h", ++ ] ++ testonly = true ++ configs += [ ":avif_fuzztest_config" ] ++ deps = [ ":libavif_enc" ] ++} ++ ++source_set("avif_fuzztest_helpers") { ++ sources = [ ++ "src/tests/gtest/avif_fuzztest_helpers.cc", ++ "src/tests/gtest/avifincrtest_helpers.cc", ++ "src/tests/gtest/aviftest_helpers.cc", ++ ] ++ testonly = true ++ configs += [ ":avif_fuzztest_config" ] ++ deps = [ ++ ":avif_apps_shared", ++ ":libavif_enc", ++ "//testing/gtest", ++ "//third_party/fuzztest:fuzztest", ++ ] ++} ++ ++# TODO: b/308013905 - These tests require seeds from ++# third_party/libavif/src/tests/data which ++# aren't available in the fuzzing environment. These targets can be enabled if ++# they are made hermetic. ++# ++# test("avif_fuzztest_dec") { ++# sources = [ "src/tests/gtest/avif_fuzztest_dec.cc" ] ++# fuzztests = [ "DecodeAvifTest.Decode" ] ++# configs += [ ":avif_fuzztest_config" ] ++# deps = [ ++# ":avif_fuzztest_helpers", ++# ":libavif_enc", ++# "//third_party/fuzztest:fuzztest_gtest_main", ++# ] ++# } ++# ++# test("avif_fuzztest_dec_incr") { ++# sources = [ "src/tests/gtest/avif_fuzztest_dec_incr.cc" ] ++# fuzztests = [ "DecodeAvifFuzzTest.DecodeIncr" ] ++# configs += [ ":avif_fuzztest_config" ] ++# deps = [ ++# ":avif_fuzztest_helpers", ++# ":libavif_enc", ++# "//third_party/fuzztest:fuzztest_gtest_main", ++# ] ++# } ++ ++test("avif_fuzztest_yuvrgb") { ++ sources = [ "src/tests/gtest/avif_fuzztest_yuvrgb.cc" ] ++ fuzztests = [ "YuvRgbFuzzTest.Convert" ] ++ configs += [ ":avif_fuzztest_config" ] ++ deps = [ ++ ":avif_fuzztest_helpers", ++ ":libavif_enc", ++ "//third_party/fuzztest:fuzztest_gtest_main", ++ ] ++} +diff --git a/third_party/libavif/DIR_METADATA b/third_party/libavif/DIR_METADATA +new file mode 100644 +index 0000000000000..beadfa62dc3ad +--- /dev/null ++++ b/third_party/libavif/DIR_METADATA +@@ -0,0 +1,6 @@ ++monorail: { ++ component: "Internals>Images>Codecs" ++} ++buganizer_public: { ++ component_id: 1456316 ++} +diff --git a/third_party/libavif/OWNERS b/third_party/libavif/OWNERS +new file mode 100644 +index 0000000000000..6946c0b7788b5 +--- /dev/null ++++ b/third_party/libavif/OWNERS +@@ -0,0 +1,2 @@ ++file://media/OWNERS ++wtc@google.com +diff --git a/third_party/libavif/README.chromium b/third_party/libavif/README.chromium +new file mode 100644 +index 0000000000000..81904b69c35c5 +--- /dev/null ++++ b/third_party/libavif/README.chromium +@@ -0,0 +1,13 @@ ++Name: libavif - Library for encoding and decoding .avif files ++Short Name: libavif ++URL: https://github.com/AOMediaCodec/libavif ++Version: N/A ++Revision: DEPS ++License: BSD-2-Clause, MIT ++License File: src/LICENSE ++Security Critical: yes ++Shipped: yes ++ ++Description: ++This contains the source to the AV1 image format demuxer; used for demuxing and ++decoding .avif files in Chromium. +diff --git a/third_party/libavif/avif_apps_shared_stubs.c b/third_party/libavif/avif_apps_shared_stubs.c +new file mode 100644 +index 0000000000000..18980cbc5b0b5 +--- /dev/null ++++ b/third_party/libavif/avif_apps_shared_stubs.c +@@ -0,0 +1,50 @@ ++// 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. ++ ++// This file provides functions necessary to link the decoder fuzz tests. The ++// functions are not used by the tests being built, but their dependencies in ++// apps/shared and avif_*_helpers.cc unconditionally reference them. ++ ++#include ++ ++#include "src/apps/shared/avifjpeg.h" ++#include "src/apps/shared/avifpng.h" ++ ++avifBool avifJPEGRead(const char * inputFilename, ++ avifImage * avif, ++ avifPixelFormat requestedFormat, ++ uint32_t requestedDepth, ++ avifChromaDownsampling chromaDownsampling, ++ avifBool ignoreColorProfile, ++ avifBool ignoreExif, ++ avifBool ignoreXMP, ++ avifBool ignoreGainMap, ++ uint32_t imageSizeLimit) { ++ fprintf(stderr, "The tests were built without JPEG support!\n"); ++ return AVIF_FALSE; ++} ++ ++avifBool avifPNGRead(const char * inputFilename, ++ avifImage * avif, ++ avifPixelFormat requestedFormat, ++ uint32_t requestedDepth, ++ avifChromaDownsampling chromaDownsampling, ++ avifBool ignoreColorProfile, ++ avifBool ignoreExif, ++ avifBool ignoreXMP, ++ avifBool allowChangingCicp, ++ uint32_t imageSizeLimit, ++ uint32_t * outPNGDepth) { ++ fprintf(stderr, "The tests were built without PNG support!\n"); ++ return AVIF_FALSE; ++} ++ ++avifBool avifPNGWrite(const char * outputFilename, ++ const avifImage * avif, ++ uint32_t requestedDepth, ++ avifChromaUpsampling chromaUpsampling, ++ int compressionLevel) { ++ fprintf(stderr, "The tests were built without PNG support!\n"); ++ return AVIF_FALSE; ++} +diff --git a/third_party/libavif/src b/third_party/libavif/src +new file mode 160000 +index 0000000000000..e7b34a1f5e9f7 +--- /dev/null ++++ b/third_party/libavif/src +@@ -0,0 +1 @@ ++Subproject commit e7b34a1f5e9f7024d08311c7bae156061b889882 diff --git a/meta-chromium/recipes-browser/chromium/files/0011-Disable-crabbyavif-to-fix-build-errors.patch b/meta-chromium/recipes-browser/chromium/files/0016-Disable-crabbyavif-to-fix-build-errors.patch similarity index 100% rename from meta-chromium/recipes-browser/chromium/files/0011-Disable-crabbyavif-to-fix-build-errors.patch rename to meta-chromium/recipes-browser/chromium/files/0016-Disable-crabbyavif-to-fix-build-errors.patch diff --git a/meta-chromium/recipes-browser/chromium/files/0017-rust-Use-adler-instead-of-adler2.patch b/meta-chromium/recipes-browser/chromium/files/0017-rust-Use-adler-instead-of-adler2.patch new file mode 100644 index 000000000..6cae0abc0 --- /dev/null +++ b/meta-chromium/recipes-browser/chromium/files/0017-rust-Use-adler-instead-of-adler2.patch @@ -0,0 +1,38 @@ +From d1d686cb5cebca571cb9eafc5a3cabff6971ddb6 Mon Sep 17 00:00:00 2001 +From: Ariel D'Alessandro +Date: Sat, 26 Apr 2025 17:19:24 -0300 +Subject: [PATCH] rust: Use adler instead of adler2 + +Upstream Rust replaced adler with adler2, for older versions of Rust we still +need to tell GN that we have the older lib when it tries to copy the Rust +sysroot into the bulid directory. + +It looks that in rust-1.85.0, `adler` has not yet been replaced with `adler2`. +Therefore, the condition should likely be adjusted. + +This patch will be dropped once Rust >= 1.86.0 is available, which +replaced adler with adler2. + +Note that currently layer provides Rust version `1.85.1`. + +[0] https://git.yoctoproject.org/meta-lts-mixins/log/?h=scarthgap/rust + +Upstream-Status: Inappropriate [specific to older versions of rust] +Signed-off-by: Ariel D'Alessandro +--- + build/rust/std/BUILD.gn | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/build/rust/std/BUILD.gn b/build/rust/std/BUILD.gn +index 7f64198b9f..d29e3466b1 100644 +--- a/build/rust/std/BUILD.gn ++++ b/build/rust/std/BUILD.gn +@@ -89,7 +89,7 @@ if (toolchain_has_rust) { + # These are no longer present in the Windows toolchain. + stdlib_files += [ + "addr2line", +- "adler2", ++ "adler", + "gimli", + "libc", + "memchr", diff --git a/meta-chromium/recipes-browser/chromium/gn-native_132.0.6834.83.bb b/meta-chromium/recipes-browser/chromium/gn-native_136.0.7103.113.bb similarity index 100% rename from meta-chromium/recipes-browser/chromium/gn-native_132.0.6834.83.bb rename to meta-chromium/recipes-browser/chromium/gn-native_136.0.7103.113.bb From 0d82376f7bcaecc693f56f83651200633d48c61e Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 2 Nov 2023 00:21:12 +0100 Subject: [PATCH 4/4] chromium: Add v4l2 m2m stateless decode configuration options Add configuration options to enable hardware video decoding using stateless V4L2 M2M device. This allows offloading e.g. h264 video playback to Hantro VPU on i.MX8MP where this was tested. To make that work, enable 'use-v4l2' and 'proprietary-codecs' PACKAGECONFIG. This commit was implemented with much great help from Jianfeng Liu . Signed-off-by: Marek Vasut --- meta-chromium/recipes-browser/chromium/chromium-gn.inc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/meta-chromium/recipes-browser/chromium/chromium-gn.inc b/meta-chromium/recipes-browser/chromium/chromium-gn.inc index e8cee463f..15c6bbf4b 100644 --- a/meta-chromium/recipes-browser/chromium/chromium-gn.inc +++ b/meta-chromium/recipes-browser/chromium/chromium-gn.inc @@ -123,7 +123,7 @@ BUILD_CC:toolchain-clang = "clang" BUILD_CXX:toolchain-clang = "clang++" BUILD_LD:toolchain-clang = "clang" -PACKAGECONFIG ??= "upower use-egl" +PACKAGECONFIG ??= "upower use-egl use-v4l2" # this makes sure the dependencies for the EGL mode are present; otherwise, the configure scripts # automatically and silently fall back to GLX @@ -157,6 +157,10 @@ PACKAGECONFIG[upower] = ",,,upower" # but remember to also use proprietary codecs so that H.264 is supported. Also note # that not all the hardware configs might be supported. PACKAGECONFIG[use-vaapi] = "use_vaapi=true use_libgav1_parser=true,use_vaapi=false,libva" +# Enable stateless V4L2 M2M video decoding support. +# This requires 'proprietary-codecs' PACKAGECONFIG +# to decode h264 streams on the V4L2 M2M device. +PACKAGECONFIG[use-v4l2] = "use_v4l2_codec=true,use_v4l2_codec=false" # Base GN arguments, mostly related to features we want to enable or disable. GN_ARGS = " \ @@ -374,6 +378,7 @@ CHROMIUM_EXTRA_ARGS ?= " \ ${@bb.utils.contains('PACKAGECONFIG', 'use-egl', '--use-angle=gles-egl', '', d)} \ ${@bb.utils.contains('PACKAGECONFIG', 'kiosk-mode', '--kiosk --no-first-run --incognito', '', d)} \ ${@bb.utils.contains('PACKAGECONFIG', 'gtk4', '--gtk-version=4', '', d)} \ + ${@bb.utils.contains('PACKAGECONFIG', 'use-v4l2', '--ozone-platform-hint=wayland --enable-features=AcceleratedVideoDecoder,AcceleratedVideoDecodeLinuxGL,AcceleratedVideoDecodeLinuxZeroCopyGL', '', d)} \ " # V8's JIT infrastructure requires binaries such as mksnapshot and