Commit graph

79641 commits

Author SHA1 Message Date
Callum Law
27381e9b00 LibWeb: Remove index based frame getters for ImageStyleValue
`ImageStyleValueResource::frame` was unused and `ImageStyleValue::frame`
was only ever used to get the current frame so it can just be inlined.
2026-06-18 10:44:25 +02:00
Callum Law
3852b3f5a8 LibWeb: Rename AnimatedDecodedImageData
To `AnimatedBitmapDecodedImageData`. This better reflects what it is and
frees up `AnimatedDecodedImageData` to be used as an abstract class in a
later commit.
2026-06-18 10:44:25 +02:00
Callum Law
a7881ca3eb LibWeb: Register DecodedImageData consumers as clients
In a future commit, ownership of animation will be transferred from
these clients to `AnimatedDecodedImageData` and we will need a way to
invalidate them for new frames.

This also revealed some `ImageProvider`s which don't yet support
animated images (e.g. `<input type="file">`, `<object>`, etc) but that
is left as a FIXME for now.
2026-06-18 10:44:25 +02:00
Callum Law
74e04ed258 LibWeb: Add DecodedImageData::default_frame helper
The index based `frame(size_t, ...)` getter is going to be removed in a
future commit.
2026-06-18 10:44:25 +02:00
Callum Law
4428eba205 LibWeb: Simplify ImageStyleValueResource
`ImageStyleValueResource` now holds a reference to a
`HTML::SharedResourceRequest` for it's entire lifetime.

We also `VERIFY` that we have created a resource (by registering a
client) before calling `ImageStyleValue::image_data` rather than
silently failing.
2026-06-18 10:44:25 +02:00
Callum Law
2335941e43 LibWeb: Register ImageObservers for all mask-images
As of 114c8a7 we paint all mask layers, not just the first, so we should
likewise observe all `mask-image` values, not just the first.
2026-06-18 10:44:25 +02:00
Callum Law
11ab66c752 LibWeb: Notify ImageStyleValue::Clients on animation
Previously image animations driven by `ImageStyleValueResource`
invalidated clients using `on_animate`, this was only implemented by the
`background` presentational attribute of `HTMLBodyElement`.

It now uses `notify_clients_did_update` which is implemented by all
clients.
2026-06-18 10:44:25 +02:00
Callum Law
ce7a963344 LibWeb: Guard ImageRequest::fetch_image against redundant fetches
All other callers of `SharedResourceRequest::fetch_resource` guard based
on `needs_fetching` so let's do that here as well (and add a `VERIFY` so
that future callers don't make the same mistake).
2026-06-18 10:44:25 +02:00
Callum Law
373327a207 LibWeb: Remove AnimatedDecodedImageData::m_highest_requested_frame
This was only ever set, not read.
2026-06-18 10:44:25 +02:00
Callum Law
d98c5d1b03 LibWeb: Inline image scaling mode computation
This allows us to remove the `frame_rect` accessor.

This also fixes a bug where we computed the scaling mode based on the
clipping rect rather than the draw rect for `ImagePaintable`
2026-06-18 10:44:25 +02:00
Callum Law
d3c0cfdc71 LibWeb: Respect SVG intrinsic sizing during object fitting
Previously we used the `frame_rect` size, this is the same as the
intrinsic size for bitmap images but is `OptionalNone` for SVG which
caused us to always fall back to the `image_rect` and thus not apply
any scaling for SVGs regardless of whether they had intrinsic sizing.
2026-06-18 10:44:25 +02:00
Aliaksandr Kalenik
f6f68ece44 Services: Deny GPU operations in WebContent
WebContent no longer creates a GPU-backed Skia context, so its Linux
sandbox does not need the broad GPU device syscall allowance. Remove
allow_gpu_device_operations() from the renderer policy while keeping the
narrower file descriptor ioctl allowances used by IPC transport setup.
2026-06-18 10:25:44 +02:00
Aliaksandr Kalenik
724ca7cc24 LibSandbox: Allow TCGETS2 fd queries
WebContent is about to stop using the broad GPU device sandbox
allowance. That also removes the accidental permission for every ioctl,
which exposes ordinary terminal attribute queries made while printing
diagnostics.

