Commit graph

1502 commits

Author SHA1 Message Date
Ali Mohammad Pur
765df1130e LibWeb: Implement the required virtual owner_cell() on HTMLCollection
This was breaking the build for me.
2026-05-14 13:27:56 +01:00
Tim Ledbetter
5e2db73c74 LibWeb: Use WeakContainer for HTMLCollection's cached elements
The element cache used `GC::Weak<Element>`, paying for a `WeakImpl`
allocation per cached element on every cache rebuild.

This get's rid of a 4% profile item when toggling state on
https://diskprices.com
2026-05-14 13:28:19 +02:00
Tim Ledbetter
da210eaa9d LibWeb: Refresh stale inherited custom-property data on ancestor change
When an ancestor's custom property changes, intermediate elements that
don't themselves consume `var()`/`inherit()` were skipped during style
recomputation, leaving their `m_custom_property_data` pointing at the
ancestor's stale `CustomPropertyData`. Deeper descendants that did
consume `var()` then resolved against the out-of-date chain.

This change adds `Element::refresh_inherited_custom_property_data()` to
re-link an element's inherited chain to its parent's current data
without re-cascading. This is called during `update_style_recursively()`
for elements that don't need a full recompute.
2026-05-13 18:46:12 +02:00
Aliaksandr Kalenik
82b016ed19 LibWeb: Rebuild async scrolling from display list
Use compositor hit-test commands in the display list to rebuild async
wheel targets, and serialize the async scroll metadata needed to
reconstruct AsyncScrollingState from the same display-list snapshot.

Driving the async scroll tree off the display list rather than a
separately collected tree has a few benefits:

- No additional full paintable tree traversal is required, since the
  information needed by the compositor is gathered while recording
  the display list.
- The display list is already serializable, so the async scroll tree
  no longer needs its own serialization path.
- It is more debuggable, as the existing display list dump now also
  covers the data used to reconstruct the async scroll tree.
- In the future we will want to include other areas that can
  interfere with hit-testing; recording them during display list
  construction makes it straightforward to preserve a hit-testing
  order that matches painting order.
2026-05-13 18:36:07 +02: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
Andreas Kling
b57cc2bb7a LibWeb: Invalidate async wheel state on listener changes
Bump a page-level wheel listener generation whenever non-passive wheel
listeners are added or removed. Store that generation in async scrolling
snapshots, and mark compositor wheel admission stale when listener state
changes before a current snapshot arrives.

This keeps the UI-process compositor wheel bypass from trusting an old
no-listener snapshot after script has installed a cancelable wheel
listener. Add async-scrolling coverage for the listener generation bump
and the fresh routing state after a blocking wheel listener is added.
2026-05-12 20:57:08 +02:00
Aliaksandr Kalenik
671cc8595a LibWeb: Send scroll-state-only updates to the rendering thread
When nothing invalidates the display list between frames, push only an
updated scroll state snapshot to the rendering thread instead of
handing it the display list again.

This is preparation for moving rendering to a separate process, where
sending the display list across the process boundary on every frame
would be expensive.
2026-05-11 22:52:38 +02:00
Daniel Gołębiewski
26b18f192e LibWeb: Basic support for scrollIntoView on boxes 2026-05-10 11:32:02 +02:00
Andreas Kling
e23ec1f841 LibWeb: Convert Document's cursor blink timer to GC::Timer
Use GC::Timer instead of Core::Timer for the cursor blink timer so
that capturing [this] in the callback properly protects the Document
from garbage collection.
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
Shannon Booth
7ad946c669 LibWeb/Bindings: Generate enum bindings in their owning IDL headers
Change the bindings generator to emit enum definitions into the
Bindings/<Thing>.h file owned by the IDL that defines them, including
support IDLs that do not have a top-level interface or namespace.

Allow enum-only modules to generate bindings headers and make generated
bindings code include those owner headers when another IDL depends on
their enums.

