Commit graph

186 commits

Author SHA1 Message Date
Aliaksandr Kalenik
93bbdf1f55 LibWeb: Use compositor surface IDs for embedded content
Display lists kept canvas and nested navigable content alive through
ExternalContentSource objects. That made the resource graph depend on
process-local object identity instead of a stable surface handle, which
blocks compositor process isolation and made teardown-sensitive embedded
content harder to reason about.

Allocate CompositorSurfaceId values for canvases and child navigables,
publish their backing stores to the owning compositor, and paint them
with DrawCompositorSurface. Child navigables now publish to parent
compositors by CompositorContextId instead of raw object pointers, so
the in-process path uses the same stable addressing model required by a
remote compositor.

Clear and skip stale child surfaces during teardown, preserve Skia
canvas state while drawing compositor surfaces, and add display-list
coverage for canvas and iframe compositor surfaces. The nested navigable
async-scrolling baseline now expects DrawCompositorSurface.
2026-05-18 15:27:59 +02:00
Andreas Kling
541828dbb1 LibWeb: Respect overflow axes for wheel scrolling
Keep the compositor scroll node max offset as the real scroll range,
even for axes that cannot be scrolled by wheel input. Track wheel
scrollability separately so hidden axes are skipped during async wheel
scrolling without clamping away an existing programmatic offset.

Use the viewport-propagated root and body overflow values when deciding
whether viewport axes accept wheel input. Apply wheel deltas only on
axes that can be wheel-scrolled in async metadata and main-thread wheel
default actions, while preserving CSSOM scroll offsets on hidden axes.

Add async scrolling coverage for hidden-axis wheel targeting, preserved
programmatic hidden-axis offsets, and body overflow-x: hidden blocking a
horizontal viewport wheel scroll despite pseudo-element overflow.
2026-05-17 14:19:36 +02:00
Aliaksandr Kalenik
8906011a6b LibWeb: Synchronize display list resources via transactions
Display lists used to own the resource storage needed to replay their
command bytes. That kept the compositor tied to in-process object
ownership: sending a display list update also meant sharing the same
resource container with the recording side.

Move resource storage out of DisplayList and make display list updates
carry a transaction of resources to add and remove. Navigable now tracks
the resources referenced by the current display list, sends only the
delta to the compositor, and trims its recording-side storage to the
active set. The compositor applies those transactions to its own storage
before replacing the cached display list.

This still carries in-process resource objects, but it puts the
ownership boundary in the right place. Command bytes and resource
lifetime are now synchronized explicitly, which is the shape needed
before the compositor can receive serializable resource updates across a
process boundary.
2026-05-16 19:35:24 +02:00
Aliaksandr Kalenik
fd823becd7 LibWeb: Move backing store management into compositor thread
BackingStoreManager was owned by Navigable and allocated on the GC heap,
which left backing-store sizing decisions on the main thread even though
the compositor thread was already responsible for allocating the actual
surfaces. That split ownership makes it harder to isolate the compositor
behind a process boundary.

Move the manager into LibWeb's compositor code and let CompositorThread
thread data own it. The main thread now reports viewport size changes
through a compositor command, and the compositor uses that message to
decide when to resize and publish backing stores. The delayed shrink
timer remains with the main-thread CompositorThread facade so it can use
the Core event loop, but it now only sends another viewport-size update.

This removes the GC edge from Navigable, drops stale WebContent includes
and keeps the existing resize padding and delayed shrink behavior.
2026-05-16 16:36:05 +02:00
Aliaksandr Kalenik
649296ec07 LibWeb: Defer stale main-thread frames during async scroll
While an async scroll present was pending, the main thread could still
record and submit a display list from a stale scroll state before the
compositor-presented frame had reached the UI process. That stale
snapshot could replace the compositor-side scroll state and cause
visible back-and-forth jumps.

