Commit graph

6 commits

Author SHA1 Message Date
Aliaksandr Kalenik
21245e7adb LibWeb: Follow paint order for async wheel hit testing
Async wheel routing used scroll node scrollports as the hit-test
surface. That works while the scrollable content is the topmost content
under the pointer, but it ignores the rest of the painted scene. A
sibling with a higher z-index can visually cover a nested scroller
without being part of that scroller's subtree. In that case the
compositor could still pick the covered scroller from its scrollport
rect and consume the wheel event, even though normal hit testing would
target the covering element and let the page or an ancestor handle the
scroll.

Record wheel hit-test targets as display-list metadata in paint order
and resolve each target to the scroll frame that should receive wheel
deltas. The compositor can then walk those targets from front to back,
preserve non-passive wheel regions as main-thread barriers, and only
scroll the node associated with the topmost hit-testable box.
2026-05-14 15:32:03 +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
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
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
ce1521441f LibWeb: Reject async wheels over nested navigables
Add main-thread wheel regions to async scrolling snapshots for embedded
navigable containers. A viewport scroll node covers the iframe box, so
the compositor must explicitly treat that rectangle as a synchronous
routing boundary before it accepts a UI-process wheel bypass.

Hit-test those regions in both internals admission and the compositor's
async enqueue path. The enqueue path now stores the hit-tested scroll
target in the queued command, ensuring accepted input is applied to the
same target that passed admission instead of being reselected later.

Add a text test for iframe routing. A wheel over the nested navigable is
rejected for async scrolling, while a wheel over the parent viewport
remains admitted.
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