Commit graph

17287 commits

Author SHA1 Message Date
Andreas Kling
f47b6f3270 LibWeb: Reduce CSS parser token memory usage
Store CSS token payloads in a variant so each token only carries the
state needed by its type. Keep delimiter, number, hash, string, and
dimension data separate instead of storing every possible payload on
every token.

Use a smaller component-value token for function and block boundary
metadata. These component values only need token type, original source
text, and source positions, so avoid embedding full token payload
storage inside every Function and SimpleBlock.

Shrink CSS source positions to explicit 32-bit counters. Guard the C++
and Rust tokenizer paths against overflow. Add size assertions for the
hot Token and ComponentValue types so future growth is intentional.
2026-06-13 14:57:52 +02:00
Andreas Kling
49730156ae LibWeb: Avoid media rule reevaluation for matchMedia
Separate MediaQueryList change reporting from stylesheet media rule
invalidation. Creating matchMedia() objects evaluates their own baseline
state, but should not make the next style update walk all active
stylesheets when the media environment has not changed.

This avoids continuous stylesheet media query reevaluation during
YouTube video playback, where repeated matchMedia() creation can make
style flushes do unnecessary work.
2026-06-13 14:00:53 +02:00
Shannon Booth
790b9bd36a LibWebView: Add async cookie deletion internals
Add Internals.deleteAllCookies(), backed by an async WebContent to
browser request and ack pair. CookieJar can now clear transient and
persisted cookies. Note that we only delete all cookies associated
with the current URL so that tests are able to run in parallel with
one another without impacting shared cookie state.
2026-06-13 10:18:33 +02:00
Aliaksandr Kalenik
5b856595b3 Meta+LibWeb/WebGL: Route all GL calls through generated GLFunctions
LibWeb's WebGL implementation currently reaches ANGLE by calling glFoo()
throughout the WebGL context and extension code. That ties the WebGL
spec layer to the concrete GL executor. A future backend that records
operations, sends them to another process, or executes them from the
Compositor would otherwise need to duplicate the WebGL logic or edit
every call site again.

Introduce GLFunctions as an explicit boundary between WebGL semantics
and GL execution. GLFunctions.json lists the GL entry points used by the
implementation, and the generator emits one forwarding method per entry
point. OpenGLContext implements those methods today, so the current
in-process ANGLE path keeps the same behavior while all callers go
through a single replaceable interface.

That boundary is needed before canvas/WebGL rendering can move to the
Compositor: the WebGL context code can keep doing validation, state
tracking, and spec-visible error handling in LibWeb, while a later
implementation can record the same GL calls and replay them where the
canvas surface is produced. The JSON source also gives the recorder and
replayer one shared description of argument shapes, avoiding two
hand-written views of the GL API drifting apart.
2026-06-13 01:58:43 +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
Aliaksandr Kalenik
f0ed472429 LibIPC: Move IPC payloads through post_message
MessageBuffer::transfer_message() handed a MessageDataType to transport
APIs that accepted Vector<u8> const&. That forced the inline-capacity
vector to be materialized as a plain Vector<u8>, and the Mach transport
then copied the same payload again into its pending-send queue.

Make the transport API take MessageDataType by value and pass the
encoded buffer with take_data(). The Mach pending queue now stores the
same type so the payload can move directly to the IO thread. The socket
transport keeps queued messages as owned headers plus moved payloads
instead of copying the payload into an AllocatingMemoryStream, while
preserving the existing chunked send and fd acknowledgement behavior.
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
b8ff139f9c LibCompress: Remove PackBitsDecoder
This is no longer used.
2026-06-12 22:37:49 +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
Tim Ledbetter
6224045e5f LibGfx: Extract Exif parsing from the TIFF decoder 2026-06-12 22:37:49 +02:00
Andreas Kling
f619caf621 LibGfx: Preserve imported Linux DMABUF handles
Keep the Linux DMABUF handle alongside the bitmap wrapper when imported
shared images reach the UI process. This lets consumers import the same
GPU backing store directly instead of only reading it through the mapped
bitmap.

