Commit graph

59 commits

Author SHA1 Message Date
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
Callum Law
8ebdaeab69 LibWeb: Transfer animation ownership to AnimatedBitmapDecodedImageData
Previously animation ownership was a messy split between
`AnimatedBitmapDecodedImageData` and the consumers (i.e.
`ImageStyleValueResource`, `HTMLImageElement`, and `SVGImageElement`)
with `AnimatedBitmapDecodedImageData` owning the frames and a current
frame index, and the consumers owning the rest of the state (e.g. loop
count, timers to drive the animation forward, their own current index).

This had a couple of main issues:
 - While `AnimatedDecodedImageData` partially synchronized animations by
   dropping unexpected advancement notifications, this didn't apply to
   other animation state which meant, for instance, that a later started
   consumer could drive the animation of an earlier one past the max
   loop count (albeit without invalidating the earlier consumer).
 - Multiple consumers didn't share frame timings, meaning animations
   could be up to a full frame out of sync visually.
 - Animations were paused depending on whether there were any consumers,
   this is different to the behavior in other browsers (where they
   continue regardless of whether there are any consumers).
 - It was an overgeneralization of how animations need to work - only
   `AnimatedBitmapDecodedImageData` works with an indexed frame model,
   with animated SVGs (although not yet implemented) relying on their
   internal event loop to be driven forward.

Given the above the new approach implemented in this commit is:
 - The API for `DecodedImageData` is animation system agnostic, only
   exposing `default_frame`, `current_frame`, and `restart_animation`
   methods not reliant on providing a specific frame index.
 - `AnimatedBitmapDecodedImageData` owns its own timer, loop count,
   etc. The animation starts when the first consumer registers and ends
   when the document is hidden or becomes inactive (or completes in the
   case of finite animations).
 - Consumers are invalidated by `AnimatedBitmapDecodedImageData` when
   required.

Tests have been added for:
 - Animations being paused when the document becomes inactive and
   restarted when it becomes active again.
 - Frame timings being synchronized across consumers.
 - Restarts triggered by `HTMLImageElement` applying to all consumers.
 - Processing ending once a non-infinite animation plays to completion.

The tests to ensure animations are cancelled when consumers are removed
(e.g. `animated-background-image-timer-stops-when-hidden.html`) have
been updated to assert the inverse since animation state is now per
resource not per consumer.
2026-06-18 10:44:25 +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
sideshowbarker
85a4f2633c LibWeb: Add an Internals hook to interrupt a navigation with a traversal
clobberNextNavigationWithATraversal() arms a one-shot that, on the next
call to Navigable::begin_navigation, re-stamps the navigable’s ongoing
navigation with a synthetic session-history traversal during the unload
check, then clears it on a later turn — draining deferred navigations.

This lets a single-process test deterministically reproduce a race
between a cross-document navigation and a concurrent traversal, which
otherwise only surfaces under scheduling jitter in a multi-process run.
2026-06-16 11:43:09 +02:00
Andreas Kling
0aaae1ac76 Tests/LibWeb: Cover UI-owned session history
Teach test-web to expose the UI-process history dump. Add focused
navigation tests for same-document traversal, fallback traversal, and
cross-document browser back and forward behavior. The expectations
assert document state and the UI-owned history snapshot.
2026-06-14 17:38:44 +02:00
Andreas Kling
24f37c6732 LibWebView: Keep browser history in the UI process
Use the LibWebView history mirror to preserve traversable session
history across WebContent process swaps. WebContent reports snapshots to
the UI process, and new renderers can be seeded from the mirror.

Browser back and forward now resolve through the UI-owned used history
steps. WebContent still runs the spec traversal path when the current
renderer has enough matching state to do so.

Handle canceled and no-op UI navigations without leaving speculative
history entries or pending WebDriver waits behind. Preserve traversal
precheck state across synchronous IPC shutdown, and avoid overwriting a
restored target entry's persisted scroll state before the document has
adopted that entry.
2026-06-14 17:38:44 +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
Sam Atkins
c7015a8647 LibWeb: Remove unused test variant metadata API
Remove internals.loadTestVariants and the IPC forwarding that reported
variant metadata back to WebView. test-web now identifies WPT variants
during collection, so no loaded document needs to expose this test-only
hook.
2026-06-09 16:48:33 +02:00
sideshowbarker
a82c7939d9 LibWeb+UI/AppKit: Implement macOS IME support
This makes macOS IME input in web content work as expected.

