Commit graph

356 commits

Author SHA1 Message Date
Luke Wilde
8dc8835b64 LibWeb+LibWebView+WebContent: Allow muted media to autoplay by default
The autoplay setting was binary and its default blocked all media,
including muted video, leaving sites that rely on muted autoplay
visibly broken. Replace it with a tri-state user-agent autoplay
policy (allow audio and video, block audio, or block audio and video)
defaulting to allowing only inaudible media to autoplay.

This is enforced through the media element's "allowed to play" check,
so unmuting a muted autoplay or calling `play()` cannot slip audio
past the policy; audible playback is permitted once the document has
been activated by the user. The policy lives in a dedicated
AutoplaySettings consulted from HTMLMediaElement instead of the
Permissions Policy "allowed to use feature" check it was previously
conflated with.
2026-06-19 09:41:32 +02:00
sideshowbarker
9f7a328d9b LibWeb: Reject canvas toDataURL()/toBlob() when not origin-clean
Problem: Drawing a cross-origin image onto a 2D canvas clears its
origin-clean flag, but toDataURL() and toBlob() ignored that flag and
serialized the bitmap regardless. So, a page could read back the
cross-origin pixels it shouldn't (per spec) be allowed to access.

Cause: The origin-clean checks in to_data_url() and to_blob() were left
as FIXMEs. Only getImageData() enforced the flag.

Fix: Throw a SecurityError exception from both serialization entry
points when the canvas isn't origin-clean — matching getImageData() and
the spec. The same check also implements the previously-stubbed
origin-clean step in the WebDriver canvas-encoding algorithm.

Fixes: https://github.com/LadybirdBrowser/ladybird/issues/10009
2026-06-18 10:52:42 +02:00
sideshowbarker
e61a91c017 LibWeb: Keep session history coherent when navigations jump the queue
Problem: A document could drop a load if it ran a stream of synchronous
same-document history navigations (say, a pushState flood) while it was
concurrently loaded again. The load never finished — so on sanitizer/
slow builds, this had been intermittently taking down unrelated tests in
CI — since test-web reuses one WebContent process, and the next test’s
load can arrive while the previous document’s history work is still
draining. A synchronous commit also claimed a session history step it
never retired — so claimed steps piled up without bound.

Cause: A sync same-document navigation committed immediately and could
jump the session-history-traversal queue while a queued apply-history-
step — such as a cross-document load — was still waiting behind it. The
queued run read the active session-history entry after the sync
navigation had installed it, but before its step number was assigned —
then judged itself stale against that still-pending step, and was
discarded. The shared step numbering was fragile under the same nesting:
A number computed from the current step alone could collide with an in-
flight one — and a stale run that completed later could write its own
step back over a newer one. 394312ab5a stopped the crash this used to
cause, but the races remained.

Fix: Treat a queued push whose displayed entry’s step is still pending
as live rather than stale — so the concurrent load isn’t dropped. Number
apply-history-step runs, and let a run commit its target step only if no
newer run has committed one — so a stale run can’t move the current step
backwards. Claim each new step past every claimed-but-uncommitted step —
rather than from the current step alone, and keep clearing the forward
session history from removing those entries. And retire the step a sync
commit claims, since it applies in the same task, and nothing else will.

See https://github.com/LadybirdBrowser/ladybird/issues/10028
2026-06-17 12:25:53 +02:00
Tim Ledbetter
3cddcc8461 LibGfx+LibWeb: Remove TIFF image decoding
This is no longer widely supported by other engines.
2026-06-12 22:37:49 +02:00
Zaggy1024
af9ab3b3fa Tests: Complete the resize during playback test upon ended and seeked
Otherwise, we may miss the ended event if the order of the events is
changed.
2026-06-11 05:49:14 -05:00
Tim Ledbetter
525ce459fc LibWeb: Avoid stale DataTransferItem access after clearing data
Previously, clearing a DataTransfer's data removed entries from the
drag data store without updating the associated `DataTransferItem`
objects. An item obtained beforehand kept an index that no longer
referenced a valid entry, so reading its kind or type accessed an
out of bounds element of the now-empty list and crashed. We now keep
the item objects in sync when clearing data, placing any stale ones
into the disabled mode.
2026-06-08 13:40:22 +02:00
Sam Atkins
89bdc5f889 LibWeb/SVG: Apply parser-created style timing
Let SVGStyleElement delegate style updates through StyleElementBase so
parser-created inline SVG `<style>` elements update when they are popped
from the parser stack, just like HTML style elements.

