Some SVG presentation attributes are only supported on certain
elements. We now support these special cases for attributes and
elements that we currently have implemented.
We were always delegating hit tests to PaintableBox if a
PaintableWithLines has no fragments, which means that anonymous
containers could overlap with previous siblings and prioritize their
border box rect. Instead, the nearest non-anonymous ancestor should take
care of hit testing the children so the correct order is maintained.
To achieve this, we no longer do an early hit test in
PaintableWithLines::hit_test() if there are no fragments and default
to the later PaintableBox::hit_test() call that does take anonymous
containers into account.
Fixes the issue seen in #4864.
This way we can reuse the logic between PaintableWithLines and
PaintableBox. It also introduces the .is_positioned() check for the
children of a PaintableWithLines, which makes sure to skip positioned
child nodes since those are handled by the StackingContext.
A PaintableWithLines will first try to see if there are any fragments
that have a hit. If not, it falls back to hit testing against its border
box rect.
However, inline content is often hoisted out of its parent into an
anonymous container to maintain the invariant that all layout nodes
either have inline or block level children. If that's the case, we
should not check the border box rect of the anonymous container, because
we might trigger a hit too early if the node has previous siblings in
its original parent node that overlap with their bounds.
By ignoring anonymous nodes, we leave the border box hit testing to the
nearest non-anonymous ancestor, which correctly applies the hit testing
order to its children.
Note that the border box rect checks whether the _untransformed_ point
is inside of it, which mirrors the behavior of PaintableBox::hit_test().
We should not need to check if the result of a hit test is actually
visible for hit testing, because if it wasn't, it should not have been
returned from PaintableBox::hit_test() in the first place.
The included WPT test passes through -1 which ends up modolo'ing
to u32 max at the IDL conversion layer, resulting in an unsigned
overflow when checking bounds.
For simplicity, this requires that the setlike Foo class has a
`void on_set_modified_from_js(Badge<Bindings::FooPrototype>)` method.
This will be called after the set is modified from a generated `add()`,
`delete()`, or `clear()` method.
Now, when Skia backend context is available by the time backing stores
are allocated, there is no need to have a separate BackingStore class.
This allows us to get rid of BackingStore -> PaintingSurface cache.
Making navigables responsible for backing store allocation will allow us
to have separate backing stores for iframes and run paint updates for
them independently, which is a step toward isolating them into separate
processes.
Another nice side effect is that now Skia backend context is ready by
the time backing stores are allocated, so we will be able to get rid of
BackingStore class in the upcoming changes and allocate PaintingSurface
directly.
Previously we could not create a `Length::ResolutionContext` using the
`for_layout_node` method if the provided node's document did not have a
layout node.
We now provide a workaround for this in the case that the
provided layout is that root layout node.
This is useful for instance if we want to create a length resolution
context when calling `NodeWithStyle::apply_style` on the root node.
When there is an active insertion point, it's necessary to tokenize
code-point-by-code-point to handle the case of document.write being
used to insert a named character reference one code point at a time.
However, when there is no insertion point defined, looking ahead at the
input and doing the matching all-at-once is more efficient since it
allows:
- Avoiding the work done in next_code_point between each code point
being matched (leading to better CPU cache usage in theory)
- Skipping ahead to the end of the match all at once, which does less
work overall than the equivalent number of next_code_point calls
(that is, skip(N) does less work than next_code_point called N times)
In my benchmarking, this provides a small performance boost (fewer
instructions, fewer cpu cycles, fewer branch misses) essentially for
free.
We were only dumping a PaintableBox' dimensions if its layout node was a
Layout::Box as well, causing us to not dump the dimensions of paintables
for inline nodes in the paintable tree.
This change fixes at least two issues:
- `update_associated_selection()` is responsible for selectionchange
dispatch, and we were incorrectly dispatching this event on ranges
that were not associated with a selection.
- `Range::get_client_rects()` was using `update_associated_selection()`
to refresh the selection state in the paintable tree for the current
range, but since a range might not be associated with a selection,
this could make the painted selection reflect the state of an
arbitrary range instead of the actual selection range.
Fixes a bug on Discord where any text typed into the message input would
get selected.
Our floating point number parser was based on the fast_float library:
https://github.com/fastfloat/fast_float
However, our implementation only supports 8-bit characters. To support
UTF-16, we will need to be able to convert char16_t-based strings to
numbers as well. This works out-of-the-box with fast_float.
We can also use fast_float for integer parsing.
By definition, the web allows lonely surrogates by default. Let's have
our string APIs reflect this, so we don't have to pass an allow option
all over the place.
To prepare for an upcoming Utf16String, this migrates Utf16View to store
its data as a char16_t. Most function definitions are moved inline and
made constexpr.
This also adds a UDL to construct a Utf16View from a string literal:
auto string = u"hello"sv;
This let's us remove the NTTP Utf16View constructor, as we have found
that such constructors bloat binary size quite a bit.
This check technically isn't necessary in
`SVGForeignObjectPaintable::paint()` because
`PaintableWithLines::paint(context, phase);` does the check already, but
I've added it there anyway to save some debugging time if someone does
add more code there. :^)
This stops `::before` and `::after` nodes showing up for every single
element in the inspector tree. Unfortunately there's no way for us to
detect that one of these doesn't exist in layout but has *some* style
specified for it, but that seems like a rare use case.