Commit Graph

25 Commits

Author SHA1 Message Date
Jelle Raaijmakers
3d2571b46e LibWeb: Implement text-decoration-skip-ink painting
Use Skia's SkTextBlob::getIntercepts() to find where glyph outlines
cross the underline/overline band, then split the decoration line into
segments with gaps around those intersections.
2026-03-26 12:15:36 +00:00
Jelle Raaijmakers
67d822cbbe LibGfx+LibWeb: Implement CanvasTextDrawingStyles.letterSpacing 2026-03-12 17:13:16 +01:00
Jelle Raaijmakers
8654e2caf4 LibWeb: Apply letter-spacing for selection rects and grapheme bounds
Fixes the selection rect on the title text of https://modern-css.com/
being misaligned with the actual characters.
2026-02-17 10:51:48 +01:00
Jelle Raaijmakers
6251f18d9b LibGfx: Add GlyphRun::slice()
Skia does not seem to have an API to easily draw parts of text runs, so
introduce ::slice() with which we can more easily construct spans of
text to render individually in future changes (e.g. ::selection
text-shadow support).
2026-02-06 10:47:50 +00:00
Callum Law
b55023fad3 LibGfx+LibWeb: Resolve font features per font rather than per element
Previously we would resolve font features
(https://drafts.csswg.org/css-fonts-4/#feature-variation-precedence)
per element, while this works for the current subset of the font feature
resolution algorithm that we support, some as yet unimplemented parts
require us to know whether we are resolving against a CSS @font-face
rule, and if so which one (e.g. applying descriptors from the @font-face
rule, deciding which @font-feature-values rules to apply, etc).

To achieve this we store the data required to resolve font features in a
struct and pass that to `FontComputer` which resolves the font features
and stores them with the computed `Font`.

We no longer need to invalidate the font shaping cache when features
change since the features are defined per font (and therefore won't ever
change).
2026-02-02 14:11:43 +00:00
Aliaksandr Kalenik
44d90af3d6 LibGfx+LibWeb: Cache SkTextBlob in GlyphRun
Previously, SkTextBlob was built on every paint in
DisplayListPlayerSkia::draw_glyph_run(), which meant:
- Repeated work when the same display list is painted multiple times
- Glyph arrays were allocated and populated on each paint

Now the blob is built once during display list recording and cached in
GlyphRun.
2026-01-24 15:22:03 +01:00
Andreas Kling
98a1bff615 LibGfx: Avoid guessing HarfBuzz segment properties for ASCII text
For ASCII text, we know the script is Latin and direction is LTR.
Set these properties directly instead of calling
hb_buffer_guess_segment_properties(), which scans the text buffer
to detect script and direction.

For non-ASCII text, use the text_type parameter to set direction
when known (Ltr/Rtl), reducing guesswork to just script detection.
2026-01-11 11:10:19 +01:00
Zaggy1024
1ae7ecc3e9 LibGfx: Free the harfbuzz buffer when measuring text width
I spotted this leak when WebContent was exiting with ASan enabled on a
page with a media element. MediaPaintable calls Gfx::Font::width(),
which calls through to measure_text_width(), which then drops an
hb_buffer_t* without freeing it.
2025-10-03 09:22:22 +02:00
Aliaksandr Kalenik
2cf10981af LibGfx+LibWeb: Implement GlyphRun::bounding_rect()
Allows us to skip painting of glyph runs lying outside of viewport.
2025-09-23 17:55:32 +02:00
Andreas Kling
66601f7d59 LibWeb: Cache results of harfbuzz text shaping
This patch introduces a per-Gfx::Font cache for harfbuzz text shaping
results. As long as the same OpenType features are used, we now cache
the results of harfbuzz shaping, saving massive amounts of time during
text layout.

As an example, it saves multiple seconds when loading the ECMAScript
specification at <https://tc39.es/ecma262>. Before this change, harfbuzz
shaping was taking up roughly 11% of a profile of loading that page.
The cache brings it down to 1.8%.

Note that the cache currently grows unbounded. I've left a FIXME about
adding some limits.
2025-09-21 13:22:38 +02:00
Andreas Kling
3dd700e4de LibWeb: Remove UTF-8 text shaping code path
We now only support the UTF-16 path. (Of course we still handle when
Utf16String is internally optimized with ASCII storage.)
2025-09-21 13:22:38 +02:00
Timothy Flynn
047f521c4c LibGfx+LibWeb: Add some extra fields to glyph run data
We currently have a mixup in LibWeb between code unit offset and glyph
offset during hit testing. These extra fields will allow us to correct
this discrepency.
2025-08-22 14:06:46 +02:00
Callum Law
8a4e9f571f LibWeb: Respect letter-spacing for last glyph of each chunk
Previously we would omit the letter spacing for the end glyph of each
chunk in a misguided attempt to conform to the spec's instruction that
we "really should not append letter spacing to the right or trailing
edge of a line", this behaviour can be removed entirely as other
browsers (Firefox, Chrome) don't implement it either.
2025-08-03 22:23:34 +02:00
Timothy Flynn
0e9b694058 LibGfx: Support UTF-16 text shaping
We can achieve this with templating the string view type, and then just
piping the view into the correct `hb_buffer_add_utf*` API.
2025-07-25 18:16:22 +02:00
Jelle Raaijmakers
df20ac0f3c LibGfx: Optimize Gfx::measure_text_width()
Instead of constructing a GlyphRun, just add the X advances of all
glyphs to determine a text's width.
2025-06-17 17:03:33 +02:00
Jelle Raaijmakers
631c857301 LibGfx: Only determine glyphs info once in TextLayout
We were calling into `hb_buffer_get_glyph_infos()` twice and setting up
an unused `Vector<hb_glyph_info_t>`.
2025-06-17 17:03:33 +02:00
Jelle Raaijmakers
7d1ee3a2fa LibGfx+LibWeb: Perform unchecked appends related to text layout
Use unchecked appends in places where we know for certain the vector has
enough capacity.
2025-06-17 11:55:28 +02:00
Jelle Raaijmakers
6710aa102a LibGfx: Return NonnullRefPtr in Gfx::shape_text()
We always return a glyph run here.
2025-06-17 11:55:28 +02:00
Jelle Raaijmakers
dd4d7d0939 LibGfx: Ensure capacity for glyph runs in TextLayout
We can reserve the capacity for new glyph runs since we already know the
glyph count.
2025-06-13 17:31:18 +02:00
Aliaksandr Kalenik
f6b0851c38 LibGfx+LibWeb: Support per-glyph font fallbacks in canvas text painting
Instead of using the first font from the FontCascadeList for all glyphs
in a text, we perform a text shaping process that finds a suitable font
for each glyph and returns a list of glyph runs, where each glyph run
represents consecutive glyphs using the same font.
2025-04-21 09:51:16 +02:00
Aliaksandr Kalenik
16e883a9a3 LibGfx+LibWeb: Don't include start.x in GlyphRun width
For some reason we were including x offset of start position into glyph
run width. This is not correct and would be revealed by the upcoming
changes.
2025-04-21 09:51:16 +02:00
Andreas Kling
ed5ad267c7 LibWeb: Keep harfbuzz hb_buffer instead of reallocating every time
Easy 1% speed-up on Speedometer 3.
2025-04-19 01:14:02 +02:00
Johan Dahlin
083f4f3d08 LibWeb: Layout/Shape font-variant-* css properties 2024-12-17 19:07:13 +01: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
Timothy Flynn
93712b24bf Everywhere: Hoist the Libraries folder to the top-level 2024-11-10 12:50:45 +01:00