Commit graph

220 commits

Author SHA1 Message Date
Sam Atkins
4050c32dab Everywhere: Make use of Badge with multiple or derived types
Now that Badge can have multiple types, and a Badge of a derived class
can convert into a Badge of the superclass, we can simplify a few method
signatures and overloads.
2026-06-11 21:55:56 +02:00
Andreas Kling
9340d2d1a3 LibWeb: Make layout nodes refcounted
Move the layout tree from GC allocation to refcounted ownership so
removed layout and paint subtrees are destroyed synchronously instead
of waiting for the next GC sweep. This dramatically reduces GC memory
usage peaks after layout tree churn and makes it easier for memory use
to fall back after large document updates.

Update layout factories, tree traversal, SVG layout node creation,
paintable back-pointers, and pseudo-element layout links to use RefPtr
ownership.

Make display: contents follow the same shape as Blink and WebKit: the
element itself does not create a layout node, and its children are
flattened into the nearest layout parent. Wrap direct non-whitespace
text in an anonymous inline node when the boxless element contributes
inherited style to that text.

Use an internal inline wrapper for display: contents pseudo-elements
so generated content can still participate in layout, painting, hit
testing, and pseudo-element queries. Keep CSSOM reporting the computed
display value from the pseudo style, not the internal wrapper.

Remove the retained out-of-tree layout node list and its testing hook,
since the flattened model does not need a side owner for boxless
elements. Add coverage for inherited text style, dynamic insertion
order, pseudo-element hit testing, and computed style queries.
2026-06-07 20:52:49 +02:00
Andreas Kling
7c06c3fd14 LibWeb: Make computed style data refcounted
Move ComputedProperties and CascadedProperties out of the GC. They no
longer contain strong references to GC-managed data.

Keep computed styles alive from DOM elements and animation updates with
RefPtr. Pass style into layout constructors by reference, since layout
only copies the values it needs while building nodes.

Use GC::Weak for cascade source links, so entries no longer keep the
style declaration or shadow root alive.
2026-06-06 23:29:48 +02:00
Callum Law
4730493667 LibWeb: Apply body attribute link colors as presentational hints
Previously we overrode the resolved values of the `activetext`,
`linktext`, and `visitedtext` system colors based on the values of the
body's `alink`, `link`, and `vlink` attributes respectively.