Also require exported Vulkan shared images to be sampleable, since the
Qt Vulkan presentation path needs to sample compositor backing stores.
2026-06-12 21:45:22 +02:00
Tim Ledbetter
b4b0233ba1 LibSandbox: Permit faccessat2, faccessat and fstatfs
SDL enumerates connected input devices through libudev whenever a
device is added or removed, which probes per-device metadata using
`faccessat2` and `fstatfs`. These calls run after the seccomp filter is
installed, and neither syscall was permitted, so connecting a gamepad
killed the WebContent process with SIGSYS. We now permit `faccessat`
alongside `faccessat2` because glibc's `faccessat` wrapper falls back
to it on kernels without `faccessat2`.
2026-06-12 21:44:10 +02:00
Andreas Kling
6134119353 LibWeb: Keep non-subject :has() dependency sticky
Keep the non-subject :has() affected bit across element style
recomputation. This bit can be discovered while matching descendant
selectors, and recomputing the anchor itself may not revisit those
selectors before a later mutation needs the dependency for targeted
:has() invalidation.

This avoids stale descendant style after targeted :has() invalidation
when a previous recompute cleared the anchor-side dependency metadata.
Repeated style invalidation tests cover the previously flaky case.
2026-06-12 15:13:29 +02:00
Andreas Kling
a0459a3ff3 LibWeb: Avoid broad invalidation for nth-child filters
Property invalidation inside :nth-child(... of ...) used to become a
whole-subtree invalidation plan. That is broader than needed for
property changes that only affect the filtered sibling list, such as
:has() becoming true or false for one sibling.

Add an invalidation plan bit that marks the element and structurally
affected siblings instead. Keep whole-subtree invalidation when a
stronger plan already requires it, and cover both :nth-child and
:nth-last-child filters with :has() regression tests.
2026-06-12 15:13:29 +02:00
Andreas Kling
8d75e310c5 LibWeb: Target structural pseudo-class match sets
Use structural-position pseudo-classes as subject match filters while
building style invalidation plans. Selectors such as `.menu:has(> .flag)
> :first-child` can then carry a concrete right-hand match set instead
of widening the `:has()` invalidation plan to the whole subtree.

Keep these pseudo-classes out of trigger-property sets since structural
topology mutations are handled separately. This avoids adding unrelated
cold topology recomputes while still letting the affected boundary
children be invalidated directly.

Add a regression test that mutates the child class used by `:has()` and
asserts that the old whole-subtree path does not produce excessive no-op
style recomputations.
2026-06-12 15:13:29 +02:00
Andreas Kling
baaaea6cf1 LibWeb: Reduce over-invalidation for :has() selectors
Feature-filter :not() arguments in :has() when the same compound also
has a concrete tag, id, class, or attribute selector. Bare negations
still stay conservative, but anchored negations no longer make unrelated
subtree mutations walk every :has() candidate.

Also avoid installing the whole-subtree :has() fallback for rightmost
complex :is()/:where() arguments that only use descendant or child
combinators. Keep the fallback for non-rightmost and sibling-combinator
cases where the existing plan cannot represent the nested selector
context.

Add counter-based style invalidation coverage for both cases.
2026-06-12 15:13:29 +02:00
Andreas Kling
4c87227078 LibWeb: Track interaction pseudo-classes in :has() metadata
Record hover, focus, focus-visible, focus-within, and target pseudo
classes in :has() invalidation metadata. This lets the existing
property invalidation path schedule :has() ancestor invalidation only
for scopes whose :has() selectors mention the changed pseudo-class.

Interaction pseudo-class invalidation previously scheduled :has()
ancestor invalidation for every style scope containing any :has()
selector. That kept selectors like .wrapper:has(:focus) * correct, but
also caused unrelated hover and focus changes to fan out through broad
:has() descendant invalidation rules.

Update style invalidation coverage so unrelated hover changes avoid the
extra :has() walk, while a descendant :has(:focus) rule still restyles
its affected descendants when focus changes.
2026-06-12 15:13:29 +02:00
Jelle Raaijmakers
de664c4c12 LibWeb: Restore context after culled display list effects
Effect culling can stop a visual context switch after applying
some ancestor contexts. The player left those contexts on the painter
stack even though the target command was skipped.

