Commit graph

429 commits

Author SHA1 Message Date
Andreas Kling
9164c9784d LibGfx: Treat PNG files with invalid frame data as transparent
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.
2024-12-19 16:49:28 +01:00
Andreas Kling
f44166ebd0 LibGfx: Allow IPC encode/decode of empty BitmapSequence
This would fail with EINVAL earlier, due to an attempt to create a
zero-length Core::AnonymousBuffer.

We fix this by transferring the buffer length separately, and only
going down the AnonymousBuffer allocation path if the length is
non-zero.
2024-12-19 16:49:28 +01:00
Lucien Fiorini
26970201bd LibGfx: Fix color opacity regression in Canvas2D
The color alpha was being overwritten by the global alpha instead of
being multiplied.
2024-12-19 13:31:12 +01:00
Lucien Fiorini
97768d8927 LibGfx: Fix dynamic_cast undefined behavior on macOS
MacOS XCode 16 breaks dynamic_cast on final classes where the base
class has a has a virtual destructor defined in the header, which
creates a different virtual table per translation unit.
This is probably a regression in Apple's Clang that causes final
classes to be incorrectly aggressively optimized.
https://stackoverflow.com/questions/79192304/macos-xcode-16-breaks-dynamic-cast-for-final-types-defined-in-shared-library
2024-12-18 18:54:20 +01:00
Lucien Fiorini
a6ef6550f3 LibWeb+LibGfx: Implement Canvas2D filters 2024-12-18 18:54:20 +01:00
Lucien Fiorini
9fd1223992 LibWeb+LibGfx: Refactor CSS filters into LibGfx
CSS filters work similarly to canvas filters, so it makes sense to have
Gfx::Filter that can be used by both libraries in an analogous way
as Gfx::Color.
2024-12-18 18:54:20 +01:00
Johan Dahlin
083f4f3d08 LibWeb: Layout/Shape font-variant-* css properties 2024-12-17 19:07:13 +01:00
Johan Dahlin
1c42d6831b LibWeb: Style font-variant-* css properties 2024-12-17 19:07:13 +01:00
Lucas CHOLLET
2174e5dfcc LibGfx: Remove ICC::Profile and friends
This is not really used anymore since the fork.
2024-12-16 07:39:49 +01:00
Aaron Van Doren
5c4e162ba9 LibGfx: Implement even-odd method for Quad::contains() and add tests 2024-12-15 23:27:42 +01:00
Pavel Shliak
ea469fbeab LibGfx: Let Painter care about TinyVG transforms
This helps us with non-uniform scales, and makes things simple
2024-12-14 23:29:43 +01:00
Pavel Shliak
6dfcdaa0d2 LibGfx: Unify bitmap set_pixel() using templates 2024-12-12 15:13:44 -07:00
Pavel Shliak
24b68259b4 LibGfx: Remove unnecessary include 2024-12-12 15:13:44 -07:00
rmg-x
e4fb25bf63 LibGfx: Redirect PNG errors and warnings to our own logging functions
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.
2024-12-10 11:58:58 -07:00
Pavel Shliak
116e7baead LibGfx: Remove aligned_within from Rect
The CenterRight and TopCenter alignment cases were
mistakenly identical due to a copy-paste error,
causing the function to behave unexpectedly.
Rather than attempting to fix it, remove aligned_within entirely.
2024-12-08 13:32:10 +00:00
Lucien Fiorini
beb621665f LibGfx: Add missing return and fix center of radial gradients 2024-12-06 20:21:57 +01:00
Lucas CHOLLET
bd93285811 LibGfx+LibWeb: Do some color management on images with an ICC profile
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
2024-12-05 17:16:41 +01:00
Lucas CHOLLET
8f8ec146a1 LibGfx: Explicitly set color space of SkImages
If not set, when copying pixels into the SkImage, skia assumes that the
color space is the same as the input, so no transformation is done. We
are currently setting the color space to sRGB, this is fine for now as
it allows us to start making some transformations, but down the road we
will want to set that to the actual output's display color space.
2024-12-05 17:16:41 +01:00
Lucas CHOLLET
407aa629a0 LibGfx: Make PaintingSurface::write_from_bitmap take a Bitmap const&
It makes it a little bit easier to distinguish which one of
read_into_bitmap and write_from_bitmap actually modify the Bitmap that
was passed to the method. NFC.
2024-12-05 17:16:41 +01:00
Lucas CHOLLET
50b978fefb LibGfx: Move BMP's ColorSpace definition into a BMP namespace 2024-12-05 17:16:41 +01:00
Lucien Fiorini
e8cc0dc998 LibWeb+LibGfx: Implement shadowBlur for Canvas2D 2024-12-05 17:07:13 +01:00
Pavel Shliak
ede0dbafc6 AK: Remove Statistics.h
This also removes MedianCut and GIFWriter
2024-12-05 16:53:28 +01:00
Psychpsyo
1881a8df4b LibGfx: Set png interlace handling on interlaced images 2024-12-04 20:29:15 +00:00
Aliaksandr Kalenik
46cbbda944 LibWeb: Increase SkSurface's generation id when it's modified by WebGL
Skia is not aware of surface modifications done by WebGL, so we need to
manually increase generation id whenver WebGL invokes a writing
function.
2024-12-03 23:35:45 +01:00
Aliaksandr Kalenik
45e0f50463 LibWeb: Flip vertically PaintingSurface attached to WebGL context
OpenGL's origin is at the bottom-left corner, while Skia's origin is at
the top-left corner. This change adds a transformation to compensate for
this difference when rendering PaintingSurface attached to WebGL
context.
2024-12-03 23:35:45 +01:00
Aliaksandr Kalenik
e683700fe6 LibWeb: Allow construction of PaintingSurface directly from IOSurface
Previously, constructing a PaintingSurface from an IOSurface required
wrapping IOSurface into a Metal texture before passing it to the
PaintingSurface constructor. This process was cumbersome, as the caller
needed access to a MetalContext to perform the wrapping.

