Commit Graph

183 Commits

Author SHA1 Message Date
Shannon Booth
fd44da6829 LibWeb/Bindings: Emit one bindings header and cpp per IDL
Previously, the LibWeb bindings generator would output multiple per
interface files like Prototype/Constructor/Namespace/GlobalMixin
depending on the contents of that IDL file.

This complicates the build system as it means that it does not know
what files will be generated without knowledge of the contents of that
IDL file.

Instead, for each IDL file only generate a single Bindings/<IDLFile>.h
and Bindings/<IDLFile>.cpp.
2026-04-21 07:36:13 +02:00
Andreas Kling
7a5b1d9de1 LibWeb: Delay generic :has() sibling scans until sibling roots
Mark elements reached by stepping through sibling combinators inside
:has() and use that breadcrumb during generic invalidation walks.

Keep the existing conservative sibling scans for mutations outside
those marked subtrees so nested :is(), :not(), and nesting cases
continue to invalidate correctly.

Also keep :has() eager within compounds that contain ::part(). Those
selectors retarget the remaining simple selectors to the part host, so
deferring :has() there changes which element the pseudo-class runs
against and can make ::part(foo):has(.match) spuriously match.

Add a counter-based sibling-scan test and a regression test covering
the ::part()/ :has() selector orderings.
2026-04-20 13:20:41 +02:00
Andreas Kling
85ff13870f LibWeb: Stop :has() invalidation walk when out of :has() scope
A DOM mutation under a document that uses any :has() rule currently
walks every ancestor up to the root, invoking invalidate_style_if_
affected_by_has() on each. Most of those ancestors have nothing to
do with :has(), so the work scales linearly with DOM depth.

Introduce an in_has_scope flag on Element, set while evaluating :has()
arguments for invalidation metadata. StyleScope's upward invalidation
walk now terminates at the first element that is neither in :has()
scope nor a :has() anchor, so it only traverses the region where some
:has() rule might actually care about the change.

Keep the existing fast :has() matching paths for normal selector
matching, but bypass them while collecting per-element metadata so the
scope markers still get populated. Node insertion also schedules the
parent for the :has() walk so newly inserted nodes still reach the real
anchor.

The css-has-invalidation suite adds focused coverage for these shapes
and updates the expected counters to reflect the shorter walks.
2026-04-20 13:20:41 +02:00
Andreas Kling
8caca053a3 LibWeb: Avoid IntersectionObserver registration lookups
IntersectionObserver updates already iterate over each observer and its
observation targets. We then looked the same target and observer pair up
again through Element's registered observer list just to read and write
previousThresholdIndex and previousIsIntersecting.

Store that mutable state with the observer-side observation target
instead. The element-side list now only keeps strong observer
references for lifetime management and unobserve/disconnect.

This deviates from the spec's storage model, so document the difference
next to the preserved spec comments.
2026-04-17 08:02:30 +02:00
Shannon Booth
8642801889 LibWeb: Set fragment scripting mode from the context document
This corresponds with the editorial change to the HTML standard
introducing the parsing mode enum of:

https://github.com/whatwg/html/commit/01c45cede

And a follow up normative change of:

https://github.com/whatwg/html/commit/508706c80

Making fragment parsing derive its scripting mode from the context
document.
2026-04-14 23:01:36 +02:00
Andreas Kling
0f4575e7d0 LibWeb: Clear stale layout state for inactive documents
IntersectionObserver can keep elements from a navigated iframe's old
document alive until a later rendering update. Once that document tears
down its layout tree, descendant nodes and pseudo-elements can still
retain stale layout and paintable pointers, and destruction can bypass
the usual inactive-document teardown entirely.

Clear per-node layout and paintable pointers across the inactive
document subtree before tearing down the layout tree, and do the same
from destroy() for documents that never go through
did_stop_being_active_document_in_navigable().

Add a crash test that observes an iframe target, navigates the iframe,
and waits for rendering updates without touching stale layout state.

