Commit graph

17491 commits

Author SHA1 Message Date
Tim Ledbetter
360bfd66f6 LibWeb: Apply the font-variant-emoji property to font selection 2026-06-20 23:51:46 +02:00
Tim Ledbetter
57103da08d LibGfx+LibWeb: Make emoji font fallback presentation-aware
Previously, font selection ignored the Unicode emoji presentation of a
code point. Emoji-capable code points were always resolved through
pre-baked color emoji and symbol fonts. Text-default code points which
lacked the `Emoji_Presentation` property, were therefore rendered as
color emoji rather than text. We now classify each code point's default
presentation from its `Emoji_Presentation` property and any trailing
variation selector.
2026-06-20 23:51:46 +02:00
Tim Ledbetter
bebcf95883 LibGfx: Remove bogus early return from Font::is_emoji_font() 2026-06-20 23:51:46 +02:00
Andreas Kling
2bf1f41805 LibWeb: Make computed properties immutable
Move CSS animation values into a mutable overlay on computed properties
and make base computed style data immutable after construction. Base
style mutation now goes through a builder that is consumed on publish,
so installed styles no longer expose mutation APIs.

Build new base style data for inherited style updates instead of cloning
and mutating installed computed properties. Element-specific computed
style adjustments now run before publication, while animation and
transition updates continue to mutate only the animated overlay.
2026-06-20 23:43:17 +02:00
sideshowbarker
d7c08964cb LibJS: Throw rather than crashing on a deep prototype-chain get
Problem: Converting an object with a pathologically-deep prototype chain
to a primitive was segfaulting.

Cause: Object::internal_get implements [[Get]] by recursing into the
prototype’s [[Get]] (parent->internal_get) when the property isn’t an
own property. For a sufficiently deep prototype chain, that C++
recursion exhausts the native stack, and segfaults. The bytecode
interpreter’s call-stack limit doesn’t cover this native recursion.

Fix: Before recursing into the prototype in Object::internal_get, check
VM::did_reach_stack_space_limit(), and throw a CallStackSizeExceeded
InternalError — the same way the interpreter and other recursive runtime
operations guard the native stack. The deep-chain get now throws a
catchable call-stack-size-exceeded error, rather than crashing.

Fixes https://github.com/LadybirdBrowser/ladybird/issues/3584
2026-06-20 23:34:33 +02:00
Shannon Booth
7b0dd6ab30 LibTextCodec: Use encoding_rs for legacy codecs
Replace the generated C++ legacy codec implementations with a
small Rust wrapper around encoding_rs.

This keeps the existing LibTextCodec API while moving label lookup,
legacy decode/encode, validation, and streaming decoder state to Rust.
The generated index data and generator are no longer needed.

It also fixes several TextDecoder EOF cases due to a more correct
implementation. encoding_rs finalizes decoders according to the
Encoding Standard, so incomplete UTF-8/Big5 tails and malformed
UTF-16 surrogate tails produce the required single replacement at
end-of-queue instead of being dropped, buffered, or double-counted
by our old hand-written decoders.
2026-06-20 21:56:43 +02:00
Shannon Booth
250842d36a LibURL: Use encoding_rs for form URL encoding
Replace the Rust URL form-encoding callback bridge into C++ TextCodec
with a direct encoding_rs encoder.

This keeps percent-encode-after-encoding entirely in Rust and removes
liburl_rust's dependency on LibTextCodec.

It also happens to fix ISO-2022-JP URL encoding of literal U+FFFD.

The LibTextCodec reverse lookup treats generated 0xFFFD table holes as
real JIS0208 mappings, so literal U+FFFD skipped the encoder-error
path. encoding_rs treats U+FFFD as unmappable, so URL encoding emits
the required numeric character reference.
2026-06-20 21:56:43 +02:00
Shannon Booth
62e4da6d3e LibTextCodec: Make StreamingDecoder own decoder lookup
Pass an encoding label to StreamingDecoder instead of requiring
callers to pre-resolve a Decoder reference.