With this change SkiaBackendContext maintains a reference to the
MetalContext which makes it possible to do:
IOSurface -> MetalTexture -> SkSurface within a PaintingSurface
constructor.
2024-12-03 23:35:45 +01:00
Pavel Shliak
af9d855b70 LibGfx: Delete DeprecatedPath 2024-11-25 21:13:53 +01:00
Pavel Shliak
dbfe5be9ff LibGfx: Delete DeprecatedPainter 2024-11-25 21:13:53 +01:00
Pavel Shliak
39c500ec7c LibGfx: Use Skia for TinyVG rendering 2024-11-25 12:14:24 +01:00
Psychpsyo
b22341fc77 LibGfx: Support AVIF images with missing pixi property 2024-11-23 03:57:54 +00:00
Pavel Shliak
1c733993e0 LibGfx: Do not provide BPP 2024-11-22 15:05:46 +01:00
Nico Weber
f4b0d17e4b LibWeb: Plumb svg stroking state to DisplayListPlayerSkia
The state is still ignored there, so no behavior change, but this
should make it fairly easy to actually implement complete stroking
support for SVGs.
2024-11-22 12:21:29 +01:00
Borna Lang
201648485f LibGfx: Reimplement from_hsla
- Hue now wraps properly when negative or larger than 360
- The hsl to rgb conversion now closely mirrors the code example from
  the spec.