Fixes #8670
2026-04-11 16:03:26 +02:00
Sam Atkins
ed6a5f25a0 LibWeb: Implement scoped custom element registries 2026-03-27 19:49:55 +00:00
Sam Atkins
96f84b1322 LibWeb/DOM: Give Element a CustomElementRegistry 2026-03-27 19:49:55 +00:00
Luke Wilde
df32da5e86 LibWeb: Make every HTMLElement potentially form-associated
This can be the case for form-associated custom elements, where any
HTML element can be form-associated.
2026-03-25 13:18:15 +00:00
Callum Law
915fc4602b LibWeb: Implement CSS inherit() function
The remaining failing imported tests are due to wider issues which are
covered by FIXMEs (both existing and added in this commit)
2026-03-19 10:25:37 +01:00
Shannon Booth
cc6536b527 LibWeb/HTML: Always provide ChildrenChangedMetadata to children changed 2026-03-19 09:46:54 +01:00
Zaggy1024
2e54c18fb3 LibWeb: Use a queue to process fullscreen request completions
Instead of immediately firing fullscreenchange, defer that until
WebContent's client has confirmed that it is in fullscreen for the
content. The fullscreenchange is fired by the viewport change, so in
cases where the fullscreen transition is instantaneous (i.e. the
fullscreen state is entered at the exact moment the viewport expands),
the resize event should precede the fullscreenchange event, as the spec
requires.

This fixes the WPT element-request-fullscreen-timing.html test, which
was previously succeeding by accident because we were immediately
fullscreenchange upon requestFullscreen() being called, instead of
following spec and doing the viewport (window) resize in parallel. The
WPT test was actually initially intended to assert that the
fullscreenchange event follows the resize event, but the WPT runner
didn't actually have a different resolution for normal vs fullscreen
viewports, so the resize event doesn't actually fire in their setup. In
our headless mode, the default viewport is 800x600, and the fullscreen
viewport is 1920x1080, so we do fire a resize event when entering
fullscreen. Therefore, that imported test is reverted to assert that
the resize precedes the fullscreenchange.
2026-03-17 18:58:37 -05:00
Zaggy1024
009e25a875 LibWeb: Move RequestFullscreenError out of Element.h
This will be needed across classes to handle a queue of fullscreen
requests.
2026-03-17 18:58:37 -05:00
Zaggy1024
44ed698d4f LibWeb: Separate the active element and the element being activated
We were conflating elements being the active element and elements being
activated. The :active pseudo class is supposed to be based on whether
an element will have its activation behavior run upon a button being
released.

Store whether an element is being activated as a flag that is set/reset
by EventHandler.

Doing this allows label elements to visually activate their control
without doing a weird paintable hack, so the Labelable classes have
been yeeted.
2026-03-17 04:01:29 -05:00
Callum Law
c47f226225 LibWeb: Support CSS if() function
We don't yet support style queries
2026-03-09 14:36:18 +00:00
Callum Law
0c847e2560 LibWeb: Reset whether element uses tree counting function on recompute
This can save us some unnecessary recomputations if an element's style
changes from depending on a tree counting function to not.

Also removes an incorrect FIXME
2026-03-09 14:36:18 +00:00
Aliaksandr Kalenik
d17b7fe70d LibWeb: Track structural invalidation dependencies by direction
Split the structural-change selector metadata into directional bits for
first/last-child and forward/backward positional selectors.

This gives sibling invalidation enough information to distinguish which
side of a mutation can affect an element, instead of treating all
structural selectors as bidirectional.
2026-03-07 00:34:00 +01:00
Timothy Flynn
aabf7ae8fb LibWeb: Skip fullscreen transient activation requests for WebDriver
A transient activation is rarely going to exist when invoked from
WebDriver.
2026-03-02 15:49:13 -05:00
Timothy Flynn
2282636f98 LibWeb: Clean up the element fullscreen APIs a bit
* Don't publicly expose methods that are only used internally.

* Modernize comment style (wrap at 120 chars, use NB for our notes).

* Change the stringifier for RequestFullscreenError to return a UTF-16
  string. We were allocating a String, then transcoding it to UTF-16.

* Give helper methods clearer names, e.g.:

  fullscreen_has_error_check -> is_element_allowed_to_enter_fullscreen
2026-03-01 15:41:43 -06:00
Andreas Kling
a146225331 LibWeb: Use unsafe layout/paintable accessors where appropriate
Add unsafe_layout_node(), unsafe_paintable(), and unsafe_paintable_box()
accessors that skip layout-staleness verification. These are for use in
contexts where accessing layout/paintable data is legitimate despite
layout not being up to date: tree construction, style recalculation,
painting, animation interpolation, DOM mutation, and invalidation
propagation.

Also add wrapper APIs on Node to centralize common patterns:
- set_needs_display() wraps if (unsafe_paintable()) ...set_needs_display
- set_needs_paint_only_properties_update() wraps similar
- set_needs_layout_update() wraps if (unsafe_layout_node()) ...

