Commit graph

2488 commits

Author SHA1 Message Date
Sam Atkins
cb74affdcb LibWeb/CSS: Treat general-enclosed in @container as unknown 2026-05-20 13:00:50 +01:00
Sam Atkins
9996403e73 LibWeb/CSS: Extract base class from MediaFeature
`<media-feature>` and the upcoming `<size-feature>` from `@container`,
share the same syntax and almost all of their behaviour. To avoid a lot
of duplication, pull as much as possible into a FeatureQuery template
class that they will both inherit from.

MediaFeatureValue is renamed FeatureValue as it's also shared by both.

No behaviour change.
2026-05-20 13:00:50 +01:00
Sam Atkins
3e850f9891 LibWeb/CSS: Track container size requirements per axis
Replace `ContainerQueryFeatureRequirements::requires_size_container`
with separate width and height flags. Depending on the writing mode, a
request for the width or height of a container might need it to be a
size container, or only an inline-size container. Anything that needs
both sizes (such as the aspect ratio) can simply flag both as required.
2026-05-20 13:00:50 +01:00
Tim Ledbetter
b67d73a661 LibWeb: Apply ::first-letter pseudo-element styles
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`.
2026-05-20 12:09:19 +01:00
Callum Law
a6f24e91cc LibWeb: Simplify is_definite_size 2026-05-20 09:47:17 +01:00
Callum Law
8f27caec14 LibWeb: Simplify handling of resolution in ImageSetStyleValue
The resolution is always absolutized at style computation time so we can
just use `Resolution::from_style_value` and select the image once in
`load_any_resources` since the layout node won't change the result.
2026-05-20 09:47:17 +01:00
Callum Law
5c6749b41a LibWeb: Remove LRC from various resolved value cache keys
Lengths are resolved at style computation time so the LRC has no effect
on these resolved values.
2026-05-20 09:47:17 +01:00
Callum Law
c19a4882a8 LibWeb: Don't store transition-delay on ComputedValues
This is never used (since transitions are applied during style
computation) so is not needed.
2026-05-20 09:47:17 +01:00
Luke Wilde
5bed7f6d73 LibWeb/CSS: Root transient GC locals in style invalidation/resolution 2026-05-19 19:24:08 +02:00
Shannon Booth
73e7cacd78 LibWeb+LibIDL: Define CSSOMString as a DOMString typedef
Add the CSSOMString typedef from CSSOM and stop treating it as a builtin
IDL string type.

This makes CSSOMString follow normal typedef resolution instead of being
special-cased in LibIDL.
2026-05-19 15:33:18 +02:00
Aliaksandr Kalenik
4cd8e84dff LibGfx+LibWeb: Keep loaded font bytes shareable
Future compositor-side rendering will need WebContent to share typefaces
with the compositor process over IPC. If a typeface already keeps its
backing bytes in anonymous shared memory, IPC encoding can clone that
buffer handle instead of allocating a new shared buffer and copying the
same font data during upload.
2026-05-19 09:20:38 +02:00
Andreas Kling
f4960d9d7d LibWeb: Honor requested CSS tokenizer encoding
Keep decoded CSS text separate from tokenizer byte input. CSSOM and
already-decoded stylesheet text preserve code point preprocessing, so a
lone surrogate maps to one replacement character instead of being
re-decoded as malformed UTF-8 bytes.

Decode tokenizer byte input with the requested encoding unless that
encoding is UTF-8 and the byte stream is strictly valid UTF-8. Keep the
fast path by constructing the decoded string without validating twice
after strict validation succeeds.

Preserve UTF-8 decoder behavior on the byte fast path by stripping an
initial UTF-8 BOM and rejecting encoded surrogate bytes. Invalid UTF-8
still goes through the decoder. Add tokenizer coverage for both the C++
and Rust backends across decoded text, UTF-8 aliases, BOM-prefixed
input, invalid UTF-8, and non-UTF requested encodings.
2026-05-18 14:08:22 +02:00
Tim Ledbetter
52e082c01f LibWeb: Skip style update inside display:none subtrees
Descendants of a display:none element are not rendered and their
computed style is only observable through on-demand reads. Skip the
recursive style descent at display:none ancestors during the
top-down traversal in `update_style_recursively()`.
2026-05-18 11:31:26 +02:00
Andreas Kling
318fb4f2d0 LibWeb: Preserve immutable consumed body bytes
Keep consumed response body bytes in Core::ImmutableBytes instead of
requiring a ByteBuffer. This lets responses that already arrived as
file-backed immutable data keep that representation through body
consumption, while streamed responses can still adopt their
accumulated ByteBuffer without another copy.

Update the body consumers that only inspect bytes to read from
immutable byte views. Font loading still copies at its existing
ownership boundary, where the off-thread preparation path takes a
ByteBuffer.
2026-05-18 01:21:34 +02:00
Tim Ledbetter
07cd6f448a LibWeb: Mark grid line placement properties as requiring computation 2026-05-17 21:26:57 +02:00
Andreas Kling
11e69d5e49 LibWeb: Support dump tools without resource loading
Allow parser dump utilities to run without installing a ResourceLoader.
Short-circuit resource fetch entry points used by links, stylesheets,
and shared resource requests when no loader is present.

Keep those failures local to headless utility use so dump-html-tree can
parse real pages without a full browser page loader or request service.
2026-05-17 15:35:56 +02:00
Aliaksandr Kalenik
8906011a6b LibWeb: Synchronize display list resources via transactions
Display lists used to own the resource storage needed to replay their
command bytes. That kept the compositor tied to in-process object
ownership: sending a display list update also meant sharing the same
resource container with the recording side.

Move resource storage out of DisplayList and make display list updates
carry a transaction of resources to add and remove. Navigable now tracks
the resources referenced by the current display list, sends only the
delta to the compositor, and trims its recording-side storage to the
active set. The compositor applies those transactions to its own storage
before replacing the cached display list.

This still carries in-process resource objects, but it puts the
ownership boundary in the right place. Command bytes and resource
lifetime are now synchronized explicitly, which is the shape needed
before the compositor can receive serializable resource updates across a
process boundary.
2026-05-16 19:35:24 +02:00
Aliaksandr Kalenik
57e476bcf2 LibWeb: Preserve auto duration for scroll animations
CSS Animations Level 2 makes animation-duration default to auto. We
still initialized it to 0s and converted auto to zero while collecting
CSS animation properties, before the animation effect had its scroll
timeline. Scroll-driven animations with an omitted duration therefore
behaved like zero-duration animations, so scroll(root) progress bars did
not track the scroll position.

Make animation-duration initialize to auto and carry that value into the
effect timing normalization. Time-driven animations still resolve auto
to 0s there, while progress-based timelines resolve it against the
timeline duration. Keep treating that resolved 0s as the default when
serializing the animation shorthand so computed style remains compatible
with existing CSS Animations expectations.

Add a text regression covering an omitted duration on a scroll(root)
progress animation. The test fails before this fix because the computed
duration is 0s and the transform never advances at 25% scroll.
2026-05-15 13:47:39 +02:00
Daniel Gołębiewski
c42c438beb LibWeb: Add support for scroll-padding property 2026-05-15 12:07:27 +01:00
Daniel Gołębiewski
cda026142e LibWeb: Add support for scroll-margin property 2026-05-15 12:07:27 +01:00
Luke Wilde
de35994fc2 LibJS+LibWeb: Use the unified Visitor for Variant-holding members 2026-05-15 08:51:17 +02:00
Tim Ledbetter
a04e74f97d LibWeb: Templatize for_each_matching_attribute callback
Eliminates ~0.4% of profile time spent in AK::Function wrappers on
https://sainsburys.co.uk
2026-05-14 13:28:19 +02:00
Tim Ledbetter
68f832095a LibWeb: Skip animated property lookup when no animations are present 2026-05-14 13:28:19 +02:00
Gingeh
d8b986aaee LibWeb: Use cached hash for InvalidationSet equality 2026-05-13 14:10:54 +02:00
Callum Law
33705dc12f LibWeb: Generate CSS <paint> parsing
This changes the shape of the parsed value when we don't have a fallback
color for a `<url>` value from having no second value in the
`StyleValueList` to having an `EmptyOptionalStyleValue`.
2026-05-13 11:26:20 +01:00
Callum Law
fe121d403d LibWeb: Add EmptyOptionalStyleValue
This will be used in generated code to represent missing optionals i.e.
`<foo> <bar>?` with only a `<foo>` value will be represented by a
`StyleValueList` containing the relevant `<foo>` style value and an
`EmptyOptionalStyleValue`
2026-05-13 11:26:20 +01:00
Callum Law
6361dcaae5 Meta: Handle groups in CSS value parsing code generation
We don't yet support required groups so for the moment these just fall
back to generating the parsing code of their child
2026-05-13 11:26:20 +01:00
Sam Atkins
cb14d574de LibWeb: Invalidate descendants for container-* property changes
Whenever an ancestor's container-name or container-type changes, it
affects the matching of any `@container` queries, and so can affect the
style of any descendant.
2026-05-13 11:05:31 +01:00
Sam Atkins
67046049d9 LibWeb: Evaluate container queries when collecting matching style rules
MatchingRules now have a container_rule member which stores the nearest
ancestor CSSContainerRule, if any. When populating the rule cache, we
maintain a stack of CSSContainerRules that we are within, and use
record the last one on the MatchingRule, so that it's O(1) instead of
having to walk up the rule's ancestors each time. This does mean we
have reimplement some "for each rule" code.

When collecting rules to apply to an element, we see if the MatchingRule
has a container_rule, and if so, we evaluate that rule's query to see
if the element has a matching container. We then also match any ancestor
container rules, using the cached parent container rule.

Add a custom test to cover the case of nested name-only `@container`s,
which WPT lacks currently as far as I can tell.
2026-05-13 11:05:31 +01:00
Sam Atkins
1f66b1cc13 LibWeb: Implement ContainerQuery evaluation
ContainerQuery now stores its feature requirements. When evaluated, it
uses these and the passed-in container name to identify a container
element to match against, then evaluates its condition against that
element.

None of this is yet in use anywhere, but will be soon.
2026-05-13 11:05:31 +01:00
Sam Atkins
b6e8239203 LibWeb: Collect container query feature requirements
A given element may be a container in different ways, depending on its
`container-type` property. For a container query to match an element,
that element must have the required container type for each feature
that the query checks. This commit implement a step to collect those
required types, so that we can quickly eliminate potential container
elements that lack a required containment type.
2026-05-13 11:05:31 +01:00
Sam Atkins
2a89c56143 LibWeb/CSS: Cache CSSContainerRule's nearest ancestor CSSContainerRule
Once we start evaluating `@container` matches, we will need to check if
any ancestor `@container`s also match. Caching the nearest one, if any,
will let us skip walking the entire ancestor chain.
2026-05-13 11:05:31 +01:00
Sam Atkins
88aea2e11d LibWeb: Give BooleanExpression an evaluation context
Different users of BooleanExpression have different requirements for
evaluation:
- `@media` needs a Document
- `@supports` doesn't need anything
- `@container` needs a container Element

To support these without expanding the API, replace the Document*
parameter with a BooleanExpressionEvaluationContext type which contains
these different values.

No behaviour changes.
2026-05-13 11:05:31 +01:00
Sam Atkins
442319c676 LibWeb/CSS: Update grammar for @container
Corresponds to
efc0c6f847
2026-05-13 11:05:31 +01:00
Sam Atkins
35b43f7d3a LibWeb/CSS: Insert a combinator before all pseudo-element selectors
Previously, and according to the spec, `a::part(foo)::before` would be a
single CompoundSelector, even though it matches against 3 different
targets. This meant some awkward swapping of targets in the middle of
matching, and in particular it made `::part()` and `::slotted()` quite
hacky, requiring them to track extra data on the MatchContext to then
use later. This was scattered around and difficult to follow.

Partly inspired by Gecko, this commit instead introduces an invisible
PseudoElement combinator. After parsing a selector, we find any
CompoundSelectors that contain a pseudo-element and split them up, so
that each CompoundSelector only has a single target in the end. Where
the pseudo-element was at the start of a CompoundSelector, we insert an
invisible universal selector before it to represent its originating
element.

So now, a CompoundSelector deals with one target, and switching targets
is done at the combinator.

The one inconsistency is that we match the target of ::slotted()
and ::part() in pseudo_element_transition_target(), instead of before
then when processing the SimpleSelector. This is to avoid repeating the
same computations twice.

No outward-facing behaviour changes, though the invalidation metrics
have changed.
2026-05-13 11:03:02 +01:00
Callum Law
f578d95be0 LibWeb: Support multiple keywords in parse_specific_keyword_value
This will allow us to combine multiple calls into one and avoid
repeatedly parsing and then discarding `KeywordStyleValue`s
2026-05-13 11:00:07 +01:00
mikiubo
b9ed64d1ce LibWeb: Add dedicated overflow-clip-margin style value
Store overflow-clip-margin as a structured style value instead of
collapsing it into generic keyword/length lists during parsing.

Keep omitted visual-box as a distinct state so painting can apply
the spec default per element type (content-box for replaced,
padding-box otherwise), while preserving canonical serialization.
2026-05-12 14:09:13 +02:00
mikiubo
a3e420bb9e LibWeb: Parse visual-box in overflow-clip-margin
Support content-box, padding-box, and border-box in
overflow-clip-margin parsing, including combinations with length.

Canonicalize parsed values to match the grammar and expected CSSOM
serialization in css-overflow parsing tests.
2026-05-12 14:09:13 +02:00
Tim Ledbetter
013ede7214 LibWeb: Use targeted invalidation when adopting a stylesheet
Previously, adding or removing a constructed `CSSStyleSheet` via
`document.adoptedStyleSheets` invalidated style for the entire document
or shadow root. We now route this through the same style invalidation
machinery that's used when we add or remove `<style>` elements,
resulting in fewer full invalidations.
2026-05-10 20:19:32 +02:00
Tim Ledbetter
ca43780bba LibWeb: Move stylesheet add/remove invalidation into shared helper
No behavior change.
2026-05-10 20:19:32 +02:00
Andreas Kling
5cf90c0d0d LibWeb: Avoid stale delayed resource callbacks
Delayed preload and image animation callbacks can outlive the objects
they notify. Incremental sweeping makes this easier to hit because stale
callback state may be reclaimed before the delayed work runs.

Use a weak link element when firing preload load and error events, and
use a weak image style value from animated image timers instead of a raw
pointer.
2026-05-10 10:58:11 +02:00
Shannon Booth
5adfd1c43a LibWeb/Bindings: Generate struct definitions from IDL dictionaries
Previously we were inconsistent by generating code for enum definitions
but not generating code for dictionaries. With future changes to the
IDL generator to expose helpers to convert to and from IDL values
this produced circular depdendencies. To solve this problem, also
generate the dictionary definitions in bindings headers.
2026-05-09 10:49:49 +02:00
Tim Ledbetter
ac685a8a79 LibWeb: Only invalidate style on links matching :local-link
Currently, this is the only pseudo class which is URL-sensitive. When
we implement proper tracking of visited URLs this will need to be
replaced with something more comprehensive.
2026-05-08 12:30:29 +01:00
Tim Ledbetter
f29bc0c996 LibWeb: Use scroll compensation for background-attachment: fixed
Instead of baking the current scroll offset into the background
positioning area at record time, use the `ScrollCompensation` visual
context node to negate ancestor scroll frames dynamically at replay
time. This keeps the background fixed relative to the viewport even
when the display list is cached and replayed at different scroll
positions, and works correctly with arbitrarily nested scroll
containers.
2026-05-08 13:09:40 +02:00
Andreas Kling
98a9c36ba7 LibWeb: Make structural-position pseudos targetable when sole feature
When a sheet's rightmost compound carries :first-child, :last-child,
or :only-child but no other class/tag/id/attr feature, the sheet
add/remove path can target the boundary children directly instead of
falling back to a whole-subtree invalidation.

The narrowing in extend_style_sheet_invalidation_set_with_style_rule
deliberately only kicks in when the structural pseudo is the only
feature in the rightmost compound. A selector like `.foo:first-child`
keeps targeting `.foo` rather than every first-child in the
document.

Adds matchers for :first-child / :last-child / :only-child in
InvalidationSetMatcher so the targeted walk can recognize them on
each candidate element.
2026-05-07 19:32:27 +02:00
Andreas Kling
62440c1472 LibWeb: Make :host, :root, and interaction-state pseudos targetable
Stylesheet add/remove previously fell back to a whole-subtree
invalidation whenever a sheet's rightmost compound carried one of
these pseudo-classes. They each match a small, knowable set of
elements at any moment, so the invalidation walk can target them
directly:

- :host matches one element per shadow root and :root matches the
  html element. Mark them targetable.
- :hover, :focus, :focus-visible, :focus-within, :active, and
  :target all match at most a handful of elements at a time. Mark
  them targetable and add matchers in InvalidationSetMatcher that
  consult Document::hovered_node, focused_area, target_element,
  and the element's own focused/active state.
2026-05-07 19:32:27 +02:00
Andreas Kling
0ee13f9a82 LibWeb: Use targeted invalidation for @keyframes in added/removed sheets
@keyframes rules only affect elements that already reference the named
animation. Instead of falling back to a whole-subtree invalidation
when a sheet contains @keyframes, walk the sheet's @keyframes rules in
StyleSheetList::add_sheet/remove_sheet and reuse the existing per-rule
helper to dirty just the elements that reference each animation-name.
2026-05-07 19:32:27 +02:00
Andreas Kling
89933f18d1 LibWeb: Don't force broad invalidation when adding/removing @font-face
@font-face declares a resource whose effect on computed style is
deferred until the font actually loads, which is handled by the
CSSFontLoaded path. Adding or removing the at-rule itself does not
change any element's computed style, so the sheet add/remove path
no longer has to fall back to a whole-subtree invalidation when a
sheet contains @font-face.
2026-05-07 19:32:27 +02:00
Sam Atkins
d7344a96bb LibWeb: Parse and propagate container and container-name properties 2026-05-07 17:48:53 +02:00
Aliaksandr Kalenik
f8640d813a LibGfx+LibWeb: Make DecodedImageFrame a value type
DecodedImageFrame only wraps a ref-counted Bitmap and color-space
metadata. The frame object itself does not provide shared mutable
state or lifetime ownership beyond those members, so ref-counting it
adds an unnecessary layer of indirection.
2026-05-07 16:08:13 +02:00