Check the async-scroll present defer condition before recording the
frame. The existing post-record check remains in place for races that
become pending while recording is in progress.
2026-05-16 14:50:46 +02:00
Aliaksandr Kalenik
429b7fc809 LibWeb: Rebase pending async scrolls over main-thread state
Async scrolling kept only the compositor-visible absolute scroll offset
for pending scrolls. If script changed the same scrolling box before
the main thread adopted the pending offset, adoption could write the
stale absolute compositor offset back to the DOM and lose the script
update.

Track the unadopted compositor delta alongside the absolute offset
used for compositor presentation. When fresh scroll state reaches the
compositor, and when the main thread adopts pending async scrolls,
apply that delta on top of the current main-thread offset instead of
assigning the old absolute value.

Adoption can run during the event-loop scroll steps, before the later
rendering-update layout pass has made paintables safe to query. Keep
element adoption on the stored DOM scroll offset and apply viewport
deltas through the navigable, so a dirty layout tree does not trip the
paintable freshness invariant.

The async scrolling text test covers the script-scroll race and also
dirties layout before adoption. The old paintable-box adoption path
crashed in that case.
2026-05-15 21:13:18 +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
Luke Wilde
de35994fc2 LibJS+LibWeb: Use the unified Visitor for Variant-holding members 2026-05-15 08:51:17 +02:00
Aliaksandr Kalenik
d353954993 LibWeb: Adopt async scroll offsets for nested scroll nodes
Nested scroll nodes were present in the async scroll tree, but the
compositor rejected any non-viewport wheel target and tracked only one
pending viewport offset. That prevented element scrollports from being
scrolled asynchronously and made compositor-side offsets impossible to
adopt after the main thread rebuilt scroll state.

Let async wheel commands target any scroll node selected by the tree.
Store every offset produced by a compositor scroll and reapply pending
offsets by stable ID across display-list and scroll-state updates. The
main thread now adopts viewport, element and pseudo-element offsets
before rendering-update observers run, including scroll event
bookkeeping for element scrollers.

Carry the wheel hit-test rejection reason through the enqueue path while
doing this, so main-thread and blocking-wheel regions remain explicit
rather than being collapsed into a missing target. Existing nested
async-scrolling text tests cover the successful nested scroll path.
2026-05-14 19:41:32 +02:00
Aliaksandr Kalenik
82b016ed19 LibWeb: Rebuild async scrolling from display list
Use compositor hit-test commands in the display list to rebuild async
wheel targets, and serialize the async scroll metadata needed to
reconstruct AsyncScrollingState from the same display-list snapshot.

Driving the async scroll tree off the display list rather than a
separately collected tree has a few benefits:

- No additional full paintable tree traversal is required, since the
  information needed by the compositor is gathered while recording
  the display list.
- The display list is already serializable, so the async scroll tree
  no longer needs its own serialization path.
- It is more debuggable, as the existing display list dump now also
  covers the data used to reconstruct the async scroll tree.
- In the future we will want to include other areas that can
  interfere with hit-testing; recording them during display list
  construction makes it straightforward to preserve a hit-testing
  order that matches painting order.
2026-05-13 18:36:07 +02:00
Andreas Kling
76fc843978 LibWeb: Run observers after compositor-only scrolls
Adopt pending async viewport scroll offsets before the rendering update
runs scroll steps and IntersectionObserver updates. Queue a rendering
update after the compositor applies an async viewport scroll so
compositor-only wheel scrolling can notify observers without waiting for
unrelated main-thread work.
2026-05-13 15:00:31 +02:00
Andreas Kling
d4c645b7a4 LibWeb: Preserve async scroll offset across scroll updates
Keep compositor-side scroll snapshots aligned with async viewport
scrolling when main-thread scroll state arrives while an async viewport
offset is pending. A stale scroll-state-only update could otherwise
replace the snapshot used for display list replay and wheel hit-testing
with an older viewport offset, even though the compositor had already
presented newer async scroll positions.