And add Document::layout_is_up_to_date() which checks whether layout
tree update flags are all clear.
2026-02-26 21:09:08 +01:00
Simon Farre
bc17805b2b LibWeb: Implement requestFullscreen algorithm
The required functionality to exit fullscreen will be in a followup
commit.
2026-02-23 18:44:26 +00:00
Simon Farre
db076bab92 LibWeb: Add Fullscreen event handlers to Document and Element
This also adds a stub to the Permissions Policy checks.
2026-02-23 18:44:26 +00:00
Andreas Kling
9e8e568b43 LibWeb: Use structural sharing for CSS custom properties
Replace per-element OrderedHashMap storage for custom properties with
a RefCounted chain (CustomPropertyData) that enables structural
sharing. Each chain node stores only the properties declared directly
on its element, with a parent pointer to the inherited chain.

Elements that don't override any custom properties share the parent's
data directly (just a RefPtr copy). During cascade, only entries that
actually differ from the parent are stored in own_values - the rest
are inherited through the chain. During var() resolution, resolved
values are compared against the parent's and matching entries are
dropped, enabling further sharing.

The chain uses a depth limit (max 32) with flattening, plus
absorption of small parent nodes (threshold 8) to keep lookups fast.

This reduces custom property memory from ~79 MB to ~5.7 MB on
cloudflare.com.
2026-02-13 14:57:15 +01:00
Aliaksandr Kalenik
fde2015846 LibWeb: Reduce recompilation impact of DOM/Element.h
Remove unused/redundant includes from Element.h:
- AK/IterationDecision.h (redundant)
- ARIA/AttributeNames.h (redundant via ARIAMixin.h)
- CSS/CascadedProperties.h (redundant via PseudoElement.h)
- CSS/StylePropertyMapReadOnly.h (pointer types only)
- HTML/LazyLoadingElement.h (unused in header)

Extract IntersectionObserverRegistration struct from
IntersectionObserver.h into its own lightweight header.
This breaks the heavy transitive include chain through
IntersectionObserverEntry.h and Geometry/DOMRect.h that
was pulled into every file including Element.h.

Indirect recompilation impact reductions:
- IntersectionObserver.h: ~1387 -> ~27 files
- LazyLoadingElement.h: ~1387 -> ~1002 files
2026-02-11 20:02:28 +01:00
Callum Law
379db7a42c LibWeb: Support animation-timeline scroll() value 2026-02-11 10:49:34 +01:00
Aliaksandr Kalenik
40429292fe LibWeb: Forward-declare RequiredInvalidationAfterStyleChange in Element
Replace the direct #include of StyleInvalidation.h in Element.h with a
forward declaration in Forward.h. Element.h only uses the type in
function declarations, so the complete type is not needed.

This reduces the recompilation impact of modifying StyleInvalidation.h
from ~1380 files to ~4 files, since Element.h is transitively included
by nearly every HTML and SVG element header.
2026-02-11 06:52:11 +01:00
Aliaksandr Kalenik
c62996abd7 LibWeb: Avoid dynamic_cast in SlottableMixin::assigned_slot()
`SlottableMixin::assigned_slot()` was using `as<DOM::Node>(*this)` to
get a `Node` reference. Since `SlottableMixin` has no inheritance
relationship with `Node`, `as_if<>` can't use `static_cast` and falls
through to `dynamic_cast`, which is expensive. Replace this with a
virtual `slottable_as_node()` accessor overridden in `Element` and
`Text`.

This showed up as hot in profiles when loading the GC heap explorer
page.
2026-02-07 16:43:50 +01:00
Andreas Kling
8d2081d3ff LibWeb: Mark Element::attribute_changed() as MUST_UPCALL
The base implementation handles critical bookkeeping like element
ID/name registration and slot assignment. Forgetting to call it
from a derived class would be a correctness bug.
2026-02-06 13:50:54 +01:00
Luke Wilde
babfd70ca7 LibGC: Enforce that a Cell type must declare the allocator to use
This ensures that we are explicitly declaring the allocator to use when
allocating a cell(-inheriting) type, instead of silently falling back
to size-based allocation.