Restore the painter stack back to the common ancestor when effect
culling aborts the switch.
2026-06-12 04:59:57 +01:00
Jelle Raaijmakers
db04e1b819 LibWeb: Annotate compute_transform() with CSS Transforms 2 steps
Quote the transformation matrix computation steps from the spec
verbatim, which documents that we do not yet apply the offset property
(step 6).
2026-06-12 01:10:24 +02:00
Jelle Raaijmakers
b06cbbf81e LibGfx+LibWeb: Use matrix helpers in TransformationStyleValue::to_matrix
Using the new perspective_matrix() helper resolves a FIXME in
AccumulatedVisualContext as well.
2026-06-12 01:10:24 +02:00
Jelle Raaijmakers
f1ade8186a LibWeb: Drop unused include from PaintableBox.h 2026-06-12 01:10:24 +02:00
Jelle Raaijmakers
7390818b5a LibWeb: Apply the z component of transform-origin
compute_transform() resolved transform-origin to a 2D point, so 3D
rotations pivoted around the element's own plane. Build the conjugation
T(0, 0, z) * M * T(0, 0, -z) into the matrix instead; this composes
with the 2D origin at paint time into the full 3D conjugation.
2026-06-11 22:13:24 +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
Zaggy1024
ae04222247 LibMedia: Don't display video frames that are late
Frames are considered late if the time is ahead by half their duration.
The fudging is necessary because Matroska (and perhaps other formats)
store their frame durations in different time units than their
timestamps.

Skipping these should make it clear when decoding is running behind,
instead of displaying the video in slow motion while audio runs at a
normal rate.

To give an accurate counting for video playback quality when it is
implemented, we'll most likely want to count all pulled frames in an
update as dropped if the last frame is dropped. Otherwise the frame
drop count will only increase at the display rate when decoding is
continually running behind.
2026-06-11 21:49:55 +02:00
Zaggy1024
c58b9be7d5 LibMedia: Stop clearing video sinks' frames early on moving seeks
This is already handled by the seeking state enum later. We could end
up displaying nothing if MovedPosition isn't immediately followed by a
displayable frame.
2026-06-11 21:49:55 +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
0b9e59f61f LibDevTools: Allow editing Web Storage
Firefox sends the same storage actor mutation requests for Web Storage
that it uses for cookies. Handle addItem, editItem, removeItem, and
removeAll for localStorage and sessionStorage actors.

Apply the changes through the browser-process storage jar and emit the
matching store update packets so the Storage panel stays current after a
DevTools-initiated edit.
2026-06-11 16:08:33 +01: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
Sam Atkins
ddb4bdadd7 LibDevTools: Populate DevTools Web Storage
Firefox exposes localStorage and sessionStorage through the same
storage actor protocol used by cookies. Add matching resources for the
current tab so the Storage panel can list key/value pairs.

Read the values through WebContent rather than directly from the
browser process. Session storage lives in LibWeb, and using the same
path for both stores keeps the actor independent of the backing store.
2026-06-11 16:08:33 +01:00
Sam Atkins
5b5f848689 LibDevTools: Make ErrorOr -> JsonValue helpers public
We want these for local/session storage too, so avoid duplicating them.
2026-06-11 16:08:33 +01:00
Sam Atkins
9e4cd527aa WebContent+LibWebView: Add dumping for session storage 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
aa4139d002 LibDevTools: Allow adding and removing DevTools cookies
Firefox enables the Storage panel cookie toolbar from the storage traits
and calls addItem, removeItem, removeAll, or removeAllSessionCookies
for the selected host.

Advertise those operations and route them through the existing cookie
mutation delegate. Deletions reuse the visible storage host matching so
bulk actions stay scoped to the cookie tree item Firefox selected.
2026-06-11 15:03:47 +01:00
Sam Atkins
4113968e77 LibDevTools: Allow editing DevTools cookies
Firefox sends editItem when a cookie table cell is changed. Handle
that request by locating the original cookie, applying the edited
field, and forwarding the replacement through the delegate mutation
hook.

