77352 Commits

Author SHA1 Message Date
Andreas Kling
51758f3022 LibJS: Make bytecode register allocator O(1)
Generator::allocate_register used to scan the free pool to find the
lowest-numbered register and then Vec::remove it, making every
allocation O(n) in the size of the pool. When loading https://x.com/
on my Linux machine, we spent ~800ms in this function alone!

This logic only existed to match the C++ register allocation ordering
while transitioning from C++ to Rust in the LibJS compiler, so now
we can simply get rid of it and make it instant. :^)

So drop the "always hand out the lowest-numbered free register" policy
and use the pool as a plain LIFO stack. Pushing and popping the back
of the Vec are both O(1), and peak register usage is unchanged since
the policy only affects which specific register gets reused, not how
aggressively.
2026-04-21 13:59:55 +02:00
Timothy Flynn
06796f5f7f LibURL+LibWeb+LibWebView: Convert about:version to a proper WebUI
Passing the browser command line and executable path to every WebContent
process just in case we load about:version always felt a bit weird. We
now use the WebUI framework to load this information on demand.
2026-04-21 06:59:11 -04:00
Andrew Kaster
5c835157c6 Documentation+Meta: Remove references to nonexistent Toolchain directory
After b1d708dd16, the Toolchain directory
was removed from the repository. Some documentation and scripts still
referenced it, so this commit removes those references. The only
remaining references are in the gitignore file, to prevent bisections
from being polluted by the presence of a Toolchain directory in the
working copy.
2026-04-21 06:56:32 -04:00
Shannon Booth
fd44da6829 LibWeb/Bindings: Emit one bindings header and cpp per IDL
Previously, the LibWeb bindings generator would output multiple per
interface files like Prototype/Constructor/Namespace/GlobalMixin
depending on the contents of that IDL file.

This complicates the build system as it means that it does not know
what files will be generated without knowledge of the contents of that
IDL file.

Instead, for each IDL file only generate a single Bindings/<IDLFile>.h
and Bindings/<IDLFile>.cpp.
2026-04-21 07:36:13 +02:00
Andrew Kaster
f7c932f50e Meta: Add option to select GUI Framework to ladybird.py 2026-04-20 18:41:42 -04:00
Andrew Kaster
c16d5ebe0e CMake: Set VCPKG_MANIFEST_FEATURES as a cache variable
This reduces vcpkg churn when it thinks that the manifest features have
changed, but they haven't due to the Gui framework staying the same.
2026-04-20 18:41:42 -04:00
Undefine
8cee6ba5a0 Meta: Remove a Qt option related from RequestServer's CMakeLists
Since those are no longer set in the top level CMake file this is no
longer necessary.
2026-04-20 16:41:29 -06:00
Undefine
61c6b9230a Meta: Add the check-style target unconditionally
Python3 is guaranteed to be available as we require it to run some
generators.
2026-04-20 16:41:29 -06:00
Undefine
e39a8719fd Meta: Move most dependency checks to check_for_dependencies.cmake
This file was here for quite a long while now. Let's finally move most
of the dependency checks to one centralized place.
2026-04-20 16:41:29 -06:00
Undefine
8721dbe094 Meta: Remove unused git-patch.cmake
It remains used ever since the Swift stuff got removed.
2026-04-20 16:41:29 -06:00
Undefine
942786d263 Meta+LibWeb: Pull a vcpkg Angle port change to remove an include hack
The issue mentioned there was resolved on the vcpkg side and only
required pulling in this one change.
2026-04-20 16:41:29 -06:00
Undefine
2536690aa6 Meta: Remove a global link to Threads::Threads
Globally linking to anything isn't a good thing to do and this doesn't
seem to be necessary. If it ends up breaking any platform it can be
readded as a specific link later.
2026-04-20 16:41:29 -06:00
Undefine
26a62dd8d2 Meta: Remove ladybird_option
This was just a wrapper around set, which doesn't serve much purpose
since the SerenityOS days.
2026-04-20 16:41:29 -06:00
Undefine
3ac8098888 Meta: Add NetBSD CMake presets file 2026-04-20 16:41:29 -06:00
Undefine
61c9e819bb Meta: Replace the Android BuildLagomTools.sh script with Python code
There weren't many changes required to integrate it with ladybird.py
and that seems much cleaner.
2026-04-20 16:41:29 -06:00
R-Goc
1ea9c00f7c Utilities: Mark unused variable with maybe_unused
This marks s_keep_running_repl as maybe_unused as it is set but unused
when running on Windows where we don't provide REPL functionality.
2026-04-20 15:45:58 -06:00
R-Goc
d7a8dd668d LibGfx: Remove unused globals
This commit removes an unused but set global found with the new
-Wunused-but-set-globals warning on clang main. This warning is a
subgroup of -Wunused-but-set-variable so we already have it enabled.
2026-04-20 15:45:58 -06:00
Jonathan Gamble
3ca76a42ec test-web: Break live display and terminal code out of main.cpp 2026-04-20 20:26:40 +02:00
Jonathan Gamble
e8ca424b13 test-web: Compensate live display for short terminals 2026-04-20 20:26:40 +02:00
Jonathan Gamble
7279917b5b test-web: Remove deferred warnings
Deferred warnings were originally  intended to suppress output during
live display, ostensibly to avoid glitch scrolls.