This was incorrect and the spec instead expects us to apply these to the
relevant link elements as presentational hints while leaving those
colors untouched for other users.
2026-06-04 16:14:05 +02:00
Callum Law
843bd808cf LibWeb: Move `:visited: matching into helper method
And add spec text to explain why it never does.

We will be checking whether the `:visited` pseudo class matches in more
places in a future commit so this avoids duplicating FIXMEs.
2026-06-04 16:14:05 +02:00
Callum Law
b1e3306a24 LibWeb: Remove "attempted pseudo-class match" machinery
This is no longer used anywhere after fa57975
2026-06-04 16:14:05 +02:00
Andreas Kling
f945e7a85b LibWeb: Clear detached rendering state on removal
Drop paintables and cached computed style from DOM nodes when they leave
the tree. Detached DOM snapshots can otherwise retain large paintable
and computed style graphs after layout state has already been removed.

This keeps retained paintable and CSS style value counts flat in the
GitHub pull request tab switching scenario. Add coverage for removing a
styled select, which must not run style-change hooks while clearing
removed state.
2026-05-30 12:31:17 +02:00
Andreas Kling
48482b7638 LibWeb: Clear stale pseudo-element layout nodes
Synthetic pseudo-elements can keep strong references to layout
subtrees after they stop rendering or after their originating element
is removed. Clear those stale layout-node pointers during
pseudo-element recreation and DOM removal.
2026-05-30 12:31:17 +02:00
Andreas Kling
5a740161b3 LibWeb: Refresh animations after inherited restyles
Use the existing animated style update path when document style
recalculation reaches an element through inherited style recomputation.
Paused or filled animations can contain inherit, rem, rch, or other
font-relative keyframe values that depend on parent or root metrics.
Those dependencies can change even when the target's inherited computed
values do not otherwise change.

Make the document traversal opt in explicitly so animation-driven
inherited recomputation does not schedule another animation update while
propagating animated inherited values.

Add coverage for a media-gated root font-size change affecting a paused
rem-based animation. Update the font-stretch WPT expectation now that
its inherited-animation case passes.
2026-05-25 19:18:10 +02:00
Andreas Kling
ceb25e10d4 LibWeb: Avoid full viewport resize style invalidations
Use the viewport metric dependency flags to restyle only elements whose
computed values can change after a viewport resize. Descendants that
inherit changed values are reached through the existing inherited-style
update path.

Keep targeted style reads correct by treating pending media query
evaluation as style dirtiness. Seed the style computer with the latest
viewport before resolving pending animated style, so viewport-unit
keyframes do not use stale metrics.

Share pseudo-element recomputation with inherited-style updates, so
pseudos stay current when their originating element changes only via
inherited values.

Schedule animated style updates when inherited style recomputation can
affect existing animations.

Add viewport resize coverage for media queries, inherited font metrics,
monospace font-size recascade, line-height percentages, font-relative
and pending viewport-unit animations, inherited pseudo-elements, direct
pseudo viewport dependencies, and canvas currentColor reads.
2026-05-25 11:35:35 +02:00
Shannon Booth
637fd51595 LibWeb: Unify WebIDL C++ type generation
Represent WebIDL C++ types with a single CppType model that tracks
nullability, optional presence, and contained storage.

GC-like values now use GC::Ref/GC::Ptr directly, while containers choose
"plain", "Root", or "Conservative" container types depending on what
they contain. For example, sequence<Element> becomes a RootVector of
GC::Ref values, while sequence<SomeDictionary> becomes a
ConservativeVector only when the dictionary contains GC-like values.
This moves the generated bindings away from wrapping GC values in
GC::Root by default.

This has broad fallout as the types passed to interfaces for GC
objects changes almost fully across the board.
2026-05-23 18:26:12 +02:00
Callum Law
199e82fc73 LibWeb: Forward non-synthetic pseudo-elt accesses to relevant element
This adds a new class `ElementReferencePseudoElement` which forwards
any accesses to the referenced element for "element-reference" pseudo
elements.

This allows us to, for instance:
 - Access the underlying `ComputedProperties` in getComputedStyle, which
   includes inline style.
 - Store and access `CustomPropertyData`
 - Access the layout node for "resolved value" computation
 - Apply animations from `update_animated_style_if_needed`

We register these with the originating element when calling
`set_associated_shadow_host_pseudo_element`, this requires us to append
the element to the tree beforehand since we need to be able to get the
shadow host.
2026-05-21 14:26:22 +01:00
Callum Law
507380d8c5 LibWeb: Rename get_pseudo_element_node to pseudo_element_layout_node
This matches the naming convention of the newly introduced
`pseudo_element_unsafe_layout_node` and the top-level
`Element::layout_node`
2026-05-21 14:26:22 +01:00
Callum Law
0f92554427 LibWeb: Introduce Element::pseudo_element_unsafe_layout_node
This is used whereever we use `unsafe_layout_node`. There's no
difference in behavior for `SyntheticPseudoElement` but once we
implement element-reference pseudo-elements it will call
`unsafe_layout_node` on the referenced element rather than `layout_node`
2026-05-21 14:26:22 +01:00
Callum Law
977c054e77 LibWeb: Rename use_pseudo_element
`associated_shadow_host_pseudo_element` is clearer on what this is.
2026-05-21 14:26:22 +01:00
Callum Law
79f6cc1d7a LibWeb: Make DOM::PseudoElement abstract
And add a new `SyntheticPseudoElement` sub-class.

This will allow us to implement `ElementReferencePseudoElement` in the
next commit.
2026-05-21 14:26:22 +01:00
Callum Law
28afdb327a LibWeb: Limit some pseudo-element functionality to synthetic only
Most of this functionality was already implicitly disallowed for
element-reference pseudo-elements by the fact that we weren't creating
entries in `m_pseudo_element_data` for them, but we need to explicitly
limit it in preparation of creating those entries.

Due to the above this is mostly non-functional apart from a regression
where we no longer support custom properties on element-reference
pseudo-elements. Previously when setting custom properties for an
element-reference pseudo-element we would call `ensure_pseudo_element()`
which created a synthetic pseudo-element entry distinct from the
referenced element which only stored custom property data - this was
clearly wrong and will be implemented properly in a future commit.
2026-05-21 14:26:22 +01:00
Callum Law
5e302c87b4 LibWeb: Remove unused Element::has_pseudo_element() 2026-05-21 14:26:22 +01:00
Callum Law
468c696ec7 LibWeb: Combine pseudo element clearing methods
These two methods were the same just with slightly different names and
badges so let's combine them.
2026-05-21 14:26:22 +01:00
Tim Ledbetter
d760cec702 LibWeb: Stop retaining fragment-parsing documents after adoption
When adopting an element, we now set the node document of each of its
attributes to the new document. Without this, `Attr` objects retained
document pointers back to a temporary document created during fragment
parsing, these documents were then kept alive after the parsed nodes
were moved into the real document.
2026-05-21 08:56:41 +02:00
Andreas Kling
c92ea86c30 LibWeb: Invalidate shadow focus-within styles
Match :focus-within by walking flat-tree parents so shadow hosts and
slotted content follow the Selectors definition instead of DOM ancestry.

When focus state changes, also run pseudo-class invalidation in shadow
style scopes that can observe the focused node. This lets shadow-root
rules such as :host(:focus-within)::before and ::slotted(:focus) update
without waiting for an unrelated DOM mutation to restyle the host.

Add focused coverage for host pseudo-elements, shadow descendants, and
slotted controls, and update the style-invalidation counter baseline for
the lower focus-family no-op restyle counts.
2026-05-21 08:56:05 +02:00
Andreas Kling
99b1780d57 LibWeb: Reject non-rendered elements as focus targets
Do not let elements inside display:none subtrees become focus targets.
The HTML focusable-area model only allows elements to be focusable when
they are rendered, delegate rendering to their children, or are relevant
canvas fallback content.

Preserve blur for the current focused area after script hides it, since
the unfocusing steps operate on the old focus target. Check display:none
through the flat-tree style parent chain, so slotted controls inside
hidden slot subtrees cannot become focused.

Cover hidden ancestors with materialized computed style, display:none
controls, display:contents, hidden focused controls, and slotted cases
inside hidden and visible shadow-tree subtrees.
2026-05-21 08:56:05 +02:00
Sam Atkins
585849fcf0 LibWeb: Parse and evaluate @container <size-feature>s
e.g., `@container (width >= 300px) {}` and similar.

During style computation, flag any elements whose style depends on a
size container. Then re-evaluate their style after the initial layout
has been computed and size containers have a size. This may take
multiple passes, as these may have further descendants that depend on
their size, etc. We limit this to 8 passes currently.

SizeFeature itself is very similar to MediaFeature, but queries the
container element instead. There are only 6 size features specified, so
they're hard-coded instead of generated from JSON.

Also add a counter test for the narrower restyle path.
2026-05-20 13:00:50 +01: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
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
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
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
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
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
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
Andreas Kling
4b3abc6958 LibWeb: Move invalidation set matching into a helper
Element.cpp still contained the CSS logic for deciding whether an
invalidation set references features present on an element. Move that
matcher into CSS::Invalidation::InvalidationSetMatcher.

The helper uses Element's public API for classes, id, attributes,
pseudo-class state, and removed-attribute tracking. This keeps Element
focused on DOM state while CSS::Invalidation owns selector feature
matching.
2026-04-29 15:47:23 +02:00
Andreas Kling
eeab3671c2 LibWeb: Move attribute style invalidation into a helper
Element.cpp still encoded the CSS consequences of attribute changes:
class/id invalidation keys, pseudo-class triggers, and shadow-host
stylesheet fallout. Move that policy into AttributeInvalidator.

Element now reports attribute changes to the helper and exposes a small
state hook to remember removed attributes while invalidation is pending.
2026-04-29 15:47:23 +02:00
Andreas Kling
85e33738f5 LibWeb: Move :has() element invalidation into the helper
Element exposed a small method that encoded how :has()-affected elements
are marked dirty. Move that policy into CSS::Invalidation alongside the
rest of the :has() mutation invalidation helpers.

This keeps Element focused on DOM state while preserving the existing
subject and non-subject :has() invalidation behavior.
2026-04-29 15:47:23 +02:00
Andreas Kling
356a369aa6 LibWeb: Avoid descendant recomputes for same-parent moves
Moving a node within the same parent changes sibling and positional
relationships, but it does not make every descendant of the moved node
need a fresh computed style. Handle this as a structural mutation at
the old and new sibling edges and dirty only the moved root and the
affected ancestors, instead of marking the entire moved subtree.

Factor the existing previous- and next-sibling structural invalidation
out of Node::invalidate_style() into invalidate_structurally_affected_-
siblings(), and pull the ancestor child-needs-style-update walk into
mark_ancestors_as_having_child_needing_style_update(). The new
invalidate_style_after_same_parent_move() reuses both helpers.

Whether the moved root itself needs its own style recomputed depends
on whether any selector matched against it (or against a descendant)
relied on its position in the sibling list. Track that via two new
sticky bits on Element, set during selector matching:

  - m_affected_by_structural_pseudo_class_in_non_subject_position
  - m_affected_by_sibling_combinator_in_non_subject_position

Both are write-once (sticky) because matching descendants can set them
while we're not currently re-matching this element's own selectors;
keeping them set is conservative and avoids stale descendant style.

When neither bit is set and the element only carries subject-position
positional/sibling/has() involvement, we just dirty the root and skip
its descendants.

Rebaseline same-parent-move-root-only and the structural-feature filter
counters to reflect the new path. Matching behavior is unchanged.
2026-04-28 15:34:49 +02:00
Andreas Kling
11d9d4a7a5 LibWeb: Match attribute invalidation by presence and recent removal
Element::includes_properties_from_invalidation_set() previously
short-circuited and returned true for the id and class attributes,
because the parsed id and class-name state was treated as the source of
truth and the attribute presence check could disagree with it. That
shortcut over-invalidated for any [class] or [id] selector even when
neither attribute had ever been touched on the element.

Drop the special case and answer attribute presence queries the same
way for every attribute: the element either currently has the attribute,
or has had it removed earlier in this style update batch.

To handle the just-removed case, track the set of attribute names that
were removed since the last invalidation pass on a new per-Element
Vector<FlyString, 1> m_removed_attributes_for_style_invalidation. The
StyleInvalidator clears the vector for each element it visits during
perform_pending_style_invalidations, so it only ever holds names from
the current batch.

Rebaseline the affected attribute-presence tests; counters drop because
elements that never had id/class no longer match [class] / [id]
invalidations.
2026-04-28 15:34:49 +02:00
Tim Ledbetter
6bb037aec7 LibWeb: Skip backward sibling invalidation when no child needs it
We now track when a parent has a child affected by a backward structural
pseudo-class. These are selectors whose match result for an element can
depend on siblings after that element, such as `:last-child`,
`:only-child`, `:last-of-type`, `:only-of-type`, `:nth-last-child`, and
`:nth-last-of-type`.

When inserting or removing a node, previous siblings only need style
invalidation if one of them was matched against such a selector. Use the
parent-level flag to skip the previous-sibling walk when no child under
that parent can be affected.

This saves a lot of invalidation work on sites that insert a lot of
nodes into the DOM via JS.
2026-04-26 16:14:43 +02:00
Sam Atkins
6d02296eb5 LibWeb: Pass better information to node moving/removing steps
Corresponds to:
73de9e5e1b
097be9feaa
2026-04-22 14:05:49 +01:00
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