This lets SVG style imports participate in script-blocking stylesheet
checks while keeping dynamic text, type, and media changes from
re-blocking parser scripts.
2026-06-04 16:39:54 +01:00
Sam Atkins
5d566040d6 LibWeb/DOM: Evaluate style media for script blocking
Evaluate the associated stylesheet's media queries when a parser-created
`<style>` sheet is created, and re-evaluate them when the media
attribute changes.

This lets HTMLStyleElement::contributes_a_script_blocking_style_sheet()
honor the media clause from the HTML script-blocking rules. A
still-loading parser-created style is removed from the script-blocking
set as soon as its media no longer matches.
2026-06-04 16:39:54 +01:00
Sam Atkins
bb4f8a6621 LibWeb: Track parser-created style sheets
Create parser-blocking style sheets when parser-created `<style>`
elements are popped from the stack of open elements, and ignore dynamic
style updates while those elements are still open in the parser.

Make the shared style-element script-blocking predicate describe the
active style sheet instance. Stale script-blocking entries are removed
when that style sheet is replaced or removed.
2026-06-04 16:39:54 +01:00
Sam Atkins
fb6526c083 Tests: Move 'html' tests to 'HTML' 2026-06-04 23:11:20 +12:00
aplefull
52f45aef4e LibWeb+LibJS: Don't crash when serializing deeply nested values
Deeply nested structures passed to JSON.stringify or structuredClone
would cause a lot of recursion, eventually causing a crash.

We now throw an InternalError instead, same as other browser engines.
2026-06-03 13:00:01 +01:00
Tim Ledbetter
c05141aac7 LibWeb: Collapse whitespace when gathering find in page text
Previously, the text searched by find-in-page was gathered from each
text node's rendered string, which still contains uncollapsed
whitespace. We now collapse runs of whitespace to a single space and
trim leading and trailing whitespace per block when building the
searchable text, while keeping each character mapped back to its DOM
position so matches still resolve to correct ranges.
2026-05-30 21:17:05 +02:00
Zaggy1024
d36647427e LibWeb: Always set media track enabled state
...and avoid telling the media element about it unless the track is
actually associated. The media element should set its state later when
it queries the status upon metadata parsing.
2026-05-27 19:47:22 -05:00
Shannon Booth
2a2b0bf91a LibWeb: Use the node document realm for image requests
An HTMLImageElement can be adopted across documents while an image
update is still pending. In that case the element's wrapper realm can
still be the old iframe realm, but the image request must be created and
fetched using the element's current node document.

Using the old iframe realm associates the request with the removed
iframe's document-owned image request cache, so the adopted image can
fail to complete in the parent document. Use document().realm() when
creating/updating/fetching image requests so adopted images continue
loading in their new document.

Add a regression for an image created in an iframe, then adopted into
the parent after the iframe is removed.

Chromium and Webkit do not fire a load event for the test, but Firefox
does. All load the image, where we previously did not.

See: https://github.com/whatwg/html/issues/8492
2026-05-27 02:40:53 +01:00
Pavel Shliak
b542552f1e LibWeb: Map embedded content align to vertical-align 2026-05-26 09:35:16 +02:00
Andreas Kling
23c1e1d2b5 LibWeb: Avoid creating RAF driver when canceling frames
Treat a missing animation frame callback driver as an empty map when
canceling a frame. This keeps media controls finalization from
allocating while GC is collecting unreachable media elements.