The media decode error path can ask stderr for TCGETS2 while reporting a
corrupt video frame. Allow that narrow fd metadata query alongside
TCGETS, FIONBIO, and FIONREAD so renderer processes can keep the GPU
ioctl denial without crashing the media decode-error coverage.
2026-06-18 10:25:44 +02:00
Aliaksandr Kalenik
23885e7b4d LibWeb+WebContent+WebWorker: Drop display list player type selection
WebContent no longer chooses between CPU and GPU display list players,
and the remaining callers always use Skia raster playback. Remove the
PageClient virtual and now-single-value enum, then play SVG image and
cursor display lists directly.
2026-06-18 10:25:44 +02:00
Aliaksandr Kalenik
40d446d558 LibWebView+WebContent: Stop creating GPU Skia backend in WebContent
Canvas and display list rasterization now run in the Compositor
process, so WebContent no longer needs its own Skia GPU backend. Drop
the WebContent --force-cpu-painting option and stop forwarding it when
launching the renderer. The flag remains available for Compositor.
2026-06-18 10:25:44 +02:00
sideshowbarker
33d969682b Tests: Wait for session history convergence in UI history assertions
Problem: TestWebDriverSessionHistory failed intermittently on the slower
sanitizer CI runners. The UI history already matched what’s expected,
but webContentHistoryMatchesUI was still false — because the snapshot
was caught mid process-swap. The failing assertion varied from run to
run, making it almost certainly a sampling race.

Cause: A cross-site history navigation swaps the WebContent process and
re-seeds its history, and the UI-process mirror converges to that
asynchronously — after the script-visible navigation has finished. But
expect_ui_session_history sampled the mirror once, and asserted right
away — so it could read the state before convergence.

Fix: When a converged state is expected, wait for it instead of sampling
once: Poll until the UI history matches and WebContent matches the UI.
2026-06-18 10:23:49 +02:00
Jelle Raaijmakers
9ed75e4f50 LibWeb/CSS: Retain length precision in PercentageOr<T>
Instead of operating within the (saturating) CSSPixels constraints,
calculate the expected value using a floating point calculation first
and then create the CSSPixels value.
2026-06-18 09:59:41 +02:00
sideshowbarker
a38407d457 LibWeb: Unregister a “use” element from its document when finalized
Problem: Discarding a document that contains an SVG “use” element could
abort the process with a !is_in_list() verification failure in the
IntrusiveListNode destructor. That surfaced intermittently in our style-
invalidation stress tests, depending on GC sweep order.

Cause: A “use” element connected to a document registers itself in the
document’s list of “use” elements and unregisters during its removal
steps. A GC’ed “use” element is swept without running those removal
steps — so it stays linked. When it’s destroyed before its document,
its list node is still linked — and the destructor aborts.

Fix: Override finalize() to unregister the “use” element before
destruction. The collector finalizes every dying cell before destroying
any of them. So, the node is always unlinked in time — the same approach
DocumentObserver and NavigationObserver already use.
2026-06-18 09:39:47 +02:00
Aliaksandr Kalenik
aa1926159e Services: Move GPU runtime access to Compositor
WebGL rasterization now happens in the Compositor process, but the GPU
runtime Landlock rules still lived only in WebContent. ANGLE initializes
native EGL when a page creates a WebGL context, which happens after the
Compositor sandbox is installed, so loading libEGL.so.1 and the
Mesa/GLVND driver stack was denied.

Grant the Compositor access to native GL/Vulkan driver and configuration
paths, DRI devices, /sys, LD_LIBRARY_PATH entries, the Mesa shader
cache, and executable mappings required by the driver stack.

