From d419ddf30436e62a6e79441c1c02af1dae686681 Mon Sep 17 00:00:00 2001 From: Ariel D'Alessandro Date: Fri, 25 Apr 2025 12:44:49 -0300 Subject: [PATCH] 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 * 0018-third_party-node-update_node_binaries-Update-nodejs-.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 --- .../recipes-browser/chromium/chromium-gn.inc | 28 +- ... 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 + ...-update_node_binaries-Update-nodejs-.patch | 27 + ...6834.83.bb => gn-native_136.0.7103.113.bb} | 0 23 files changed, 4456 insertions(+), 629 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 create mode 100644 meta-chromium/recipes-browser/chromium/files/0018-third_party-node-update_node_binaries-Update-nodejs-.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/recipes-browser/chromium/chromium-gn.inc b/meta-chromium/recipes-browser/chromium/chromium-gn.inc index 98716ad3a..b2e7cc5b0 100644 --- a/meta-chromium/recipes-browser/chromium/chromium-gn.inc +++ b/meta-chromium/recipes-browser/chromium/chromium-gn.inc @@ -25,12 +25,24 @@ 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 \ + file://0018-third_party-node-update_node_binaries-Update-nodejs-.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 +487,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 ${UNPACKDIR}/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/files/0018-third_party-node-update_node_binaries-Update-nodejs-.patch b/meta-chromium/recipes-browser/chromium/files/0018-third_party-node-update_node_binaries-Update-nodejs-.patch new file mode 100644 index 000000000..30a9206b9 --- /dev/null +++ b/meta-chromium/recipes-browser/chromium/files/0018-third_party-node-update_node_binaries-Update-nodejs-.patch @@ -0,0 +1,27 @@ +From 6e3d91964a64dbacfddc4c7a38c64fd221fcdd2b Mon Sep 17 00:00:00 2001 +From: Ariel D'Alessandro +Date: Wed, 16 Jul 2025 18:44:44 -0300 +Subject: [PATCH] update_node_binaries: Update nodejs version to v22.15.0 + +Update the NodeJS version to match exactly the one shipped in these +images. + +Upstream-Status: Inappropriate [specific to our build setup] +Signed-off-by: Ariel D'Alessandro +--- + third_party/node/update_node_binaries | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/third_party/node/update_node_binaries b/third_party/node/update_node_binaries +index 4aab805844..5c3714f574 100755 +--- a/third_party/node/update_node_binaries ++++ b/third_party/node/update_node_binaries +@@ -19,7 +19,7 @@ set -eu + cd "$(dirname "$0")" + + BASE_URL="https://nodejs.org/dist" +-NODE_VERSION="v22.11.0" ++NODE_VERSION="v22.15.0" + + upload=false # Default value + 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