Cover this with a media controls GC text test.
2026-05-26 09:09:11 +02:00
Andreas Kling
ca97f68cb7 LibWeb: Normalize decoded HTML string parsing
Preserve leading BOMs when parsing already-decoded HTML strings, since
those strings do not go through the encoded byte decoder path.

Decoded markup from JS strings can also contain WTF-8 for lone surrogate
code units. Keep the common scalar UTF-8 path to a single validation and
copy, but replace surrogates before handing bytes to the Rust tokenizer.

Add text coverage for DOMParser and innerHTML string parsing, including
leading BOMs, text and attributes, lone high and low surrogates, and a
valid surrogate pair.
2026-05-24 10:14:17 +02:00
Andreas Kling
4c03a6f5fc LibWeb: Honor transparent copy compositing in canvas
Do not skip fully transparent canvas fill and stroke styles when the
current compositing operator can still affect the destination bitmap.
TradingView uses transparent copy fills while repainting its chart
canvases, and skipping those draws left old translucent chart pixels in
place so later source-over draws accumulated on top.

Add text coverage for transparent copy replacing an existing translucent
pixel before another translucent draw.
2026-05-23 19:11:01 +02:00
Martin Chrástek
a404efa999 Tests: Add explicit UTF-8 charset declarations to existing tests 2026-05-23 11:57:33 +02:00
Andreas Kling
804bf2532b LibJS: Allow cached module evaluation errors
A second root module in a failed cycle can call Evaluate after the
cycle root has already cached an evaluation error. In that case
InnerModuleEvaluation returns the cached error immediately and Evaluate
must reject the new top-level capability with that same error.

Remove the extra assertion that the module evaluation error is empty in
the abrupt completion path. Add text coverage for evaluating both roots
of a module cycle whose dependency throws during evaluation.
2026-05-23 11:36:45 +02:00
Andreas Kling
56da8f01d7 LibWeb: Reject stale image decode promises
When an image source changes before a queued decode() job can attach
fetch callbacks, the current request can still be unavailable and have
no shared resource request. Treat that as the spec's current request
changed case instead of asserting while adding callbacks.

Add text coverage for changing an image source immediately after
calling decode(), matching the WPT image-decode-path-changes crash.
2026-05-23 11:36:45 +02:00
Andreas Kling
459ad81da5 LibWeb: Add stale style focus and computed style coverage
Add coverage for focus and getComputedStyle() queries that run while
style work is pending for the target element, its ancestors, slotted
nodes, media queries, animations, and :has() invalidation.

The expected output records the current stale results so the targeted
style update change can show the behavior fix directly. Also make the
style invalidation counter tests avoid recomputation counters in cases
where the exact recomputation count is incidental to the invalidation
behavior under test.
2026-05-22 21:25:58 +02:00
Andreas Kling
e9abdc4ed0 Tests: Avoid racing iframe bad XML load test
Create the iframe inside the test with its src already set. This avoids
observing a parser-created iframe's initial load event when the test is
only trying to check that malformed XML iframe navigation fires load.
2026-05-22 15:48:00 +02:00
Sam Atkins
16f7333586 LibWeb: Ensure XML error documents always finish loading
In some cases, the XML error document would never be marked as ready for
post-load tasks, even though a load event got fired. This caused
intermittent timeouts on our iframe-load-event-for-bad-xml.html test.

Make XML error document conversion finish loading when the parser has
not already queued post-load tasks. This lets bad XML iframe loads fire
load instead of leaving the parent parser waiting indefinitely.

