Commit Graph

1637 Commits

Author SHA1 Message Date
Aliaksandr Kalenik
03f142f54d LibIPC+LibWeb: Preserve raw TransferDataEncoder attachments
Encode transfer-data attachments as raw IPC attachments instead of first
rewrapping them as IPC::File values.

This is preparatory refactoring for the upcoming Mach-port transport
introduction on macOS, where attachments should remain transport-native
rather than being normalized through file descriptors.
2026-03-21 00:45:12 +01:00
Johan Dahlin
9a34fb59aa LibWeb: Implement HTMLElement.accessKeyLabel
Implement the accessKeyLabel IDL attribute per the HTML spec.

We mimic Chromium's behavior and treat the accesskey attribute value as
a single key rather than splitting on whitespace, since no browser
besides IE/Edge implemented the spec's splitting approach.

See https://github.com/whatwg/html/issues/3769
2026-03-20 15:57:06 -05:00
Tim Ledbetter
849551714b LibWeb: Handle null navigable in Location::reload()
The specification says that a document's node navigable is null if
there is no such navigable.
2026-03-20 15:56:27 -05:00
Tim Ledbetter
279248960b LibWeb: Handle null active window in navigation abort task
There was already a null check before this task was queued, but it's
possible for the active window to become null between the time the task
is queued and executed, so we need to check again.
2026-03-20 15:56:27 -05:00
Jelle Raaijmakers
51564d2ff9 LibWeb: Prevent race condition in Storage::key()
Depending on the underlying implementation of the storage bottle, we
have to do IPC calls to get either the size or keys. We crash on an
out-of-bounds if the bottle changes size after the bounds check in step
1. Fix this by obtaining the keys immediately and using that for the
bounds check.
2026-03-20 14:04:11 +01:00
Jelle Raaijmakers
428a47cb7c LibWeb: Reduce size of Optional<HTMLToken> 2026-03-20 12:03:36 +01:00
Jelle Raaijmakers
c8baa6e179 LibWeb: Remove tasks for destroyed documents instead of running them
Previously, destroyed-document tasks were forced to be runnable to
prevent them from leaking in the task queue. Instead, discard them
during task selection so their callbacks never run with stale state.

This used to cause issues with a couple of `spin_until()`s in the past,
but since we've removed some of them that had to do with the document
lifecycle, let's see if we can stick closer to the spec now.
2026-03-19 15:24:46 -05:00
Tim Ledbetter
26389363ad LibGfx+LibWeb: Move Skia backend context to process level singleton
Previously, this was attached to the traversable navigable. Using a
singleton instead allows us to use the context for detached documents.
2026-03-19 13:35:16 +01:00
Shannon Booth
27436c3971 LibWeb/HTML: Do not run script on child removal
Matching the behaviour of the other big three browser engines,
also tested by WPT, but does not appear to be explicitly specified.

I also noticed when investigating that browser engines disagree
about whether a child mutation should trigger script execution.
For this, I've just gone with the behaviour of Webkit/Chromium of
not running script.
2026-03-19 09:46:54 +01:00
Shannon Booth
cc6536b527 LibWeb/HTML: Always provide ChildrenChangedMetadata to children changed 2026-03-19 09:46:54 +01:00
Andreas Kling
2a93576915 LibWeb: Store ImageData.data as own property for IC friendliness
The IDL-generated getter for ImageData.data lives on ImageDataPrototype,
which means every access goes through a getter call that cannot be
cached by the GetById inline cache.

By also storing the Uint8ClampedArray as an own data property directly
on each ImageData instance, the prototype getter is shadowed and
GetById can cache the access like any other data property. This matches
the approach used by WebKit and is compatible with web expectations.
2026-03-19 09:42:04 +01:00
Andrew Kaster
92e4c20ad5 LibJS: Generate FFI header using cbindgen instead of hand-rolling
Replace the BytecodeFactory header with cbindgen.

This will help ensure that types and enums and constants are kept in
sync between the C++ and Rust code. It's also a step in exporting more
Rust enums directly rather than relying on magic constants for
switch statements.