Remove the corresponding late filesystem access from WebContent.
WebContent still initializes its Skia GPU backend before installing its
sandbox, so it does not need to open the GPU runtime afterward; keep the
GPU device seccomp allowance there because Skia continues to issue
operations on already-opened GPU fds for display-list painting.
2026-06-18 08:22:09 +02:00
Aliaksandr Kalenik
d96dc6535f LibWeb+Compositor+WebContent: Simplify nested context composition
Nested navigables were represented through compositor surface ids owned
by the parent context. That forced CompositorState and ContextState to
maintain bidirectional attach/detach bookkeeping, publish child
snapshots into a surface map, and keep presentation mode variants just
to distinguish UI presentation from parent composition.

Record the child compositor context id directly in the display list and
let the compositor resolve it against the painting parent at playback
time. Child contexts now keep their parent context id and latest
rendered surface, while parents no longer track child maps or compositor
surface ids. UI presentation is represented separately from parent
composition, so closing a page only stops client presentation and nested
contexts keep using set_parent_context.
2026-06-18 07:08:34 +02:00
Aliaksandr Kalenik
1b5bdb2b41 LibWeb+LibWebView+WebWorker: Initialize transport peer pid on Windows
WebWorker control connections can transfer handles from the browser
process to the worker process, including RequestServer and ImageDecoder
transport handles sent during worker startup. On Windows, serializing
those attachments needs the destination process id so DuplicateHandle
and WSADuplicateSocketW can target the peer process. WebWorker was
excluded from the generic helper-process InitTransport handshake,
leaving the transport without a peer pid before any attachment-bearing
message was sent.

Add InitTransport to the WebWorker server endpoint, implement the
server-side peer pid exchange, expose the message type through
WebWorkerClient, and let the shared helper launcher perform the
handshake for workers as it does for other Windows IPC clients.
2026-06-18 04:06:30 +02:00
Tim Ledbetter
7bb200a663 LibWeb: Add fast_is to SVGTextContentElement 2026-06-18 01:27:28 +02:00
Tim Ledbetter
9d359d9d7c LibWeb: Add fast_is to SVGClipPathElement 2026-06-18 01:27:28 +02:00
Tim Ledbetter
7218794aaa LibWeb: Add fast_is to SVGPatternElement 2026-06-18 01:27:28 +02:00
Tim Ledbetter
d86936f09c LibWeb: Add fast_is to SVGGradientElement 2026-06-18 01:27:28 +02:00
Andreas Kling
b583fd3b79 LibWeb: Skip repaint for visual context-only style changes
Let style changes that only rebuild compatible accumulated visual
contexts avoid marking the display list dirty. This lets transform
and nonzero opacity updates send visual context tree updates without
recording a new display list.

Keep repainting changes that affect display-list contents or can change
visual context tree compatibility, including zero-crossing opacity,
transform invertibility crossings, background-attachment, clipping,
mix-blend-mode, and perspective. Schedule accumulated visual context
updates for animations independently of repaint so animated
transform/effect updates keep reaching the document.

Cover compatible visual context reuse, incompatible tree shapes, and the
display-list invalidation cases with focused LibWeb tests.
2026-06-18 00:12:42 +02:00
Andreas Kling
1b8072371b LibWeb: Preserve compatible visual context tree versions
Let accumulated visual context updates keep the previous tree version
when rebuilt with the same shape. Display lists reference visual
context tree versions, so keep compositor-only updates on the old
version unless the tree structure changes.

Add coverage for version reuse and incompatible tree shapes.
2026-06-18 00:12:42 +02:00
Andreas Kling
be5320b67c LibJS: Evaluate ToNumber for out-of-bounds typed array writes
The interpreter's fast path for PutByValue on a typed array treated an
out-of-bounds index as a silent no-op and returned without touching the
value. That is observably wrong: TypedArraySetElement evaluates
ToNumber(value) before checking the index, so a value with a valueOf
side effect must still have that side effect run even when the store is
ultimately discarded.