Then, 1af74d1a7c added log capture to the
test-web process. Suddenly, deferred warnings became deadly because
they're flushed during a tiny window after the capture notifier has
stopped draining the tee pipe but before stderr is restored.

This caused a deadlock at exit. The fix is to remove this system and
call warnln directly because display integrity is now protected by
other means.
2026-04-20 20:26:40 +02:00
Timothy Flynn
b1d708dd16 Meta: Move BuildVcpkg script to the Meta directory
It was the only thing left in the Toolchain directory.
2026-04-20 13:17:06 -04:00
Timothy Flynn
66cc1ef20b Meta: Use find_compiler.sh in fuzzer builder script
In commit b9c6263408, I had forgotten we
had this wrapper script to handle the eval magic for us. We just need
to forward the --clang-only argument to the underlying python script.
2026-04-20 13:17:06 -04:00
Timothy Flynn
5d461d3fb0 CI: Point lld at the explicitly installed version
It appears CI is currently not using lld as a linker.
2026-04-20 12:22:16 -04:00
Andreas Kling
7a5b1d9de1 LibWeb: Delay generic :has() sibling scans until sibling roots
Mark elements reached by stepping through sibling combinators inside
:has() and use that breadcrumb during generic invalidation walks.

Keep the existing conservative sibling scans for mutations outside
those marked subtrees so nested :is(), :not(), and nesting cases
continue to invalidate correctly.

Also keep :has() eager within compounds that contain ::part(). Those
selectors retarget the remaining simple selectors to the part host, so
deferring :has() there changes which element the pseudo-class runs
against and can make ::part(foo):has(.match) spuriously match.

Add a counter-based sibling-scan test and a regression test covering
the ::part()/ :has() selector orderings.
2026-04-20 13:20:41 +02:00
Andreas Kling
85ff13870f LibWeb: Stop :has() invalidation walk when out of :has() scope
A DOM mutation under a document that uses any :has() rule currently
walks every ancestor up to the root, invoking invalidate_style_if_
affected_by_has() on each. Most of those ancestors have nothing to
do with :has(), so the work scales linearly with DOM depth.

Introduce an in_has_scope flag on Element, set while evaluating :has()
arguments for invalidation metadata. StyleScope's upward invalidation
walk now terminates at the first element that is neither in :has()
scope nor a :has() anchor, so it only traverses the region where some
:has() rule might actually care about the change.

Keep the existing fast :has() matching paths for normal selector
matching, but bypass them while collecting per-element metadata so the
scope markers still get populated. Node insertion also schedules the
parent for the :has() walk so newly inserted nodes still reach the real
anchor.

The css-has-invalidation suite adds focused coverage for these shapes
and updates the expected counters to reflect the shorter walks.
2026-04-20 13:20:41 +02:00
Andreas Kling
029b4998e5 LibWeb: Skip useless sibling scans in generic :has() walks
Track whether any :has() relative selector in a style scope uses a
sibling combinator and let the generic ancestor walk consult that
before scanning ancestor siblings.