The FFI functions are now all placed in the JS::FFI namespace, which
is the cause for all the churn in the scripting parts of LibJS and
LibWeb.
2026-03-17 20:49:50 -05:00
Tim Ledbetter
40dd06491b LibWeb: Ensure list has child elements before invalidating ordinals
Previously, updating the `reversed`, `start` or `type` attribute of an
ordered list with text only children would cause a crash.
2026-03-17 16:50:06 +01:00
Zaggy1024
f213ef455d LibWeb: Cancel the animation frame callback in MediaControls destructor
Otherwise, when hiding controls, we would get a UAF on MediaControls::
update_timeline() and crash.
2026-03-17 06:00:40 -05:00
Zaggy1024
bdda60f9c8 LibWeb: Only skip labels' controls' activations on the first click
Chromium and Firefox skip calling the activation behavior on the first
click, so that double clicking toggles checkboxes twice.

Also, activation behaviors may be triggered by spacebar in the future,
so this check is limited to click events.
2026-03-17 04:01:29 -05:00
Zaggy1024
a51967311e Everywhere: Consolidate double/triple click handling to use click count
This moves normal/double/triple click checking into WebContent, the
client only has to send a click count in order to activate a double
or triple click in the content. This means that the AppKit UI will no
longer fire multiple double clicks when clicking in place more than 3
times. This matches the behavior of other browsers on macOS.

We will now also fire the click event regardless of whether a dblclick
event will follow, as the spec requires.
2026-03-17 04:01:29 -05:00
Zaggy1024
44ed698d4f LibWeb: Separate the active element and the element being activated
We were conflating elements being the active element and elements being
activated. The :active pseudo class is supposed to be based on whether
an element will have its activation behavior run upon a button being
released.

Store whether an element is being activated as a flag that is set/reset
by EventHandler.

Doing this allows label elements to visually activate their control
without doing a weird paintable hack, so the Labelable classes have
been yeeted.
2026-03-17 04:01:29 -05:00
Tim Ledbetter
a4f6ce3662 LibWeb: Use unsafe_layout_node() when handling alt attribute changes
The layout node is only accessed to clear the cached alt value, so the
layout tree doesn't need to be up to date in this case.
2026-03-17 09:07:10 +01:00
Zaggy1024
73c27f3448 LibWeb: Use requestAnimationFrame to update media controls timeline
The media element's timeupdate event only fires every 250ms. To make
the timeline update more smoothly, poll currentTime to update the
timeline every frame.
2026-03-17 01:48:59 -05:00
Zaggy1024
6f73b537f7 LibWeb: Simplify getting the Window in MediaControls callbacks 2026-03-17 01:48:59 -05:00
Zaggy1024
6cc13dbfa2 LibWeb: Skip assigning an unchanged timeline style in media controls 2026-03-17 01:48:59 -05:00
Zaggy1024
fe702847f8 LibWeb: Simplify the HTMLMediaElement null check in ~MediaControls() 2026-03-17 01:48:59 -05:00
Shannon Booth
cc711a6060 LibWeb/HTML: Fire storage events to windows without a Storage
Storage objects are created lazily when window.localStorage or
window.sessionStorage is first accessed. Previously, broadcast()
iterated over already-created Storage objects, so windows that had never
accessed these properties would not receive storage events.

Fix this by iterating over all active windows and initializing Storage
objects as part of the broadcast loop so all eligible windows receive
the event regardless of whether they had previously accessed
their storage property.
2026-03-16 13:55:07 +01:00
Shannon Booth
c4fef4c1a6 LibWeb/HTML: Introduce Window::for_each_active 2026-03-16 13:55:07 +01:00
Andreas Kling
a141c2c492 LibWeb+AK: Use AK::Queue for the microtask queue
The microtask queue is a pure FIFO (enqueue at back, dequeue from
front) but was using a Vector, making every dequeue O(n) due to
element shifting.

Replace it with AK::Queue which has O(1) dequeue. This makes a huge
difference when processing large numbers of microtasks, e.g. during
async-heavy JavaScript workloads where each `await` generates a
microtask.