Teach AsyncScrollTree to set a node scroll offset directly and use it
when reconciling both display-list and scroll-state updates. Recompute
the main-thread viewport rect after display list recording as pending
async scroll adoption can move the viewport before presentation.
2026-05-13 11:00:59 +02:00
Andreas Kling
f07b55c2df LibWeb: Scroll the viewport on the compositor thread
Use the snapshot from the previous commit to let CompositorThread apply
experimental viewport wheel deltas when async scrolling is enabled. The
event handler first performs synchronous admission on the main thread,
then enqueues a compositor scroll command instead of mutating live
document scroll state directly.

Rasterize accepted scrolls through the same compositor presentation
path added earlier. The compositor stores the newest async viewport
offset so the next main-thread display-list recording can adopt it
before repainting, preventing older paints from snapping the visible
position backward.

Keep DOM wheel dispatch on the main thread. When the compositor already
performed the default action, dispatch the wheel as non-cancelable and
suppress a second default scroll. Non-viewport targets, nested
scrollers, and pages with blocking wheel listeners stay synchronous.
2026-05-12 20:57:08 +02:00
Andreas Kling
1b810a5e15 LibWeb: Present frames through Compositor IPC
Introduce a dedicated Compositor IPC channel between the UI process and
WebContent. Use it for backing-store setup, presented bitmap delivery,
and bitmap-specific ready_to_paint acknowledgements.

This makes CompositorThread the single owner of frame presentation
bookkeeping before async scrolling starts producing frames without the
main thread.

Remove old paint and backing-store messages from WebContentClient and
PageClient so the UI process no longer observes two presentation
protocols.
2026-05-12 20:57:08 +02:00
Andreas Kling
584b2748ee LibWeb: Move RenderingThread into Compositor
Create Libraries/LibWeb/Compositor and make the existing rendering
thread the first owner in that subsystem. Rename RenderingThread to
CompositorThread so later commits can grow it into the presentation
owner without leaving that vocabulary in HTML.

Keep display-list rasterization and delivery behavior unchanged in this
commit. Add COMPOSITOR_DEBUG to AK/Debug.h.in in the same step so
compositor diagnostics live beside the rest of the project-wide debug
toggles from the start of the stack.
2026-05-12 20:57:08 +02:00
Aliaksandr Kalenik
671cc8595a LibWeb: Send scroll-state-only updates to the rendering thread
When nothing invalidates the display list between frames, push only an
updated scroll state snapshot to the rendering thread instead of
handing it the display list again.

This is preparation for moving rendering to a separate process, where
sending the display list across the process boundary on every frame
would be expensive.
2026-05-11 22:52:38 +02:00
Timothy Flynn
b221d7fe8b LibWeb+LibWebView+WebContent+UI: Add an action to cut text 2026-05-07 09:13:06 -04:00
Aliaksandr Kalenik
568b7ce7ea LibWeb: Make Paintable tree ref-counted
The Paintable tree and its supplemental painting data structures were
GC allocated because that was the easiest way to manage it and avoid
leaks introduced by ref cycles. This included the Paintable subclasses
themselves plus StackingContext, ChromeWidget, Scrollbar, ResizeHandle,
and scroll-frame state.

We are now trying to reduce GC allocation churn on layout and painting
updates, so keeping this short-lived rendering tree outside the JS heap
is a better fit. Move Paintable to RefCountedTreeNode, make painting
helpers ref-counted or weakly reference Paintables, and update the
layout and event-handler call sites to use RefPtr/WeakPtr ownership.
2026-05-07 15:03:44 +02:00
Jelle Raaijmakers
b488b7e7b1 LibWeb: Propagate line box borders debug toggle to child navigables
Only the top navigable received this setting; existing and new
descendant navigables never showed these debug boxes.
2026-05-05 23:47:23 +02:00
Aliaksandr Kalenik
5854bf10e6 LibWeb: Give the rendering thread its own Skia backend context
Sharing a single SkiaBackendContext between the main thread and the
rendering thread forces locking around every GPU operation. Now that
ImmutableBitmaps are context-neutral, the SkImage cache is per-painter,
and PaintingSurface accepts an explicit context, have the rendering
thread create its own GPU context on startup and use it for the
display-list player and backing store allocation.

