Commit graph

2080 commits

Author SHA1 Message Date
Shannon Booth
ecb6c90aeb LibWeb: Track CORS-cross-origin image data for canvas tainting
Propagate the CORS-cross-origin state from image fetch responses through
SharedResourceRequest, ImageRequest, and the available image cache.

Use that state when drawing HTML images to canvas so cross-origin image
data taints the canvas correctly.
2026-06-11 17:01:48 +02:00
Sam Atkins
e7aad5a9d3 LibWeb: Connect iframe referrerpolicy to ancestorOrigins
Corresponds to:
e161310ae7

This unfortunately isn't testable as we don't implement enough of
ancestorOrigins to be able to observe it.
2026-06-11 14:25:27 +01:00
Zaggy1024
9e2a820884 LibMedia+LibWeb: End media element playback based on the pipeline EOS
Instead of comparing the current time to the duration, the playback
manager now has an explicit Ended state that jumps to the duration. The
element simply reacts to that to trigger the ended event and attribute,
along with all the other steps involved.

This moves the ended event to fire after the seeked event, which
matches other browsers' behavior. The spec doesn't explicitly say which
order they should fire in.
2026-06-11 05:49:14 -05:00
Zaggy1024
da4e8b2b2b LibWeb: Pass the media element as an argument to task steps
Since the queued task callback is already capturing the media element
weakly, we may as well directly use that in the steps that need to
interact with the element, which is the majority of them.

Also, root the element in the callback. This ensures that any queued
tasks will fire events before the element gets collected.
2026-06-11 05:49:14 -05:00
Zaggy1024
390ac120ad LibWeb: Update media element ready state when setting current position
The time marches on steps are invoked from a few places where updating
the ready state isn't needed.
2026-06-11 05:49:14 -05:00
Zaggy1024
338c33a0ed LibWeb: Pin the media controls' time progress to the scrub position
When scrubbing, make the timeline progress match exactly to the cursor
position. Also, set the timestamp to match that progress. Both are not
allowed to change until the scrub completes.

This makes the UI stable while scrubbing after the end of the media
data in subsequent commits that jump the time to the duration at EOS.
2026-06-11 05:49:14 -05:00
Zaggy1024
2f9a42ff44 LibWeb: Swallow rejected play() promises in media controls
Whenever the controls' timeline is clicked, it pauses the media element
before seeking, then play()s on mouseup. However, the play() returns a
promise that resolves when the media actually becomes playable at the
new position. If that takes long enough that a second click pauses the
element again, then that play() promise gets rejected, and an unhandled
rejection is logged.

To prevent that, mark all play promises as handled to silence them.
2026-06-11 05:49:14 -05:00
Zaggy1024
6af0f54b15 LibWeb: Update the media controls' timeline upon progress firing
Otherwise, we don't update the buffered ranges visual when paused for
a blocked seek.
2026-06-11 05:49:14 -05:00
Sam Atkins
e0cc71d2d0 LibWeb/HTML: Ignore if select has multiple to determine placeholder
Corresponds to:
d59fb13c28

WPT has tests for this, but we don't implement listbox layout for select
so there's no testable difference here.
2026-06-11 14:46:37 +12:00
Zaggy1024
57a78f2b59 LibWeb: Transfer load delayers when elements are adopted
Otherwise, the load event will block the original document until GC
runs.

Without this, media-load-task-after-adoption.html would wait for the
idle timeout to trigger a garbage collection, which could sometimes
cause the test to time out entirely.
2026-06-11 00:34:12 +02:00
Timothy Flynn
409e5edbf1 LibURL+LibWeb+LibWebView: Move internal URLs to their own header
This nearly eliminates the compilation impact of adding a new WebUI URL.
2026-06-10 20:27:36 +02:00
Andreas Kling
45c499d185 LibJS: Isolate ArrayBuffer backing stores
Move owned ArrayBuffer and SharedArrayBuffer data blocks into the
ArrayBuffer heap partition. Keep unowned and host storage explicit, so
Wasm memory and external LibWeb buffers stay outside this partition.

Introduce DataBlock::OwnedBackingStore as the LibJS-owned byte storage
representation. Expose byte spans instead of a ByteBuffer object, giving
ArrayBuffer one allocation boundary that can later grow toward guarded
or caged storage.

Let callers that need ByteBuffer data copy from backing-store bytes.
Keep TransferArrayBuffer zero-copy by moving the DataBlock directly
instead of materializing a ByteBuffer in between.

Update the Wasm typed-array test helper to compare viewed byte ranges
after ArrayBuffer stops exposing ByteBuffer identity.
2026-06-10 14:50:10 +02:00
Tim Ledbetter
d625deaccf LibWeb: Invalidate style when form control validity changes 2026-06-08 19:28:37 +02:00
Tim Ledbetter
de0b733bed LibWeb: Implement suffering from bad input for input elements
Email field support is left unimplemented because we don't have a way
to convert email addresses to punycode.
2026-06-08 19:28:37 +02: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
sideshowbarker
a82c7939d9 LibWeb+UI/AppKit: Implement macOS IME support
This makes macOS IME input in web content work as expected.