Also install the test's iframe load handler before assigning src to
avoid a potential race condition there.
2026-05-22 09:59:19 +01:00
Aliaksandr Kalenik
640965d052 LibWeb: Allow button content boxes to shrink below intrinsic height
Button layout wraps non-flex/grid button contents in an anonymous flex
item. That flex item kept the default automatic minimum height, so
a descendant with height: 100% and width: auto could make a fixed-height
button grow to the descendant's intrinsic height. This made image-only
controls, such as site header logos, render much taller than the height
specified by author styles.

Set min-height: 0 on the anonymous button content box so
percentage-height descendants can resolve against and shrink to the
button's used height.
2026-05-21 19:34:45 +01:00
Andreas Kling
30aae77901 LibWeb: Delegate focus from shadow hosts
Handle the delegatesFocus branch of get-the-focusable-area before
rejecting non-focusable focus targets. This lets host.focus() move focus
to the first focusable delegate in the shadow tree, or preserve an
already-focused descendant.

Treat delegatesFocus shadow hosts as focus delegates even when tabindex
would otherwise make the host focusable. Skip inert delegate candidates,
and reject inert shadow hosts before looking for a delegate. Check focus
inertness through shadow-host ancestry so direct focus cannot enter
inert shadow subtrees.

Rebaseline the disabled delegatesFocus WPT now that this behavior
passes. Cover delegated focus, hidden and inert delegate candidates,
tabindex hosts, inert hosts and direct delegates inside inert hosts, and
hosts without any focusable delegate.
2026-05-21 08:56:05 +02:00
Andreas Kling
94302775bf LibWeb: Map document element focus to the viewport
Apply the focusing steps' get-the-focusable-area mapping before
rejecting a non-focusable target. This preserves documentElement.focus()
by mapping the non-focusable document element to the Document viewport.

Also map rendered navigable containers with content navigables to their
active document, while leaving hidden containers unfocused. Preserve
Window focus events for child document viewports reached through iframe
focus, while still suppressing the top-level viewport surrogate events.

Treat rendered object elements as focusable through their default
non-null tabindex, even when they show fallback or image content instead
of a child navigable.

Keep the spec focus-chain common-tail handling intact for viewport
focus. The Document object is only our surrogate for the viewport, so
designate viewport focus from the new focus target without dispatching
Window focus/focusin events for that top-level surrogate.

Pass that viewport surrogate as the fallback target for fragment
scrolling and NavigateEvent focus reset, so unfocusable body or fragment
targets still clear stale element focus.

Cover documentElement.focus() in both the activeElement and focus-chain
tests, including a tabindex document element that remains focused as an
element. Cover object focus with and without a child navigable, hidden
object focus attempts, iframe focus events, hidden iframe focus, and
blurring a focused iframe after it becomes hidden. Also cover viewport
fallback for intercepted navigation focus reset and fragment scrolling
to an unfocusable target.
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
Tim Ledbetter
11379e7c67 LibWeb: Clear selection when no find in page matches are found
Previously, if the find in page query was updated and no matches were
found we would keep the old selection instead of clearing it.

`window.find` behaves differently from the find in page UI and
preserves the old behavior.
2026-05-20 21:32:00 +02:00
Andreas Kling
1c7519f9ef LibWeb: Treat fragment parser documents as disconnected
Keep the temporary document used by HTML fragment parsing from
running post-connection work while the parser is staging nodes there.
This lets scripts from Range.createContextualFragment() remain
unstarted until the returned fragment is inserted into the real
document, and removes the script-specific preparation guard.

Strengthen parser coverage so contextual fragment scripts must wait
until the fragment is applied before running.
2026-05-17 15:35:56 +02:00
Andreas Kling
54879bc916 LibWeb: Complete Rust HTML tree construction
Finish the Rust implementation of the spec tree-construction algorithms
needed by the LibWeb test suite. Add the remaining table modes, foster
parenting, scope helpers, adoption agency handling, ruby/list/form and
select cases, frameset state, foreign-content edge cases, and parser
host callbacks.