Fall back to the slow path on an out-of-bounds or otherwise invalid
index instead of reporting success. The slow path runs the full
TypedArraySetElement algorithm, which performs the coercion and then
discards the write. Direct assignment now matches Reflect.set, which
already went through the slow path.

Fixes the staging/sm typed array out-of-bounds ToNumber test262 case
and adds a test-js regression covering direct assignment, Reflect.set,
and Reflect.defineProperty.
2026-06-17 21:24:33 +02:00
Andreas Kling
a3db2d1986 LibJS: Support source text access in JSON.parse revivers
The JSON.parse-with-source proposal (now part of ES2026) gives a
reviver a third "context" argument. For a primitive value that was
not modified by an earlier reviver call, the context has a "source"
property holding the matched JSON source text; for objects, arrays,
and forward-modified values it is an empty object.

We already had JSON.rawJSON and JSON.isRawJSON, but the reviver only
received two arguments. Implement the missing half by building a JSON
Parse Record snapshot while parsing: each primitive records the
trimmed raw token from simdjson, and arrays and objects record their
child records keyed by index and property name. InternalizeJSONProperty
threads the matching record down the tree, creates the context object,
and only attaches "source" when the record's stored value still equals
the live value (SameValue), which suppresses source for values a
reviver replaced or appended.

The record values live in heap storage the GC does not scan, and a
reviver can detach the originals from the object graph mid-walk, so
the snapshot's values are kept rooted for the duration of the walk.

Closes the six json-parse-with-source test262 failures and adds
test-js coverage for primitive source text and forward modification.
2026-06-17 21:24:33 +02:00
Aliaksandr Kalenik
7ca410c66c LibWeb: Stop storing compositor surfaces as display list resources
Compositor surfaces are only used for nested navigables now. The
display list command already carries the CompositorSurfaceId, but
playback still resolved that id through DisplayListResourceStorage and
WebContent exposed IPC for direct surface updates and clears.

Keep published child surfaces as PaintingSurface entries on the
compositor ContextState and pass that map into Skia display list
playback. Publishing and detaching nested contexts now update the parent
cache entirely inside the compositor, so WebContent no longer needs
update_compositor_surface or clear_compositor_surface messages.
2026-06-17 20:20:24 +02:00
Aliaksandr Kalenik
91bcd50224 LibGfx+LibWeb: Store Skia images with display list resources
DisplayListPlayerSkia kept a separate DecodedImageFrameSkiaImageCache
that was pruned during flushes. That made Skia image lifetime
independent of display list resource lifetime, even though resource
storage is what knows when image frames and compositor surfaces are no
longer needed.

Make DisplayListResourceStorage own an opaque stored image-frame
resource that holds the decoded frame and its lazily-created SkImage.
Removing image frames or compositor surfaces now drops the decoded frame
and Skia image together, while transactions still carry only Skia-free
decoded frames.
2026-06-17 19:17:10 +02:00
Aliaksandr Kalenik
e03e407f43 LibWeb: Stop linking ANGLE into WebContent
LibWeb still needs ANGLE GLES headers for WebGL constants and
types, but the host GL entry points now live in the Compositor. Copy
ANGLE compile interface onto LibWeb and stop linking ANGLE through
LibWeb so WebContent no longer inherits that dependency.
2026-06-17 19:07:32 +02:00
Aliaksandr Kalenik
54a07a08b4 LibWeb+Compositor: Move OpenGLContext in Compositor namespace 2026-06-17 19:07:32 +02:00
Aliaksandr Kalenik
7efdb8a900 LibWeb+Compositor: Move OpenGLContext in Compositor 2026-06-17 19:07:32 +02:00
Aliaksandr Kalenik
116668651b LibWeb+Compositor: Avoid canvas readback for canvas drawImage
2D canvas rendering now lives in the compositor, but drawing one canvas
into another still converted the source HTMLCanvasElement into a
DecodedImageFrame in WebContent. That forced a compositor readback for
every drawImage(canvas, ...) call before sending the destination canvas
commands back to the compositor.