This sets up the next commit to remove the cross-thread locking
machinery entirely.
2026-05-04 20:12:21 +02:00
Andreas Kling
e5b9dbbe96 LibWeb: Run inform_the_navigation_api_about_aborting inline
The spec says to run inline if on the navigable's active window's
relevant agent's event loop, otherwise queue. WebContent is always on
the main thread event loop, so this collapses to "always inline".
Queueing here let the abort cancel a navigate event created later in
the same task, instead of the one it was queued for.
2026-04-27 17:24:13 +02:00
Shannon Booth
8642801889 LibWeb: Set fragment scripting mode from the context document
This corresponds with the editorial change to the HTML standard
introducing the parsing mode enum of:

01c45cede

And a follow up normative change of:

508706c80

Making fragment parsing derive its scripting mode from the context
document.
2026-04-14 23:01:36 +02:00
Aliaksandr Kalenik
d9eec0d204 LibWeb: Replace ScrollStateSnapshotByDisplayList with a plain snapshot
Cleanup following the per-Navigable rasterization split: since each
Navigable now rasterizes its own display list independently, the HashMap
keyed on display list was always populated with exactly one entry. Pass
the ScrollStateSnapshot directly through the display list player and
rendering thread instead.
2026-04-07 15:09:43 +02:00
Aliaksandr Kalenik
ad2ee4fe7a LibWeb: Rasterize each Navigable independently on its own thread
Previously, iframes were rasterized synchronously as nested display
lists inside their parent's display list: the parent's paint walk called
record_display_list() on each hosted iframe document and emitted a
PaintNestedDisplayList command that the player would recurse into. Only
the top-level traversable's RenderingThread was ever active, even though
every Navigable already owned one.

The motivation for splitting this apart:
- Work in the outer document no longer has to be re-recorded when only
  an iframe changes. The parent's cached display list now references the
  iframe's rasterized output live via an ExternalContentSource, so an
  iframe invalidation just needs the parent's display list replayed, not
  re-recorded.
- Each iframe now has a self-contained rasterization pipeline, which is
  prep work for moving iframes into separate sandboxed processes.
2026-04-07 15:09:43 +02:00
Shannon Booth
bb0f244667 LibWeb: Remove ShadowRealm HTML integration 2026-04-05 13:57:58 +02:00
Aliaksandr Kalenik
e875f2b18b LibWeb: Make SessionHistoryEntry and DocumentState ref-counted
WebContent process keeps session history entries for pages we have
navigated away from. Before this change, those entries could prevent GC
objects (e.g. PolicyContainer and its CSP PolicyList) from being
collected, since the GC-allocated SHE/DocumentState held live GC::Ref
pointers into the heap.

By making both classes RefCounted and storing SerializedPolicyContainer
instead of a live PolicyContainer, history entries no longer keep alive
any GC objects. This eliminates the leak and is also a step toward
moving the session history entry tree to the UI process.
2026-04-03 14:20:09 +02:00
Psychpsyo
44ef574902 LibWeb: Properly set visibility state for nested documents
This cannot happen inside the Make Active algorithm, since that gets
called during document creation, which commonly happens before the
document's navigable is created.

Aligns us with a recent spec change and rids us of some AD_HOC
behavior.
2026-04-01 17:26:46 +02:00
Aliaksandr Kalenik
4985dabf3d LibWeb: Replace cached navigable with Navigable-maintained back-pointer
Now that Navigable directly owns its active document (m_active_document)
we can have Navigable maintain a back-pointer on Document instead of
using the old cache-with-validation pattern that fell back to a linear
scan of all navigables via navigable_with_active_document().
2026-04-01 11:51:43 +02:00
Aliaksandr Kalenik
2645695fdd LibWeb: Make Navigable directly own its active document
Previously, the active document's lifecycle was bound to
SessionHistoryEntry via DocumentState. The ownership chain was:
  Navigable → SessionHistoryEntry → DocumentState → Document

