Commit Graph

6994 Commits

Author SHA1 Message Date
Zaggy1024
5a615009ff LibWeb: Remove unused math.h include in HTMLMediaElement.h 2026-02-23 07:27:31 +01:00
Zaggy1024
228947b131 LibWeb: Include KeyCode.h where it's used
It was only transitively included through HTMLMediaElement.h in these
files.
2026-02-23 07:27:31 +01:00
Zaggy1024
83bc63ccb8 LibWeb: Traverse shadow roots when firing mouseenter/mouseleave 2026-02-23 07:27:31 +01:00
Aliaksandr Kalenik
eb210bb3af LibWeb: Replace OrderedHashMap with page-table Vector in LayoutState
Each NodeWithStyle is assigned a sequential layout index during the
pre-layout tree traversal. LayoutState stores UsedValues in a
PagedStore — a two-level page table indexed by layout_index that
gives O(1) lookup via two array accesses, with pages allocated
lazily on first write. UsedValues are stored directly in pages
(Optional<T>) rather than behind heap pointers, eliminating
per-entry malloc/free calls and improving cache locality.

This cuts ensure_used_values_for() from ~14% to ~7% in profiles
on https://www.nyan.cat/.
2026-02-23 01:13:35 +01:00
devgianlu
f14410c19f LibWeb: Do not pass GC::Ptr by reference
Also change it to `GC::Ref` since it's nonnull.
2026-02-22 14:55:30 -05:00
devgianlu
fd80acd730 LibWeb: Specify why origin is missing from credentials IDL
The spec is outdated with respect to what is actually implemented
by browsers. Point to a PR that aims to update the spec.
2026-02-22 14:55:30 -05:00
devgianlu
68c53f437e LibWeb: Make CredentialUserData accessors const
Also remove the default constructor.
2026-02-22 14:55:30 -05:00
devgianlu
1edf60bf08 LibWeb: Make {,Federated,Password}Credential accessors const 2026-02-22 14:55:30 -05:00
devgianlu
db5c63c774 LibWeb: Default impl of Credential.isConditionalMediationAvailable
Provide the default implementation for
`is_conditional_mediation_available`.
2026-02-22 14:55:30 -05:00
devgianlu
1fd1ea3b97 LibWeb: Remove Credential.willRequestConditionalCreation
This method has been removed from the spec as unused.
2026-02-22 14:55:30 -05:00
Adam Colvin
d2f10c76fd LibWeb: Reject invalid alt text values in CSS content property parsing
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.
2026-02-22 13:55:22 -05:00
Aliaksandr Kalenik
55f4009163 LibWeb: Walk linked list directly in transform_rect_to_viewport()
The chain is already in element→root order, which matches the linked
list's natural traversal via parent pointers. No need to collect into
a Vector first.
2026-02-22 16:09:15 +01:00
Aliaksandr Kalenik
d79fbd903d LibWeb: Cache parsed CSS values for SVG width/height attributes
width_style_value_from_attribute() and
height_style_value_from_attribute() were showing up as hot functions
when profiling YouTube Music. They call parse_css_value() on every
invocation, but the underlying attributes rarely change. The call path
is SVGSVGBox::natural_size() → negotiate_natural_metrics() → these
functions, so they are invoked on every layout pass.
2026-02-22 16:09:15 +01:00
Tim Ledbetter
79d5fdc871 LibWeb: Avoid division by zero in multi-column column count calculation 2026-02-22 15:07:06 +01:00
Aliaksandr Kalenik
9f36972e06 LibWeb: Include zero-area boxes when measuring scrollable overflow
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.
2026-02-22 14:23:44 +01:00
Andreas Kling
395a126110 LibWeb: Use cached bitmap in SVGDecodedImageData::paint()
Use the existing bitmap() method which caches the ImmutableBitmap,
instead of creating a fresh snapshot from the painting surface on
every paint call.