This keeps descendant-only :has() invalidations from walking unrelated
siblings while preserving the existing behavior for selectors that use
+ or ~. Add counter-based test coverage so the reduced sibling scans
stay visible through the invalidation counters.
2026-04-20 13:20:41 +02:00
Andreas Kling
e1d62eaf85 LibWeb: Bucket :has() invalidation metadata by feature
Record per-feature :has() invalidation metadata instead of only tracking
whether some selector somewhere mentions a class, id, attribute, tag,
or pseudo-class. The new buckets preserve the relative selector and a
coarse scope classification for each :has() argument, which gives the
next invalidation step enough information to route mutations more
precisely.

Keep this commit behavior-preserving for mutation handling by only
switching the lookup path over to the new metadata buckets. Expose a
test-only counter for the number of candidate :has() metadata entries a
mutation matched, and add coverage showing that one feature can map to
one or multiple :has() buckets without forcing a document-wide yes/no
answer.
2026-04-20 13:20:41 +02:00
Andreas Kling
55ebd8a589 LibWeb: Ignore invalidation rule order when merging plans
Treat structurally equivalent invalidation plans as equal even when
their descendant or sibling rules were accumulated in a different
order. This lets :has() invalidation merge more of the repeated
descendant-only payloads that still showed up after the earlier
structural dedup.

Add a :has() invalidation counter test that exercises equivalent
selector permutations so this shape stays covered.
2026-04-20 13:20:41 +02:00
Andreas Kling
04fd26a02b LibWeb: Fast-path simple descendant compound :has()
Teach :has() matching to recognize the common case of a single
descendant compound made only of tag and class selectors. This lets us
stay on the cheap per-element matcher instead of recursing through the
full relative-selector machinery for each candidate descendant.

Keep the optimization limited to that simple selector shape and fall
back to the generic matcher for everything else.
2026-04-20 13:20:41 +02:00
Andreas Kling
b20bbbc6b3 LibWeb: Fast-path simple child-tag :has() matching
Avoid the generic relative-selector matcher for child-only tag
selectors inside :has(). These selectors can be answered by walking the
anchor's direct children and checking the tag match directly, which
keeps a very hot path cheaper.

Preserve the existing ancestor cache behavior and fall back to the
generic matcher for all other selector shapes.
2026-04-20 13:20:41 +02:00
Andreas Kling
97e2b05004 LibWeb: Merge equivalent style invalidation plans
Compare invalidation sets, rules, and plans structurally so repeated
descendant and sibling invalidation entries can be merged even when
they were built as separate payload objects.

Also deduplicate pending and active descendant invalidations in the
style invalidator so equivalent rules are not re-applied as the DOM
walk descends. This reduces :has() invalidation fanout while keeping
behavior the same.
2026-04-20 13:20:41 +02:00
Andreas Kling
a72fae8d36 LibWeb: Add test-only counters for :has() invalidation work
Introduce a small set of counters on Document that track the work done
while processing :has() invalidation: how often the upward walk runs,
how many elements it visits, how often matches_has_pseudo_class() is
invoked, how well the per-pass result cache performs, and how many
elements transition from clean to needs-style-update.

Expose the counters through internals so tests can assert precise bounds
on the invalidation work triggered by a mutation, which regular
reference tests cannot express.

Add a css-has-invalidation test suite that covers subject-position,
non-subject-position, sibling-combinator, and no-:has() cases. The
baseline tests share a helper script so later coverage can reuse the
same counter-printing path.

The counters are test-only observation; they do not affect style
computation itself.
2026-04-20 13:20:41 +02:00
Andreas Kling
e5d4c5cce8 LibJS: Check TDZ state in asm environment calls
GetCalleeAndThisFromEnvironment treated a binding as initialized when
its value slot was not <empty>. Declarative bindings do not encode TDZ
in that slot, though: uninitialized bindings keep a separate initialized
flag and their value starts as undefined.

That let the first slow-path TDZ failure populate the environment cache,
then a second call at the same site reused the cached coordinate and
turned the required ReferenceError into a TypeError from calling
undefined.