Fixes https://github.com/LadybirdBrowser/ladybird/issues/9712
2026-06-08 10:23:14 +09:00
Andreas Kling
42a6253d64 LibWeb: Avoid idle callback churn in hidden documents
Do not start idle periods for hidden documents. This prevents
background tabs from promoting chained requestIdleCallback work into
new idle tasks immediately.

Also avoid queueing a follow-up idle task after the last runnable idle
callback has been consumed.

This fixes an issue where opening GitHub links in background tabs would
cause their WebContent processes to churn 100% CPU until you open them.
2026-06-08 01:56:11 +02:00
Andreas Kling
5c169091de LibWeb: Propagate outerText replacement exceptions
Propagate exceptions from the outerText replace step instead of assuming
that replacement always succeeds. Replacing the document element with a
rendered text fragment can legitimately fail with a DOMException.

Add a reduced crash test for setting outerText on documentElement.
2026-06-08 01:04:08 +02:00
Andreas Kling
613a04e4df LibWeb: Skip styleless nodes for rendered text
Rendered text collection needs computed style only for nodes that are
being rendered. A stale layout node can remain without style or a styled
parent, so treat that as not rendered instead of asserting while reading
innerText or outerText.

Add reduced crash coverage for reading outerText from a style element
after disabling and adopting it into another document.
2026-06-08 01:04:08 +02:00
Andreas Kling
57bf4bec64 LibWeb: Ignore invalid body background hints
The body background attribute can fail to produce an image style
value. Applying presentational hints should ignore the attribute in
that case instead of asserting.

Add reduced crash coverage for updating style after an invalid body
background hint is adopted into the active document.
2026-06-08 01:04:08 +02:00
Andreas Kling
485ca67164 LibWeb: Skip inactive media element tasks
Media element tasks are queued as element tasks. The element can move
to another document before the queued task runs.

Abort the task if the media element's current document is no longer
fully active. This preserves the media resource fetch invariant.

Add reduced crash coverage for adoption into an inactive document.
2026-06-08 01:04:08 +02:00
Andreas Kling
fe51d6ce5d LibWeb: Handle blurring nodes without a browsing context
DOMParser-created documents do not have a browsing context, but elements
created in them can still be passed to the HTML blur() steps. The
unfocusing steps only have a top-level focus chain when the old target
finds itself in a browsing context, so return early when there is none.

Add reduced crash coverage for blurring a body element created in a
DOMParser document.
2026-06-08 01:04:08 +02:00
Andreas Kling
7afc862bc0 LibWeb: Handle BarProp without a top-level context
BarProp.visible first handles a null browsing context, but the
top-level browsing context lookup can also return null when the
relevant document is no longer fully active. Return true in that
case instead of dereferencing the null result.

Add a reduced Crash/HTML test from the domato fuzz-00063 sanitizer
finding that reads menubar.visible through an inactive frame window.
2026-06-08 01:04:08 +02:00
Andreas Kling
e9b8c3f7c6 LibWeb: Skip COOP access reporting for inactive documents
WindowProxy property access can reach COOP access reporting after iframe
removal. That leaves the accessed active document not fully active.

The reporting algorithm only applies to fully active documents. Return
early for inactive documents instead of asserting. Add a crash test for
accessing a window proxy after iframe removal.
2026-06-08 01:04:08 +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
Zaggy1024
e24540330e LibWeb: Enable playback rates other than 1.0
The allowed range for now is 0.0-64.0. If that turns out to be too wide
a range, we'll reduce it.

Chromium and Firefox are more restrictive, only allowing between a
minimum non-zero number and 16.0. They also allow 0.0.
2026-06-06 19:58:17 -05:00
Zaggy1024
7ddbc2d7dd LibWeb+LibMedia: Wire up setting the pipeline's playback rate
However, the playback rate is still limited to 1.0 at the element,
because audio stretching is not yet implemented.
2026-06-06 19:58:17 -05: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
Andreas Kling
222c1f7044 LibWeb: Move CSS image loading state to Document
Move the SharedResourceRequest, animation timer, and current frame
state out of ImageStyleValue and into a Document-owned table keyed
by resolved image URL. ImageStyleValue now keeps only URL metadata
and its client list, so image style values no longer need to trace
GC edges themselves.

Thread the Document through AbstractImageStyleValue APIs that need
decoded image data. CSS image fetches snapshot the stylesheet base URL,
referrer behavior, and origin-clean state instead of retaining the
stylesheet.

