Commit graph

2101 commits

Author SHA1 Message Date
Andreas Kling
a11c281dc3 Compositor: Handle pinch zoom asynchronously
Apply pinch zoom deltas to the compositor's visual viewport transform
so the currently presented display list can respond without waiting for
the WebContent main thread. Keep the normal WebContent pinch event path
so the real VisualViewport state and DOM-visible events catch up after.

Only take the compositor path when async scrolling is enabled and there
are no blocking wheel listeners, since pinch zoom dispatches a synthetic
wheel event that script may cancel. Coalesce queued pinch events in
WebContent so main-thread catch-up can adopt multiple gesture deltas
together.

Use the compositor visual viewport transform for wheel hit testing and
consume wheel deltas as visual viewport pan while zoomed. Scale the
handoff to layout viewport scrolling by the inverse visual viewport
scale, so touchpad momentum does not jump when the visual viewport hits
an edge.
2026-06-16 02:03:59 +02:00
Aliaksandr Kalenik
be9ee28afc LibGfx: Stop caching Skia images during canvas playback
The decoded-frame Skia image cache is useful for display-list
rasterization because decoded image resources can be replayed over many
frames. The cache lets that path reuse SkImage wrappers and GPU-backed
copies instead of rebuilding them whenever the same resource is painted.

For canvas, commands are consumed into one backing surface and decoded
frames are already held by the command or paint style for the draw. A
per-painter cache does not match that usage model, and can keep decoded
frames and Skia images alive after the draw has consumed them.

This removes the cache from PainterSkia and drops the now-unused pruning
hook from CanvasCommandPlayer. With the cache gone, PainterSkia can hold
its painting surface directly instead of allocating a private Impl.
DisplayListPlayerSkia keeps owning the cache, so display-list
rasterization keeps the SkImage reuse behavior.
2026-06-16 00:38:30 +02:00
Andreas Kling
394312ab5a LibWeb: Let newer navigations win history races
Treat pending session history entries as absent from the used step
graph, and share that through a small step_value() helper so
snapshotting, Navigation API entry construction, target-entry lookup,
and forward clearing do not drift apart.

Keep cross-document history application tied to the navigation id that
created it. Queued changing-navigable work now finishes without
applying when a later navigation has already replaced its target, and
any traversal sentinel is cleared through the shared setter so queued
navigations can drain.

When navigation arrives while traversal is still ongoing, keep only the
newest pending navigation. This matches Chromium, WebKit, and Gecko on
sites that click through product or category links while prior loads
settle.

Revalidate queued same-document child continuations before running them
from null-document tasks, so removed frames or frames claimed by newer
navigations do not receive stale history state.

Preserve nested-history descriptors even when all child entries are
pending, keeping live child navigable identity available for later UI
process history seeds.

Add regression coverage for iframe renavigation during history commit,
for pending child history followed by a real navigation, and for removed
iframes with queued history updates.
2026-06-16 00:00:38 +02:00
Andreas Kling
2d9db6c1f8 LibWeb: Keep stale child history tasks runnable
Child navigables can lose document-associated apply-history tasks when
a parent page replaces or destroys the child document. Queue child tasks
with no document association so they remain runnable, and share that
choice for both activation and update-only continuations. Keep top-level
work associated with the active document to preserve initial about:blank
Window reuse.

Also abandon a queued child fetch if its parent document is already gone
before reading the parent's relevant settings object. This matches
browser behavior for detached frame navigations and avoids resuming
stale work against a discarded parent.

The Twinings menu to Black Tea to Earl Grey product flow now reaches the
product main content under Ladybird WebDriver. Existing navigation
coverage and the full LibWeb text suite cover the local history cases.
2026-06-16 00:00:38 +02:00
Andreas Kling
b06955277a LibWeb: Stabilize same-document history mirrors
Same-document navigations now commit synchronously in WebContent, while
the UI process mirror learns about them over asynchronous IPC. A stale
UI seed could be accepted back into a live non-initial document and
overwrite its latest entry, making queued traversals target unreachable
entries.

Share descriptor comparison helpers between LibWeb and LibWebView.
Reject stale top-level seeds against the active document latest entry,
and let the UI process adopt WebContent current snapshots when a seed is
rejected. Test-only session history dumps now first send WebContent
current state synchronously, so dumps observe the converged state.

Allow post-load UI seeds to carry UI-owned nested histories that the
freshly loaded top-level document has not reconstructed yet. Add unit
coverage for matching those seeds while still checking top-level state.
2026-06-16 00:00:38 +02:00
Andreas Kling
327437cfc6 LibWeb: Commit same-document navigations synchronously
Finalize fragment navigations and URL/history updates immediately when
no traversal state is active. Keep the queued same-document finalizer as
the fallback for reentrant traversal work and child navigables whose
nested history is not installed yet.

Share the entry-list portion of same-document navigation finalization
between the fast path and queued fallback, so append and replace
bookkeeping cannot drift.

Preserve unrelated ongoing cross-document navigations when a page starts
a load and then performs a same-document history update in the same
task. This matches Chromium, WebKit, and Gecko: the same-document
update must not cancel the pending real navigation.