This fixes a number of WPT tests in
/css/css-color/parsing/color-computed-hsl.html
2024-11-22 12:10:30 +01:00
Pavel Shliak
b60cb699a9 LibMedia: Clean up #include directives
This change aims to improve the speed of incremental builds.
2024-11-21 14:08:33 +01:00
Lucas CHOLLET
248e4bb517 LibGfx: Round values in Color::with_opacity()
`svg-gradient-userSpaceOnUse` is now rendered to something closer to
what firefox does, so it is at least some progress.
2024-11-21 11:59:44 +00:00
Lucas CHOLLET
b4ba65c6e5 LibGfx: Round values in Color::from_hsv() 2024-11-21 11:59:44 +00:00
Pavel Shliak
8a07131229 LibGfx: Clean up #include directives
We actually include what we use where we use it.
This change aims to improve the speed of incremental builds.
2024-11-20 21:13:23 +01:00
Jonne Ransijn
ec5ea0d686 LibGfx: Return family names by reference to avoid unnecessairy cloning 2024-11-20 15:38:03 +01:00
Pavel Shliak
ed409eacf5 LibGfx: Remove unused Bitmap loaders 2024-11-19 21:48:45 +01:00
Pavel Shliak
ed80e929e5 LibGfx: Sync to_skia_color_type 2024-11-18 19:17:51 +01:00
Lucas CHOLLET
6affbf78c2 LibGfx: Adjust matrices for XYZ -> sRGB conversions
TL;DR: There are two available sets of coefficients for the conversion
matrices from XYZ to sRGB. We switched from one set to the other, which
is what the WPT tests are expecting.

All RGB color spaces, like display-p3 or rec2020, are defined by their
three color chromacities and a white point. This is also the case for
the video color space Rec. 709, from which the sRGB color space is
derived. The sRGB specification is however a bit different.

In 1996, when formalizing the sRGB spec the authors published a draft
that is still available here [1]. In this document, they also provide
the matrix to convert from the XYZ color space to sRGB. This matrix can
be verified quite easily by using the usual math equations. But hold on,
here come the plot twist: at the time of publication, the spec contained
a different matrix than the one in the draft (the spec is obviously
behind a pay wall, but the numbers are also reported in this official
document [2]). This official matrix, is at a first glance simply a
wrongly rounded version of the one in the draft publication. It however
has some interesting properties: it can be inverted twice (so a
roundtrip) in 8 bits and not suffer from any errors from the
calculations.

So, we are here with two versions of the XYZ -> sRGB matrix, the one
from the spec, which is:
 - better for computations in 8 bits,
 - and official. This is the one that, by authority, we should use.
And a second version, that can be found in the draft, which:
 - makes sense, as directly derived from the chromacities,
 - is publicly available,
 - and (thus?) used in most places.

The old coefficients were the one from the spec, this commit change them
for the one derived from the mathematical formulae. The Python script to
compute these values is available at the end of the commit description.

More details about this subject can be found here [3].

[1] https://www.w3.org/Graphics/Color/sRGB.html
[2] https://color.org/chardata/rgb/sRGB.pdf
[3] https://photosauce.net/blog/post/making-a-minimal-srgb-icc-profile-part-3-choose-your-colors-carefully

The Python script:

```python
# http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html

from numpy.typing import NDArray
import numpy as np

### sRGB
# https://www.w3.org/TR/css-color-4/#predefined-sRGB
srgb_r_chromacity = np.array([0.640, 0.330])
srgb_g_chromacity = np.array([0.300, 0.600])
srgb_b_chromacity = np.array([0.150, 0.060])
##

## White points
white_point_d50 = np.array([0.345700, 0.358500])
white_point_d65 = np.array([0.312700, 0.329000])
#

r_chromacity = srgb_r_chromacity
g_chromacity = srgb_g_chromacity
b_chromacity = srgb_b_chromacity
white_point = white_point_d65

def tristmimulus_vector(chromacity: NDArray) -> NDArray:
    return np.array([
        chromacity[0] /chromacity[1],
        1,
        (1 - chromacity[0] - chromacity[1]) / chromacity[1]
    ])

tristmimulus_matrix = np.hstack((
    tristmimulus_vector(r_chromacity).reshape(3, 1),
    tristmimulus_vector(g_chromacity).reshape(3, 1),
    tristmimulus_vector(b_chromacity).reshape(3, 1),
))

scaling_factors = (np.linalg.inv(tristmimulus_matrix) @
                   tristmimulus_vector(white_point))

M = tristmimulus_matrix * scaling_factors

np.set_printoptions(formatter={'float_kind':'{:.6f}'.format})
xyz_65_to_srgb = np.linalg.inv(M)

# http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
# Let's convert from D50 to D65 using the Bradford method.
m_a = np.array([
    [0.8951000, 0.2664000, -0.1614000],
    [-0.7502000, 1.7135000, 0.0367000],
    [0.0389000, -0.0685000, 1.0296000]
])

cone_response_source = m_a @ tristmimulus_vector(white_point_d50)
cone_response_destination = m_a @ tristmimulus_vector(white_point_d65)

cone_response_ratio = cone_response_destination / cone_response_source
m = np.linalg.inv(m_a) @ np.diagflat(cone_response_ratio) @ m_a

D50_to_D65 = m
xyz_50_to_srgb = xyz_65_to_srgb @ D50_to_D65

print(xyz_50_to_srgb)
print(xyz_65_to_srgb)
```
2024-11-17 22:18:40 +01:00
Lucas CHOLLET
63873f3809 LibWeb/CSS: Add support for the rec2020 color space in color()
This color space is often used as a reference in WPT tests, having
support for it makes us pass 15 new tests:
  - css/css-color/rec2020-001.html
  - css/css-color/rec2020-002.html
  - css/css-color/rec2020-003.html
  - css/css-color/rec2020-004.html
  - css/css-color/rec2020-005.html
  - css/css-color/predefined-011.html
  - css/css-color/predefined-012.html
