This introduces a new API in ImageDecoderPlugins that allow an image
decoder to return a CICP struct. Also, we use this API in
ImageDecoder::color_space() to create a color space corresponding to
these CICP.
We have to be careful to always destroy the jpeglib decompression struct
before returning from JPEGLoadingContext::decode. We were doing this in
jpeglib error handlers, but we have a couple of paths that bail from the
decoder via TRY. These paths were neither cleaning up memory nor setting
the image decoder to an error state.
So this patch sets up a scope guard to ensure we free the decompressor
upon exit from the function. And it delegates the responsibility of
setting the decoder state to the caller (of which there is only one),
to ensure all error paths result in an error state.
If we have a valid PNG header with geometry info etc, we should still
display it as *something*, even if the image data itself is missing or
corrupted.
This matches the behavior of other browsers, and is something that
Cloudflare Turnstile checks for.
To achieve this, we split the PNG decoder's initialization into two
steps: "everything except reading frame data" and "reading frame data".
If the latter step fails, we yield a transparent bitmap with the
geometry from the PNG's IHDR chunk.
Before, libpng would use its own internal logging mechanism to print
non-fatal errors and warnings to stdout/stderr. This made it confusing
when trying to search the Ladybird codebase for those messages as they
didn't exist.
This commit uses `png_set_error_fn` from libpng to redirect those
messages to our own custom logging functions instead.
This patch introduces the `Gfx::ColorSpace` class, this is basically a
serializable wrapper for skia's SkColorSpace. Creation of the instances
of this class (and thus ICC profiles parsing) is performed in the
ImageDecoder process. Then the object is serialized and sent through
IPC, to finally be handed to skia for rendering.
However, to make sure that we're not making all LibGfx's users dependent
on Skia as well, we need to ensure the `Gfx::ColorSpace` object has no
dependency on objects from Skia. To that end, the only member of the
`ColorSpace` class is the opaque `ColorSpaceImpl` struct. Though, there
is on issue with that design, the code in `DisplayListPlayer.cpp` needs
access to the underlying `sk_sp<SkColorSpace>`. It is provided by a
template function, that is only specialized for this type.
Doing this work allows us to pass the following WPT tests:
- https://wpt.live/css/css-color/tagged-images-001.html
- https://wpt.live/css/css-color/tagged-images-003.html
- https://wpt.live/css/css-color/tagged-images-004.html
- https://wpt.live/css/css-color/untagged-images-001.html
Other test cases can also be found here:
- https://github.com/svgeesus/PNG-ICC-tests
Note that SkColorSpace support quite a limited amount of color spaces,
so color profiles like the ones in [1] or the v4 profiles in [2] are not
supported yet. In fact, SkColorSpace only accepts skcms_ICCProfile with
a linear conversion to XYZ D50.
[1] https://www.color.org/browsertest.xalter
[2] https://www.color.org/version4html.xalter