This was regressed by d9e04ec9e8 which replaced draw_painting_surface
with a per-call snapshot to remove the DrawPaintingSurface dependency,
but didn't use the existing bitmap cache.
2026-02-22 14:22:51 +01:00
Andreas Kling
cd364ea375 LibWeb: Don't require layout to toggle cursor blink state
The cursor blink timer fires every 500ms and only needs to toggle
the blink state and mark the paintable as needing display. If the
paintable doesn't exist yet, we can simply skip the blink -- the
cursor will appear after the next natural rendering update.

This avoids a potentially expensive synchronous layout every 500ms
for what is a purely cosmetic operation.
2026-02-22 13:24:05 +01:00
Andreas Kling
3a2de5374c LibWeb: Don't require layout to determine clientLeft and clientTop
These properties only return the computed border width, which is a
style-level value that doesn't depend on layout geometry. Replace
the full update_layout() call with update_style_if_needed_for_element()
and resolve border widths directly from computed properties.

This avoids potentially expensive synchronous layout when only
CSS computed values are needed.

Very profitable on https://x.com/ where we avoid lots of layout work.
2026-02-22 13:24:05 +01:00
Andreas Kling
675a7d4c0c LibWeb: Remove redundant update_style() in is_potentially_scrollable()
update_layout() already calls update_style() as its first step, so
the follow-up update_style() call was always a no-op.
2026-02-22 13:24:05 +01:00
Andreas Kling
52eefc3714 LibWeb: Remove unused CanvasSetFillStyle layout reason 2026-02-22 12:43:01 +01:00
Andreas Kling
20cc055ec9 LibWeb: Don't require layout node when setting canvas 2D strokeStyle
Use update_style_if_needed_for_element() and resolve colors via
computed properties instead of forcing a full layout update.
2026-02-22 12:43:01 +01:00
Andreas Kling
c7bf2021bc LibWeb: Don't require layout node when setting canvas 2D fillStyle
Use update_style_if_needed_for_element() and resolve colors via
computed properties instead of forcing a full layout update.
2026-02-22 12:43:01 +01:00
Andreas Kling
ca72156497 LibWeb: Don't require layout node when setting canvas 2D shadowColor
Use update_style_if_needed_for_element() and resolve colors via
computed properties instead of forcing a full layout update.
2026-02-22 12:43:01 +01:00
Andreas Kling
cbf8b70d42 LibWeb: Don't require layout node when setting canvas 2D filter
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.
2026-02-22 12:43:01 +01:00
Andreas Kling
ef6368924e LibWeb: Add Document::update_style_if_needed_for_element()
This is a targeted version of update_style() that only performs a
style update if the given element (or its ancestors) actually have
dirty style. Useful when we only need up-to-date computed properties
for a specific element.
2026-02-22 12:43:01 +01:00
Tim Ledbetter
a4aaed5e83 LibWeb: Propagate error from Notification contructor 2026-02-22 11:37:33 +01:00
Shannon Booth
3a9a8e38f8 LibWeb/Fetch: Prevent file:// URLs from calling fetch() API
Thanks to Oscar Uribe for the report.

Co-Authored-By: Jelle Raaijmakers <jelle@ladybird.org>
2026-02-21 23:00:57 +01:00
Shannon Booth
006445d7bd LibWeb/Fetch: Write file scheme origin checking in a more readable way
Put the origin into a variable and make use of early return
to error out. No functional impact intended.
2026-02-21 23:00:57 +01:00
Shannon Booth
d6d80e5d52 LibWeb: Load cookies test from HTTP server
Allowing us to remove the internals hook.
2026-02-21 23:00:57 +01:00
Shannon Booth
62ca5f71a6 LibWeb: Consider opaque file scheme origins as potentially trustworthy 2026-02-21 23:00:57 +01:00
Andreas Kling
77a3de4561 LibWeb: Handle ancestors without layout nodes in offsetParent
When walking the flat tree in HTMLElement::offset_parent(), ancestors
may not have layout nodes (e.g., they have display:none). This can
happen when an element is slotted into a shadow root where the slot
is inside a display:none container.

