Commit Graph

9 Commits

Author SHA1 Message Date
Tim Ledbetter
d49a2dcfa1 LibWeb: Implement word-break functionality using UAX#14 line breaking
We now use ICU's line break iterator to determine soft wrap
opportunities, enabling correct line breaking for CJK text.
2026-02-14 16:23:18 -05:00
Andreas Kling
3877026082 LibWeb: Pre-generate items in InlineLevelIterator
Instead of generating items lazily during iteration (and using a
lookahead queue for peeking), we now pre-generate all items upfront
in the constructor.

This allows next() and next_non_whitespace_sequence_width() to be
simple O(1) array accesses instead of doing generation work.

To handle tabs correctly (which need to know the accumulated width of
content before them on the line), we track m_accumulated_width_for_tabs
during pre-generation and reset it on forced breaks.
2026-01-11 11:10:19 +01:00
Andreas Kling
10737e22d1 LibWeb: Pre-generate text chunks in InlineLevelIterator
Instead of lazily generating text chunks via ChunkIterator with a peek
queue that used O(n) take_first() operations, we now pre-generate all
chunks upfront when entering a text node.

This makes chunk access O(1) via simple array indexing, which speeds up
both next() calls and forward lookups for bidi direction resolution.
2026-01-11 11:10:19 +01:00
Callum Law
bbb344d534 LibWeb: Compute font features in ComputedProperties
By doing this in computed properties rather than InlineLevelIterator we
only do it once per element rather than once per text fragment.

Reduces runtime of this process from ~15% to ~0.2% when loading
https://en.wikipedia.org/wiki/2023_in_American_television
2025-11-10 12:11:36 +01:00
Jelle Raaijmakers
9e9db9a9dd LibWeb: Store correct text offsets in PaintableFragment
Previously, we were collapsing whitespace in Layout::TextNode and then
passed the resulting string for further processing through ChunkIterator
-> InlineLevelIterator -> InlineFormattingContext -> LineBuilder ->
LineBoxFragment -> PaintableFragment. Our painting tree is where we deal
with things like range offsets into the underlying text nodes, but since
we modified the original string, the offsets were wrong.

This changes the way we generate fragments:

  * Layout::TextNode no longer collapses whitespace as part of its
    stored "text for rendering", but moves this logic to ChunkIterator
    which splits up this text into separate views whenever whitespace
    needs to be collapsed.

  * Layout::LineBox now only extends the last fragment if its end offset
    is equal to the new fragment's start offset. Otherwise, there's a
    gap caused by collapsing whitespace and we need to generate a
    separate fragment for that in order to have a correct start offset.

Some tests need new baselines because of the fixed start offsets.

Fixes #566.
2025-09-12 15:34:09 -04:00
Jelle Raaijmakers
4a514020e0 LibWeb: Remove unused include from InlineLevelIterator 2025-06-17 17:03:33 +02:00
Johan Dahlin
083f4f3d08 LibWeb: Layout/Shape font-variant-* css properties 2024-12-17 19:07:13 +01:00
Shannon Booth
f87041bf3a LibGC+Everywhere: Factor out a LibGC from LibJS
Resulting in a massive rename across almost everywhere! Alongside the
namespace change, we now have the following names:

 * JS::NonnullGCPtr -> GC::Ref
 * JS::GCPtr -> GC::Ptr
 * JS::HeapFunction -> GC::Function
 * JS::CellImpl -> GC::Cell
 * JS::Handle -> GC::Root
2024-11-15 14:49:20 +01:00
Timothy Flynn
93712b24bf Everywhere: Hoist the Libraries folder to the top-level 2024-11-10 12:50:45 +01:00