Teach the canvas command stream to carry a DrawCanvas command that names
the source canvas surface. The destination 2D context now flushes the
source canvas, records that command, and immediately flushes the
destination command list so the compositor copies the source surface at
the drawImage call boundary. Bitmap sources continue to use DrawBitmap,
and true readback APIs still read pixels explicitly.
2026-06-17 19:07:32 +02:00
Aliaksandr Kalenik
f215d9bb9a LibWeb+WebContent: Restore canvas contexts after Compositor loss
Compositor-backed canvas contexts keep their transports tied to a single
Compositor connection. When that connection dies, the 2D backing
storage and WebGL GL objects disappear with it, but WebContent does not
surface the loss to canvas contexts or create fresh host contexts after
reconnect.

Track compositor loss through the WebContent connection, mark WebGL
contexts lost, dispatch the standard context events, and rebuild the
remote proxy when the page opts into restoration. For 2D canvas, queue
the canvas context loss steps, discard the dead backing storage, and
create new storage before firing contextrestored.
2026-06-17 19:07:32 +02:00
Aliaksandr Kalenik
a80babffb6 LibWeb+Compositor: Run canvas contexts in the Compositor
Canvas rendering is a major remaining path where WebContent directly
owns GPU-facing drawing state. Back 2D and WebGL canvas contexts with
remote Compositor transports, so WebContent talks to canvas surfaces
through IPC while the Compositor owns the rasterization resources.

This is a large step toward GPU sandboxing because canvas GPU work now
lives behind the Compositor boundary. It also gives OffscreenCanvas the
process-independent canvas plumbing that HTMLCanvasElement now uses,
making worker-owned canvases possible without another WebContent-local
rendering path.
2026-06-17 19:07:32 +02:00
Aliaksandr Kalenik
5f0e95de13 Meta+LibWeb+Compositor: Add remote canvas transports
The display list can now refer to canvas ids, but WebContent still had
no channel for creating or updating those canvas resources in the
Compositor. Both 2D and WebGL canvases would have had to grow the IPC
plumbing in the same commit that changes the rendering contexts.

This adds the Compositor-side CanvasHost, WebContent transport objects,
and the IPC/CMake pieces needed to allocate, update, read back, and
destroy remote canvas contexts. The rendering contexts are not switched
over yet, keeping this as plumbing for later commits.
2026-06-17 19:07:32 +02:00
Aliaksandr Kalenik
9a8a7798ec Meta+LibWeb: Generate WebGL command proxy scaffolding
Moving WebGL execution into the Compositor needs a serializable command
stream and a client-side proxy that can queue commands before sending
them over IPC. The existing generator metadata only described direct GL
wrappers, so generated code could not distinguish async commands from
sync calls or object factory methods.

This teaches the WebGL metadata and generators about command streams and
adds the unused LibWeb proxy/list types. No rendering behavior changes
yet; the later host wiring can build on these generated interfaces
without mixing the metadata churn into that commit.
2026-06-17 19:07:32 +02:00
Aliaksandr Kalenik
af8b41e1cb LibWeb+Compositor: Add canvas display-list surfaces
Canvas contexts need a compositor-owned surface path that can be shared
by 2D canvas and WebGL. Add CanvasId and a CanvasSurfaceRegistry, pass
the registry into display-list playback, and teach Skia playback how to
resolve and draw a registered canvas surface.