Guard layout_node() accesses with null checks. If an ancestor has no
layout node, it cannot be positioned or establish a containing block,
so it cannot be the offset parent for those reasons.
2026-02-21 22:08:36 +01:00
Aliaksandr Kalenik
795222fab3 LibWeb: Validate grid-template-areas rectangles at parse time
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.
2026-02-21 21:46:34 +01:00
Praise-Garfield
52ee05cb5d LibWeb: Visit ImportMapParseResult in HTMLScriptElement::visit_edges
The m_result Variant can hold a GC::Ref<ImportMapParseResult> when the
script element has type="importmap", but visit_edges only traced the
GC::Ref<Script> arm. This left the ImportMapParseResult unvisited,
allowing the GC to collect it while the element still held a reference.

ImportMapParseResult inherited from JS::Script::HostDefined, but no
JS::Script or JS::Module ever stored it as host_defined data, so
visit_host_defined_self was dead code. This removes the HostDefined
inheritance entirely and switches m_result visitation to Variant::visit
with a lambda that catches all GC::Ref arms.
2026-02-21 11:14:45 -05:00
Andreas Kling
786e93b6c7 LibWeb: Avoid unnecessary GC::Root copies in find_if lambdas
The find_if lambdas in CustomElementRegistry and TraversableNavigable
were taking GC::Root parameters, causing implicit conversion from
GC::Ref (or copying of GC::Root) for each element visited. Each
GC::Root creation/destruction allocates and frees a RootImpl, making
linear scans over these vectors far more expensive than necessary.

Use auto const& to match the actual vector element types.

This was 2.3% of CPU time while opening a YouTube video.
2026-02-21 15:53:22 +01:00
Andreas Kling
057f11bf8f LibWeb: Cache absolute padding and border box rects on PaintableBox
These rects are computed from immutable layout data but were
recomputed from scratch on every call, with the CSSPixels saturating
arithmetic showing up as a significant cost in profiles.

Cache them lazily alongside the existing m_absolute_rect cache.

This was 3.3% of CPU time while playing a YouTube video.
2026-02-21 15:53:22 +01:00
Andreas Kling
8497da8a13 LibWeb: Cache CSS::Display on Paintable for O(1) display() lookups
Paintable::display() was chasing through layout_node().display() which
goes through computed_values().display() on every call. Since display
never changes after the Paintable is constructed, cache it as a member
set in the constructor.

This was 1.6% of CPU time while playing a YouTube video.
2026-02-21 15:53:22 +01:00
Andreas Kling
a4d949ff55 LibWeb: Inline trivial CSS::Display query methods
Move all the simple bool query methods (is_table_inside,
is_table_cell, is_none, is_block_outside, etc.) from Display.cpp into
Display.h as inline definitions. These are trivial one-liners called
in very hot painting and layout paths.

Keep only to_string() and from_short() out-of-line.
2026-02-21 15:53:22 +01:00
Andreas Kling
18710f790f LibWeb: Shrink CSS::Display by giving explicit u8 size to inner enums
CSS::Display::Type and CSS::Display::ListItem defaulted to int (4
bytes each). Give them explicit u8 underlying types, shrinking
CSS::Display from 12 bytes to 4 bytes.
2026-02-21 15:53:22 +01:00
Andreas Kling
ea6c0e431a LibWeb: Inline CSSPixels methods and optimize device pixel math
Make CSSPixels::to_float(), to_double(), and to_int() constexpr inline
instead of out-of-line in the .cpp file. These are trivial one-liners
called in very hot painting paths.

Also optimize DevicePixelConverter::rounded_device_rect() to work
directly with CSSPixels values instead of constructing an intermediate
Rect<double> and scaling it.
2026-02-21 15:53:22 +01:00
Andreas Kling
7f830a0533 LibWeb: Pass ResolvedBackground by const reference in paint_background
It was passed by value, copying a Vector<ResolvedBackgroundLayerData>
on every call. This function is called for every PaintableBox on every
frame.
2026-02-21 15:53:22 +01:00
Andreas Kling
1b41c9109d LibWeb: Cache is_body() on layout nodes
Cache the result of the body element check as a bool set once during
NodeWithStyle construction, instead of calling document().body() (which
walks the children of <html>) on every call. This is called from
PaintableBox::paint_background() for every box on every frame.