Fixes https://github.com/LadybirdBrowser/ladybird/issues/9712
2026-06-08 10:23:14 +09:00
Sam Atkins
c4e8817246 LibWeb+Tests: Update layout before accessibility tree dumps
The accessibility tree builder consults layout nodes while applying
inclusion and exclusion rules. DevTools can request an accessibility
tree after style or layout has been dirtied, which made those
layout-node lookups trip the stale-layout verification.

Update layout before serializing the accessibility tree, matching the
DOM tree dump path. Add an internals regression test that dirties
layout before requesting an accessibility dump.
2026-06-01 08:28:45 +01:00
Luke Wilde
f6e5af0cb5 Tests/LibWeb: Add HSTS tests with internals helpers
Add internals.setHSTSPolicy, internals.ingestHSTSHeader, and
internals.isKnownHSTSHost so tests can drive HSTS state without an
HTTPS server. Extract ResourceLoader::try_store_hsts_policy_for_url
so the ingest helper exercises the same code path the network layer
uses for Strict-Transport-Security response headers.
2026-05-29 22:23:33 +02:00
sideshowbarker
03f6f25b11 LibWeb: Skip user-select:none when extracting selected text
Problem: Select All (Ctrl+A or the context menu) followed by Ctrl+C
unexpectedly copies text from elements with user-select:none — breaking
compat with Chrome and Firefox, which both exclude user-select:none
content from the clipboard.

Cause: Navigable::selected_text() walks the selection range via
visible_text_in_range() and concatenates each text node’s data. The walk
filters out nodes without a layout, but not nodes whose used value of
user-select is ‘none’.

Fix: Add a user-select check at each visible_text_in_range() walk point.
The Selection range itself is left unchanged. Selection.toString() still
returns the full text per spec — but the clipboard-extraction path now
excludes user-select: none subtrees, per spec
2026-05-28 12:15:21 +01:00
Andreas Kling
6ca9214b4c LibWeb: Respect root color scheme for loading canvases
Only use the loading-time top-level canvas fallback when the root
color-scheme value is still normal. An explicit light scheme on the
root element already gives the canvas a light used scheme, so replacing
it with the preferred dark scheme makes the viewport disagree with the
computed system colors until readiness advances.

Add internals coverage for the document canvas scheme and a text test
that exercises the loading state with a dark preferred color scheme.
2026-05-27 20:57:38 +02:00
Aliaksandr Kalenik
9ab311507e LibWeb+UI: Synthesize ctrl-wheel events for pinches
Trackpad pinches applied directly as visual viewport zoom, so pages
could not observe the gesture or cancel the browser default. Canvas
apps such as maps expect the ctrl-wheel path instead.
2026-05-27 12:53:08 +02:00
Andreas Kling
212330205f LibWeb: Fix link drag cancellation state
Clear mousedown activation state whenever primary mousedown tracking is
reset. Also route local link drag cancellation through the drag-and-drop
end path when Escape, viewport leave, or mouseup outside the viewport
ends the drag.

These paths can otherwise leave drag input suppression active after the
user has ended or canceled the drag, or skip the required dragend event
for source cleanup.

Add an internals mouseLeave primitive and a focused text test. It covers
stale :active state, dragend dispatch for cancellations, viewport leave,
outside-viewport mouseup, Escape canceling, and later click delivery
after each canceled drag.
2026-05-27 09:52:15 +02:00
Andreas Kling
44a6da5165 LibWeb: Avoid cold rule cache builds for :has() checks
Cache lightweight selector insights on each stylesheet so cold style
scopes can answer whether :has() invalidation is relevant without
building a complete rule cache. This avoids forcing rule caches for
shadow roots whose active sheets do not contain :has() selectors.

Imported sheets contribute to their parent sheet's effective rules, so
an imported sheet load or CSSOM change also clears ancestor selector
insight caches.

Add test-only counters and regression coverage for cold shadow roots
with and without :has() selectors, plus delayed imported :has() rules.
2026-05-23 22:03:46 +02:00
Andreas Kling
f9ef74bb0a LibWeb: Stabilize style invalidation counter tests
Counter tests reset their counters before measured mutations, but setup
and cleanup could leave pending style invalidation work behind. A later
case could then pay for stale work in its measured counter window. That
made exact recomputation baselines depend on prior test order.