Remember each client's registered resolved URL when unregistering. This
keeps a later document base change from leaving an animated image
resource alive.

Add text coverage for inline relative image base URLs, stylesheet
referrers, imported stylesheet origin-clean behavior, inline @import
initiator type, and unregistering an animated background image after a
base element change.
2026-06-06 23:29:48 +02:00
Timothy Flynn
87cdeda93c LibSyntax+LibJS+LibWeb+LibWebView: Remove unused syntax highlighter code
A future patch will port LibSyntax away from UTF-32. The less code that
needs to be ported, the easier that will be.
2026-06-06 18:42:18 +02:00
Aliaksandr Kalenik
852c7a10f3 LibWeb: Let image paint callers own clipping
DecodedImageData::paint() used to take both a destination and a
clip rectangle even though most callers passed the same value. SVG
image painting used that API to wrap every nested SVG display list in
save/add-clip/restore, which put an unbounded command in front of
the bounded nested-list command and made offscreen SVG image content
harder to cull.

Move clipping to ImagePaintable, where the object-fit destination can
be compared with the replaced element box. CSS image and marker
painting continue to draw into their destination rect, while repeated
background images keep their explicit tile clip. The scaled decoded
image display-list command now stores only its destination rect and
uses that as its bounds; playback still clips decoded images to that
rect so bitmap rendering stays unchanged.
2026-06-06 13:23:21 +01:00
Andreas Kling
570ea59277 LibWeb: Run same-document commit handlers during entry update
Move Navigation API commit handler completion into a helper. This lets
same-document entry updates run currententrychange before the intercept
handlers. Keep same-document traversals from aborting the ongoing
NavigateEvent before that entry update runs.

Add text coverage for intercepted and non-intercepted same-document
history traversals updating the Navigation API current entry before
navigatesuccess.
2026-06-06 11:34:50 +02:00
Andreas Kling
3ec9733efe LibWeb: Resume intercepted history traversals
When a traverse navigate event is intercepted, queue the resume step
specified by the Navigation API. This keeps intercepted traversals from
stopping at URL update time.

Do not resume that queued step if the intercepted NavigateEvent was
aborted or replaced by a newer ongoing event before it runs. Add tests
for the basic intercepted traverse case and the superseded intercepted
traverse case.
2026-06-06 11:34:50 +02:00
Andreas Kling
6ecfcd3e68 LibWeb+LibJS: Cache decoded JS bytecode sidecars
Add a ref-counted decoded bytecode cache backing so bytecode cache
materialization can create fresh script or module records from a shared
decoded sidecar without passing around one-shot raw blob ownership.

Keep that backing in ExecutableBacking for records materialized from
bytecode cache sidecars, so the immutable decoded data stays alive for
as long as the installed record needs it.

Cover the shared backing path with a bytecode-cache test that
materializes and runs two scripts from one decoded backing.
2026-06-06 09:15:09 +02:00
Andreas Kling
72720bc229 LibWeb: Preserve JS bytecode in memory cache
Store JavaScript bytecode side data in the WebContent HTTP memory
cache and replay it when serving cached responses. Also update an
already-complete memory-cache entry when asynchronous bytecode cache
generation finishes, so the first source-only response does not keep
shadowing the disk-cache sidecar during same-process navigations.

Keep the HTTP memory-cache backfill keyed with the request headers that
populated the memory-cache entry, so Vary responses still receive their
generated bytecode sidecar.

Add LibHTTP coverage for round-tripping bytecode side data through a
memory-cache entry, attaching it after the response body has already
been cached, and matching Vary headers during updates. Add LibWeb
coverage for preserving the memory-cache request headers when cloning
responses.
2026-06-06 09:15:09 +02:00
Andreas Kling
ec421d7fa4 LibWeb+LibJS: Validate bytecode cache blobs off-thread
Warm cache hits used to validate bytecode cache blobs on the main
thread. Route script and module sidecars through a worker step that
decodes and validates the cache blob, then returns the validated blob
for main-thread materialization.

Keep the source bytes mmap-backed and avoid decoding the full source on
cache hits. The main thread still computes the UTF-16 source length so
validation can reject stale blobs before materialization.

Remove the decoded source length getter now that sidecar validation uses
the explicit validation API instead.
2026-06-05 21:55:55 +02:00
Andreas Kling
bf81464904 LibWeb+LibJS: Remove rust_pipeline_available
The Rust pipeline is always available now, so the getter only wrapped
code that always ran. Remove it and make the JavaScript fetch paths use
the off-thread Rust pipeline directly.