This removes redundant decoder_for() plumbing from callers and lets
StreamingDecoder hide how chunked decoder state is represented.
2026-06-20 21:56:43 +02:00
Shannon Booth
ebc439f0f2 LibWeb/Infra: Add some missing AK includes
To prevent my clangd from complaining.
2026-06-20 21:56:43 +02:00
Shannon Booth
be6192dab2 LibWeb: Avoid TextCodec when parsing JSON bytes
Use String::from_utf8_with_replacement_character() directly for Infra's
parse JSON bytes algorithm instead of constructing a more generic
TextCodec UTF-8 decoder.
2026-06-20 21:56:43 +02:00
Shannon Booth
c982385ffe LibTextCodec: Remove unused PDFDocEncoding
PDFDocEncoding has no remaining users left. Remove the decoder and
label plumbing. Retarget the lazy source-code decoding regression
test to Windows-1252 so it still covers non-UTF source decoding.
2026-06-20 21:56:43 +02:00
Andreas Kling
784ca98041 LibSandbox: Allow listing read-write directories
Include directory read access in Landlock read-write directory rules.
Without it, paths such as /dev/dri could be writable but not enumerable
after sandboxing, which made Mesa fail while probing GPU devices.

Allow the Compositor to open /dev/udmabuf as well when the device is
present, matching the other GPU device nodes exposed to the process.
2026-06-19 19:12:26 +02:00
Andreas Kling
b759954486 Compositor: Allow GPU driver executable mappings on Linux
Let the Linux Compositor sandbox permit writable executable mappings
used lazily by GPU drivers after WebGL context creation. Keep this
allowance scoped to the Compositor process so WebContent retains the
existing memory mapping restrictions.
2026-06-19 19:12:26 +02:00
Andreas Kling
523cdab7d9 LibWeb: Don't serialize UnresolvedStyleValue comparison text when unused
UnresolvedStyleValue::create() serialized the component values into a
comparison string unconditionally, but the result is only used when the
caller supplied separate original source text. On the common path that
serialization (including float formatting of every numeric token) was
computed and immediately discarded.

Move the serialization into the branch that actually uses it. This is
hot during var() substitution, where many intermediate
UnresolvedStyleValues are created and never compared.
2026-06-19 18:47:04 +02:00
Aliaksandr Kalenik
1a0f8d4372 LibIPC: Coalesce Mach read notifications
TransportMachPort wrote to its event-loop notification pipe for every
received message. Large bursts could spend significant time in the IO
thread just waking the main loop, even when a previous read notification
was still pending and would already drain the queued messages.

Track whether a read notification is pending while holding the incoming
queue mutex, and only write a new pipe byte when the queue needs a wake.
EOF still schedules a notification, and synchronous waiters continue to
use the condition variable for every arrival.
2026-06-19 18:21:06 +02:00
Ali Mohammad Pur
b3f3d68291 LibWeb+LibWasm: Keep WebAssembly cache storage stable
These need to stay in place across rehashes so we can avoid querying
their address on every collection cycle.
2026-06-19 17:01:47 +02:00
Ali Mohammad Pur
530c95fde5 LibWasm: Remove all gc, function-refs and EH test exceptions 2026-06-19 17:01:47 +02:00
Ali Mohammad Pur
8a74f52571 LibWasm: Partially implement the (new) exception handling proposal
This implements try_table and throw_ref execution in the interpreter.
2026-06-19 17:01:47 +02:00
Ali Mohammad Pur
16d1486cc9 LibWasm: Implement the wasm-gc instruction set in the BC interpreter 2026-06-19 17:01:47 +02:00
Ali Mohammad Pur
87961e3c92 LibWasm: Back wasm-gc aggregate instances with the LibGC heap 2026-06-19 17:01:47 +02:00
Ali Mohammad Pur
76f17f7703 LibGC: Add support for coordinated multi-heap collection
Allow having separate GC heaps and implement coordinated marking between
them; this is useful for keeping wasm and js GC heaps separated with a
clear boundary.
2026-06-19 17:01:47 +02:00
Ali Mohammad Pur
62cb073ada LibWasm: Validate the wasm-gc and function-references instructions
Actual implementations are still trap-on-exec.
2026-06-19 17:01:47 +02:00
Ali Mohammad Pur
42c0a430f5 LibWasm: Implement the spec's type matching relations 2026-06-19 17:01:47 +02:00
Ali Mohammad Pur
3ca552b37b LibWasm: Parse wasm-gc types
No more unsupported heap refs.
2026-06-19 17:01:47 +02:00
Tim Ledbetter
5ec468bfdd LibJS: Store module indirect bindings in a HashMap
Previously, these were stored in a vector that was linearly scanned.
For large sites this vector could contain hundreds of entries, so
a HashMap gives a significant speedup.
2026-06-19 16:27:19 +02:00
Andreas Kling
6eba8860f7 LibWeb: Add a lazy fast reject filter for :has()
Build a per-anchor Bloom-style filter for :has() argument matching
after an anchor sees a second check for the same traversal scope. The
filter stores salted tag, id, class, and attribute-name hashes from the
child or descendant scope and rejects arguments whose required
identifiers are absent.