Add a test-only Internals hook that flushes pending style work without
forcing layout. Use it to make warm counter measurements start from a
clean style state. Cold paths keep using a plain counter reset so they
still exercise cold rule-cache behavior.

Rebaseline these counter tests now that they no longer include cleanup
work from previous cases.
2026-05-23 22:03:46 +02:00
Andreas Kling
17902b02ab LibWeb: Stop idle animated CSS image timers
Keep animated ImageStyleValue frame advancement owned by the
style value. The current frame and loop state live there, so a
separate document scheduler would duplicate ownership of that state.

Start the ImageStyleValue timer only while it has layout clients.
Stop it when the last client unregisters, or when a finite animation
completes. Expose a document-scoped active timer count through
internals for focused regression tests.

Clear image observers when layout nodes detach. Use current-node
cleanup for per-DOM-node clearing, and explicit subtree cleanup for
tree replacement, full tree teardown, and synthetic pseudo-elements.
This keeps large document clearing linear.

Unregister generated-content image providers during layout detach
instead of waiting for GC to finalize the provider.

Cover hidden animated background images, generated content images,
layout node replacement, full layout tree teardown, and document
scoping for the internals counter.
2026-05-23 11:36:53 +02:00
Andreas Kling
a289601eb0 LibWeb: Expose content blocker test controls
Add internals helpers so text tests can install local blocker rules and
toggle content blocking without browser-process IPC. Clear installed
rules after each non-crashed test-web case so blocker state cannot leak
into the next test.
2026-05-21 21:16:56 +02:00
Andreas Kling
a36f8aa36d LibWeb: Keep ResizeObserver targets weakly
Store ResizeObservation targets weakly, matching Blink and WebKit. A
ResizeObserver can be kept alive by the document while it has observed
targets, but the observation itself should not keep a removed target and
its subtree alive forever.

Prune dead observations before gathering active resize observations.
Snapshot the document observer list before pruning so unregistering an
observer cannot mutate the intrusive list being iterated. Keep gathered
active targets rooted while broadcasting callbacks, since an earlier
callback can remove a later target and trigger GC before delivery.

Expose an internals helper to force environment-bound test objects to be
treated as garbage. Add text coverage for both pruning a dead observer
during gather and GC during an earlier resize observer callback.
2026-05-16 18:48:52 +02:00
Aliaksandr Kalenik
f743263871 LibWeb: Let internals.wheel await async scroll adoption
Async scrolling tests used requestAnimationFrame() as a proxy for the
compositor thread to return pending scroll updates to the main thread.
That waited for a rendering opportunity, so tests could observe stale
DOM scroll offsets when the compositor update had not been adopted yet.

Make internals.wheel() return a promise that resolves after a tracked
async scroll operation has been applied by Navigable. Tracking is opt-in
from the internals test API, so regular page wheel input and compositor
IPC keep the boolean async-scroll path without allocating operation IDs.
Tracked test scrolls are the only operations that record completions.

Update async scrolling and wheel propagation tests to await the wheel
promise directly instead of relying on animation frame timing in tests.
2026-05-15 19:10:27 +02:00
Andreas Kling
d36d336c82 LibWeb: Allow viewport async scroll with nested scrollers
Allow compositor wheel routing to stay enabled when the scroll tree also
contains non-viewport scroll nodes. The compositor still rejects an
individual wheel whose hit-test target is not the viewport, so element
scrollers continue to fall back to the main thread until their scroll
offsets can be adopted safely.

Move the routing admission helper next to the async scrolling state and
expose test-only internals for the routing result and wheel target. Add
coverage for a page that has both a viewport scroller and a nested
element scroller.
2026-05-12 20:57:08 +02:00
Andreas Kling
191bd46cb8 LibWeb: Add compositor scroll state snapshots
Record the scroll geometry that CompositorThread can safely reason about
while the main thread is painting. The snapshot contains stable scroll
node IDs, parent links, scroll bounds, sticky inputs, and wheel blocker
regions in display-list coordinate space.

Add AsyncScrollingState and AsyncScrollTree under LibWeb/Compositor. The
state is the immutable main-thread snapshot; the tree is the mutable
compositor-side copy that can replay scroll deltas and sticky offsets
without touching DOM, layout, or paintables.

