`CSSColorValue`s which have unresolved `calc` components should be able
to be resolved. Previously we would always resolve them but with
incorrect values.
This is useful as we will now be able to now whether we should serialize
colors in their normalized form or not.
Slight regression in that we now serialize (RGB, HSL and HWB) colors
with components that rely on compute-time information as an empty
string, but that will be fixed in the next commit.
These new methods are built on top of the spec's
`simplify_a_calculation_tree` algorithm where the old methods were
ad-hoc.
These methods are not used anywhere yet as callers will need to be
migrated over from the deprecated methods one-by-one to account for
differences in behaviour.
No functionality changes.
The existing resolve methods are not to spec and we are working to
replace them with new ones based on the `simplify_a_calculation_tree`
method.
These are marked as deprecated rather than replaced outright as work
will need to be done on the caller side to be made compatible with the
new methods, for instance the new methods can fail to resolve (e.g.
if we are missing required context), where the existing methods will
always resolve (albeit sometimes with an incorrect value).
No functionality changes.
When setting a declaration for a property in a logical property group,
it should appear after all other declarations which belong to the same
property group but have different mapping logic (are/aren't a logical
alias).
Gains us 1 WPT pass.
We should not serialize a group of properties `longhands` as a single
shorthand if there is any property declared between the first and
last property in `longhands` which is not part of `longhands` but
belongs to the same logical property group, and has different mapping
logic to any of property in `longhands`
When parsing values in `process_a_keyframes_argument` we don't expand
properties using `StyleComputer::for_each_property_expanding_shorthands`
unlike most other places - this means that if we parse a `border` we end
up with the `border`'s sub-properties (`border-width`, `border-style`,
`border-color`) still in their unexpanded forms (`CSSKeywordValue`,
`LengthStyleValue`, `StyleValueList`, etc) rather than
`ShorthandStyleValue`s which causes a crash when serializing the
`border` value in `KeyframeEffect::get_keyframes`.
The proper fix here is to parse `border`'s sub-properties directly to
`ShorthandStyleValue`s instead of relying on
`StyleComputer::for_each_property_expanding_shorthand` to do this
conversion for us but this may be a while off.
This commit also imports the previously crashing tests.
On FreeBSD some symbols like `environ` or `__progname` are not exported
anywhere and are filled in by the dynamic loader. `environ` is
a special case because we make use of it explicitly so we need to mark
it a weak symbol so the linker doesn't complain.
This commit is a three-parter that is hard to separate without breaking
marker rendering:
1. Any marker style that results in a string, except for a literal
string (e.g. `list-style-type: "@"`), should get the string ". "
appended. We forgot to do this for the alpha and roman types.
2. Instead of using the "pixel size rounded up" from a font and adding
an arbitrary 1 to that, we now use the exact pixel size for as long
as possible to improve our vertical positioning of markers.
3. Instead of always adding a "default marker width" to the marker
content width, we now only do this if we did not have text metrics
available (i.e. the marker style is not a text type). This greatly
improves horizontal positioning of text markers.
For contenteditable `Selection` in collapsed state represents cursor
position, so whenever it's update, we should also reset the blink timer.
Fixes bug on Discord when cursor is blinking while it is being moved by
pressing arrow keys.
Both functions schedule HTML event loop processing but that's
unnecessary, because we schedule a rendering task that checks if
style/layout needs an update 60/s anyway.
We were previously handling this ad-hoc via logic in
`get_property_internal` but this didn't cover all contexts (for
instance `CSSStyleProperties::serialized`.
Gains us 9 more WPT tests as we now cover properties which weren't
included in the previous ad-hoc approach.
Some shorthand properties work differently to normal in that mapping of
provided values to longhands isn't necessarily 1-to-1 and depends on the
number of values provided, for example `margin`, `border-width`, `gap`,
etc.
These properties have distinct behaviors in how they are parsed and
serialized, having them marked allows us to implement theses behaviors
in a generic way.
No functionality changes.
Our currently implementation of structured serialization has a design
flaw, where if the serialized/transferred type was not used in the
destination realm, it would not be seen as exposed and thus we would
not re-create the type on the other side.
This is very common, for example, transferring a MessagePort to a just
inserted iframe, or the just inserted iframe transferring a MessagePort
to it's parent. This is what Google reCAPTCHA does.
This flaw occurred due to relying on lazily populated HashMaps of
constructors, namespaces and interfaces. This commit changes it so that
per-type "is exposed" implementations are generated.
Since it no longer relies on interface name strings, this commit
changes serializable types to indicate their type with an enum,
in line with how transferrable types indicate their type.
This makes Google reCAPTCHA work on https://www.google.com/recaptcha/api2/demo
It currently doesn't work on non-Google origins due to a separate
same-origin policy bug.
If the MessagePort is not entangled, then m_transport is null, meaning
it's not valid to read from the transport.
This fixes the cross-piping streams WPT crash test crashing in the
upcoming commit.
Make sure we have a parent element before trying to look at it!
I've also pulled out a stub function for getting a custom property's
initial value, so that there's only one place to change once we support
`@property` more.
We were always creating an anonymous container for the inline contents
of table cells, but the layout node we spawn for the table cells
themselves already is capable of dealing with inline nodes. Regular
logic should kick in for dealing with the block/inline node invariant.
Because we defined `th { text-align: center }` in our UA stylesheet, it
received a higher precedence than inherited (inline) styles. Firefox
deals with this by defining a custom `text-align` value that prioritizes
any inherited value before defaulting to `text-align: center`.
We now do this as well :^)
When layouting a replaced element with natural width and height (e.g. a
raster graphic), the replaced element would correctly end up with its
natural size in the main-axis dimension. For the cross axis dimension
however, the replaced element was stretched or squished to the flex
containers inner cross size, which is wrong. Instead, we need to respect
the replaced elements aspect ratio.
Since the touched code does not have a direct correspondence to any spec
text, I am not fully certain that the change is completely correct.
However, tests agree with it, so the new code seems more correct than
the old one at least.
This fixes 50 WPT subtests in `css/css-flexbox`, most of which are
already in-tree. I have also created a new test for a scenario that did
not seem to be covered by WPT.
By keeping track of the enclosing range around all Unicode ranges of a
FontCascadeList entry, we can quickly reject any code point that's
outside all ranges.
This knocks font_for_code_point() from 7% to 3% in the profile when
scrolling on https://screenshotone.com/
Until now, every paint phase of every PaintableBox injected its own
clipping sequence into the display list:
```
before_paint: Save
AddClipRect (1)
...clip rectangles for each containing block with clip...
AddClipRect (N)
paint: ...paint phase items...
after_paint: Restore
```
Because we ran that sequence for every phase of every box, Skia had to
rebuild clip stack `paint_phases * paintable_boxes` times. Worse,
usually most paint phases contribute no visible drawing at all, yet we
still had to emit clipping items because `before_paint()` has no way to
know that in advance.
This change takes a different approach:
- Clip information is now attached as metadata `ClipFrame` to each
DisplayList item.
- `DisplayListPlayer` groups consecutive commands that share a
`ClipFrame`, applying the clip once at the start of the group and
restoring it once at the end.
Going from 10 ms to 5 ms in rasterization on Discord might not sound
like much, but keep in mind that for 60fps we have 16 ms per frame and
there is a lot more work besides display list rasterization we do in
each frame.
* https://discord.com/channels/1247070541085671459/1247090064480014443
- DisplayList items: 81844 -> 3671
- rasterize time: 10 ms -> 5 ms
- record time: 5 ms -> 3 ms
* https://github.com/LadybirdBrowser/ladybird
- DisplayList items: 7902 -> 1176
- rasterize time: 4 ms -> 4 ms
- record time: 3 ms -> 2 ms
In the upcoming change, device pixel conversion of ClipFrame will
happen during display list replay, where PaintContext is not available,
so let’s move it out of PaintContext.
Before this change, we were always behaving as if box-sizing were
content-box for block-level replaced element widths.
This fixes the squishy logo on https://videolan.org/
Introduces a few ad-hoc modifications to the DAFSA aimed to increase
performance while keeping the data size small.
- The 'first layer' of nodes is extracted out and replaced with a lookup
table. This turns the search for the first character from O(n) to O
(1), and doesn't increase the data size because all first characters
in the set of named character references have the
values 'a'-'z'/'A'-'Z', so a lookup array of exactly 52 elements can
be used. The lookup table stores the cumulative "number" fields that
would be calculated by a linear scan that matches a given node, thus
allowing the unique index to be built-up as normal with a O(1) search
instead of a linear scan.
- The 'second layer' of nodes is also extracted out and searches of the
second layer are done using a bit field of 52 bits (the set bits of
the bit field depend on the first character's value), where each set
bit corresponds to one of 'a'-'z'/'A'-'Z' (similar to the first
layer, the second layer can only contain ASCII alphabetic
characters). The bit field is then re-used (along with an offset) to
get the index into the array of second layer nodes. This technique
ultimately allows for storing the minimum number of nodes in the
second layer, and therefore only increasing the size of the data by
the size of the 'first to second layer link' info which is 52 * 8 =
416 bytes.
- After the second layer, the rest of the data is stored using a
mostly-normal DAFSA, but there are still a few differences:
- The "number" field is cumulative, in the same way that the
first/second layer store a cumulative "number" field. This cuts
down slightly on the amount of work done during the search of a
list of children, and we can get away with it because the
cumulative "number" fields of the remaining nodes in the DAFSA
(after the first and second layer nodes were extracted out) happens
to require few enough bits that we can store the cumulative version
while staying under our 32-bit budget.
- Instead of storing a 'last sibling' flag to denote the end of a
list of children, the length of each node's list of children is
stored. Again, this is mostly done just because there are enough
bits available to do so while keeping the DAFSA node within 32
bits.
- Note: Together, these modifications open up the possibility of
using a binary search instead of a linear search over the
children, but due to the consistently small lengths of the lists
of children in the remaining DAFSA, a linear search actually seems
to be the better option.
The new data size is 24,724 bytes, up from 24,412 bytes (+312, -104 from
the 52 first layer nodes going from 4-bytes to 2-bytes, and +416 from
the addition of the 'first to second layer link' data).
In terms of raw matching speed (outside the context of the tokenizer),
this provides about a 1.72x speedup.
In very named-character-reference-heavy tokenizer benchmarks, this
provides about a 1.05x speedup (the effect of named character reference
matching speed is diluted when benchmarking the tokenizer).
Additionally, fixes the size of the named character reference data when
targeting Windows.
When the XML parser appends child nodes to a template element, it must
actually append the template element's contents. This special behavior
caused us to return to the wrong parent element after adding child
nodes to a template element, leading to a crash.
It's useful to have tests that dump display list items, so we can more
easily see how changes to the display list recording process affect the
output. Even the small sample test added in this commit shows that we
currently record an unnecessary AddClipRect item for empty paint phases.
For now, the dump doesn't include every single property of an item, but
we can shape it to include more useful information as we iterate on it.
Previously, calling `BlockContainer::paintable_with_lines()` would cast
a `PaintableBox` to a `PaintableWithLines` without verifying that the
cast was valid, which isn't the cast for `FieldsetPaintable`, for
example. This method now returns null if it isn't poossible to cast to
`PaintableWithLines`.
Recently, we moved the backing store manager into Navigable, which means
we now try to allocate a backing store for all navigables, including
those corresponding to SVG image documents. This change disables that
behavior for all navigables except top-level non-SVG traversables,
because otherwise it causes issues when we stop repainting: the browser
process was notified about an allocated backing stores that does not
correspond to the page, and then all subsequent repaints are ignored
until the window is resized.