Also add a for_each() method to AK::Queue so the GC can visit the
queued tasks.
2026-03-16 09:38:20 +01:00
Jelle Raaijmakers
0a81470bff LibWeb: Rewrite unload/destroy document lifecycle to follow the spec
1. unload_a_document_and_its_descendants() now follows the spec
   algorithm structure: recursively unload child navigables via queued
   tasks (step 4), wait for them (step 5), then queue this document's
   own unload as a separate task (step 6). Previously, this was
   flattened into a single spin that unloaded all descendants and the
   document together, followed by a non-spec call to
   destroy_a_document_and_its_descendants().

2. unload() step 19 now calls destroy() when the document is not
   salvageable, as the spec requires. Previously this was a no-op with a
   comment deferring to unload_a_document_and_its_descendants().

3. destroy_top_level_traversable() step 2 now calls
   destroy_a_document_and_its_descendants() instead of destroy().

The iframe-unloading-order test, which exercises named iframe access
during unload handlers (the scenario the previous logic was designed to
protect), still passes.

Fixes #7825
2026-03-15 09:03:20 -04:00
Jelle Raaijmakers
f2a199d321 LibWeb: Reformat and add spec steps
No functional changes.
2026-03-15 09:03:20 -04:00
Jelle Raaijmakers
28a7c0bed8 LibWeb: Use source-filtered spin in check_if_unloading_is_canceled()
check_if_unloading_is_canceled() can be called nested inside an outer
spin_processing_tasks_with_source_until (via apply_the_history_step ->
pump -> deferred_invoke -> begin_navigation). A regular spin_until()
deadlocks in that scenario because m_skip_event_loop_processing_steps
is true, causing process() to return early without ever executing the
queued tasks.

Since both spins here wait exclusively for NavigationAndTraversal
tasks, switch them to spin_processing_tasks_with_source_until() which
bypasses process() and directly executes matching tasks from the queue.
2026-03-15 09:03:20 -04:00
Jelle Raaijmakers
e80e2fb4b8 LibWeb: Restore skip flag to its original value in EventLoop
Before, we could re-enter into this method and it would clear the skip
flag once the innermost call would finish. Instead, remember what the
flag's original value was and restore that.
2026-03-15 09:03:20 -04:00
Andreas Kling
a25fc5ad8a LibCore+LibWeb: Add ScopedAutoreleasePool and use it on macOS
On macOS, Objective-C methods frequently return autoreleased objects
that accumulate until an autorelease pool is drained. Our event loop
(Core::EventLoop) and rendering thread both lacked autorelease pools,
causing unbounded accumulation of autoreleased objects.

The rendering thread was the worst offender: every Skia flush triggers
Metal resource allocation which sets labels on GPU textures via
-[IOGPUMetalResource setLabel:], creating autoreleased CFData objects.
With ~1M+ such objects at 112 bytes each, this leaked ~121MB. Metal
command buffer objects (_MTLCommandBufferEncoderInfo, etc.) also
accumulated, adding another ~128MB.

Add Core::ScopedAutoreleasePool, a RAII wrapper around the ObjC runtime
autorelease pool (no-op on non-macOS), and drain it:
- Every event loop pump (like NSRunLoop does)
- Every compositor loop iteration on the rendering thread
2026-03-15 11:42:43 +01:00
Aliaksandr Kalenik
19627bba54 LibIPC: Return TransportHandle directly from create_paired()
Previously, `create_paired()` returned two full Transport objects, and
callers would immediately call `from_transport()` on the remote side to
extract its underlying fd. This wasted resources: the remote
Transport's IO thread, wakeup pipes, and send queue were initialized
only to be torn down without ever sending or receiving a message.

Now `create_paired()` returns `{Transport, TransportHandle}` — the
remote side is born as a lightweight handle containing just the raw fd,
skipping all unnecessary initialization.