Expose the state through internals and add text tests for tree shape,
parent links, sticky areas, blocker hit testing, nested scrollers, and
admission decisions. Keep the directory skipped unless the feature is
enabled with --enable-async-scrolling.
2026-05-12 20:57:08 +02:00
Andreas Kling
a870475f2b LibWeb: Expose style recomputation counters through Internals
We already had Internals counters for :has() invalidation work and
the high-level invalidation passes. Add four more that record how
often Element::recompute_style and recompute_inherited_style run,
and how often each bails out as a no-op. The new tests on this
branch use these counters to assert that mutations don't trigger
redundant style recomputation.
2026-04-26 10:40:58 +02:00
Shannon Booth
cc6e048bd6 LibWeb+LibIDL: Remove support for #import directives during parsing
These no longer serve any purpose now that we run the IDLGenerator
on all of these files at once.
2026-04-24 20:08:29 +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
Zaggy1024
ed8ba673de LibWeb: Add internals.gcAsync() to run collection with an emptier stack
This will allow us to have more predictable and effective testing of GC
than the synchronous version.
2026-04-08 03:03:38 +02:00
Aliaksandr Kalenik
0914cd07c3 LibWeb: Add internals.dumpSessionHistory() for navigation testing
Dumps the calling navigable's session history entries with relative step
numbers and filename-only URLs, making the output stable across test
runs. Each entry shows its step index, filename (with fragment if any),
and a "(current)" marker when it matches the traversable's current step.
2026-04-04 11:30:55 +02: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
Shannon Booth
d6d80e5d52 LibWeb: Load cookies test from HTTP server
Allowing us to remove the internals hook.
2026-02-21 23:00:57 +01:00
Aliaksandr Kalenik
0bec9a1e5d LibWeb: Add dumpPaintableTree() to Internals API
Expose the paintable tree dump through the internals object, analogous
to the existing dumpLayoutTree(). This is useful for testing and
debugging painting behavior.
2026-02-15 17:47:30 +01:00
Shannon Booth
bc93ba4530 LibWeb/Bindings: Implement [SecureContext] extended attribute
Unfortunately this is a bit of a pain to test as it is surprisingly
difficult to create a non secure context in our test harness.
This is because both file scheme URLs and localhost are considered
secure contexts.

To test this, add a very specific internals setter to change the
top level origin of the environment for the current realm.
2026-02-14 20:22:40 +01:00
Praise-Garfield
56287ca90f LibWeb: Clear textarea with empty string for WebDriver
The WebDriver clear handler for textarea elements sets the raw
value to child_text_content() instead of an empty string. This
is a copy-paste from the adjacent reset handler, which correctly
uses child_text_content() per its own spec. The clear spec says
"set the raw value of element to an empty string".
2026-02-13 15:29:02 -05:00
Aliaksandr Kalenik
5be98aaa07 LibWeb: Add internals.dumpLayoutTree(node) API
This new testing API dumps the layout subtree rooted at a given DOM
node. It will be useful for testing partial layout tree rebuilds, where
we need to verify the layout tree structure for specific subtrees rather
than the entire document.
2026-02-09 21:05:45 +01:00
Jelle Raaijmakers
f55fe69d4d LibWeb: Rework Internals' mouse control
Instead of defining somewhat high level mouse actions, allow granular
control of mouse clicks and mouse down/up/move events. We will want to
simulate things like holding down a mouse button after double clicking
and then dragging the mouse to another position in the future, and this
enables that.
2026-02-06 14:18:10 +00:00
Jelle Raaijmakers
c56c933014 LibWeb+WebContent: Instantly update DPI for painting and media queries
If our UI informed the page of a DPI change, we would store the new
device pixel ratio and leave it at that. It would take a layout/style
update (e.g. by clicking the page) to actually render the page using the
new DPI. This is very visible on macOS when moving the Ladybird window
from a 1x resolution monitor to a HiDPI 2x monitor.

