Skip to content

Commit

Permalink
Bug 1774537 - Propagate last snap target id(s) from APZ to the conten…
Browse files Browse the repository at this point in the history
…t. r=botond

Depends on D149495

Differential Revision: https://phabricator.services.mozilla.com/D149496
  • Loading branch information
hiikezoe committed Jul 12, 2022
1 parent 94a7d9b commit 88f14ab
Show file tree
Hide file tree
Showing 13 changed files with 203 additions and 70 deletions.
28 changes: 19 additions & 9 deletions gfx/layers/RepaintRequest.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@
#include <iosfwd>
#include <stdint.h> // for uint8_t, uint32_t, uint64_t

#include "FrameMetrics.h" // for FrameMetrics
#include "mozilla/DefineEnum.h" // for MOZ_DEFINE_ENUM
#include "mozilla/gfx/BasePoint.h" // for BasePoint
#include "mozilla/gfx/Rect.h" // for RoundedIn
#include "mozilla/gfx/ScaleFactor.h" // for ScaleFactor
#include "mozilla/TimeStamp.h" // for TimeStamp
#include "Units.h" // for CSSRect, CSSPixel, etc
#include "UnitTransforms.h" // for ViewAs
#include "FrameMetrics.h" // for FrameMetrics
#include "mozilla/DefineEnum.h" // for MOZ_DEFINE_ENUM
#include "mozilla/gfx/BasePoint.h" // for BasePoint
#include "mozilla/gfx/Rect.h" // for RoundedIn
#include "mozilla/gfx/ScaleFactor.h" // for ScaleFactor
#include "mozilla/ScrollSnapTargetId.h" // for ScrollSnapTargetIds
#include "mozilla/TimeStamp.h" // for TimeStamp
#include "Units.h" // for CSSRect, CSSPixel, etc
#include "UnitTransforms.h" // for ViewAs