Also replace `release_underlying_transport_for_transfer()` (which
returned a raw int fd) with `release_for_transfer()` (which returns a
TransportHandle directly), hiding the socket implementation detail
from callers including MessagePort.
2026-03-14 18:25:18 +01:00
Aliaksandr Kalenik
da6b928909 LibIPC+LibWeb: Introduce IPC::Attachment abstraction
Replace IPC::File / AutoCloseFileDescriptor / MessageFileType in
the IPC message pipeline with a new IPC::Attachment class. This
wraps a file descriptor transferred alongside IPC messages, and
provides a clean extension point for platform-specific transport
mechanisms (e.g., Mach ports on macOS) that will be introduced later.
2026-03-13 20:22:50 +01:00
Andreas Kling
269d5f739b LibWeb: Use repeating timers for setInterval() to reduce drift
The timer nesting level throttling change (7577fd2a57) inadvertently
reverted the repeating timer optimization from 4d27e9aa5e, causing
setInterval() to use single-shot timers that re-arm after the callback
completes. This meant the next firing was scheduled relative to callback
completion rather than the previous fire time, causing drift
proportional to callback execution time.

For example, DiabloWeb's 50ms game loop with ~20ms of WASM work per
frame was only achieving 14 FPS (71ms intervals) instead of 20 FPS.

Fix this by using repeating Core::Timer for setInterval() again. The
repeating timer fires on schedule regardless of callback duration. On
re-arm, we update the callback (for nesting level changes) and the
interval (in case nesting level clamping kicks in), but don't restart
the timer since it's already running on the correct schedule.
2026-03-13 03:31:25 +00:00
Aliaksandr Kalenik
429847e843 LibWeb+LibWebView+WebWorker: Send service sockets to workers over IPC
Instead of passing RequestServer and ImageDecoder socket FDs as
command-line arguments to WebWorker, send them over the main IPC channel
after launch. The worker-agent handoff now carries all three transport
handles (worker, RequestServer, ImageDecoder) so the connection path
matches WebContent.
2026-03-12 20:32:55 +01:00
Aliaksandr Kalenik
3bea3908b2 LibIPC+LibWeb+LibWebView+Services: Add IPC::TransportHandle
Add IPC::TransportHandle as an abstraction for passing IPC
transports through .ipc messages. This replaces IPC::File at
all sites where a transport (not a generic file) is being
transferred between processes.

TransportHandle provides from_transport(),
clone_from_transport(), and create_transport() methods that
encapsulate the fd-to-socket-to-transport conversion in one
place. This is preparatory work for Mach port support on
macOS -- when that lands, only TransportHandle's internals
need to change while all .ipc definitions and call sites
remain untouched.
2026-03-12 20:32:55 +01:00
Jelle Raaijmakers
1d904d2295 LibWeb: Reduce noise from <img>'s decoding attribute
Our implementation of image decoding and its effect on
presenting/rendering the DOM is already effectively "async". The value
"auto" is implementation-defined, but should likely default to async
behavior as well. That leaves us with `decoding="sync"`, for which we
should still show a FIXME.
2026-03-12 16:58:00 +00:00
Jelle Raaijmakers
67d822cbbe LibGfx+LibWeb: Implement CanvasTextDrawingStyles.letterSpacing 2026-03-12 17:13:16 +01:00
Jelle Raaijmakers
54a222f75e LibWeb: Remove unused include from CanvasState 2026-03-12 17:13:16 +01:00
Aliaksandr Kalenik
3012c0fe72 LibWeb: Store scroll frames by value in contiguous storage
Replace per-frame heap-allocated RefCounted ScrollFrame objects with a
single contiguous Vector<ScrollFrame> inside ScrollState. All frames for
a viewport are now stored in one allocation, using type-safe
ScrollFrameIndex instead of RefPtr pointers.

This reduces allocation churn, improves cache locality, and moves
parent-chain traversal (cumulative offset, nearest scrolling ancestor)
into ScrollState — similar to how visual context nodes were recently
consolidated into AccumulatedVisualContextTree.
2026-03-12 12:06:40 +01:00
Tim Ledbetter
36f74ba96c Revert "LibJS: Shrink ExecutionContext by replacing ScriptOrModule …"
… with Cell*.