This made it impossible to move SessionHistoryEntry to the UI process
(which cannot own DOM::Document). This commit decouples the two by
giving Navigable a direct m_active_document field that serves as the
authoritative source for active_document().

- Navigable owns m_active_document directly; active_document() reads
  from it instead of going through the active session history entry.

- DocumentState no longer holds a Document pointer. Instead, it stores
  a document_id for "same document?" checks. Same-document navigations
  share a DocumentState and thus the same document_id, while
  cross-document navigations create a new DocumentState with a new ID.

- A pending_document parameter is threaded through
  finalize_a_cross_document_navigation → apply_the_push_or_replace →
  apply_the_history_step so the newly created document reaches
  activation without being stored on DocumentState.

- For traversal, the population output delivers the document.
  A resolved_document is computed per continuation from either the
  pending document, the population output, or the current active
  document (for same-document traversals).
2026-04-01 11:51:43 +02:00
Aliaksandr Kalenik
f3ea882d6e LibWeb: Remove "signal to continue SHTQ" from document loading
This promise was previously used to signal the session history traversal
queue that it could continue processing, but is no longer needed.
2026-04-01 06:47:59 +02:00
Shannon Booth
0086a7899d LibWeb: Remove some uneeded navigation error propogation
We should not have any errors to propogate down these paths.
2026-04-01 04:41:11 +02:00
Aliaksandr Kalenik
2a69fd4c52 LibWeb: Replace spin_until in apply_the_history_step with state machine
Replace the blocking spin_processing_tasks_with_source_until calls
in apply_the_history_step_after_unload_check() with an event-driven
ApplyHistoryStepState GC cell that tracks 5 phases, following the
same pattern used by CheckUnloadingCanceledState.

Key changes:
- Introduce ApplyHistoryStepState with phases:
  WaitingForDocumentPopulation, ProcessingContinuations,
  WaitingForChangeJobCompletion, WaitingForNonChangingJobs and Completed
- Add on_complete callbacks to apply_the_push_or_replace_history_step,
  finalize_a_same_document_navigation,
  finalize_a_cross_document_navigation, and
  update_for_navigable_creation_or_destruction
- Remove spin_until from Document::open()
- Use null-document tasks for non-changing navigable updates and
  document unload/destroy to avoid stuck tasks when documents become
  non-fully-active
- Defer completely_finish_loading when document has no navigable yet,
  and re-trigger post-load steps in activate_history_entry for documents
  that completed loading before activation

Co-Authored-By: Shannon Booth <shannon@serenityos.org>
2026-03-31 09:47:59 +02:00
Aliaksandr Kalenik
df96b69e7a LibWeb: Replace spin_until in HTMLParser::the_end() with state machine
HTMLParser::the_end() had three spin_until calls that blocked the event
loop: step 5 (deferred scripts), step 7 (ASAP scripts), and step 8
(load event delay). This replaces them with an HTMLParserEndState state
machine that progresses asynchronously via callbacks.

The state machine has three phases matching the three spin_until calls:
- WaitingForDeferredScripts: loops executing ready deferred scripts
- WaitingForASAPScripts: waits for ASAP script lists to empty
- WaitingForLoadEventDelay: waits for nothing to delay the load event

Notification triggers re-evaluate the state machine when conditions
change: HTMLScriptElement::mark_as_ready, stylesheet unblocking in
StyleElementBase/HTMLLinkElement, did_stop_being_active_document, and
DocumentLoadEventDelayer decrements. NavigableContainer state changes
(session history readiness, content navigable cleared, lazy load flag)
also trigger re-evaluation of the load event delay check.

Key design decisions and why:

1. Microtask checkpoint in schedule_progress_check(): The old spin_until
   called perform_a_microtask_checkpoint() before checking conditions.
   This is critical because HTMLImageElement::update_the_image_data step
   8 queues a microtask that creates the DocumentLoadEventDelayer.
   Without the checkpoint, check_progress() would see zero delayers and
   complete before images start delaying the load event.