We now instantly update the backing stores and mark media queries for
reevaluation. Moving the Ladybird window on macOS now immediately
updates the page when dragging it to a HiDPI monitor.
2026-02-06 09:01:26 +01:00
InvalidUsernameException
ecce9f5b68 LibWeb: Add method to set highlighted nodes via internals-object
Upcoming commits will fix some regressions related to the highlighting
of nodes from within the inspector. Let's add the necessary
infrastructure so that we can write regression tests and avoid breaking
things again.
2026-02-01 14:29:59 +01:00
Aliaksandr Kalenik
1f6ee6c63a LibWeb: Add internals.dumpStackingContextTree() for testing
This new API allows tests to inspect the stacking context tree structure
which is useful for verifying that stacking context invalidation and
rebuilding work correctly.
2026-01-28 18:05:41 +01:00
Jelle Raaijmakers
bf77aeb3dc Tests/LibWeb: Support WPT variant meta tags in test-web
Add support for WPT test variants, which allow a single test file to be
run multiple times with different URL query parameters. Tests declare
variants using `<meta name="variant" content="?param=value">` tags.

When test-web encounters a test with variants, it expands that test into
multiple runs, each with its own expectation file using the naming
convention `testname@variant.txt` (e.g., `test@run_type=uri.txt`).

Implementation details:
- WebContent observes variant meta tags and communicates them to the
  test runner via a new `did_receive_test_variant_metadata` IPC call
- test-web dynamically expands tests with variants during execution,
  waking idle views after each test completion to pick up new work
- Use index-based test tracking to avoid dangling references when the
  test vector grows during variant expansion
- Introduce TestRunContext to group test run state, and store a static
  pointer to it for signal handler access

This enables proper testing of WPT tests that use variants, such as the
html5lib parsing tests (which test uri, write, and write_single modes)
and the editing/bold tests (which split across multiple ranges).
2026-01-16 16:44:13 +00:00
Timothy Flynn
96806a3f90 LibWeb: Update cursor and tooltip UI state regardless of event handlers
If a script on the page cancels a mousemove event, we would return early
and neglect to update the cursor. This is seen regularly on "Diablo Web"
where they set the cursor to "none" on the main canvas, and also cancel
mousemove events.
2025-12-03 12:23:56 +01:00
Timothy Flynn
813986237e LibWeb: Add some tests that exercise the HTTP disk cache
Our HTTP disk cache is currently manually tested against various sites.
This patch adds some tests to cover various scenarios, including non-
cacheable responses, expired responses, and revalidation.

In order to ensure we hit the disk cache in RequestServer, we must
disable the in-memory cache in WebContent.
2025-11-20 09:33:49 +01:00
Tim Ledbetter
74940726d0 LibWeb: Add an Internals method to dump the GC graph 2025-11-04 10:34:43 +01:00
Dowsley
c6b289c3dc LibWeb: Derive implicit aria-level for h1–h6 from tag name 2025-10-10 17:18:02 +01:00
Aliaksandr Kalenik
0fbadba2e1 LibWeb: Add a test to ensure "resize" event on VV is fired on pinch-zoom 2025-10-10 15:37:45 +02:00
Timothy Flynn
efa9311527 LibWeb+WebContent+UI: Port text pasting to UTF-16 2025-09-19 06:38:52 -04:00
Luke Wilde
9adf27f009 LibWeb: Add tests for Gamepad API by utilising virtual SDL3 joysticks 2025-09-01 21:10:47 +02:00
Andreas Kling
1402c143a9 LibWeb: Add Internals.getShadowRoot(element)
This lets you access closed shadow roots from JavaScript, even though
they're not normally accessible to JavaScript. This can be used to poke
into UA shadow roots in tests.
2025-08-07 22:15:36 +02:00
Luke Wilde
a2f3a5a6ce LibWeb: Send a beforeinput event for pasting
This allows us to paste text into Discord.
2025-07-23 22:04:45 +02:00
Jelle Raaijmakers
e4b2253b63 Tests: Replace load-reference-page debug action with internals method
WPT reference tests can add metadata to tests to instruct the test
runner how to interpret the results. Because of this, it is not enough
to have an action that starts loading the (mis)match reference: we need
the test runner to receive the metadata so it can act accordingly.

This sets our test runner up for potentially supporting multiple
(mis)match references, and fuzzy rendering matches - the latter will be
implemented in the following commit.
2025-07-17 12:59:11 +01:00
Aliaksandr Kalenik
8ae7417445 LibWeb: Add internals call to dump display list
It's useful to have tests that dump display list items, so we can more
easily see how changes to the display list recording process affect the
output. Even the small sample test added in this commit shows that we
currently record an unnecessary AddClipRect item for empty paint phases.

For now, the dump doesn't include every single property of an item, but
we can shape it to include more useful information as we iterate on it.
2025-07-13 19:15:05 +02:00