Fixes wpt/png/exif-chunk.html.
At some point there should probably be some mechanism to handle this
outside of the individual decoder plugins. The TIFF decoder seems to
have its own version of this, and as far as I can tell, the JPEG decoder
doesn't handle this at all, even though that's probably the most common
use case for Exif orientations. :^)
We were transforming coordinates for SVG gradients in a pretty
convoluted way: an inverse, unscaled transformation matrix was set up in
order to work around some (old?) technical limitations.
Rework this so the coordinate transformation no longer needs to be
inversed. This fixes gradients with "userSpaceOnUse" for its
gradientUnits attribute, which might cause coordinates to lie outside of
the bounding box of the gradient.
Two tests have updated reference screenshots with minor pixel updates;
this is probably the result of floating point precision improvements by
not inversing the matrix.
One test (svg-text-effects) has a bigger change: the gradient stops seem
to have moved along the text. This does seem to match other browsers
slightly better, so I'm moving forward with this ref update.
The support in LibWeb is quite easy as the previous commits introduced
helpers to support lab-like colors.
Now for the methods in Color:
- The formulas in `from_lab()` are derived from the CIEXYZ to CIELAB
formulas the "Colorimetry" paper published by the CIE.
- The conversion in `from_xyz50()` can be decomposed in multiple steps
XYZ D50 -> XYZ D65 -> Linear sRGB -> sRGB. The two first conversion
are done with a singular matrix operation. This matrix was generated
with a Python script [1].
This commit makes us pass all the `css/css-color/lab-00*.html` WPT
tests (0 to 7 at the time of writing).
[1] Python script used to generate the XYZ D50 -> Linear sRGB
conversion:
```python
import numpy as np
# http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
# First 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]
])
# D50
chromaticities_source = np.array([0.96422, 1, 0.82521])
# D65
chromaticities_destination = np.array([0.9505, 1, 1.0890])
cone_response_source = m_a @ chromaticities_source
cone_response_destination = m_a @ chromaticities_destination
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
# https://en.wikipedia.org/wiki/SRGB#From_CIE_XYZ_to_sRGB
# Then, the matrix to convert to linear sRGB.
xyz_65_to_srgb = np.array([
[3.2406, - 1.5372, - 0.4986],
[-0.9689, + 1.8758, 0.0415],
[0.0557, - 0.2040, 1.0570]
])
# Finally, let's retrieve the final transformation.
xyz_50_to_srgb = xyz_65_to_srgb @ D50_to_D65
print(xyz_50_to_srgb)
```
Handling tabs during text shaping caused issues because we tried to
index 'input_glyph_info' whilst iterating until 'glyph_count' and these
can be different sizes.
The difference is due to when one or more characters get
merged into the same glyph when calling 'input_glyph_info' (see
https://lazka.github.io/pgi-docs/HarfBuzz-0.0/classes/glyph_info_t.html).
We don't want to render tabs as they come up as tofu characters so
instead let's strip them out of the text chunk before starting text
shaping.
The reason we were keeping track of the pre-shaping buffer was to know
where we had tab characters in the input. This is a very strange way of
doing that, but since it broke the web, let's patch it up quickly.
Follow-up to #1870 which broke text layout on many web pages.
This fixes a browser crash as experienced on Wikipedia when encountering
the ≠ entity. As a side-effect, this also affects some tab-align and
-wrap tests.
This will be the first step is making better use of system libraries
like fontconfig and CoreText to load system fonts for use by the UI
process and the CSS style computer.
If the image data to decode is incomplete, e.g. a corrupt image missing
its last scanlines the decoder would previously keep looping for ever.
By breaking out of the loop if no more scanlines were produced we can at
least display the partial image up to that point.
Before this change we were serializing them in a bogus 8-digit hex color
format that isn't actually recognized by HTML.
This code will need more work when we start supporting color spaces
other than sRGB.
There is an issue where gifs with many frames cannot be loaded, as each
bitmap is sent over IPC using a separate file descriptor, and there is
limit on the maximum number of descriptors per IPC message. Thus, trying
to load gifs with more than 64 frames (the current limit) causes the
image decoder process to die.
This commit introduces the BitmapSequence class, which is a thin wrapper
around the type Vector<Optional<NonnullRefPtr<Gfx::Bitmap>>> and
provides an IPC encode/decode routine that collates all bitmap data into
a single buffer so that only a single file descriptor is required per
IPC transfer, even if multiple frames are being sent.
All places where text shaping happens, the callback is used to simply
append a glyph into the end of glyphs vector. This change removes the
callback parameter and makes the text shaping function return a glyph
run.
Instead of asking Skia for the family name every time we're called,
just cache the string once and make subsequent calls fast.
This knocks a 3.2% item off the profile entirely on
https://tailwindcss.com (at least on macOS with the CoreText backend)
This brings back the optimization we had in the old OpenType
implementation where we cache lookup tables for code point / glyph ID
mappings.
This noticeably improves performance on https://tailwindcss.com/ by
knocking an 8% profile item down to 0.2%. :^)
Getting the first font in a font cascade list with an empty font list
results in an OOTB index error. If the font list is empty, the last
resort font should be returned instead.
It would be nice if we could somehow move this work to the GPU, but even
with some basic local optimization (mostly coalescing bounds checks and
inlining pixel data access), this knocks a 13% item down to 9% in a
profile of loading https://vercel.com/
Before this change, we were only checking for actual glyph containment
in a font if unicode ranges were specified. However that is not
sufficient for emoji support, where we want to continue searching for
a font until one containing emojis is found.
This change should move us forward toward emoji support, as we are no
longer limited by our own OpenType implementation, which was failing
to parse the TrueType Collection format used to store emoji fonts
(at least on macOS).
This is a preparation for upcoming changes where Gfx::Typeface will
depend on `FontDatabase::should_force_fontconfig()`, so we will no
longer be able to construct typefaces from FontDatabase constructor
because of circular dependency.
When trying to use pkgconfig for finding libjxl, the build fails
trying to link the cross-compiler's libc++.
Using this way libjxl also requires hwy library.
Findlibjxl.cmake was taken from SDL_image and altered to include its license.