Bug 1259296 - Scroll snap in the compositor in response to wheel events. r=kats

MozReview-Commit-ID: 9fOlssstgvR

--HG--
extra : source : fbdee753c4618cbc1a7c79e3ec07b7479f93a05d
extra : histedit_source : dd42dfa282ea2e14fe5c9e028acc699746fcf8bc
This commit is contained in:
Botond Ballo 2016-04-04 17:43:21 -04:00
Родитель 4d0aaaafea
Коммит 4058840cb9
3 изменённых файлов: 114 добавлений и 31 удалений

Просмотреть файл

@ -1819,6 +1819,11 @@ nsEventStatus AsyncPanZoomController::OnScrollWheel(const ScrollWheelInput& aEve
mozilla::Telemetry::Accumulate(mozilla::Telemetry::SCROLL_INPUT_METHODS,
(uint32_t) ScrollInputMethodForWheelDeltaType(aEvent.mDeltaType));
// Wheel events from "clicky" mouse wheels trigger scroll snapping to the
// next snap point. Check for this, and adjust the delta to take into
// account the snap point.
bool scrollSnapping = MaybeAdjustDeltaForScrollSnapping(delta, aEvent);
switch (aEvent.mScrollMode) {
case ScrollWheelInput::SCROLLMODE_INSTANT: {
ScreenPoint distance = ToScreenCoordinates(
@ -1850,6 +1855,14 @@ nsEventStatus AsyncPanZoomController::OnScrollWheel(const ScrollWheelInput& aEve
// update it.
ReentrantMonitorAutoEnter lock(mMonitor);
if (scrollSnapping) {
// If we're scroll snapping use a smooth scroll animation to get
// the desired physics. Note that SmoothScrollTo() will re-use an
// existing smooth scroll animation if there is one.
CSSPoint snapPoint = mFrameMetrics.GetScrollOffset() + (delta / mFrameMetrics.GetZoom());
SmoothScrollTo(snapPoint);
} else {
// Otherwise, use a wheel scroll animation, also reusing one if possible.
if (mState != WHEEL_SCROLL) {
CancelAnimation();
SetState(WHEEL_SCROLL);
@ -1868,6 +1881,7 @@ nsEventStatus AsyncPanZoomController::OnScrollWheel(const ScrollWheelInput& aEve
WheelScrollAnimation* animation = mAnimation->AsWheelScrollAnimation();
animation->Update(aEvent.mTimeStamp, deltaInAppUnits, nsSize(velocity.x, velocity.y));
}
break;
}
}
@ -3937,13 +3951,14 @@ void AsyncPanZoomController::ShareCompositorFrameMetrics() {
}
}
void AsyncPanZoomController::ScrollSnapNear(const CSSPoint& aDestination) {
Maybe<CSSPoint> AsyncPanZoomController::FindSnapPointNear(
const CSSPoint& aDestination, nsIScrollableFrame::ScrollUnit aUnit) {
mMonitor.AssertCurrentThreadIn();
APZC_LOG("%p scroll snapping near %s\n", this, Stringify(aDestination).c_str());
CSSRect scrollRange = mFrameMetrics.CalculateScrollRange();
if (Maybe<nsPoint> snapPoint = ScrollSnapUtils::GetSnapPointForDestination(
mScrollMetadata.GetSnapInfo(),
nsIScrollableFrame::DEVICE_PIXELS,
aUnit,
CSSSize::ToAppUnits(mFrameMetrics.CalculateCompositedSizeInCssPixels()),
CSSRect::ToAppUnits(scrollRange),
CSSPoint::ToAppUnits(mFrameMetrics.GetScrollOffset()),
@ -3953,8 +3968,15 @@ void AsyncPanZoomController::ScrollSnapNear(const CSSPoint& aDestination) {
// of the scroll frame's scroll range. Clamp it here (this matches the
// behaviour of the main-thread code path, which clamps it in
// nsGfxScrollFrame::ScrollTo()).
cssSnapPoint = scrollRange.ClampPoint(cssSnapPoint);
SmoothScrollTo(cssSnapPoint);
return Some(scrollRange.ClampPoint(cssSnapPoint));
}
return Nothing();
}
void AsyncPanZoomController::ScrollSnapNear(const CSSPoint& aDestination) {
if (Maybe<CSSPoint> snapPoint =
FindSnapPointNear(aDestination, nsIScrollableFrame::DEVICE_PIXELS)) {
SmoothScrollTo(*snapPoint);
}
}
@ -3996,5 +4018,29 @@ void AsyncPanZoomController::ScrollSnapToDestination() {
}
}
bool AsyncPanZoomController::MaybeAdjustDeltaForScrollSnapping(
ParentLayerPoint& aDelta, const ScrollWheelInput& aEvent)
{
// Don't scroll snap for pixel scrolls. This matches the main thread
// behaviour in EventStateManager::DoScrollText().
if (aEvent.mDeltaType == ScrollWheelInput::SCROLLDELTA_PIXEL) {
return false;
}
ReentrantMonitorAutoEnter lock(mMonitor);
CSSPoint scrollOffset = mFrameMetrics.GetScrollOffset();
CSSToParentLayerScale2D zoom = mFrameMetrics.GetZoom();
CSSPoint destination = mFrameMetrics.CalculateScrollRange().ClampPoint(
scrollOffset + (aDelta / zoom));
nsIScrollableFrame::ScrollUnit unit =
ScrollWheelInput::ScrollUnitForDeltaType(aEvent.mDeltaType);
if (Maybe<CSSPoint> snapPoint = FindSnapPointNear(destination, unit)) {
aDelta = (*snapPoint - scrollOffset) * zoom;
return true;
}
return false;
}
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -25,6 +25,7 @@
#include "Layers.h" // for Layer::ScrollDirection
#include "LayersTypes.h"
#include "mozilla/gfx/Matrix.h"
#include "nsIScrollableFrame.h"
#include "nsRegion.h"
#include "PotentialCheckerboardDurationTracker.h"
@ -622,15 +623,6 @@ protected:
// Common processing at the end of a touch block.
void OnTouchEndOrCancel();
// Snap to a snap position nearby the current scroll position, if appropriate.
void ScrollSnap();
// Snap to a snap position nearby the destination predicted based on the
// current velocity, if appropriate.
void ScrollSnapToDestination();
// Helper function for ScrollSnap() and ScrollSnapToDestination().
void ScrollSnapNear(const CSSPoint& aDestination);
uint64_t mLayersId;
RefPtr<CompositorBridgeParent> mCompositorBridgeParent;
@ -763,7 +755,6 @@ public:
AsyncTransformComponentMatrix GetCurrentAsyncTransformWithOverscroll(AsyncMode aMode) const;
/* ===================================================================
* The functions and members in this section are used to manage
* the state that tracks what this APZC is doing with the input events.
@ -1156,6 +1147,35 @@ private:
// be checkerboarding. Combined with other info, this allows us to meaningfully
// say how frequently users actually encounter checkerboarding.
PotentialCheckerboardDurationTracker mPotentialCheckerboardTracker;
/* ===================================================================
* The functions in this section are used for CSS scroll snapping.
*/
// If |aEvent| should trigger scroll snapping, adjust |aDelta| to reflect
// the snapping (that is, make it a delta that will take us to the desired
// snap point). Returns true iff. the delta was so adjusted.
bool MaybeAdjustDeltaForScrollSnapping(ParentLayerPoint& aDelta,
const ScrollWheelInput& aEvent);
// Snap to a snap position nearby the current scroll position, if appropriate.
void ScrollSnap();
// Snap to a snap position nearby the destination predicted based on the
// current velocity, if appropriate.
void ScrollSnapToDestination();
// Snap to a snap position nearby the provided destination, if appropriate.
void ScrollSnapNear(const CSSPoint& aDestination);
// Find a snap point near |aDestination| that we should snap to.
// Returns the snap point if one was found, or an empty Maybe otherwise.
// |aUnit| affects the snapping behaviour (see ScrollSnapUtils::
// GetSnapPointForDestination). It should generally be determined by the
// type of event that's triggering the scroll.
Maybe<CSSPoint> FindSnapPointNear(const CSSPoint& aDestination,
nsIScrollableFrame::ScrollUnit aUnit);
};
} // namespace layers

Просмотреть файл

@ -6,8 +6,9 @@
#ifndef InputData_h__
#define InputData_h__
#include "nsIDOMWheelEvent.h"
#include "nsDebug.h"
#include "nsIDOMWheelEvent.h"
#include "nsIScrollableFrame.h"
#include "nsPoint.h"
#include "nsTArray.h"
#include "Units.h"
@ -577,6 +578,22 @@ public:
return SCROLLDELTA_LINE;
}
static nsIScrollableFrame::ScrollUnit
ScrollUnitForDeltaType(ScrollDeltaType aDeltaType)
{
switch (aDeltaType) {
case SCROLLDELTA_LINE:
return nsIScrollableFrame::LINES;
case SCROLLDELTA_PAGE:
return nsIScrollableFrame::PAGES;
case SCROLLDELTA_PIXEL:
return nsIScrollableFrame::DEVICE_PIXELS;
default:
MOZ_CRASH();
}
return nsIScrollableFrame::LINES;
}
enum ScrollMode
{
SCROLLMODE_INSTANT,