This allows us to replace the hand made NavigationType.h header with
one generated by bindings.
2026-05-09 10:49:49 +02:00
Andreas Kling
1fcd61614c Revert "LibWeb: Reuse initial about:blank window for first same-origin load"
This reverts commit 7fc7263a4d.

Speculative revert to fix WPT runner.
2026-05-09 00:52:16 +02:00
Callum Law
40ebd94ca9 LibWeb: Update stale ScrollTimelines after layout
This is required by the spec and fixes a flaky test
2026-05-08 22:59:16 +02:00
Callum Law
34f0eea89a LibWeb: Update animations in AnimationTimeline::set_current_time
These steps need to be run whenever update_current_time is called and in
a future commit that will be more than just the one place currently.

This also removes the early return in `set_current_time` if the new
`current time` is the same as the old one, since we want to update
animations regardless (e.g. to run pending tasks)
2026-05-08 22:59:16 +02:00
Aliaksandr Kalenik
998ec2af83 LibWeb: Store display lists in a flat command buffer
Replace Vector<Variant<...>> display-list storage with a contiguous byte
buffer of command headers, trivially-destructible payloads, and inline
data spans. Variable-size data such as glyphs, paths, dash arrays,
gradient stops, and nested command bytes is appended next to the command
that references it.

The flat representation is prep work for sending display lists over IPC
to a dedicated rasterization process, which the previous Variant-based
structure could not support directly. It also avoids walking command
destructors when a display list is discarded and reduces per-command
allocation and indirection, improving memory use and data locality.
2026-05-08 20:45:17 +02:00
Aliaksandr Kalenik
f56745b15b LibWeb: Store display list resources separately
Commands used to keep rendering resources directly in the variant:
image frames, external content and video sources, filters, SVG paint
styles, and nested display lists. That makes the command stream own its
dependencies and prevents it from becoming a POD-like byte buffer.

Add DisplayListResourceStorage and replace those command fields with
stable resource IDs. The storage deduplicates resources by their
existing IDs and can copy only the resources referenced by a captured
command sequence, giving the future IPC boundary a clear list of
resources that must be communicated to the rasterization process.
2026-05-08 20:45:17 +02:00
Shannon Booth
29033939f3 LibWeb/DOM: Prefix inline event handler source text with "on"
EventTarget stores event handler entries under bare event names like
click and error, because those keys are also used in places that need
the event type rather than the IDL/content-attribute spelling.

That means we cannot only reuse the stored key when synthesizing the
function source for inline handlers. To handle this, prefix the name
with "on".
2026-05-08 15:49:01 +01:00
Shannon Booth
7fc7263a4d LibWeb: Reuse initial about:blank window for first same-origin load
Follow the spec reuse of the initial same-origin about:blank window for
a browsing context's first real navigation. This fixes a crash in
promise-job-entry-different-function-realm.html by preserving the
correct iframe realm.

Making this change also requires another AD-HOC workaround to defer
updating the reused window's associated document until activation,
since doing so during document creation makes the browsing context's
active document change too early.
2026-05-08 16:24:54 +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
e211c3dcd5 LibWeb: Only invalidate style for relevant links on navigation 2026-05-08 12:30:29 +01: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
Aliaksandr Kalenik
568b7ce7ea LibWeb: Make Paintable tree ref-counted
The Paintable tree and its supplemental painting data structures were
GC allocated because that was the easiest way to manage it and avoid
leaks introduced by ref cycles. This included the Paintable subclasses
themselves plus StackingContext, ChromeWidget, Scrollbar, ResizeHandle,
and scroll-frame state.