This also removes the unreachable synchronous fallback branches from the
classic script and module fetch paths.
2026-06-05 21:55:55 +02:00
Shannon Booth
13bae036d8 LibWeb: Do not refer to removed C++ DAFSA code generator 2026-06-05 20:23:24 +02:00
Zaggy1024
0ce19a19ea LibWeb: Leave input elements' text node contents unchanged while typing
Replacing the text node's contents with the normalized value after each
keystroke made it impossible to type some inputs. For example, `1e`
would cause the text node to be emptied, making it impossible to type
`1e2`. Also, `time`, `date`, and other time-related input types had no
intermediate valid values, so it was genuinely impossible to type in
them.

Additionally, typed numbers weren't being parsed as floats before
normalization, so even just typing `1.` would clear the text node, so
it was impossible to type a fractional number.
2026-06-05 12:49:24 +02:00
Zaggy1024
e6664213ac LibWeb: Fall back to TextInputBox for unsupported input types
This isn't strictly correct as it stands currently, since the size
attribute isn't supposed to affect type="time" and others, but those
types currently end up with zero width instead.

Size could probably be applied through shadow DOM style, and the input
layout box would simply allow content sizing.
2026-06-05 12:49:24 +02:00
Callum Law
f28e7120ea LibWeb: Ensure that shadow roots have hosts before appending children
This change gives each shadow root its host before appending its
children, and asserts that a root has no children when it's assigned to
a host. This ensures the children inherit the correct connectedness.

Otherwise, without this change, the user-agent shadow trees for color
and file inputs append their children before the shadow root is given
a host which, if the input element has already been inserted, means the
children stay marked disconnected despite being present in the rendered
tree. Disconnected nodes then skip layout invalidations they should
trigger.

Fixes a crash when submitting a prompt on https://chatgpt.com
2026-06-05 18:08:21 +09:00
Andreas Kling
789d7cba48 LibWeb: Use direct references to main event loops
Post off-thread font, script, and DNS completion work back to direct
Core::EventLoop references. These callbacks target the process main
loop, which is intentionally kept alive for the lifetime of the
process.
2026-06-05 09:18:39 +02:00
Andreas Kling
164ed80244 Meta: Enable exit-time destructor warnings for libraries
Enable -Wexit-time-destructors for all in-tree library targets and
update process-lifetime library statics so they no longer register
exit-time destructors. Long-lived caches, lookup tables, singleton
registries, and generated constants now use NeverDestroyed or leaked
references where the data is intended to live until process exit.

Update LibWeb, LibLine, and the binding generators so regenerated
sources follow the same rule instead of reintroducing destructed
statics.
2026-06-04 19:20:49 +02: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
c1953f93c7 LibWeb: Move style element hooks to StyleElementBase
Move HTMLStyleElement's dynamic update handling, media/type attribute
handling, and script-blocking predicate skeleton into StyleElementBase
so style elements can share that plumbing.
2026-06-04 16:39:54 +01:00
sideshowbarker
898be8badb LibWeb: Cancel the async-scroll hover update when the document changes
Problem: A document loaded into a navigable just after a previous
document in that navigable had been async-scrolling could receive hover
and mouseover/mouseout boundary events which nothing in that document
triggered. In our CI, that manifested as an intermittent flake/failure
of the async-scrolling/hover-updates-after-async-scroll.html test —
whose first mouseover count came up one short: A leftover refresh had
moved hover onto the target before the test added its listeners.

Cause: A navigable tears down a document’s input state implicitly: Its
hover target and mousedown target are GC::Weak references that null
themselves once the document is collected. The post-scroll hover refresh
wasn’t getting that automatic teardown. It runs off a Core::Timer that’s
stopped when the navigable is destroyed — but was *not* being stopped
when the navigable swaps in a new active document. So, a scroll in one
document left a refresh that fired against the next.

Fix: Cancel the pending refresh when the navigable’s active document
changes — the same boundary at which the weak references null. That
gives the timer the same teardown the rest of the input state already
has — with no per-document tracking state.
2026-06-04 11:06:14 +02:00
Zaggy1024
effb3fad3c LibWeb: Stop rounding to the nearest integer when dragging range inputs
set_value_as_number() already snaps the value to the nearest step, the
round and FIXME here were unnecessary.
2026-06-03 21:26:53 -05:00
Zaggy1024
10ba2ddbb7 LibWeb: Access range inputs' mouse events' clientX by casting
This is a bit more legible, and should be a bit more efficient than a
property lookup by name as well.
2026-06-03 21:26:53 -05:00
Andreas Kling
afb0fa2413 LibJS: Hash encoded source identity in bytecode cache
Switch bytecode cache source identity from decoded UTF-16 source text to
the original encoded response bytes plus the effective source encoding.
Store the decoded source length in the cache blob header so warm loads
can build lazy SourceCode objects without decoding the source before
checking the sidecar.

This removes the main-thread decoded_source_text_info pass from valid
warm-cache script and module loads. The source is only decoded on cache
miss, or when a rejected sidecar falls back to source compilation.
2026-06-03 14:11:23 +02: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