Preserve behavior that depends on the C++ DOM integration, including
parser-created custom element reactions, fragment quirks mode, arbitrary
fragment namespaces, template fragment mode, fragment form ownership,
MathML annotation-xml boundaries, contextual fragment scripts, parser
script source positions, document.close() parser state, void-element
insertion, and duplicate attribute tracking.

Add focused tests for the parser edge cases that are easy to regress at
the boundary between the Rust tree builder and the C++ DOM host.
2026-05-17 15:35:56 +02:00
Yuval Carmon
eaf1078c98 LibWeb: Use stop_fetch() for overlapping HTMLLinkElement fetches
When a link element's href changes, the spec expects the callback
to check if "el contributes a script-blocking style sheet"
(step 6). This check examines current fetch state, which fails
when old fetch callbacks run after a new fetch has started.

Use FetchController::stop_fetch() instead of abort() to prevent
old fetch callbacks from executing entirely. This ensures only the
current fetch's callback runs, allowing it to correctly check
current state per spec without race conditions.
2026-05-13 04:17:24 -05:00
Zaggy1024
1285174a2e Tests: Stop worrying about exact media element ready states in events
Instead, just verify a minimum for each event. Ready states aren't
deterministic when following spec anyway.
2026-05-13 02:05:35 -05:00
Jelle Raaijmakers
1aeb080250 LibCompress: Treat LZW decoding errors as end of stream
The LZW data for both GIF and TIFF images is sometimes intentionally
missing an end-of-information (EOI) code, which technically is a
decoding error, but in practive is handled gracefully by Firefox, Safari
and Chrome for GIFs and Safari for TIFFs. Let's mirror their behavior.

The included WPT test exposes the fact that trailing garbage bytes can
also result in decoding errors. We handle this in the LZW logic rather
than in the image decoding since our LZW implementation is currently
only used by GIF and TIFF decoding. The error is logged behind the
LZW_DEBUG flag.
2026-04-29 20:28:15 +02:00
Aliaksandr Kalenik
4762c4fa5c LibWeb: Add incremental HTML parsing
Introduce IncrementalDocumentParser, which streams the response body
through a TextCodec::StreamingDecoder into the HTMLTokenizer one chunk
at a time. The tokenizer pauses when it runs out of input and resumes
once the next chunk is appended; when the body closes we close the
tokenizer's input stream so it can finish the parse.

DocumentLoading routes HTML responses through the new parser instead of
buffering the full body before handing it to HTMLParser.
2026-04-29 04:12:44 +02:00
Aliaksandr Kalenik
70ac025eff LibWeb: Implement the speculative HTML parser
When the HTML parser blocks on a synchronous external script, run a
separate tokenizer over the unparsed input and issue speculative fetches
for the resources it finds (script src, link rel=stylesheet|preload, img
src), with <base href> tracking and template/foreign-content skipping.

Also fills in the previously-stubbed "consume a preloaded resource"
algorithm and the document's "map of preloaded resources", so that
<link rel="preload"> followed by a matching consumer deduplicates to
a single fetch.
2026-04-26 18:48:29 +02:00
Aliaksandr Kalenik
54244f9e4a LibWeb: Re-evaluate picture source set on source mutations
The img inside a <picture> has to re-run "update the image data" when
nearby <source> elements change, so script-driven swaps of srcset (and
the other dimension/media attributes) actually take effect.

Per the HTML spec, the relevant mutations for an img element include:
"The element's parent is a picture element and a source element that
 is a previous sibling has its srcset, sizes, media, type, width or
 height attributes set, changed, or removed."

The same applies to source insertion, moving, and removal.

Fixes image loading on https://www.apple.com/mac/
2026-04-26 17:49:19 +02:00
Luke Wilde
3d3b02b9c0 LibJS: Use the real globalThis value
Previously it used `realm.[[GlobalObject]]` instead of
`realm.[[GlobalEnv]].[[GlobalThisValue]]`.