Return Firefox-style errorString values so invalid edits can be
rejected without changing the table contents.
2026-06-11 15:03:47 +01:00
Sam Atkins
76a10bb82d LibHTTP: Expose cookie date parser
DevTools needs to parse the same cookie expiry timestamp syntax that
Set-Cookie accepts. Expose the existing RFC6265 cookie-date parser so
callers do not need to duplicate a stricter HTTP-date parser.
2026-06-11 15:03:47 +01:00
Sam Atkins
11b053b154 LibWebView: Add DevTools cookie mutation helpers
DevTools needs to edit and delete cookies from the browser process. Add
a small mutation surface to CookieJar and expose it through the DevTools
delegate while preserving the existing cookie notification path.
2026-06-11 15:03:47 +01:00
Sam Atkins
47204bd3dd LibDevTools: Report cookie storage changes
Firefox keeps the Storage table current through storesUpdate messages
from the storage actor. Forward browser cookie change notifications to
the cookies actor and classify visible rows against a fresh cookie
snapshot.

The existing cookie-change notifications report cookies that are
relevant to a specific page, whereas DevTools wants all cookies
relevant for a host, so we end up having to provide two different sets
of cookies to `notify_cookies_changed()`.
2026-06-11 15:03:47 +01:00
Sam Atkins
20f922cbdb LibWebView+LibDevTools: Populate DevTools cookies
Firefox asks the cookies actor for rows after selecting a Storage host.
Read the browser cookie jar through the DevTools delegate and serialize
matching cookies with the fields Firefox expects.

This keeps mutation support disabled, but makes existing cookies visible
in the Storage panel.
2026-06-11 15:03:47 +01:00
Sam Atkins
deec1ec2c3 LibDevTools: Add cookie storage actor
Firefox discovers Storage panel data through watcher resources. This
adds a read-only cookies actor with the fields and empty store response
expected by the Storage panel.

Mutation traits are reported as unsupported for now.

DevTools storage resources all have a "host" key derived from the URL,
which we produce in `storage_host_for_url()`.
2026-06-11 15:03:47 +01:00
Sam Atkins
b2724268fe LibWebView: Notify cookie-change listeners after changing them
Cookie listeners may query the jar while handling a notification. For
example, DevTools does this when the Storage panel computes whether a
cookie was added, changed, or deleted.

Insert the cookie before sending the notification, so that listeners see
the new state, not the old one.
2026-06-11 15:03:47 +01:00
Andreas Kling
31ffb2f214 LibWeb: Use the id cache for document element get_element_by_id()
ParentNode::get_element_by_id() only used the cached id-to-element map
when called on a document or shadow root; on any element it fell back
to a linear walk of the subtree. The document element's inclusive
subtree contains every element in the document, so the document's
cache gives the same answer.

This matters because SVGSVGElement::children_changed() resolves the
document URL fragment with get_element_by_id() on itself whenever the
document URL has a fragment. SVG sprite sheets are typically fetched
via URLs like sprite.svg#icon-name, and the sprite's outermost svg
element is its document element, so every child appended during
parsing rescanned the growing document. These lookups were 2.3% of
all CPU samples when loading chatgpt.com.
2026-06-11 15:28:59 +02:00
Andreas Kling
c419bb526b LibWeb: Track connected SVG use elements in a per-document list
Every SVG element insertion, removal, attribute change, and children
change walked the entire document looking for use elements to notify
about possible referenced-subtree changes. On pages with large SVG
documents this is quadratic: loading chatgpt.com spent 7% of all CPU
samples in these full-document scans, nearly all of it while parsing
an SVG icon sprite sheet.

Instead, keep every use element connected to a document's node tree in
an intrusive list owned by that document, and only iterate that list
(usually empty or tiny) when an SVG element changes.

Subtleties:

- A use element inserted by the same subtree insertion as its
  referenced element, but after it in tree order, used to be found by
  the document-wide scan from the referenced element's insertion
  steps. Now SVGUseElement::inserted() re-resolves the reference if
  the shadow tree is still unpopulated. A new test covers both tree
  orders.

- Node.moveBefore() runs moving steps without insertion or removal
  hooks. Now SVGUseElement::moved_from() updates list membership when
  moving across document-tree and shadow-tree boundaries. A new test
  covers both directions.

- Removal hooks run after the subtree has been detached, so use
  elements being removed alongside the changed element may still be
  registered. Filter them out structurally via root().is_document(),
  since Node::is_connected() is a flag that is updated in hook order
  and can still be stale at this point.
2026-06-11 15:28:59 +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
Sam Atkins
935b9e8e41 LibWeb/DOM: Give Document ancestor origin lists 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