That makes us pass the following WPT tests:
- css/css-color/srgb-linear-001.html
- css/css-color/srgb-linear-002.html
- css/css-color/srgb-linear-003.html
This was a silly mistake on my end and percentages values are not
covered by device-independent color space, so I had to add support for
srgb to run a WPT test that made me realize the mistake.
This makes the following test pass:
- css/css-color/predefined-002.html
It makes the following WPT tests pass:
- css/css-color/predefined-001.html
- css/css-color/xyz-003.html
- css/css-color/xyz-d50-003.html
- css/css-color/xyz-d50-004.html
- css/css-color/xyz-d65-003.html
Also we now render the reference of color-mix-currentcolor-nested-for-
color-property.html properly. Which means that it's now different from
the actual test, that is still rendered incorrectly. In other word, the
false positive for this test is now turned into a true negative.
These operations should still apply even if they are off screen, because
they affect painting of things outside of their bounding rectangles.
This commit makes us always apply these, regardless of if they are in
the visible region. However, if they are outside that region, we
replace them with simple clip-rect commands, which have the same
effect (not painting anything) but are cheaper than computing a full
mask bitmap.
This also adds support for `xyz` as it defaults to `xyz-d65`. We now
pass the following WPT tests:
- css/css-color/xyz-001.html
- css/css-color/xyz-002.html
- css/css-color/xyz-004.html
- css/css-color/xyz-d65-001.html
- css/css-color/xyz-d65-002.html
- css/css-color/xyz-d65-004.html
A few are skipped for now:
- A few ref tests fail
- Crash tests are not supported by our runner and time out
- top-level-is-scope.html crashes and needs further investigation
This save() call did not have matching restore(). For mask application
it's display list builder responsibility to emit save() and restore()
so mask is applied only to relevant portion.
Progress on https://www.jetbrains.com/
We paint grid item nodes as a stacking context when they have no
`z-index` style set. However, a grid item could already have a stacking
context established - for example, when the `filter` style is applied.
This causes these nodes to be drawn twice.
Skip painting grid item nodes if a stacking context is already present.
These are created when a style rule has properties listed after another
rule. For example:
```css
.test {
--a: 1;
--b: 1;
--c: 1;
.thing {
/* ... */
}
/* These are after a rule (.thing) so they're wrapped in a
CSSNestedDeclarations: */
--d: 1;
--e: 1;
--f: 1;
}
```
They're treated like a nested style rule with the exact same selectors
as their containing style rule.
For example, this:
```css
.foo {
color: red;
&:hover {
color: green;
}
}
```
now has the same effect as this:
```css
.foo {
color: red;
}
.foo:hover {
color: green;
}
```
CSSStyleRule now has "absolutized selectors", which are its selectors
with any `&`s resolved. We use these instead of the "real" selectors
when matching them, meaning the style computer doesn't have to know or
care about where the selector appears in the CSS document.
...traversal. We've already fixed step 3 and 9 to not filter out
non-positioned stacking contexts, because modern CSS has more ways to
create stacking context besides being positioned with z-index (like by
using "transform", "filter" or "clip-path" properties).
See following spec issue for more details https://github.com/w3c/csswg-drafts/issues/2717
Visual improvement on https://basecamp.com/
Prior to this change, SVGs were following the CSS painting order, which
means SVG boxes could have established stacking context and be sorted by
z-index. There is a section in the spec that defines what kind of SVG
boxes should create a stacking context
https://www.w3.org/TR/SVG2/render.html#EstablishingStackingContex
Although this spec is marked as a draft and rendering order described in
this spec does not match what other engines do.
This spec issue comment has a good summary of what other engines
actually do regarding painting order
https://github.com/w3c/svgwg/issues/264#issuecomment-246432360
"as long as you're relying solely on the default z-index (which SVG1
does, by definition), nothing ever changes order when you apply
opacity/filter/etc".
This change aligns our implementation with other engines by forbidding
SVGs to create a formatting context and painting them in order they are
defined in tree tree.
We were overly aggressive in clipping SVG roots, which effectively made
them behave as if they always had `overflow: hidden`.
This fixes incorrect clipping of the logo on https://basecamp.com/
Scroll offset of body does not affect position of fixed elements, so
nearest scrollable lookup should early return from ancestor scrollable
lookup loop once "position: fixed" box is encountered.
Fixes regression introduced in 866608532a
Sticky positioning is implemented by modifying the algorithm for
assigning and refreshing scroll frames. Now, elements with
"position: sticky" are assigned their own scroll frame, and their
position is refreshed independently from regular scroll boxes.
Refreshing the scroll offsets for sticky boxes does not require display
list invalidation.
A separate hash map is used for the scroll frames of sticky boxes. This
is necessary because a single paintable box can have two scroll frames
if it 1) has "position: sticky" and 2) contains scrollable overflow.
We *could* even skip creating a paintable for hidden nodes, but that
means that dynamic updates to the CSS visibility property would require
mutating the paint tree, so let's keep it simple for now.
SVG and and CSS border rendering now sits on top of SkPath instead of
the old Gfx::DeprecatedPath.
Due to an imperceptible (255, 255, 255) vs (255, 254, 255) color diff
in one ref test, I changed that test to not depend on border rendering
for a positive result, since that was incidental.
While introducing clip and scroll frame trees, I made a mistake by
assuming that the paintable tree includes boxes from nested navigables.
Therefore, this comment in the code was incorrect, and clip/scroll
frames were simply not assigned for iframes:
// NOTE: We only need to refresh the scroll state for traversables
// because they are responsible for tracking the state of all
// nested navigables.
As a result, anything with "overflow: scroll" is currently not
scrollable inside an iframe
This change fixes that by ensuring clip and scroll frames are assigned
and refreshed for each navigable. To achieve this, I had to modify the
display list building process to record a separate display list for each
navigable. This is necessary because scroll frame ids are local to a
navigable, making it impossible to call
`DisplayList::apply_scroll_offsets()` on a display list that contains
ids from multiple navigables.
Instead of carrying the display list for a mask in each command that
might potentially be affected by "background-clip: text", this change
introduces a new AddMask command that is applied once for all
background layers within one box.
The new AddMask command includes a rectangle for the mask destination
that is translated by the corresponding scroll offset.
Fixes https://github.com/LadybirdBrowser/ladybird/issues/857
add_clip_rect() accepts a rectangle in viewport-relative coordinates,
so it must be translated by the enclosing scroll offset to be displayed
correctly inside a scrollable box.
Overflow clipping is currently implemented as:
1. Create clip frame for each box with hidden overflow
2. Calculate clip rect for each clip frame by intersecting padding boxes
of all boxes with hidden overflow in containing block chain
3. Assign enclosing clip frame (closest clip frame in containing block
chain) to each PaintableBox
4. Apply clip rect of enclosing clip frame in Paintable::before_paint()
It breaks when any CSS transform other than simple translation is lying
between box with hidden overflow and a clipped box, because clip
rectangle will be applied when transform has already changed.
The fix is implemented by relying on the following rule:
"For elements whose layout is governed by the CSS box model, any value
other than none for the transform also causes the element to establish
a containing block for all descendants."
It means everything nested into a stacking context with CSS transform
can't escape its clip, so it's safe to apply its clip for all children.
Moves paint_table_borders() call into PaintableBox::paint() to make
scroll offset and clip rectangle of enclosing scrollable be applied
in ::before_paint().
These test work with LibGfx painter but won't longer work after
switching to Skia, because it produces slightly different antialiasing,
rounding in color blending, etc.
This change will make it easier to disable screenshot comparison tests
on a specific platform or have per-platform expectations.
Additionally, it's nice to be able to tell if a ref-test uses a
screenshot as an expectation by looking at the test path.