This was 0.9% of CPU time while playing a YouTube video.
2026-02-21 15:53:22 +01:00
Aliaksandr Kalenik
7cc973fa77 LibWeb: Lazify ElementByIdMap resolution and cache first element
Eliminate O(n) tree-order sorted insert on every add() by simply
appending elements and deferring order resolution to lookup time. Cache
the first-in-tree-order element in get() so repeated getElementById()
calls avoid repeated subtree traversal.

Improves performance on YouTube where add() was hot in profiles while
scrolling through comments.
2026-02-21 13:56:00 +01:00
Shannon Booth
26cf55dc77 LibWeb/CSP: Prefer use of Optional<StringView> for algorithm matching
Over using the null state of StringView.
2026-02-21 12:37:44 +01:00
Tim Ledbetter
3991555439 LibWeb: Block opaque origins in CSP frame-ancestors check
This matches the behavior of other engines.
2026-02-21 12:30:48 +01:00
Callum Law
21c7de49f8 LibWeb: Remove outdated FIXME
As of 020c4aa we parse all shorthands as `ShorthandStyleValue`s and thus
this FIXME is irrelevant
2026-02-21 06:33:40 +00:00
Tim Ledbetter
83bd30b957 LibWeb: Stop inline elements after table-cell being swallowed into table
The `is_ignorable_whitespace()` check in table fixup traverses anonymous
block wrappers to see if they contain only whitespace. It rejected
out-of-flow and text descendants but silently skipped in-flow non-text
elements like `<span>`, misclassifying wrappers with real content as
ignorable and absorbing them into the table structure.
2026-02-21 05:48:53 +00:00
Tim Ledbetter
8240fa0dc8 LibWeb: Resolve percentage table widths in wrapper width computation
Previously, a table with `width: 100%` and `margin: auto` whose content
was narrower than the viewport would be centered based on content
width rather than filling the containing block. Resizing the viewport
wider than the content would shift the table progressively further to
the right.

Co-authored-by: Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
2026-02-21 05:16:56 +01:00
Aliaksandr Kalenik
e87fece8c6 LibWeb: Force position:static on non-root SVG elements
SVG elements (except the outermost <svg>) use SVG's coordinate system,
not the CSS box model, so CSS positioning doesn't apply to them.

This adds SVGElement::adjust_computed_style() to force position:static
on all SVG elements except the outermost <svg> element (which has no
owner_svg_element()). SVGSymbolElement's existing override now calls
Base::adjust_computed_style() to inherit this behavior.

With this in place, the FIXME in layout_absolutely_positioned_element()
for SVG boxes becomes unreachable and is replaced with
VERIFY_NOT_REACHED().
2026-02-21 05:12:55 +01:00
Andreas Kling
5fdcf207f8 LibWeb: Avoid GC allocation in ResizeObservation::is_active()
Extract the box size computation into a new compute_box_size() that
returns a plain struct with two doubles, and use it in is_active()
instead of calculate_box_size() which allocates a GC-managed
ResizeObserverSize object.

Since is_active() only needs to compare sizes and immediately discards
the result, there's no reason to involve the GC. The GC-allocating
calculate_box_size() now delegates to compute_box_size() internally.

This was 2.6% of CPU time while playing a YouTube video.
2026-02-21 03:51:28 +01:00
Andreas Kling
935f76f88e LibWeb: Cache visibility in Paintable::resolve_paint_properties()
Cache the result of the visibility+opacity check as a bit field
(m_visible) computed in resolve_paint_properties(), which already runs
before each paint when paint properties need updating.

This makes Paintable::is_visible() a simple inline bit field read
instead of chasing through layout_node->computed_values() every time.

This was 3.3% of CPU time while playing a YouTube video.
2026-02-21 03:51:28 +01:00