2. deferred_invoke in schedule_progress_check():
   I tried Core::Timer (0ms), queue_global_task, and synchronous calls.
   Timers caused non-deterministic ordering with the HTML event loop's
   task processing timer, leading to image layout tests failing (wrong
   subtest pass/fail patterns). Synchronous calls fired too early during
   image load processing before dimensions were set, causing 0-height
   images in layout tests. queue_global_task had task ordering issues
   with the session history traversal queue. deferred_invoke runs after
   the current callback returns but within the same event loop pump,
   giving the right balance.

3. Navigation load event guard (m_navigation_load_event_guard): During
   cross-document navigation, finalize_a_cross_document_navigation step
   2 calls set_delaying_load_events(false) before the session history
   traversal activates the new document. This creates a transient state
   where the parent's load event delay check sees the about:blank (which
   has ready_for_post_load_tasks=true) as the active document and
   completes prematurely.
2026-03-28 23:14:55 +01:00
Aliaksandr Kalenik
200c72ae5c LibWeb: Remove spin_until from check_if_unloading_is_canceled()
Replace the two spin_processing_tasks_with_source_until() calls in
TraversableNavigable::check_if_unloading_is_canceled() with a
callback-based GC cell (CheckUnloadingCanceledState) that tracks
completion across both phases (traverse navigate event + per-document
beforeunload handlers) and invokes a callback when done.

This required making check_if_unloading_is_canceled() async
(callback-based), splitting apply_the_history_step() into pre-check
and continuation parts, and updating all callers to move session
history traversal queue promise resolution into callbacks.

The trusted-event test is rebaselined because beforeunload now fires
as a queued NavigationAndTraversal task rather than being processed
inline by spin_until. This allows the unhandledrejection microtask
to run before the beforeunload task, swapping their order.
2026-03-28 04:17:21 +01:00
Jelle Raaijmakers
450c15c63b LibWeb: Finalize session history entry during async sniff bytes
In e97de2e7e3 we added a guard to prevent
crashes, but we should've still finalized the session history entry.
2026-03-27 05:18:30 +01:00
Aliaksandr Kalenik
ce81f16530 LibWeb: Remove SessionHistoryEntry::clone() and DocumentState::clone()
With apply_to() now self-contained (carrying its own replacement
DocumentState rather than reading from the live entry), the clone at
the traversal call site is no longer needed.

The clone previously served two purposes:
1. Input snapshot: freeze entry fields before deferred population.
   Now solved by changing populate_session_history_entry_document() to
   take explicit input parameters, snapshotted before the
   deferred_invoke.
2. Output isolation: absorb apply_to() and post-population adjustments
   without mutating the live entry during unload. Now solved by storing
   the PopulateSessionHistoryEntryDocumentOutput on the continuation
   state and deferring all mutations (including the origin-based
   classic_history_api_state reset and navigable_target_name clear)
   to after_potential_unload.

The post-population adjustments run unconditionally in
after_potential_unload, covering both the population path and the
non-population path (e.g. traversal to an already-populated error
entry).
2026-03-27 02:34:55 +01:00
Aliaksandr Kalenik
49690f1e1e LibWeb: Separate input/output in populate_session_history_entry_document
Previously, populate_session_history_entry_document() took a
SessionHistoryEntry as both input and output — reading URL and
document_state fields while also mutating the entry across a chain of
async functions. This made it very hard to reason about data flow.

Refactor the internal helpers
(create_navigation_params_from_a_srcdoc_resource,
create_navigation_params_by_fetching, NavigationParamsFetchStateHolder,
perform_navigation_params_fetch) to take individual field values instead
of reading from the entry, and accumulate redirect mutations on the
state holder rather than writing them to the entry immediately.