Check Binding.initialized in the asm fast path instead and cover the
cached second-hit case with a regression test.
2026-04-20 11:23:34 +02:00
Yayoi-cs
d8aee7f1e6 LibJS: Refresh TypedArray cached data pointers on shared memory grow
WebAssembly.Memory({shared:true}).grow() reallocates the underlying
AK::ByteBuffer outline (kmalloc+kfree) but, per the threads proposal,
must not detach the associated SharedArrayBuffer.

ArrayBuffer::detach_buffer was the only path that walked m_cached_views
and cleared the cached raw m_data pointer on each TypedArrayBase, so
every existing view retained a dangling pointer into the freed outline.
The AsmInterpreter GetByValue / PutByValue fast paths dereference that
cached pointer directly, yielding a use-after-free triggerable from
JavaScript.

Add ArrayBuffer::refresh_cached_typed_array_view_data_pointers() which
re-derives m_data for each registered view from the current outline
base (and refreshes UnownedFixedLengthByteBuffer::size), and call it
from Memory::refresh_the_memory_buffer on the SAB-fixed-length path
where detach is spec-forbidden.
2026-04-20 09:43:08 +02:00
Nicolas Danelon
ea22c19ab3 Base: Improve about:version and about:processes
This patch updates the about:version page to use the shared Ladybird
WebUI styling and present version, build, and runtime details in cards.

It also adds the Ladybird logo and a page title to about:processes,
without otherwise changing the process table behavior.
2026-04-19 22:53:59 +02:00
Andreas Kling
d629cc379a LibWeb: Cache parsed selectors in Element.matches() and .closest()
Element::matches() and Element::closest() were re-parsing the selector
string on every call. The document already maintains a parsed-selector
cache for querySelector/querySelectorAll.

This patch folds that cache's lookup, parse, namespace filtering and
insertion behind a Document::parse_or_cache_selector_list(string)
and calls it from all four entry points. We also bump the cache's
limit to get more hits.

Saves 100ms of main thread time when loading the "insights" view on
our GitHub repo on my Linux machine. :^)
2026-04-19 21:32:55 +02:00
Zaggy1024
726ddf0b92 LibGfx: Move yuv crate binding declarations to a separate module file 2026-04-19 09:06:25 -05:00
Shannon Booth
706011bd9b LibWeb: Respect image response MIME type over .svg URL suffix
SharedResourceRequest was treating any URL ending in .svg as SVG, even
when the response Content-Type was some other format (like image/webp).
This could result in transformed CDN image URLs to fail decoding.

Only use the .svg URL suffix fallback when no MIME type was provided.
2026-04-19 15:57:47 +02:00
Tete17
1af8cc471d LibWeb: Validate JWK key pair consistency for OKP importKey
For private key JWK imports, after decoding both d and x, derive
the public key from d and verify it matches x. A private key that
doesn't correspond to the provided public key doesn't "contain the
private key" as required by RFC 8037 Section 2.
2026-04-19 13:35:36 +02:00
Tete17
32af84b698 LibWeb: Validate JWK key length for OKP importKey
After base64url-decoding the x and d fields during JWK import,
verify the decoded byte length matches the expected key size for
the curve (32 for Ed25519/X25519, 57 for Ed448, 56 for X448).
A truncated value does not "contain the public/private key" as
required by RFC 8037 Section 2.
2026-04-19 13:35:36 +02:00
Tete17
00e9396cfe LibWeb: Fix Ed448 raw key length check in importKey
Ed448 public keys are 57 bytes (456 bits), not 56 bytes (448 bits).
The curve is named "Ed448" after its 448-bit prime field, but per
RFC 8032 Section 5.2.5, the parameter b=456 and both private and
public keys are 57 bytes. This caused importKey to reject valid raw
Ed448 public keys with a DataError.

Note: The spec incorrectly says "not 448" for this check.
See https://github.com/w3c/webcrypto/pull/425#discussion_r3070135408
2026-04-19 13:35:36 +02:00
Jonathan Gamble
1c5907d87f LibWeb: Correct initiator origin logic for new top level traversables 2026-04-19 13:11:48 +02:00
Timothy Flynn
10ce847931 LibJS+LibUnicode: Use LibUnicode as appropriate for lexing JavaScript
Now that LibUnicode exports its character type APIs in Rust, we can use
them to lex identifiers and whitespace.