namespace IPC {
template <typename T>
Expand Down Expand Up @@ -65,7 +66,8 @@ struct RepaintRequest {
const ScreenMargin& aDisplayportMargins,
const ScrollOffsetUpdateType aScrollUpdateType,
APZScrollAnimationType aScrollAnimationType,
const APZScrollGeneration& aScrollGenerationOnApz)
const APZScrollGeneration& aScrollGenerationOnApz,
const ScrollSnapTargetIds& aLastSnapTargetIds)
: mScrollId(aOther.GetScrollId()),
mPresShellResolution(aOther.GetPresShellResolution()),
mCompositionBounds(aOther.GetCompositionBounds()),
Expand All @@ -82,6 +84,7 @@ struct RepaintRequest {
mPaintRequestTime(aOther.GetPaintRequestTime()),
mScrollUpdateType(aScrollUpdateType),
mScrollAnimationType(aScrollAnimationType),
mLastSnapTargetIds(aLastSnapTargetIds),
mIsRootContent(aOther.IsRootContent()),
mIsScrollInfoLayer(aOther.IsScrollInfoLayer()) {}

Expand All @@ -104,6 +107,7 @@ struct RepaintRequest {
mPaintRequestTime == aOther.mPaintRequestTime &&
mScrollUpdateType == aOther.mScrollUpdateType &&
mScrollAnimationType == aOther.mScrollAnimationType &&
mLastSnapTargetIds == aOther.mLastSnapTargetIds &&
mIsRootContent == aOther.mIsRootContent &&
mIsScrollInfoLayer == aOther.mIsScrollInfoLayer;
}
Expand Down Expand Up @@ -198,6 +202,10 @@ struct RepaintRequest {
return mScrollAnimationType;
}

ScrollSnapTargetIds CopyLastSnapTargetIds() const {
return mLastSnapTargetIds;
}

protected:
void SetIsRootContent(bool aIsRootContent) {
mIsRootContent = aIsRootContent;
Expand Down Expand Up @@ -298,6 +306,8 @@ struct RepaintRequest {

APZScrollAnimationType mScrollAnimationType;

ScrollSnapTargetIds mLastSnapTargetIds;

// Whether or not this is the root scroll frame for the root content document.
bool mIsRootContent : 1;

Expand Down
97 changes: 59 additions & 38 deletions gfx/layers/apz/src/AsyncPanZoomController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1976,7 +1976,7 @@ nsEventStatus AsyncPanZoomController::OnKeyboard(const KeyboardInput& aEvent) {
CSSPoint destination = GetKeyboardDestination(aEvent.mAction);
ScrollOrigin scrollOrigin =
SmoothScrollAnimation::GetScrollOriginForAction(aEvent.mAction.mType);
bool scrollSnapped = MaybeAdjustDestinationForScrollSnapping(
Maybe<CSSSnapTarget> snapTarget = MaybeAdjustDestinationForScrollSnapping(
aEvent, destination, GetScrollSnapFlagsForKeyboardAction(aEvent.mAction));
ScrollMode scrollMode = apz::GetScrollModeForOrigin(scrollOrigin);

Expand Down Expand Up @@ -2013,6 +2013,9 @@ nsEventStatus AsyncPanZoomController::OnKeyboard(const KeyboardInput& aEvent) {
SetState(KEYBOARD_SCROLL);
}

if (snapTarget) {
mLastSnapTargetIds = std::move(snapTarget->mTargetIds);
}
SetState(NOTHING);

return nsEventStatus_eConsumeDoDefault;
Expand All @@ -2023,13 +2026,13 @@ nsEventStatus AsyncPanZoomController::OnKeyboard(const KeyboardInput& aEvent) {
// update it.
RecursiveMutexAutoLock lock(mRecursiveMutex);

if (scrollSnapped) {
if (snapTarget) {
// If we're scroll snapping, use a smooth scroll animation to get
// the desired physics. Note that SmoothMsdScrollTo() will re-use an
// existing smooth scroll animation if there is one.
APZC_LOG("%p keyboard scrolling to snap point %s\n", this,
ToString(destination).c_str());
SmoothMsdScrollTo(destination, ScrollTriggeredByScript::No);
SmoothMsdScrollTo(std::move(*snapTarget), ScrollTriggeredByScript::No);
return nsEventStatus_eConsumeDoDefault;
}

Expand Down Expand Up @@ -2418,8 +2421,9 @@ nsEventStatus AsyncPanZoomController::OnScrollWheel(
RecursiveMutexAutoLock lock(mRecursiveMutex);
startPosition = Metrics().GetVisualScrollOffset();
}
MaybeAdjustDeltaForScrollSnappingOnWheelInput(aEvent, delta,
startPosition);
Maybe<CSSSnapTarget> snapTarget =
MaybeAdjustDeltaForScrollSnappingOnWheelInput(aEvent, delta,
startPosition);

ScreenPoint distance = ToScreenCoordinates(
ParentLayerPoint(fabs(delta.x), fabs(delta.y)), aEvent.mLocalOrigin);
Expand All @@ -2436,11 +2440,14 @@ nsEventStatus AsyncPanZoomController::OnScrollWheel(
CallDispatchScroll(startPoint, endPoint, handoffState);
ParentLayerPoint remainingDelta = endPoint - startPoint;
if (remainingDelta != delta) {
// If any scrolling happened, set KEYBOARD_SCROLL explicitly so that it
// If any scrolling happened, set WHEEL_SCROLL explicitly so that it
// will trigger a TransformEnd notification.
SetState(WHEEL_SCROLL);
}

if (snapTarget) {
mLastSnapTargetIds = std::move(snapTarget->mTargetIds);
}
SetState(NOTHING);

// The calls above handle their own locking; moreover,
Expand All @@ -2465,14 +2472,15 @@ nsEventStatus AsyncPanZoomController::OnScrollWheel(
CSSPoint startPosition = GetCurrentAnimationDestination(lock).valueOr(
Metrics().GetVisualScrollOffset());

if (MaybeAdjustDeltaForScrollSnappingOnWheelInput(aEvent, delta,
startPosition)) {
if (Maybe<CSSSnapTarget> snapTarget =
MaybeAdjustDeltaForScrollSnappingOnWheelInput(aEvent, delta,
startPosition)) {
// If we're scroll snapping, use a smooth scroll animation to get
// the desired physics. Note that SmoothMsdScrollTo() will re-use an
// existing smooth scroll animation if there is one.
APZC_LOG("%p wheel scrolling to snap point %s\n", this,
ToString(startPosition).c_str());
SmoothMsdScrollTo(startPosition, ScrollTriggeredByScript::No);
SmoothMsdScrollTo(std::move(*snapTarget), ScrollTriggeredByScript::No);
break;
}

Expand Down Expand Up @@ -3811,12 +3819,14 @@ void AsyncPanZoomController::SmoothScrollTo(const CSSPoint& aDestination,
}

void AsyncPanZoomController::SmoothMsdScrollTo(
const CSSPoint& aDestination, ScrollTriggeredByScript aTriggeredByScript) {
CSSSnapTarget&& aDestination, ScrollTriggeredByScript aTriggeredByScript) {
if (mState == SMOOTHMSD_SCROLL && mAnimation) {
APZC_LOG("%p updating destination on existing animation\n", this);
RefPtr<SmoothMsdScrollAnimation> animation(
static_cast<SmoothMsdScrollAnimation*>(mAnimation.get()));
animation->SetDestination(aDestination, aTriggeredByScript);
animation->SetDestination(aDestination.mPosition,
std::move(aDestination.mTargetIds),
aTriggeredByScript);
} else {
CancelAnimation();
SetState(SMOOTHMSD_SCROLL);
Expand All @@ -3829,10 +3839,11 @@ void AsyncPanZoomController::SmoothMsdScrollTo(
}

StartAnimation(new SmoothMsdScrollAnimation(
*this, Metrics().GetVisualScrollOffset(), initialVelocity, aDestination,
*this, Metrics().GetVisualScrollOffset(), initialVelocity,
aDestination.mPosition,
StaticPrefs::layout_css_scroll_behavior_spring_constant(),
StaticPrefs::layout_css_scroll_behavior_damping_ratio(),
aTriggeredByScript));
std::move(aDestination.mTargetIds), aTriggeredByScript));
}
}

Expand Down Expand Up @@ -3983,6 +3994,7 @@ void AsyncPanZoomController::CancelAnimation(CancelAnimationFlags aFlags) {
}

SetState(NOTHING);
mLastSnapTargetIds = ScrollSnapTargetIds{};
mAnimation = nullptr;
// Since there is no animation in progress now the axes should
// have no velocity either. If we are dropping the velocity from a non-zero
Expand Down Expand Up @@ -4409,7 +4421,7 @@ void AsyncPanZoomController::RequestContentRepaint(
: APZScrollAnimationType::TriggeredByUserInput;
}
RepaintRequest request(aFrameMetrics, aDisplayportMargins, aUpdateType,
animationType, mScrollGeneration);
animationType, mScrollGeneration, mLastSnapTargetIds);

if (request.IsRootContent() && request.GetZoom() != mLastNotifiedZoom &&
mState != PINCHING && mState != ANIMATING_ZOOM) {
Expand Down Expand Up @@ -4511,6 +4523,10 @@ bool AsyncPanZoomController::UpdateAnimation(
*aOutDeferredTasks = mAnimation->TakeDeferredTasks();
if (!continueAnimation) {
SetState(NOTHING);
if (mAnimation->AsSmoothMsdScrollAnimation()) {
mLastSnapTargetIds =
mAnimation->AsSmoothMsdScrollAnimation()->TakeSnapTargetIds();
}
mAnimation = nullptr;
}
// Request a repaint at the end of the animation in case something such as a
Expand Down Expand Up @@ -5318,7 +5334,8 @@ void AsyncPanZoomController::NotifyLayersUpdated(
}

if (scrollUpdate.GetMode() == ScrollMode::SmoothMsd) {
SmoothMsdScrollTo(destination,
// FIXME: Need to use ScrollSnapTargetIds coming from the main-thread.
SmoothMsdScrollTo(CSSSnapTarget{destination},
scrollUpdate.GetScrollTriggeredByScript());
} else {
MOZ_ASSERT(scrollUpdate.GetMode() == ScrollMode::Smooth);
Expand Down Expand Up @@ -6087,7 +6104,7 @@ void AsyncPanZoomController::SetTestAsyncZoom(
ScheduleComposite();
}

Maybe<CSSPoint> AsyncPanZoomController::FindSnapPointNear(
Maybe<CSSSnapTarget> AsyncPanZoomController::FindSnapPointNear(
const CSSPoint& aDestination, ScrollUnit aUnit,
ScrollSnapFlags aSnapFlags) {
mRecursiveMutex.AssertCurrentThreadIn();
Expand All @@ -6104,19 +6121,20 @@ Maybe<CSSPoint> AsyncPanZoomController::FindSnapPointNear(
// 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()).
return Some(scrollRange.ClampPoint(cssSnapPoint));
return Some(CSSSnapTarget{scrollRange.ClampPoint(cssSnapPoint),
snapTarget->mTargetIds});
}
return Nothing();
}

void AsyncPanZoomController::ScrollSnapNear(const CSSPoint& aDestination,
ScrollSnapFlags aSnapFlags) {
if (Maybe<CSSPoint> snapPoint = FindSnapPointNear(
if (Maybe<CSSSnapTarget> snapTarget = FindSnapPointNear(
aDestination, ScrollUnit::DEVICE_PIXELS, aSnapFlags)) {
if (*snapPoint != Metrics().GetVisualScrollOffset()) {
if (snapTarget->mPosition != Metrics().GetVisualScrollOffset()) {
APZC_LOG("%p smooth scrolling to snap point %s\n", this,
ToString(*snapPoint).c_str());
SmoothMsdScrollTo(*snapPoint, ScrollTriggeredByScript::No);
ToString(snapTarget->mPosition).c_str());
SmoothMsdScrollTo(std::move(*snapTarget), ScrollTriggeredByScript::No);
}
}
}
Expand Down Expand Up @@ -6155,8 +6173,9 @@ void AsyncPanZoomController::ScrollSnapToDestination() {
if (predictedDelta != ParentLayerPoint()) {
snapFlags |= ScrollSnapFlags::IntendedDirection;
}
if (MaybeAdjustDeltaForScrollSnapping(ScrollUnit::DEVICE_PIXELS, snapFlags,
predictedDelta, startPosition)) {
if (Maybe<CSSSnapTarget> snapTarget = MaybeAdjustDeltaForScrollSnapping(
ScrollUnit::DEVICE_PIXELS, snapFlags, predictedDelta,
startPosition)) {
APZC_LOG(
"%p fling snapping. friction: %f velocity: %f, %f "
"predictedDelta: %f, %f position: %f, %f "
Expand All @@ -6166,37 +6185,38 @@ void AsyncPanZoomController::ScrollSnapToDestination() {
(float)Metrics().GetVisualScrollOffset().y, (float)startPosition.x,
(float)startPosition.y);

SmoothMsdScrollTo(startPosition, ScrollTriggeredByScript::No);
SmoothMsdScrollTo(std::move(*snapTarget), ScrollTriggeredByScript::No);
}
}

bool AsyncPanZoomController::MaybeAdjustDeltaForScrollSnapping(
Maybe<CSSSnapTarget> AsyncPanZoomController::MaybeAdjustDeltaForScrollSnapping(
ScrollUnit aUnit, ScrollSnapFlags aSnapFlags, ParentLayerPoint& aDelta,
CSSPoint& aStartPosition) {
RecursiveMutexAutoLock lock(mRecursiveMutex);
CSSToParentLayerScale zoom = Metrics().GetZoom();
if (zoom == CSSToParentLayerScale(0)) {
return false;
return Nothing();
}
CSSPoint destination = Metrics().CalculateScrollRange().ClampPoint(
aStartPosition + (aDelta / zoom));

if (Maybe<CSSPoint> snapPoint =
if (Maybe<CSSSnapTarget> snapTarget =
FindSnapPointNear(destination, aUnit, aSnapFlags)) {
aDelta = (*snapPoint - aStartPosition) * zoom;
aStartPosition = *snapPoint;
return true;
aDelta = (snapTarget->mPosition - aStartPosition) * zoom;
aStartPosition = snapTarget->mPosition;
return snapTarget;
}
return false;
return Nothing();
}

bool AsyncPanZoomController::MaybeAdjustDeltaForScrollSnappingOnWheelInput(
Maybe<CSSSnapTarget>
AsyncPanZoomController::MaybeAdjustDeltaForScrollSnappingOnWheelInput(
const ScrollWheelInput& aEvent, ParentLayerPoint& aDelta,
CSSPoint& aStartPosition) {
// Don't scroll snap for pixel scrolls. This matches the main thread
// behaviour in EventStateManager::DoScrollText().
if (aEvent.mDeltaType == ScrollWheelInput::SCROLLDELTA_PIXEL) {
return false;
return Nothing();
}

// Note that this MaybeAdjustDeltaForScrollSnappingOnWheelInput also gets
Expand All @@ -6217,18 +6237,19 @@ bool AsyncPanZoomController::MaybeAdjustDeltaForScrollSnappingOnWheelInput(
ScrollSnapFlags::IntendedDirection, aDelta, aStartPosition);
}

bool AsyncPanZoomController::MaybeAdjustDestinationForScrollSnapping(
Maybe<CSSSnapTarget>
AsyncPanZoomController::MaybeAdjustDestinationForScrollSnapping(
const KeyboardInput& aEvent, CSSPoint& aDestination,
ScrollSnapFlags aSnapFlags) {
RecursiveMutexAutoLock lock(mRecursiveMutex);
ScrollUnit unit = KeyboardScrollAction::GetScrollUnit(aEvent.mAction.mType);

if (Maybe<CSSPoint> snapPoint =
if (Maybe<CSSSnapTarget> snapPoint =
FindSnapPointNear(aDestination, unit, aSnapFlags)) {
aDestination = *snapPoint;
return true;
aDestination = snapPoint->mPosition;
return snapPoint;
}
return false;
return Nothing();
}

void AsyncPanZoomController::SetZoomAnimationId(
Expand Down
24 changes: 12 additions & 12 deletions gfx/layers/apz/src/AsyncPanZoomController.h
Original file line number Diff line number Diff line change
Expand Up @@ -1521,7 +1521,7 @@ class AsyncPanZoomController {

// Start a smooth-scrolling animation to the given destination, with MSD
// physics that is suited for scroll-snapping.
void SmoothMsdScrollTo(const CSSPoint& aDestination,
void SmoothMsdScrollTo(CSSSnapTarget&& aDestination,
ScrollTriggeredByScript aTriggeredByScript);

// Returns whether overscroll is allowed during an event.
Expand Down Expand Up @@ -1754,6 +1754,7 @@ class AsyncPanZoomController {
// is in a panning state.
TimeDuration mTouchStartRestingTimeBeforePan;
Maybe<ParentLayerCoord> mMinimumVelocityDuringPan;
ScrollSnapTargetIds mLastSnapTargetIds;
// Extra offset to add to the async scroll position for testing
CSSPoint mTestAsyncScrollOffset;
// Extra zoom to include in the aync zoom for testing
Expand Down Expand Up @@ -1794,20 +1795,19 @@ class AsyncPanZoomController {
// |aUnit| affects the snapping behaviour (see ScrollSnapUtils::
// GetSnapPointForDestination).
// Returns true iff. a target snap point was found.
bool MaybeAdjustDeltaForScrollSnapping(ScrollUnit aUnit,
ScrollSnapFlags aFlags,
ParentLayerPoint& aDelta,
CSSPoint& aStartPosition);
Maybe<CSSSnapTarget> MaybeAdjustDeltaForScrollSnapping(
ScrollUnit aUnit, ScrollSnapFlags aSnapFlags, ParentLayerPoint& aDelta,
CSSPoint& aStartPosition);

// A wrapper function of MaybeAdjustDeltaForScrollSnapping for
// ScrollWheelInput.
bool MaybeAdjustDeltaForScrollSnappingOnWheelInput(
Maybe<CSSSnapTarget> MaybeAdjustDeltaForScrollSnappingOnWheelInput(
const ScrollWheelInput& aEvent, ParentLayerPoint& aDelta,
CSSPoint& aStartPosition);

bool MaybeAdjustDestinationForScrollSnapping(const KeyboardInput& aEvent,
CSSPoint& aDestination,
ScrollSnapFlags aSnapFlags);
Maybe<CSSSnapTarget> MaybeAdjustDestinationForScrollSnapping(
const KeyboardInput& aEvent, CSSPoint& aDestination,
ScrollSnapFlags aSnapFlags);

// Snap to a snap position nearby the current scroll position, if appropriate.
void ScrollSnap(ScrollSnapFlags aSnapFlags);
Expand All @@ -1824,9 +1824,9 @@ class AsyncPanZoomController {
// |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,
ScrollUnit aUnit,
ScrollSnapFlags aSnapFlags);
Maybe<CSSSnapTarget> FindSnapPointNear(const CSSPoint& aDestination,
ScrollUnit aUnit,
ScrollSnapFlags aSnapFlags);

friend std::ostream& operator<<(
std::ostream& aOut, const AsyncPanZoomController::PanZoomState& aState);
Expand Down
Loading

0 comments on commit 88f14ab

Please sign in to comment.