We are now trying to reduce GC allocation churn on layout and painting
updates, so keeping this short-lived rendering tree outside the JS heap
is a better fit. Move Paintable to RefCountedTreeNode, make painting
helpers ref-counted or weakly reference Paintables, and update the
layout and event-handler call sites to use RefPtr/WeakPtr ownership.
2026-05-07 15:03:44 +02:00
Andreas Kling
d3d59a0c00 LibWeb: Account DOM state as external memory
Report event listener storage, registered observers, static node
lists, DOMTokenList tokens, and abort signal dependency storage
through the GC external memory hook.
2026-05-07 10:03:09 +02:00
Andreas Kling
a414136d7c LibWeb: Account text and image storage as external memory
Report DOM character data, decoded image frames, ImageBitmap pixel
buffers, and 2D canvas surfaces through the GC external memory hook.
This lets image and text-heavy pages participate in GC threshold
calculations through their retained backing storage.
2026-05-07 10:03:09 +02:00
Sam Atkins
f62d754c91 LibWeb/DOM: Spec-comment Element::tab_index()
A recent change added the "MathML a element" to the list in step 3, but
we do not currently implement this element.
2026-05-06 17:42:36 +01:00
Aliaksandr Kalenik
76c79ee522 LibGfx: Remove ImmutableBitmap
DecodedImageFrame now owns decoded bitmap pixels directly, so the
separate ImmutableBitmap wrapper no longer carries useful semantics.
Remove the class and pass decoded image frames or bitmaps at the
boundaries where pixels are actually required.

The Skia image cache now keys off DecodedImageFrame, matching the
display-list commands that paint decoded images. Video frames stay
owned by LibMedia, with the explicit YUV-to-bitmap conversion living
at HTMLVideoElement's decoded-frame entry point for canvas and WebGL
callers.
2026-05-05 14:39:17 -05:00
Tim Ledbetter
78b47109af LibWeb: Use the ASCII line segmenter for eligible text 2026-05-05 18:59:07 +02:00
Tim Ledbetter
1cc288730c LibWeb: Stop storing CascadedProperties on each element
`CascadedProperties` is now allocated fresh when style is recomputed.
`Element` and `PseudoElement` no longer keep hold of cascaded
properties.
2026-05-05 16:02:23 +02:00
Tim Ledbetter
c26922c898 LibWeb: Cache values needed after the cascade finishes
Previously, we consulted `cascaded_properties()` in a couple of places
after the cascade pass for the relevant element had finished, forcing
`CascadedProperties` to outlive style resolution.

We now keep the small set of values these consumers need on
`ComputedProperties`. We keep hold of resolved specified values for
properties whose computation depends on inherited info, so they can be
re-resolved when an ancestor changes. We also keep the raw winning
cascaded font-size, as this is needed by the time-traveling monospace
font quirk implemented by `recascade_font_size_if_needed()`.
2026-05-05 16:02:23 +02:00
Tim Ledbetter
08ece2af93 LibWeb: Skip @media rule re-evaluation when nothing has changed
The `m_needs_media_query_evaluation` tracks when we need to evaluate
media rules, but we were evaluating them unconditionally during style
updates.
2026-05-05 11:23:11 +02:00
Aliaksandr Kalenik
2222654db4 LibWeb: Skip update_layout in IntersectionObserver internal lookups
When the update intersection observations steps run (HTML rendering
update step 19), the algorithm calls Element::get_bounding_client_rect()
on each observed target and on element-typed roots. That path always
calls update_layout_if_needed_for_node() before reading the paintable
rect.

By the time step 19 runs, layout is already up to date: step 16 has
just laid out the document, and the preamble of step 19 itself flushes
any post-step-16 invalidation with a single update_layout call. So each
per-target update_layout call inside getBoundingClientRect is a
guaranteed no-op early-exit.
2026-05-03 12:25:04 +02:00
Shannon Booth
e2f0c340d4 LibWeb: Remove some outdated #import related FIXMEs
We no longer require IDL files to import from one another, so these
FIXMEs about circular references have been fixed.
2026-05-03 10:56:45 +02:00
Callum Law
130c3cbb5a LibWeb: Don't cancel animations if element is display none is animated
According to the spec we should only cancel animations if the value of
display would be none when ignoring animations/transitions.
2026-05-01 18:46:14 +02:00
Callum Law
73d57be72d LibWeb: Make has_inclusive_ancestor_with_display_none const 2026-05-01 18:46:14 +02:00
Jelle Raaijmakers
a6499b621e LibWeb: Restrict ShadowRoot layout update to node when setting innerHTML
We were invalidating the entire document's layout tree when a shadow
root's innerHTML was updated, but we already support more granular
layout updates for shadow roots - so make sure to only invalidate the
node's layout.

Reduces the time needed to obtain a layout and painting tree for
https://pomax.github.io/bezierinfo/ by 21% on my machine.
2026-04-30 21:26:25 +02:00
Tim Ledbetter
d1fc4b4234 LibWeb: Route presentational hints through the CSS cascade
Previously, presentational hints bypassed the regular cascade pipeline
and wrote directly into `CascadedProperties` under
`CascadeOrigin::Author`. That meant `var()` substitution and the
invalid-at-computed-value-time fallback had to be duplicated in a
separate per-element pass, which in practice missed the IACVT step and
could leave a `GuaranteedInvalidStyleValue` in the cascaded
properties. This caused a crash in downstream code that assumed the
value had been resolved.

This introduces an `AuthorPresentationalHint` cascade origin and feeds
them through the cascade as normal declarations. This means that
`var()` resolution now happens in only one place.
2026-04-30 19:50:28 +01:00
Johan Dahlin
f7499105dd LibWeb: Implement inline PDF viewing using the bundled pdf.js viewer 2026-04-30 07:46:12 +02:00
Andreas Kling
c919f1c28f LibWebView: Add style invalidation counter dump option
Add --dump-style-invalidation-counters=N to Ladybird and propagate it
to WebContent helper processes.

When enabled, WebContent dumps the current document style invalidation
counters with dbgln() after every N recorded style invalidations. This
makes it possible to collect the counters while browsing without adding
temporary C++ logging.
2026-04-30 00:24:04 +02:00
Aliaksandr Kalenik
f785e13ae9 LibWeb: Schedule rendering updates on demand
Previously a fixed-rate paint refresh timer kept queueing rendering
update tasks at the maximum configured frame rate, regardless of whether
anything had actually changed. This wasted CPU on idle pages, which
spend most of their time in a steady state where no style, layout, or
paint work is needed.

Replace the repeating timer with a single-shot frame timer driven by
PageClient::request_frame(). A rendering update is now scheduled only
when something requires one. The configured maximum frame rate is
preserved as a ceiling on how closely consecutive frames can follow each
other.
2026-04-29 20:54:53 +02:00
Andreas Kling
007dc28d16 LibWeb: Move shadow root style invalidation into the helper
Element::set_shadow_root directly selected the style invalidation reason
used when a shadow root changes. Move that mapping into
CSS::Invalidation::ElementStateInvalidator.

Element still owns the shadow-root state transition and the required
layout-tree invalidation. CSS invalidation now owns the style dirtiness
for that state change.
2026-04-29 15:47:23 +02:00
Andreas Kling
b0bb2bd0a8 LibWeb: Move active state invalidation into the helper
Element::set_being_activated directly selected the style invalidation
reason used for :active changes. Move that mapping into
CSS::Invalidation::ElementStateInvalidator.

The element continues to own its activation state. CSS invalidation now
owns the style invalidation work associated with changing that state.
2026-04-29 15:47:23 +02:00
Andreas Kling
79c32f88d2 LibWeb: Move pending :has() invalidation into the helper
Document.cpp still flushed pending :has() invalidation by walking the
document and shadow-root style scopes directly. Move that CSS-specific
flush into CSS::Invalidation::HasMutationInvalidator.