This avoids repeatedly walking the same subtree for unrelated :has()
arguments while preserving the single-check case. More complex
direct-child arguments use the descendant scope so hashes from later
descendant compounds cannot cause false rejections.

Keep the filter conservative for quirks-mode class selectors and for
sibling-combinator relative selectors during invalidation metadata
collection. Text tests cover cache-primed misses for both cases.
2026-06-19 14:52:48 +02:00
Sam Atkins
fdfe806e68 LibDevTools+LibWeb: Let DevTools remove IndexedDB data
Firefox exposes removal operations for IndexedDB databases, object
stores, and records from the Storage panel. Route those actor requests
to LibWeb so DevTools can delete the selected data and receive the
update or clear event needed to refresh the panel.
2026-06-19 14:25:39 +02:00
Sam Atkins
e667aaaab1 LibDevTools+LibWeb: Send IndexedDB change updates
The Storage panel expects storesUpdate messages after watched storage
changes. Summarize committed IndexedDB mutation logs into DevTools paths
and forward them through WebContent so Firefox can refresh database,
object-store, and record rows without polling.

Firefox's behaviour is less than ideal here. A lot of things don't
update automatically even inspecting a page in Firefox. Some
things (like new databases) won't show up until you fully refresh the
page. So that makes it a bit hard to know that we're doing things
correctly. As far as I can tell, we are at least behaving as well as
Firefox requires.

We do have one workaround: Firefox doesn't display record updates
without a manual refresh, and in fact any change messages for them show
up as rows in the host's database table. So for now, we filter them out
to avoid visual weirdness in the inspector.
2026-06-19 14:25:39 +02:00
Sam Atkins
cb47dbfc7a LibDevTools+LibWeb: Show IndexedDB in DevTools
Firefox asks the storage watcher for an indexed-db resource before it
shows IndexedDB entries in the Storage panel. Add an IndexedDB actor and
serialize the live LibWeb database registry on demand, so WebContent can
return the host tree and table rows without duplicating database state.

Use the LibWeb inspection helpers to read IndexedDB internals, and keep
the Firefox protocol shape in LibDevTools. WebContent only forwards the
serialized response over the existing DevTools IPC path.
2026-06-19 14:25:39 +02:00
Sam Atkins
d48bb33fc7 LibWeb: Add IndexedDB inspection helpers
DevTools needs to inspect IndexedDB state from WebContent, but the
storage registry and object store data live behind LibWeb internals.
Expose a small inspection API that can enumerate IndexedDB hosts,
databases, object stores, and records without making DevTools know about
the internal database objects directly.
2026-06-19 14:25:39 +02:00
Sam Atkins
988045ca90 LibWeb/IndexedDB: Add Key to Forward.h 2026-06-19 14:25:39 +02:00
Sam Atkins
a3e85ada85 LibDevTools: Share storage field descriptor creation
Storage actors all describe table columns with the same DevTools field
object shape. Extract a helper for constructing those objects so that
cookies, local storage, session storage, and soon IndexedDB, do not each
spell out the JSON fields by hand.
2026-06-19 14:25:39 +02:00
sideshowbarker
8e2eee7654 LibGfx: Reject undersized backing storage when creating bitmaps
Problem: A borked ImageDecoder could send a BitmapSequence over IPC with
metadata for a (large) bitmap while shipping a too-small backing buffer.
Decoding it produced a Gfx::Bitmap that reported the (large) geometry
but pointed at the too-small buffer — making the first write go OOB.

