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.
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.
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
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.
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