The session-history mirror tests now observe synchronous UI updates. A
navigation test covers the pending-load plus pushState race.
2026-06-16 00:00:38 +02:00
Andreas Kling
5aac297558 LibWeb: Keep child navigable history updates coherent
Normalize the target step again at the end of applying a history
step, since iframe removal can leave the originally computed target
step unused before the asynchronous application finishes. Let the UI
history snapshot use the same used-step mapping when it serializes a
current item for the UI process.

Handle late child-frame navigation commits whose original nested
history entry disappeared before finalization. Removed iframes have no
live nested history list to update, and initial about:blank still needs
its first real navigation to replace the remaining initial child entry.

Add coverage for iframe pushState before nested history readiness and
for removing and recreating an iframe after an initial same-document
history update.
2026-06-15 01:15:09 +02:00
Andreas Kling
24f37c6732 LibWebView: Keep browser history in the UI process
Use the LibWebView history mirror to preserve traversable session
history across WebContent process swaps. WebContent reports snapshots to
the UI process, and new renderers can be seeded from the mirror.

Browser back and forward now resolve through the UI-owned used history
steps. WebContent still runs the spec traversal path when the current
renderer has enough matching state to do so.

Handle canceled and no-op UI navigations without leaving speculative
history entries or pending WebDriver waits behind. Preserve traversal
precheck state across synchronous IPC shutdown, and avoid overwriting a
restored target entry's persisted scroll state before the document has
adopted that entry.
2026-06-14 17:38:44 +02:00
Andreas Kling
9e2ec2dc5c LibWeb: Add session history serialization support
Add structured helpers for the history data mirrored by LibWebView.
Cover POST resources, history state, navigation API state, scroll
positions, and entry metadata.

Keep this below the UI model so browser-side history code can move data
through typed objects instead of ad-hoc strings.
2026-06-14 17:38:44 +02:00
Aliaksandr Kalenik
73352ef2d2 LibGfx+LibWeb: Paint 2D canvas via record-and-replay
Move CanvasRenderingContext2D onto the same record-and-replay model that
the compositor-process path will use, but keep playback local for now.
Draw calls append CanvasCommandList entries and flush/readback paths
replay the commands into a local CanvasCommandPlayer-owned surface.
2026-06-13 20:41:03 +02:00
Aliaksandr Kalenik
60f27523c6 LibIPC: Adopt Mach OOL payloads on receive
Mach transport already sends payloads as out-of-line virtual-copy
regions, but the receive path immediately copied each payload into a new
Vector and deallocated the kernel mapping. That made the IPC IO thread
touch every byte before the main thread could decode the message.

Add ReceivedMessageBytes as the raw-message byte storage and let the
Mach transport adopt the OOL region directly. The mapping now lives
until the raw message storage is destroyed, so invalid descriptor paths
and normal queue teardown both release it through the same destructor.
Socket transports keep their existing receive copy path by wrapping
vectors in the same storage type, and the direct raw-message consumers
now decode from its ReadonlyBytes view.
2026-06-13 00:27:57 +01:00
Tim Ledbetter
45ca0c1158 LibWeb: Skip meta http-equiv processing outside a document tree
The pragma directives specification steps should only run when a meta
element is inserted into the document, meaning it is in a document tree
after the insertion steps have run. We previously ran the pragma
algorithms for any insertion, so inserting a meta element with
`http-equiv=content-language` into a detached subtree dereferenced a
null document element.
2026-06-13 10:51:37 +12: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
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
Sam Atkins
2629c36dcc LibWeb/HTML: Make disabled select disable its option/optgroup children
Corresponds to:
f7b4402195
2026-06-11 19:07:27 +02:00
Sam Atkins
e3c1fb99d1 LibWeb/HTML: Add resource timing URL to iframes
Corresponds to:
9ef207c159
...but also fills in some FIXMEs we already had.
2026-06-11 19:07:27 +02:00
Sam Atkins
8f32063bd1 LibWeb/HTML: Update image naturalWidth/naturalHeight spec steps
Partly corresponds to:
4ff60b0849

We don't actually implement image densities yet, but this gives us a
FIXME as a clear point to implement that.
2026-06-11 19:07:27 +02:00
Sam Atkins
d501148f46 LibWeb/HTML: Break up step 15 of "update the image data"
Corresponds to:
fc559a5fd5

No code changes.
2026-06-11 19:07:27 +02:00
Sam Atkins
7158294dfb LibWeb/HTML: Correct button activation steps to use element not this
Corresponds to:
60c8816e32

Spec only, no code changes.
2026-06-11 19:07:27 +02:00
Sam Atkins
c60134158c LibWeb/HTML: Don't prepare_script() when src attribute is removed
Corresponds to:
c22fb1b32c

We already behaved this way, this just brings us in line with the spec.
2026-06-11 19:07:27 +02:00
Sam Atkins
a75e9f23db LibWeb+LibDevTools: Report Web Storage changes
Firefox keeps the Storage panel current by sending store update packets
when localStorage or sessionStorage changes. Forward successful Web
Storage mutations to the storage actors and emit the matching update or
clear packet.

Use listener IDs for storage updates so the local and session storage
actors can subscribe independently.
2026-06-11 16:08:33 +01:00
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