This only adds the shared display-list command and registry plumbing.
Existing canvas elements still publish their old compositor surfaces, so
the behavior change is left for the later canvas-host commits.
2026-06-17 19:07:32 +02:00
Aliaksandr Kalenik
7dadfa2e52 LibGfx: Expose the maximum canvas area
Canvas size validation needs the same area limit in both WebContent and
compositor-side canvas hosts.
2026-06-17 19:07:32 +02:00
Aliaksandr Kalenik
12f9318106 LibGfx: Let PaintingSurface read from source offsets
Remote canvas readback needs to copy subrects out of a larger Skia
surface instead of always copying from the origin.
2026-06-17 19:07:32 +02:00
sideshowbarker
6757971d59 Tests/LibDNS: Make TestDNSResolver independent of live DNS
Problem: TestDNSResolver resolved google.com against 1.1.1.1 over the
real network. Whenever a CI runner couldn’t reach external DNS, the
lookup returned no records, and the test failed.

Fix: Stand up a local UDP and TCP server on 127.0.0.1 that answers the
query with a canned A and AAAA record, and point the resolver at it.
2026-06-17 18:27:33 +02:00
sideshowbarker
d6014c8869 LibDNS: Serialize answer and authority records in Message::to_raw
Problem: Message::to_raw could only encode queries: It asserted the
answer and authority counts were zero and never wrote those. So, a
response — which carries answers — couldn’t be serialized at all.

Fix: Write the answer and authority records as well — alongside the
existing question and additional sections, and using the existing
ResourceRecord::to_raw. Then drop the query-only assertions. The order
matches the wire format: question, answer, authority, additional.
2026-06-17 18:27:33 +02:00
Tim Ledbetter
61bba95948 UI/Qt: Autofocus the about:history search input 2026-06-17 12:31:07 +02:00
Tim Ledbetter
0db82b3133 LibWebView+UI/Qt: Reuse an existing history tab when viewing history
Previously, the "View History" action always opened a new tab. We now
switch to an existing `about:history` tab when one exists in the active
window and fall back to opening a new tab otherwise.
2026-06-17 12:31:07 +02:00
Tim Ledbetter
d4e15cb0af UI/Qt: Add keyboard shortcut to view history
Bind the canonical history shortcut for each platform to the
"View History" action: Ctrl+H on Linux and Windows, and Cmd+Y on
macOS.
2026-06-17 12:31:07 +02:00
sideshowbarker
766bc991ed LibWebView: Make the session-history-mirror merge linear
Problem: While a document was concurrently loaded, a burst of sync same-
document history navigations (e.g. a pushState flood) could spin the UI
process at full CPU — and on slow/Sanitizer builds, intermittently time
out other tests (since one WebContent process is reused across tests).

Cause: The UI process keeps an authoritative session-history mirror, and
merges each WebContent snapshot into it. find_merge_anchor compares each
local entry against each incoming one. Every URL comparison serializes
both URLs. When a snapshot briefly diverges from the mirror, the anchor
is no longer near the end. So, the search degraded to a deep quadratic
walk — with a string serialization per-comparison. A flood compounded
that from both ends: Every pushState added a top-level entry — driving
the count each walk must cover into the hundreds — and also triggered a
history update. So, the merge ran again for every one of them.

Fix: Index the incoming entries by serialized URL once — keyed as URL
equality compares (full serialization, fragment included). So, the URL-
keyed anchor searches are linear, not quadratic.
2026-06-17 12:25:53 +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
sideshowbarker
427a66d448 LibWeb: Add internals.loadURL() to start UI-process-style loads
This adds an internals.loadURL(url) that defers Page::load so it starts
outside the calling task and can land between session-history traversal-
queue steps — as a load requested by ConnectionFromClient::load_url in
the UI process can, but as a load started from script never does.

Use case: Some session-history races are reachable only when a load
request arrives from the UI process between event-loop pumps — while the
session history traversal queue is mid-drain. A load started from script
enters navigate() inside the calling task, and claims the ongoing
navigation up front — so it can never land in that window. And so,
without this function, we can’t write tests for those kinds of races.
2026-06-17 12:25:53 +02:00