Introduce PopulateSessionHistoryEntryDocumentOutput, a GC cell that
collects all mutations (document, redirect URL, classic history API
state, replacement document state, resource cleared flag, and
finalization data). The completion_steps callback now receives this
output object (or nullptr on cancellation), and callers apply it to the
entry via apply_to().

The replacement DocumentState for the redirect path is built eagerly at
redirect time from values captured on the state holder, making
apply_to() fully self-contained — it never reads from the target entry's
live document_state. This is important for the traversal path where the
entry may be mutated during unload (e.g. window.name writes
navigable_target_name through the active session history entry).
2026-03-27 02:34:55 +01:00
Jelle Raaijmakers
e97de2e7e3 LibWeb: Check for an active browsing context in the sniff bytes callback
The navigable can lose its browsing context while waiting for network
tasks to complete. Fixes a crash seen in the `encoding` WPT tests.
2026-03-26 18:48:27 +01:00
Shannon Booth
346fa16b1e LibWeb: Don't cancel pending navigations in navigate to a javascript URL
Other browsers appear to only do this for form submission, not for
all javascript URL navigations. Let's remove the handling in the
general javascript URL navigation handling so that our behaviour
diference to other browsers is limited specifically to form
elements, instead of the general case.

Unfortunately this does (expectedly) cause the test added in
3e0ea4f62 to start timing out, so that test is marked as skipped.
2026-03-25 22:05:25 +01:00
Timothy Flynn
58791db818 AK+LibWeb: Move generation of random UUIDs into AK
This will let us use this more outside of LibWeb more easily.

Stop handling tiny OOM while we are here.
2026-03-24 12:04:50 -04:00
Jelle Raaijmakers
dd6d17d60d LibWeb: Don't crash accessing stale nested navigable paintable
The scroll state collection loop in
record_display_list_and_scroll_state() called paintable() on hosted
documents, which asserts layout is up to date. This crashes when a
nested document has stale layout but a cached display list, e.g. a
render-blocked iframe whose DOM was modified by document.open().
Since scroll offsets are independent of layout freshness, use
unsafe_paintable() to skip the assertion.
2026-03-24 12:47:02 +01: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
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
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
Aliaksandr Kalenik
eae94a8a46 LibWeb: Route repaint requests through paintables, not Document
Rename Document::set_needs_display() to set_needs_repaint() and make it
private. External callers must now go through Node/Paintable which
route the request to the document internally.

Fix one existing misuse in AnimationEffect that was calling
document-level set_needs_display() instead of routing through the
target element's paintable.

This is preparation for per-paintable display list command caching:
repaint requests must go through specific paintables so their cached
command lists can be invalidated.
2026-03-04 19:35:45 +01:00
Tim Ledbetter
65b08e7d9f LibWeb: Use correct point type in to_top_level_position()
This occurred because 90a211b changed the return type of
`transform_rect_to_viewport()` but 7fc945d didn't take this into
account.
2026-03-01 09:54:59 +00:00
Tim Ledbetter
7fc945d524 LibWeb: Account for scroll and transforms in to_top_level_position()
This change means the right click context menu is displayed in the right
place when clicking inside an iframe on a scrolled page, including when
the iframe has CSS transforms applied to it.
2026-03-01 08:31:41 +00:00
Andreas Kling
a146225331 LibWeb: Use unsafe layout/paintable accessors where appropriate
Add unsafe_layout_node(), unsafe_paintable(), and unsafe_paintable_box()
accessors that skip layout-staleness verification. These are for use in
contexts where accessing layout/paintable data is legitimate despite
layout not being up to date: tree construction, style recalculation,
painting, animation interpolation, DOM mutation, and invalidation
propagation.

Also add wrapper APIs on Node to centralize common patterns:
- set_needs_display() wraps if (unsafe_paintable()) ...set_needs_display
- set_needs_paint_only_properties_update() wraps similar
- set_needs_layout_update() wraps if (unsafe_layout_node()) ...

And add Document::layout_is_up_to_date() which checks whether layout
tree update flags are all clear.
2026-02-26 21:09:08 +01:00