Stop converting between CSS and device pixels as part of rendering - the
display list should be as simple as possible, so convert to DevicePixels
once when constructing the display list.
Fixes the included imported test. Note that this required a minor
edit of the WPT import to work with our test harness setup to
try and create a non secure context setup as both file:// and
localhost are considered secure contexts.
In high concurrency, sometimes 400+ blob urls and iframe loads take
longer than 30 seconds, especially on sanitizer runs when memory is
tight. Reduce the number of urls and iframes to 84.
perform_a_scroll_of_the_viewport() accesses paintable_box() without
ensuring layout is up to date. This can lead to a null dereference
if the paintable tree was torn down (e.g. by adding a dialog to the top
layer via showModal()) between the last layout update and the scroll.
One concrete path: Window::scroll() has an optimization that skips
update_layout when scrolling to (0, 0), but still calls
perform_a_scroll_of_the_viewport if the viewport is at a non-zero
position.
Fix by adding an update_layout call at the top of
perform_a_scroll_of_the_viewport.
During SVG subtree relayout, position:fixed elements inside
<foreignObject> use the viewport as their containing block. Since the
viewport is outside the SVG subtree, it was not pre-populated in the
LayoutState, causing a VERIFY failure in ensure_used_values_for().
Fix this by unconditionally pre-populating the viewport node from its
paintable in relayout_svg_root().
The spec requires us to follow the steps in FontFace::load() whenever a
font is loaded. The simplest way to do so, is to make that the only way
we load fonts. :^)
To support this, FontFace::load() uses its connected CSSFontFaceRule's
ParsedFontFace if it's available.
The 1 regression in generic-family-keywords-003.html seems to be a false
positive: we don't support the system-ui font keyword.
Add a pre-computed `has_empty_effective_clip` flag on
AccumulatedVisualContext that propagates from parent to child. When a
clip rect or clip path has zero area, all descendant commands are
skipped at display list recording time in `DisplayList::append()`,
so they are never stored or executed.
This allows skipping ~10% of display list commands in the Discord app.
Previously, PaintNestedDisplayList was treated as an opaque command,
printing only its name and rect without showing the nested display
list's contents. This made it impossible to debug painting issues
involving SVG masks/clips, CSS background-clip: text, and iframe
content through display list dumps.
Refactor the command dump loop into a recursive lambda that expands
nested display lists inline with increased indentation.
Per the CSS Overflow spec, overflow properties apply only to block
containers, flex containers, and grid containers — not SVG graphics
elements. Add an `is<SVGPaintable>` check in
`overflow_property_applies()` to return false for SVG inner elements
like `<g>`, `<rect>`, `<path>`.
This doesn't affect `<svg>` elements (which use `SVGSVGPaintable`, a
direct `PaintableBox` subclass) or `<foreignObject>` (which uses
`SVGForeignObjectPaintable`, a `PaintableWithLines` subclass) — both
correctly keep their overflow clips.
This test captures the current (incorrect) behavior where setting
`overflow: hidden` on an SVG `<g>` element produces a clip in the
display list. Per the CSS Overflow spec, overflow properties only apply
to block containers, flex containers, and grid containers — not SVG
graphics elements.
This applies the same pattern used for background-clip: text (commit
f2e6f70fbb).
Results in visible performance improvement in Discord app where
previously, according to profiles, we spent lots of time allocating
surfaces for masks.
relayout_svg_root() clears individual stacking contexts via
reset_for_relayout() but didn't call invalidate_stacking_context_tree().
The viewport's stacking context remained non-null, so
build_stacking_context_tree_if_needed() skipped the rebuild. This caused
foreignObject to lose its stacking context after relayout, breaking SVG
mask application.
This test verifies that SVG mask application on foreignObject is
preserved after partial SVG relayout. Currently the mask is not applied
to the foreignObject content after relayout because the stacking context
tree is not rebuilt.
This exposes an existing issue with interpolation where it is not clear
in what situations zero-valued dimensions should be excluded from the
interpolated value of a dimension-percentage mix (e.g. `calc(50% + 0px)`
vs `50%`) - but this is just a serialization issue as both
representations are resolved to the same used value
This is part of the rendering spec, but we had neglected to do this
before. It causes one WPT check to fail, but other browsers get the
same result on that check, so I guess we can call that a win. :^)
The CSS content property's alt text (after `/`) was incorrectly
accepting any content value. Per the CSS Content Module Level 3 spec,
alt text only accepts <string>, <counter>, and <attr()> values. This
change adds type validation in the alt text parsing branch to reject
URLs, quote keywords, images, and other non-alt-text value types.
This fixes 64 subtests in the content-invalid WPT test.
The CSS Overflow spec says scrollable overflow should include "the
scrollable overflow areas of all of the above boxes (including
zero-area boxes)", but we were skipping zero-area boxes entirely via
an early return. This meant elements like a position:relative container
that collapses to zero height (because its only child is absolutely
positioned) would never have their children's overflow counted.
Setting the filter property on a CanvasRenderingContext2D would crash
with a null pointer dereference if the canvas element had no layout
node (e.g. a detached canvas not in the document).
Instead of forcing a full layout update and requiring a layout node,
we now only update style if needed and resolve lengths via the
element's computed properties when available, falling back to
document-level defaults otherwise. This matches the pattern used by
CanvasTextDrawingStyles.
This aligns our behaviour closer to other browsers, which
_mostly_ consider file scheme URLs as opaque. For test
purposes, allow overriding this behaviour with a commandline
flag.
To allow for a future change where one test will be loaded over
HTTP (allowing us to remove the internals hook), and another test
which verifies cookies do not work for file URLs.
When files have an opaque origin, the "file" scheme is omitted from the
blob URL serialization in the stack trace.
This change normalizes the output in the test so that both tuple
file origins and opaque file origins (which may serialize as
'blob:ladybird/') is accepted, ensuring the test passes in
both scenarios.
Move grid area rectangle computation and validation from layout to the
CSS parser. Named grid areas that don't form filled-in rectangles now
correctly invalidate the declaration per spec.
Add focused coverage for the ElementByIdMap that is easy to regress
while optimizing lookup paths.
The dynamic mutations test verifies duplicate id tree order semantics
remain correct after reordering, id changes, removals, and
reintroduction.
The shadow root routing test verifies lookups stay routed to the correct
scope when an element with an id is removed and moved across shadow
roots and into the document.
Stress-test the isContentEditable property across various scenarios:
dynamic contenteditable changes, node moves between editable/noneditable
subtrees, insertion/removal, design mode toggle, deep nesting, nested
contenteditable overrides, and plaintext-only mode.
There are actually a couple of bugs here:
1. As of commit ebda8fcf11, editing hosts
are now excluded from Node::is_editable. Since this special hit test
handling is specifically for contenteditable nodes, we would not
enter this branch for these nodes.
2. We were not checking if the contenteditable node actually contained
the hit testing position. So if a page had multiple empty editable
nodes, we would just return whichever was hit test first.
These bugs were exposed by 7c9b3c08fa.
This commit resulted in the text cursor hit test node being set as the
document focus node. If we returned the wrong result, we would not set
the correct node.
This was seen on discord, where clicking the message box would result in
the search box being focused.
The grammar groups this component together meaning that all
sub-components must occur together i.e.
`ordinal slashed-zero small-caps` is valid but
`ordinal small-caps slashed-zero` is not.
We also reuse the logic for parsing from the longhand
`font-variant-numeric` property for simplicity.
The grammar groups this component together meaning that all
sub-components must occur together i.e.
`common-ligatures no-contextual small-caps` is valid but
`common-ligatures small-caps no-contextual` is not.
We also reuse the logic for parsing from the longhand
`font-variant-ligatures` property for simplicity.
The grammar groups this component together meaning that all
sub-components must occur together i.e. `jis78 full-width small-caps` is
valid but `jis78 small-caps full-width` is not.
We also reuse the logic for parsing from the longhand
`font-variant-east-asian` property for simplicity.
Our HTTP test server supports a limited amount of byte range request
formats. The format we were using was incorrect, causing the server to
fail an assertion. We now ensure the response body is piped as expected
to catch issues like this in the future.