Since this is done in allocate_cell, this will only be detected for
types that are actively being allocated. However, since that means
they're _not_ being allocated, that means it's safe to not declare
an allocator to use for those. For example, the base TypedArray<T>,
which is never directly allocated and only the defined specializations
are ever allocated.
2026-01-20 12:00:11 +01:00
Psychpsyo
fe2bc2bfe7 LibWeb: Improve scrollingElement handling
This change is currently entirely undetectable because of what the
added FIXME talks about. Currently, the HTML element's overflow is
always set to visible in both axes, so it getting set to "clip" in
the imported test ends up not mattering at all.
2026-01-13 11:47:13 +00:00
Tim Ledbetter
ba7b0c60f0 LibWeb: Move hyperlink navigation methods to DOM::Element
This allows us to use these methods from `SVGAElement` without
inheriting  `HTMLHyperlinkElementUtils`, which we can't do for
`SVGAElement` due to a naming conflict with the `href()` method in
`SVGURIReferenceMixin`.
2026-01-13 10:05:40 +01:00
Sam Atkins
d84a0d411c LibWeb/HTML: Return Promises from Element scroll methods
This re-applies 3a7fcde341 which was
reverted in cacadc8806. The issues it had
were bugs in the previous commit and have been resolved.
2026-01-08 14:50:09 +00:00
Tim Ledbetter
cacadc8806 Revert "LibWeb/HTML: Return Promises from Element scroll methods"
This reverts commit 3a7fcde341.
2025-12-26 19:33:51 +01:00
Sam Atkins
3a7fcde341 LibWeb/HTML: Return Promises from Element scroll methods
Corresponds to part of:
c548a9a1d4
2025-12-23 14:24:28 +01:00
Sam Atkins
bf57b18b9a LibWeb/DOM: Expose Element's parts list
The existing part_list() method used by the bindings lazily creates a
DOMTokenList, which we don't want to do just to check if an Element has
any parts defined.
2025-12-15 14:12:39 +00:00
Sam Atkins
17e59932f4 LibWeb/DOM: Stub out Element.requestPointerLock()
Does just enough to make classic.minecraft.net load and let you play.
Without actual pointer lock it's quite awkward though.
2025-12-09 12:11:21 +01:00
Sam Atkins
01b7800068 LibWeb/DOM: Add the Element.part attribute 2025-12-08 09:44:32 +00:00
Sam Atkins
f1f7f4fbbf LibWeb/DOM: Use GC::Ptr/Ref instead of raw pointers on DOM::Element APIs
No behaviour change, though this does clarify that class_list() always
returns a value.
2025-12-08 09:44:32 +00:00
Callum Law
12e8f503aa LibWeb: Support non-fixed <random-value-sharing>
This works by generating random values using XorShift128PlusRNG at
compute time and then caching them on the document using the relevant
random-caching-key
2025-12-01 11:00:33 +00:00
Lorenz A
7260159b8f LibWeb: Add loading event to style element 2025-11-30 19:22:02 +01:00
Lorenz A
3bc061d028 LibWeb: Allow all elements with tabindex attribute to be focusable 2025-11-12 13:57:05 +01:00
Tim Ledbetter
154e9db033 LibWeb: Cache the value of Element::lang()
This reduces the time spent in
`SelectorEngine::matches_lang_pseudo_class()` from 1.9% to 0.41% on
https://cloudflare.com
2025-11-12 12:36:16 +01:00
Jelle Raaijmakers
b6f5c91a35 LibWeb: Shave 168 bytes off of ARIAMixin
Instead of keeping the vectors inside ARIAMixin, point to the heap using
OwnPtrs.
2025-11-07 16:59:26 +01:00
Jelle Raaijmakers
9d26626200 LibWeb: Shave 24 bytes off of each DOM::Element 2025-11-07 16:59:26 +01:00
Luke Wilde
82bd3d3891 LibWeb: Avoid invoking Trusted Types where avoidable
Prevents observably calling Trusted Types, which can run arbitrary JS,
cause crashes due to use of MUST and allow arbitrary JS to modify
internal elements.
2025-11-06 11:43:06 -05:00
Tete17
db41ea8117 LibWeb: Amend Element interface to make it compatible with TrustedTypes 2025-10-27 16:14:20 +00:00
Tete17
e2adce84e7 LibWeb: Implement TrustedTypes spec for the concept of set_attribute_ns 2025-10-27 16:14:20 +00:00
Tete17
df543cf31a LibWeb: Implement TrustedTypes spec for set_attribute on Element
This part of the spec is still under a PR in GitHub, but it should be
safe to implement like it is.
2025-10-27 16:14:20 +00:00
Callum Law
12716dccf0 LibWeb: Avoid including ComputedProperties.h in Element.h
This reduces the size of the recompile when ComputedProperties.h is
modified from ~1200 to ~70
2025-10-27 14:50:54 +00:00
Callum Law
f49cf75d44 LibWeb: Don't pass unnecessary PropertyComputationDependencies struct
Since we now have access to the `AbstractElement` through the
`ComputationContext` we can just set the flag that this element relies
on tree counting functions directly, no need to pass this struct around.
2025-10-22 00:01:30 +02:00