Cause: BitmapSequence decode reads size_in_bytes and the bitmap geometry
as independent fields, and only checked if size_in_bytes matched the
transferred buffer size — never that either is consistent with the
geometry. The single-frame fast path then handed the buffer to
Bitmap::create_with_anonymous_buffer with no verification.

Fix: Make the two bitmap factories that take externally-provided storage
enforce that it covers the geometry. create_with_anonymous_buffer now
fails with buffers smaller than the minimum expected size_in_bytes — and
create_with_raw_data similarly rejects data too small for the geometry.

Fixes https://github.com/LadybirdBrowser/ladybird/issues/10036
2026-06-19 13:43:07 +02:00
Callum Law
3fa446f68e LibSandbox: Dont expand landlock file access to entire directory
Previously passing a file path (rather than a directory) to
`add_landlock_path_if_exists` would grant access to the containing
directory - this was a bit of a footgun.

We now only grant access to exactly the path requested, which is in line
with how the MacOS implementation works as well.
2026-06-19 13:40:17 +02:00
Callum Law
30c33bd918 LibSandbox: Remove redundant restrict_filesystem_with_landlock overload
None of the callers actually passed `ReadonlySpan<StringView>` so we can
achieve the same thing by giving a default argument to the
`ReadonlySpan<LandlockPath>` overload.
2026-06-19 13:40:17 +02:00
sideshowbarker
9d64cd8c9b LibGfx: Reject the Invalid bitmap format from IPC decoders
Problem: A borked process sending a Gfx::Bitmap (inside BitmapSequence)
or a Gfx::ShareableBitmap over IPC could set BitmapFormat::Invalid as
the format field. The receiving process then aborted while decoding the
message — an IPC-reachable crash.

Cause: The helper that both decoders use for validating the format read
off the wire accepts BitmapFormat::Invalid. The decoders go on to build
a bitmap with that format. But that triggers an assert — because
minimum_pitch only knows the four real pixel formats.

Fix: Drop BitmapFormat::Invalid from is_valid_bitmap_format. It’s an
indicator of an absent/unknown format, never one a real bitmap can have.
And any real bitmap is never encoded with it. So, both BitmapSequence
and ShareableBitmap decode now return a clean decode error for it.
2026-06-19 10:33:36 +02:00
Callum Law
fdca036ff3 LibWeb: Implement CSS progress() math function
`no-clamp` tests are added in-tree since there aren't any in WPT yet.
2026-06-19 09:33:06 +01:00
Luke Wilde
8dc8835b64 LibWeb+LibWebView+WebContent: Allow muted media to autoplay by default
The autoplay setting was binary and its default blocked all media,
including muted video, leaving sites that rely on muted autoplay
visibly broken. Replace it with a tri-state user-agent autoplay
policy (allow audio and video, block audio, or block audio and video)
defaulting to allowing only inaudible media to autoplay.

This is enforced through the media element's "allowed to play" check,
so unmuting a muted autoplay or calling `play()` cannot slip audio
past the policy; audible playback is permitted once the document has
been activated by the user. The policy lives in a dedicated
AutoplaySettings consulted from HTMLMediaElement instead of the
Permissions Policy "allowed to use feature" check it was previously
conflated with.
2026-06-19 09:41:32 +02:00
Andreas Kling
ca87f977e6 LibWeb: Reject child selectors with a parent hash filter
For selectors whose rightmost relation is an immediate child combinator,
collect hashes that must be present on the subject parent and reject the
rule early when the current parent cannot satisfy them. This avoids full
selector matching for common child-combinator tails.
2026-06-19 09:36:53 +02:00
Andreas Kling
14fc971035 LibWeb: Bucket :host selectors by subject pseudo-class
Only shadow hosts can match :host selectors, so route them through the
subject pseudo-class bucket instead of the generic other bucket. Full
selector matching still validates the shadow-root context and any
arguments.
2026-06-19 09:36:53 +02:00
Andreas Kling
8e473cb703 LibWeb: Bucket pseudo :is() rules by originating element
Split pseudo-element rules whose originating compound contains :is() or
:where() across the cheap buckets from their selector-list alternatives
when the rule would otherwise land in the pseudo-element other bucket.