2024-11-16 10:29:46 +01:00
Lucas CHOLLET
2173219eac LibGfx: Fix parameters name of Color::from_linear_srgb
And sort the declarations alphabetically while touching it.
2024-11-16 10:29:46 +01:00
Lucas CHOLLET
0b9c4b8adc LibWeb/CSS: Add support for the prophoto-rgb color space in color()
That makes us pass the following WPT tests:
 - css/css-color/prophoto-rgb-001.html
 - css/css-color/prophoto-rgb-002.html
 - css/css-color/prophoto-rgb-003.html
 - css/css-color/prophoto-rgb-004.html
 - css/css-color/prophoto-rgb-005.html
 - css/css-color/predefined-009.html
 - css/css-color/predefined-010.html
2024-11-16 10:29:46 +01:00
Lucas CHOLLET
596a4e55dd LibWeb/CSS: Add support for the display-p3 color space in color()
This color space is often used as a reference in WPT tests, having
support for it makes us pass 15 new tests:
  - css/css-color/display-p3-001.html
  - css/css-color/display-p3-002.html
  - css/css-color/display-p3-003.html
  - css/css-color/display-p3-004.html
  - css/css-color/display-p3-005.html
  - css/css-color/display-p3-006.html
  - css/css-color/lab-008.html
  - css/css-color/lch-008.html
  - css/css-color/oklab-008.html
  - css/css-color/oklch-008.html
  - css/css-color/predefined-005.html
  - css/css-color/predefined-006.html
  - css/css-color/xyz-005.html
  - css/css-color/xyz-d50-005.html
  - css/css-color/xyz-d65-005.html
2024-11-16 10:29:46 +01:00
Lucas CHOLLET
f949334a9a LibGfx: Use a more explicit formula in Color::from_linear_srgb
NFC. I prefer having the constants expanded, it makes it easier to trace
them back to the initial formula.
2024-11-16 10:29:46 +01:00
Lucas CHOLLET
a59d9a3986 LibWeb/CSS: Add support for the a98-rgb color space in color()
This makes us pass the following WPT tests:
 - css/css-color/a98rgb-001.html
 - css/css-color/a98rgb-002.html
 - css/css-color/a98rgb-003.html
 - css/css-color/a98rgb-004.html
 - css/css-color/predefined-007.html
 - css/css-color/predefined-008.html
2024-11-16 10:29:46 +01:00
Andrew Kaster
9812fac2c3 Meta+LibGfx: Exclude Metal and Vulkan headers from Clang module map
These headers are platform-specific, and shouldn't need to be used by
Swift code anyway.
2024-11-15 10:51:45 -07:00
Tim Ledbetter
b08f12d3e6 LibGfx: Add a method to copy a Bitmap to a PaintingSurface 2024-11-13 14:38:39 +01:00
Aliaksandr Kalenik
7460f0c6e2 LibGfx: Delete unused DisjointRectSet 2024-11-11 02:46:35 +01:00