Previously, font selection ignored the Unicode emoji presentation of a
code point. Emoji-capable code points were always resolved through
pre-baked color emoji and symbol fonts. Text-default code points which
lacked the `Emoji_Presentation` property, were therefore rendered as
color emoji rather than text. We now classify each code point's default
presentation from its `Emoji_Presentation` property and any trailing
variation selector.
Move the layout tree from GC allocation to refcounted ownership so
removed layout and paint subtrees are destroyed synchronously instead
of waiting for the next GC sweep. This dramatically reduces GC memory
usage peaks after layout tree churn and makes it easier for memory use
to fall back after large document updates.
Update layout factories, tree traversal, SVG layout node creation,
paintable back-pointers, and pseudo-element layout links to use RefPtr
ownership.
Make display: contents follow the same shape as Blink and WebKit: the
element itself does not create a layout node, and its children are
flattened into the nearest layout parent. Wrap direct non-whitespace
text in an anonymous inline node when the boxless element contributes
inherited style to that text.
Use an internal inline wrapper for display: contents pseudo-elements
so generated content can still participate in layout, painting, hit
testing, and pseudo-element queries. Keep CSSOM reporting the computed
display value from the pseudo style, not the internal wrapper.
Remove the retained out-of-tree layout node list and its testing hook,
since the flattened model does not need a side owner for boxless
elements. Add coverage for inherited text style, dynamic insertion
order, pseudo-element hit testing, and computed style queries.
Stop creating unattached DOM Text nodes for string items in generated
CSS content. These text nodes are layout artifacts, so store their text
directly in a GeneratedTextNode instead of pretending they have DOM
backing.
Teach text shaping and first-letter splitting to read text through the
layout text source while keeping DOM-specific behavior behind an
optional DOM text accessor. This preserves generated first-letter
handling without rooting fake DOM nodes.
Add crash coverage for generated content surviving GC and rebaseline
layout dumps that now identify generated text explicitly.
Keep one per-TextNode chunk list so repeated inline layouts can skip
segmenting text and resolving fonts for each chunk. The cache entry is
keyed by the wrapping mode, whitespace behavior, word-break value, and
font cascade used to produce it.
Store rendered text, segmenters, and chunks behind one text-dependent
cache key. This keeps cached Utf16Views and segmenter state anchored to
current text when inherited text style changes without rebuilding the
layout tree.
Keep the cached font cascade alive while chunks are cached so a later
font-list allocation cannot compare equal by reusing the same address.
Add innerText coverage for style-only text-transform and white-space
changes, since that path constructs ChunkIterator directly.
We now apply first letter styles by splitting text with a first-letter
style applied into 2 `TextSliceNode` objects. The
`DOM::Text` layout node always points at the non first-letter slice
and the first-letter slice is reachable via
`TextSliceNode::first_letter_slice()`.
First letter splitting works by `TreeBuilder` walking a block
container's inline descendants to find the first typographic letter
unit per the pattern given in css-pseudo level 4, which is then
wrapped in an anonymous inline box styled with the `::first-letter`
computed properties.
Consumers that map between DOM offsets and layout geometry
are updated to visit all slices of a `DOM::Text` through
`TextOffsetMapping`.
The Paintable tree and its supplemental painting data structures were
GC allocated because that was the easiest way to manage it and avoid
leaks introduced by ref cycles. This included the Paintable subclasses
themselves plus StackingContext, ChromeWidget, Scrollbar, ResizeHandle,
and scroll-frame state.
We are now trying to reduce GC allocation churn on layout and painting
updates, so keeping this short-lived rendering tree outside the JS heap
is a better fit. Move Paintable to RefCountedTreeNode, make painting
helpers ref-counted or weakly reference Paintables, and update the
layout and event-handler call sites to use RefPtr/WeakPtr ownership.
When inline layout emits a whitespace chunk, it previously selected the
surrounding text's font without checking whether that font actually
contains a glyph for the whitespace codepoint. On pages that use
`@font-face` rules sharded by `unicode-range` (e.g. a Roboto webfont
split across one file for Cyrillic letters and another for basic Latin),
the shard covering the letters is picked for an adjacent space even
though the space codepoint lives in a different shard. HarfBuzz then
shapes the space with a font that has no glyph for it and emits
`.notdef`, rendering spaces as tofu boxes.
Check `contains_glyph(space_code_point)` on each candidate in
`font_for_space()` and fall through to
`FontCascadeList::font_for_code_point()` for the whitespace codepoint
when no surrounding font has the glyph.
Fixes whitespace rendering on web.telegram.org/a.
This fixes an issue where having an emoji font first in the font-family
cascade list would cause us to get the space width from the emoji font
as well.
We now look at adjacent text chunks when deciding which font to use for
space widths, instead of just blindly obeying the font-family value.
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.
Previously, it was possible for an up/down arrow press to place the
cursor in the middle of a multi-code point grapheme cluster. We want to
prevent this in a way that matches the behavior of other browsers.
Both Chrome and Firefox will map the starting position to a visually
equivalent position in the target line with harfbuzz and ICU segmenters.
The need for this is explained in a code comment. The result is a much
more natural feeling of text navigation.
This migrates TextNode::text_for_rendering() to Utf16String and deals
with the fallout. As a consequence, this effectively reverts commit
3df83dade8.
The layout test expecation file updates are because we now express text
lengths and offsets in UTF-16 code units.
The selection-over-multiple-code-units expectation file update actually
represents a correctness fix. Our result now matches Firefox.
This reduces the number of `.cpp` files that need to be recompiled when
one of the below header files changes as follows:
Painting/Command.h: 1030 -> 61
Painting/DisplayList.h: 1030 -> 60
Painting/DisplayListRecorder.h: 557 -> 59
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
Various whitespace-related issues have been fixed, and support for the
different CSS white-space values is improved enough that I think we can
stop doing the hack where we just prune whitespace nodes from the tree
and actually let them show up.
This is a nice step forward for correctness with the slight downside of
cluttering up layout tree dumps with tons of whitespace text nodes.
But hey, that's the web we know & love. :^)
Fixes#4427.
Layout nodes now only carry CSS computer values with them. The main
idea here is to give them only what they need to perform layout, and
leave the rest back in the DOM.
Now that we have RTTI in userspace, we can do away with all this manual
hackery and use dynamic_cast.
We keep the is<T> and downcast<T> helpers since they still provide good
readability improvements. Note that unlike dynamic_cast<T>, downcast<T>
does not fail in a recoverable way, but will assert if the object being
casted is not a T.
Boxes can now be floated left or right, which makes text within the
same block formatting context flow around them.
We were creating way too many block formatting contexts. As it turns
out, we don't need one for every new block, but rather there's a set
of rules that determines whether a given block creates a new block
formatting context.
Each BFC keeps track of the floating boxes within it, and IFC's can
then query it to find the available space for line boxes.
There's a huge hack in here where we assume all lines are the exact
line-height. Making this work with vertically non-uniform lines will
require some architectural changes.
Fragment painting was very limited by only being called during the
foreground paint phase. We now paint fragments as part of every phase
(and the phase is passed to paint_fragment() of course!)
Bring the names of various boxes closer to spec language. This should
hopefully make things easier to understand and hack on. :^)
Some notable changes:
- LayoutNode -> Layout::Node
- LayoutBox -> Layout::Box
- LayoutBlock -> Layout::BlockBox
- LayoutReplaced -> Layout::ReplacedBox
- LayoutDocument -> Layout::InitialContainingBlockBox
- LayoutText -> Layout::TextNode
- LayoutInline -> Layout::InlineNode
Note that this is not strictly a "box tree" as we also hang inline/text
nodes in the same tree, and they don't generate boxes. (Instead, they
contribute line box fragments to their containing block!)
2020-11-22 15:56:27 +01:00
Renamed from Libraries/LibWeb/Layout/LayoutText.h (Browse further)