Fixes #8870.
2026-04-19 10:39:26 +02:00
Timothy Flynn
11719369e8 LibRegex+LibUnicode: Migrate Unicode Rust FFI methods to LibUnicode
Let's not have LibRegex be the home of LibUnicode FFI. Move these to
LibUnicode so that we can:

1. Use these helpers in other libraries more easily.
2. Swap out icu4c methods with icu4x methods all within LibUnicode.
2026-04-19 10:39:26 +02:00
Timothy Flynn
46912fce8d LibUnicode: Hide the Unicode allocator override behind a feature
A future commit will make LibJS and LibRegex depend on LibUnicode's rust
module. The global allocator overrides will cause a compliation error:

    error: the `#[global_allocator]` in this crate conflicts with global
    allocator in: libunicode_rust

This hides the allocator override behind a feature flag that is enabled
for the standalone LibUnicode shared library.
2026-04-19 10:39:26 +02:00
Pavel Shliak
94b29821a1 LibWeb/HTML: Remove duplicate area tag in XMLSerializer 2026-04-19 10:38:32 +02:00
Aliaksandr Kalenik
14dc9e8ca2 LibHTTP: Short-circuit CacheIndex eviction when under its size limit
remove_entries_exceeding_cache_limit() is called after every network
response, but the cache is usually still under budget and nothing needs
to evict. Every one of those calls currently still runs the
window-function eviction SQL over the whole CacheIndex table just to
conclude there is nothing to do.

Short-circuit the call when the cache is already within its configured
size limit. To make that check cheap, maintain m_total_estimated_size
as a running total of the cache's estimated byte size, so the no-op
case becomes a single u64 compare and the DB is only touched when
there is real work.

Bookkeeping:
- Seed the total in CacheIndex::create() via a new
  select_total_estimated_size statement (COALESCE(..., 0) so an empty
  index returns 0 rather than NULL).
- Each Entry caches serialized_request_headers_size and
  serialized_response_headers_size so we don't re-serialize to
  recompute its footprint; Entry::estimated_size() centralizes the
  arithmetic.
- create_entry() adds the new entry's size. Any row it displaces is
  removed via DELETE ... RETURNING so the total stays accurate even
  for entries that were never loaded into m_entries.
- remove_entry() and the bulk DELETE statements were extended with
  the same RETURNING clause for the same reason.
- update_response_headers() shifts the total by the signed delta
  between old and new serialized header size.

Also COALESCEs estimate_cache_size_accessed_since over an empty table
to 0 so callers don't have to special-case NULL.
2026-04-19 01:31:37 +02:00
Aliaksandr Kalenik
d8b28a68cc LibHTTP: Replace loaded cache entries in CacheIndex
create_entry() issues INSERT OR REPLACE in SQL, so the on-disk row is
correctly overwritten when a (cache_key, vary_key) pair is re-inserted.
But the in-memory m_entries vector was only appended to, leaving the
stale Entry alongside the new one. Subsequent find_entry() calls could
then return the old metadata even though the DB had moved on.
2026-04-19 01:31:37 +02:00
Andreas Kling
e1d35d7da9 LibWeb+LibGfx: Decompress WOFF2 fonts off the main thread
Add an off-thread preparation step for downloaded vector fonts so
WOFF2 resources can be decompressed before LibWeb tries to create a
typeface from them. This avoids doing the conversion work on the main
thread during @font-face loading.

Expose raw WOFF2-to-TTF conversion from LibGfx's WOFF2 loader and use
that from the new preparation path. Keeping the libwoff2 integration
in LibGfx preserves the layering between LibWeb and the third-party
decoder while still letting LibWeb schedule the work off-thread.
2026-04-18 23:46:20 +02:00
Timothy Flynn
e955f5d5e2 LibGfx: Reformat rust module
This code was added while our rustfmt config was in a PR.
2026-04-18 14:22:49 +02:00