Document continues to own the flag that says a :has() flush is needed.
The helper now owns the style-scope work needed to invalidate elements
affected by pending :has() mutations.
2026-04-29 15:47:23 +02:00
Andreas Kling
b8c2469566 LibWeb: Move media query style invalidation into a helper
Document.cpp still handled CSS fallout from stylesheet media query match
changes directly. Move active stylesheet evaluation, rule-cache
invalidation, shadow-root fallout, and slot propagation into the CSS
invalidation helper.

Document continues to decide when media queries should be evaluated.
The helper now owns the style invalidation consequences when stylesheet
media queries change match state.
2026-04-29 15:47:23 +02:00
Andreas Kling
0a938fdd51 LibWeb: Move slot style propagation into the helper
Document.cpp still knew how style changes on a slot propagate to
assigned light-DOM nodes. Move that flat-tree inheritance invalidation
into CSS::Invalidation::SlotInvalidator.

The style update walk continues to decide when an element's style
changed. The helper now owns the ::slotted() consequence of dirtying
assigned slottables for a changed slot.
2026-04-29 15:47:23 +02:00
Andreas Kling
98b13da3b4 LibWeb: Move adopted stylesheet invalidation into a helper
AdoptedStyleSheets.cpp still handled CSS-side fallout from adopted sheet
list mutations directly. Move sheet attachment and media-query setup to
a CSS invalidation helper, along with rule-cache invalidation.

The observable array callbacks continue to validate JS values and
same-document construction rules. The helper now owns the CSS work for
when a constructed stylesheet becomes visible to, or is removed from, a
Document or ShadowRoot.
2026-04-29 15:47:23 +02:00
Andreas Kling
c191d51af1 LibWeb: Move slotted style invalidation into a helper
Slottable.cpp still handled the style invalidation fallout from slot
assignment changes directly. Move that ::slotted()-related policy into
CSS::Invalidation::SlotInvalidator.

Slot assignment remains DOM bookkeeping. The helper now owns the
choice to dirty element slottables when they gain or lose assignment
to a slot.
2026-04-29 15:47:23 +02:00
Andreas Kling
bc0059cfd5 LibWeb: Move text directionality invalidation into the helper
CharacterData.cpp still handled the style invalidation fallout from text
mutations under dir=auto ancestors directly. Move that behavior into the
CSS language invalidation helper.

CharacterData continues to own text replacement and layout text updates.
The helper now owns the inherited :dir() restyle and :has(:dir(...))
ancestor scheduling that can follow from text content changes.
2026-04-29 15:47:23 +02:00
Andreas Kling
1ba3ec6ae7 LibWeb: Move part style invalidation into a helper
Element.cpp still handled the style invalidation fallout from part and
exportparts attribute changes directly. Move that ::part-related policy
into CSS::Invalidation::PartInvalidator.

Element continues to update the DOM token state for part attributes. The
helper now owns the style dirtiness for elements targeted through ::part
and for shadow-tree descendants exposed through exportparts.
2026-04-29 15:47:23 +02:00
Andreas Kling
b0effb3167 LibWeb: Move language style invalidation into a helper
Element.cpp still handled the CSS invalidation fallout from dir and lang
attribute changes directly. Move the descendant style dirtiness and
:has(:dir/:lang) ancestor scheduling into CSS::Invalidation.

Element continues to parse and store the DOM-facing attribute state. The
new helper owns the inherited style invalidation behavior that follows
from language and directionality changes.
2026-04-29 15:47:23 +02:00
Andreas Kling
3d8fa1ed26 LibWeb: Move node style invalidation into a helper
Node.cpp still contained the CSS policy for full style invalidation and
property-based invalidation plans. Move that logic into
CSS::Invalidation::NodeInvalidator.

Node remains the public DOM entry point for callers that need to
invalidate style. The helper now owns the :has() metadata probing,
style-scope plan lookup, and subtree/sibling invalidation scheduling.
2026-04-29 15:47:23 +02:00