In LibWeb, that corresponds to Window and WindowProxy respectively.
2026-04-23 20:43:01 +01:00
Zaggy1024
22c1b72588 LibWeb: Prevent dragstart after a prevented mousedown or dragstart
Also, explicitly prevent drag events from firing when the context menu
opens. This will only be the case on macOS, since its context menu is
opened by Ctrl+mousedown. This replaces the prior exception preventing
drag events when Ctrl is held during mousedown.

Fixes #9018 and #9019
2026-04-22 07:34:18 -04:00
Zaggy1024
ccd9bdac56 Tests: Make each drag-and-drop-element.html subtest stateless
The event handler captures shouldn't be necessary here, we can just
print the events that are relevant to each testcase element.
2026-04-22 07:34:18 -04:00
Zaggy1024
04cc5bced9 LibWeb: Update video elements' natural dimensions during playback
This tightens the implementation of video element sizing to the spec by
implementing two spec concepts:
- The media resource's natural width and height, and
- The video element's natural width and height.
The element's natural dimensions change based on the representation,
which has many inputs, so update checks are triggered from many
locations.

The resize event is fired when the media resource's natural dimensions
change, and the layout is invalidated if the element's natural
dimensions change.

Tests for a few important resize triggers have been added.
2026-04-21 19:11:24 -05:00
Tim Ledbetter
e5d615cb11 LibWeb: Implement autofocus candidate processing
This change implements the algorithms necessary to focus elements with
the autofocus attribute on page load.
2026-04-21 23:47:05 +02:00
Shannon Booth
706011bd9b LibWeb: Respect image response MIME type over .svg URL suffix
SharedResourceRequest was treating any URL ending in .svg as SVG, even
when the response Content-Type was some other format (like image/webp).
This could result in transformed CDN image URLs to fail decoding.

Only use the .svg URL suffix fallback when no MIME type was provided.
2026-04-19 15:57:47 +02:00
Jonathan Gamble
1c5907d87f LibWeb: Correct initiator origin logic for new top level traversables 2026-04-19 13:11:48 +02:00
Zaggy1024
5ab536b33c Tests: Remove the timeout between steps in media source tests
The goal with these timeouts was to eagerly fail the test and not spend
an excessive amount of time waiting for the full test-web timeout.
However, since CI uses sanitizers, it's plausible that the time it
takes between steps, especially the fetch, could exceed that. Instead,
let's just let test-web time these out.

Hopefully this will make the test green on CI.
2026-04-10 15:30:08 -05:00
Zaggy1024
ab9776955f LibMedia: Allow audio tracks to be enabled without a mixing sink
This allows audio elements in headless mode to advance their ready
states past HAVE_CURRENT_DATA.
2026-04-10 15:21:07 -05:00
Zaggy1024
2d00a28f08 Tests: Simplify the HTMLMediaElement-load-after-decode-error.html test
Use promises to await the expected sequence of events. Also, don't
assume that canplaythrough will fire after error. That depends on the
implementation.
2026-04-10 15:21:07 -05:00
Callum Law
27a00f19c5 LibWeb: Update correct value for canvas stroke style setter
When setting to a non-string value (i.e. a `CanvasGradient` or
`CanvasPattern`) we would accidentally update the fill style instead of
the stroke style.
2026-04-08 14:31:43 +01:00
Timothy Flynn
cfe7ddc805 LibWeb: Add support for handling drag-and-drop events of DOM elements
This allows dragging elements on the page and dropping them onto other
elements. This does not yet support dragging text.

The test added here is manual; the WPT tests rely heavily on WebDriver
actions.
2026-04-05 11:34:42 -04:00
Timothy Flynn
b7076c366d LibWeb: Work around a spec bug regarding cancelling dragenter events
The spec dictates that dragenter events must be cancelled in order for
drops to be accepted on the entered element. Web reality disagrees, as
all three major browsers do not have this requirement.
2026-04-05 11:34:42 -04:00