From 804e85265e63a81796c4e9a34a4f390eb5b6f8b4 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Wed, 29 May 2024 18:24:41 -0400 Subject: [PATCH] LibGfx/WebPWriter: Use an IsOpaque struct for tracking opacity No behavior change, but this makes it easy to correctly set this flag when adding an indexing transform: Opacity then needs to be determined based on if colors in the color table have opacity, not if the indexes into the color table do. With this struct, only the first time something sets opacity is honored, giving us those semantics. --- .../ImageFormats/WebPWriterLossless.cpp | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/Userland/Libraries/LibGfx/ImageFormats/WebPWriterLossless.cpp b/Userland/Libraries/LibGfx/ImageFormats/WebPWriterLossless.cpp index 47704d3c117..b7fa52d2aa4 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/WebPWriterLossless.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/WebPWriterLossless.cpp @@ -18,6 +18,23 @@ namespace Gfx { +namespace { + +struct IsOpaque { + bool is_fully_opaque { false }; + bool is_opacity_known { false }; + + void set_is_fully_opaque_if_not_yet_known(bool is_fully_opaque) + { + if (is_opacity_known) + return; + this->is_fully_opaque = is_fully_opaque; + is_opacity_known = true; + } +}; + +} + NEVER_INLINE static ErrorOr write_image_data(LittleEndianOutputBitStream& bit_stream, Bitmap const& bitmap, PrefixCodeGroup const& prefix_code_group) { // This is currently the hot loop. Keep performance in mind when you change it. @@ -213,7 +230,7 @@ static ErrorOr write_normal_code_lengths(LittleEndianOutputBitStr return CanonicalCode::from_bytes(bit_lengths.span().trim(code_count)); } -static ErrorOr write_VP8L_coded_image(ImageKind image_kind, LittleEndianOutputBitStream& bit_stream, Bitmap const& bitmap, bool& is_fully_opaque) +static ErrorOr write_VP8L_coded_image(ImageKind image_kind, LittleEndianOutputBitStream& bit_stream, Bitmap const& bitmap, IsOpaque& is_fully_opaque) { // https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification#5_image_data // spatially-coded-image = color-cache-info meta-prefix data @@ -291,7 +308,7 @@ static ErrorOr write_VP8L_coded_image(ImageKind image_kind, LittleEndianOu prefix_code_group[i] = TRY(write_normal_code_lengths(bit_stream, code_lengths[i], alphabet_sizes[i])); if (i == 3) - is_fully_opaque = non_zero_symbol_count == 1 && symbols[0] == 0xff; + is_fully_opaque.set_is_fully_opaque_if_not_yet_known(non_zero_symbol_count == 1 && symbols[0] == 0xff); } // For code #5, use a simple empty code, since we don't use this yet. @@ -303,7 +320,7 @@ static ErrorOr write_VP8L_coded_image(ImageKind image_kind, LittleEndianOu return {}; } -static ErrorOr write_VP8L_image_data(Stream& stream, Bitmap const& bitmap, bool& is_fully_opaque) +static ErrorOr write_VP8L_image_data(Stream& stream, NonnullRefPtr bitmap, IsOpaque& is_fully_opaque) { LittleEndianOutputBitStream bit_stream { MaybeOwned(stream) }; @@ -323,7 +340,10 @@ static ErrorOr write_VP8L_image_data(Stream& stream, Bitmap const& bitmap, ErrorOr compress_VP8L_image_data(Bitmap const& bitmap, bool& is_fully_opaque) { AllocatingMemoryStream vp8l_data_stream; - TRY(write_VP8L_image_data(vp8l_data_stream, bitmap, is_fully_opaque)); + IsOpaque is_opaque_struct; + TRY(write_VP8L_image_data(vp8l_data_stream, bitmap, is_opaque_struct)); + VERIFY(is_opaque_struct.is_opacity_known); + is_fully_opaque = is_opaque_struct.is_fully_opaque; return vp8l_data_stream.read_until_eof(); }