This reverts commit d3495c62a7.
2026-03-11 23:13:18 +00:00
Jelle Raaijmakers
2e42421553 LibWeb: Invalidate paint cache for input/textarea on focus change
The invalidate_style() calls on text nodes in did_receive_focus() and
did_lose_focus() were no-ops since Node::invalidate_style() returns
early for character data nodes. Replace them with set_needs_repaint()
which properly invalidates the containing PaintableWithLines' paint
cache, ensuring selection highlights are cleared and the caret is
repainted when switching focus between text controls.

Fixes #8363
2026-03-11 16:44:19 +00:00
Aliaksandr Kalenik
2e881978af LibIPC+LibWeb+LibWebView+Services: Add Transport::create_paired()
Consolidate the repeated socketpair + adopt + configure pattern from
4 call sites into a single Transport::create_paired() factory method.
This fixes inconsistent error handling and socket configuration across
call sites, and prepares for future mach port support on macOS.
2026-03-11 14:42:24 +01:00
Andreas Kling
d3495c62a7 LibJS: Shrink ExecutionContext by replacing ScriptOrModule with Cell*
Replace the 16-byte Variant<Empty, GC::Ref<Script>, GC::Ref<Module>>
with a simple 8-byte GC::Ptr<Cell> that points to either a Script or
Module (or is null for Empty).

A helper function script_or_module_from_cell() converts back to the
full ScriptOrModule variant when needed (e.g. in
VM::get_active_script_or_module).
2026-03-11 13:33:47 +01:00
Andreas Kling
5f463ed989 LibJS: Replace arguments Span with argument_count in ExecutionContext
The arguments Span (pointer + size = 16 bytes) was always derivable
from the tail array layout: data = values + (total_count - arg_count).

Replace it with a u32 argument_count and derive the span on demand
via arguments_span() / arguments_data() accessors.

Shrinks ExecutionContext from 136 to 120 bytes.
2026-03-11 13:33:47 +01:00
Andreas Kling
f02b67a700 LibJS: Remove context_owner from ExecutionContext
This field was only used by LibWeb to prevent GC collection of the
EnvironmentSettingsObject while its execution context is on the stack.

This is unnecessary because the ESO is already reachable through the
realm's host_defined pointer: EC -> realm -> host_defined ->
PrincipalHostDefined -> environment_settings_object.

Shrinks ExecutionContext from 152 to 144 bytes.
2026-03-11 13:33:47 +01:00
Aliaksandr Kalenik
9d2ebe90ed LibWeb: Store visual context nodes in arena-based tree
Replace per-node heap-allocated AtomicRefCounted
AccumulatedVisualContext objects with a single contiguous Vector inside
AccumulatedVisualContextTree. All nodes for a frame are now stored in
one allocation, using type-safe VisualContextIndex instead of RefPtr
pointers.

This reduces allocation churn, improves cache locality, and opens the
door for future snapshotting of visual context state — similar to how
scroll offsets are snapshotted today.
2026-03-11 11:16:36 +01:00
Aliaksandr Kalenik
01a7c8e424 LibWeb: Add PaintableBox::transform_rect_to_viewport()
Extract the repeated pattern of transforming a rectangle from absolute
coordinates to viewport coordinates via the accumulated visual context
into a helper method.
2026-03-11 02:31:30 +01:00
Jelle Raaijmakers
2efd7cdf8c LibWeb: Apply correct text baseline in CRC2D::text_path()
Fixes the vertical alignment of text in buttons on
https://lazyslug.com/lifeview/plugin/viewer.html.
2026-03-10 11:33:35 +01:00
Tim Ledbetter
36f59a406e LibWeb: Put HTML parser debug message behind a flag 2026-03-10 11:14:04 +01:00
zac
2e930e83ce LibWeb: Prevent cursor movement when collapsing text selection
Previously if you had a selection and you pressed the left/right arrow
key it would collapse the selection *and* perform the movement. This is
not how most text editors work and felt unnatural.
2026-03-10 02:53:27 +01:00