Use per-collection generation stamps to suppress duplicate candidates
when more than one alternative bucket applies to the same originating
element. Add text coverage for class, attribute, and complex combinator
arguments reaching generated pseudo-element style.
2026-06-19 09:36:53 +02:00
Andreas Kling
093a24d3f9 LibWeb: Bucket heading pseudo-class rules
Treat :heading as a subject pseudo-class bucket so heading rules are
only enumerated for h1 through h6 elements. The selector matcher still
checks functional :heading() levels, so the bucket only narrows rule
collection before normal matching.
2026-06-19 09:36:53 +02:00
Andreas Kling
f45bf0e770 LibWeb: Bucket ancestor-filtered rules by ancestor hash
Add a late rule-cache bucket for selectors that do not expose a
current-element bucket but do expose ancestor-filter metadata. These
rules previously stayed in the global other bucket and relied on the
ancestor filter after broad enumeration.

Visit the new buckets only when the current ancestor bloom filter may
contain the bucket hash. Keep pseudo-class invalidation caches opted
out because those caches answer targeted invalidation questions rather
than normal style collection.

On the GitHub profile, other-bucket candidates fell from about 5.50k
to about 1.07k per 1k rule collection calls.
2026-06-19 09:36:53 +02:00
Andreas Kling
f39890bdc8 LibWeb: Bucket subject pseudo-class rules
Put rules whose rightmost compound has no id, class, tag, or
attribute bucket into a subject pseudo-class bucket when they have a
required cheap element-state pseudo-class such as :hover, :focus, or
:checked.

Also let :is() and :where() selector lists use a regular bucket when
every alternative exposes the same mandatory bucket key. Pseudo-class
invalidation rule caches keep using broad buckets because they must
consider rules while the matching state is changing.
2026-06-19 09:36:53 +02:00
Aliaksandr Kalenik
48874609f4 LibIPC: Inline small Mach IPC message bodies
The Mach transport always sent the serialized IPC bytes as an
out-of-line descriptor. That asks Mach to transfer the payload through a
VM region even when the message is only a small control message.

Use a second data message ID for inline bodies whose full Mach message
fits within 4 KiB. Inline messages carry the unpadded payload length
before the serialized bytes so the receiver can ignore Mach message-size
padding, while larger messages keep using the existing out-of-line
descriptor path.
2026-06-19 02:44:35 +02:00
Andreas Kling
bfcb51cfc3 LibWeb: Collect ancestor hashes from subject selector lists
When :is() or :where() appears in the subject compound, collect hashes
from ancestor compounds inside its argument selectors. Keep only hashes
shared by every alternative, and do not treat the argument selector
subject as an ancestor.
2026-06-19 01:40:49 +02:00
Andreas Kling
0b2a5ac143 LibWeb: Salt ancestor filter hashes by selector component
Separate ancestor filter hashes for tag names, ids, classes, and
attributes. This avoids false positives where identical strings in
different selector component kinds satisfy each other, while keeping the
filter conservative.
2026-06-19 01:40:49 +02:00
Andreas Kling
bc5d153e60 LibWeb: Improve ancestor hashes for selector-list pseudo-classes
Collect hashes from :is() and :where() selector lists by keeping only
hashes present in every alternative. This lets the ancestor filter
reject more selectors without changing matching semantics.
2026-06-19 01:40:49 +02:00
Andreas Kling
8d85a17527 LibWeb: Extract ancestor hashes from :is() and :where()
Look through single-argument :is() and :where() pseudo-classes when
collecting ancestor-filter hashes. Reuse hashes from the rightmost
compound of the argument selector, including nested wrappers, because
that compound matches the same ancestor element.

Keep selector lists with multiple alternatives conservative, since no
single hash is mandatory for every branch.
2026-06-19 01:40:49 +02:00
Andreas Kling
bc201e3257 LibWeb: Bucket more :is() and :where() rules
Look through single-argument :is() and :where() selectors when
selecting a rule-cache bucket. Use mandatory ids, classes, tag names
or attributes from the rightmost compound of the argument selector,
including nested :is() and :where() wrappers.

Leave multi-argument lists in the broad bucket, since a single key
would not be mandatory for every alternative.
2026-06-19 01:40:49 +02:00