Commit 49365ac1 authored by Rahul Arakeri's avatar Rahul Arakeri Committed by Commit Bot

[Compositor threaded scrollbar scrolling] Added design doc.

This CL adds a design doc for the feature in a markdown format
under cc/input.

Bug: 973568
Change-Id: I1686bc4e73dfb1113f2ab301d23756c080ae4323
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1982712
Commit-Queue: Rahul Arakeri <arakeri@microsoft.com>
Reviewed-by: default avatarDavid Bokan <bokan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#727794}
parent 9cdb801d
......@@ -104,3 +104,51 @@ browser window.
Also called the "Layout Viewport" in web/Blink terminology. This is the main
"content scroller" in a given page, typically the document (`<html>`) element.
This is the scroller to which position: fixed elements remain fixed to.
## Compositor threaded scrollbar scrolling
Contact: arakeri@microsoft.com
### Introduction
Scrollbar scrolling using the mouse happens on the main thread in Chromium. If
the main thread is busy (due to reasons like long running JS, etc), scrolling
by clicking on the scrollbar will appear to be janky. To provide a better user
experience, we have enabled off-main-thread scrollbar interaction for composited
scrollers. This frees up the main thread to perform other tasks like processing
javascript, etc. The core principal here is that MouseEvent(s) are converted to
GestureEvent(s) and dispatched in a VSync aligned manner. Choosing this design
also helps with the grand scrolling unification.
### High-level design:
![Image has moved. Contact arakeri@microsoft.com](https://github.com/rahul8805/CompositorThreadedScrollbarDocs/blob/master/designDiag.PNG?raw=true)
### Core Implementation Details:
This is the basic principle:
- A new class called "cc::ScrollbarController" manages the state and behavior
related to translating Mouse events into GestureScrolls.
- When a kMouseDown arrives at InputHandlerProxy::RouteToTypeSpecificHandler,
it gets passed to the ScrollbarController to determine if this event will cause
scrollbar manipulation.
- The ScrollbarController returns enough data to the InputHandlerProxy to inject
gesture events to the CompositorThreadEventQueue (CTEQ). For example, in the
case of a mouse down, a GestureScrollBegin(GSB) and a GestureScrollUpdate(GSU)
are added to the CTEQ.
- Depending on the action, there can be more synthetic GSUs that get added to
the CTEQ. (For eg: thumb drags).
- The WebInputEvent::kMouseUp is responsible for cleaning up the scroll state.
- GestureScrollBegin gets dispatched first. This sets up the scroll_node and
other state necessary to begin scrolling in LayerTreeHostImpl::ScrollBegin.
This is as usual for all gesture based scrolls.
- GestureScrollUpdate(s) get handled next. Scroll deltas get applied to the node
that was set up during GestureScrollBegin. Depending on the type of scroll,
this may lead to an animated scroll (eg: LayerTreeHostImpl::ScrollAnimated for
autoscroll/mouse clicks) or a regular scroll. (eg: LayerTreeHostImpl::ScrollBy
for thumb drags)
- Finally, the GestureScrollEnd is dispatched and it clears the scrolling state
(like the CurrentlyScrollingNode) and calls SetNeedsCommitOnImplThread().
### Miscellaneous resources.
- [Demo page](https://rahul8805.github.io/DemoPages/BouncyMoon.html)
- [Lightning talk](https://www.youtube.com/watch?v=FOCHCuGA_MA&t=1150s)
- [input-dev thread](https://groups.google.com/a/chromium.org/forum/#!topic/input-dev/6ACOSDoAik4)
- [Full design doc](https://docs.google.com/document/d/1JqykSXnCkqwA1E3bUhhIi-IgEvM9HZdKtIu_S4Ncm6o/edit#heading=h.agf18oiankjh)
......@@ -11,6 +11,106 @@
#include "cc/layers/layer_impl.h"
#include "cc/layers/painted_scrollbar_layer_impl.h"
// High level documentation:
// https://source.chromium.org/chromium/chromium/src/+/master:cc/input/README.md
// Click scrolling.
// - A click is considered as a kMouseDown and a kMouseUp in quick succession.
// Every click on a composited non-custom arrow leads to 3 GestureEvents in
// total.
// - GSB and GSU on get queued in the CTEQ on mousedown and a GSE on mouseup.
// - The delta scrolled is constant at 40px (scaled by the device_scale_factor)
// for scrollbar arrows and a function of the viewport length in the case of
// track autoscroll.
// Thumb dragging.
// - The sequence of events in the CTEQ would be something like GSB, GSU, GSU,
// GSU..., GSE
// - On every pointermove, the scroll delta is determined is as current pointer
// position - the point at which we got the initial mousedown.
// - The delta is then scaled by the scroller to scrollbar ratio so that
// dragging the thumb moves the scroller proportionately.
// - This ratio is calculated as:
// (scroll_layer_length - viewport_length) /
// (scrollbar_track_length - scrollbar_thumb_length)
// - On pointerup, the GSE clears state as mentioned above.
// VSync aligned autoscroll.
// - Autoscroll is implemented as a "scroll animation" which has a linear timing
// function (see cc::LinearTimingFunction) and a curve with a constant velocity.
// - The main thread does autoscrolling by pumping events at 50ms interval. To
// have a similar kind of behaviour on the compositor thread, the autoscroll
// velocity is set to 800px per second for scrollbar arrows.
// - For track autoscrolling however, the velocity is a function of the viewport
// length.
// - Based on this velocity, an autoscroll curve is created.
// - An autoscroll animation is set up. (via
// LayerTreeHostImpl::ScrollAnimationCreateInternal) on the the known
// scroll_node and the scroller starts animation when the pointer is held.
// Nuances:
// Thumb snapping.
// - During a thumb drag, if a pointer moves too far away from the scrollbar
// track, the thumb is supposed to snap back to it original place (i.e to the
// point before the thumb drag started).
// - This is done by having an imaginary no_snap_rect around the scrollbar
// track. This extends about 8 times the width of the track on either side. When
// a manipulation is in progress, the mouse is expected to stay within the
// bounds of this rect. Assuming a standard scrollbar, 17px wide, this is how
// it'd look like.
// https://github.com/rahul8805/CompositorThreadedScrollbarDocs/blob/master/snap.PNG?raw=true
// - When a pointerdown is received, record the original offset of the thumb.
// - On every pointermove, check if the pointer is within the bounds of the
// no_snap_rect. If false, snap to the initial_scroll_offset and stop processing
// pointermove(s) until the pointer reenters the bounds of the rect.
// - The moment the mouse re-enters the bounds of the no_snap_rect, we snap to
// the initial_scroll_offset + event.PositionInWidget.
// Thumb anchoring.
// - During a thumb drag, if the pointer runs off the track, there should be no
// additional scrolling until the pointer reenters the track and crosses the
// original mousedown point.
// - This is done by sending "clamped" deltas. The amount of scrollable delta is
// computed using LayerTreeHostImpl::ComputeScrollDelta.
// - Since the deltas are clamped, overscroll doesn't occur if it can't be
// consumed by the CurrentlyScrollingNode.
// Autoscroll play/pause.
// - When the pointer moves in and out of bounds of a scrollbar part that can
// initiate autoscrolls (like arrows or track), the autoscroll animation is
// expected to play or pause accordingly.
// - On every ScrollbarController::WillBeginMainFrame, the pointer location is
// constantly checked and if it is outside the bounds of the scrollbar part that
// initiated the autoscroll, the autoscroll is stopped.
// - Similarly, when the pointer reenters the bounds, autoscroll is restarted
// again. All the vital information during autoscrolling such the velocity,
// direction, scroll layer length etc is held in
// cc::ScrollbarController::AutoscrollState.
// Shift + click.
// - Doing a shift click on any part of a scrollbar track is supposed to do an
// instant scroll to that location (such that the thumb is still centered on the
// pointer).
// - When the MouseEvent reaches the
// InputHandlerProxy::RouteToTypeSpecificHandler, if the event is found to have
// a "Shift" modifier, the ScrollbarController calculates the offset based on
// the pointers current location on the track.
// - Once the offset is determined, the InputHandlerProxy creates a GSU with
// state that tells the LayerTreeHostImpl to perform a non-animated scroll to
// the offset.
// Continuous autoscrolling.
// - This builds on top of the autoscolling implementation. "Continuous"
// autoscrolling is when an autoscroll is in progress and the size of the
// content keeps increasing. For eg: When you keep the down arrow pressed on
// websites like Facebook, the autoscrolling is expected to keep on going until
// the mouse is released.
// - This is implemented by monitoring the length of the scroller layer at every
// frame and if the length increases (and if autoscroll in the forward direction
// is already in progress), the old animation is aborted and a new autoscroll
// animation with the new scroller length is kicked off.
namespace cc {
// This class is responsible for hit testing composited scrollbars, event
// handling and creating gesture scroll deltas.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment