Bug 1222524 - Change behaviour of axis-lock with nested APZCs. r=botond

This commit is contained in:
Chris Lord 2015-11-17 14:01:06 +00:00
parent c9acccc5f3
commit 143382c045
4 changed files with 89 additions and 10 deletions

View File

@ -1204,6 +1204,8 @@ nsEventStatus AsyncPanZoomController::OnTouchStart(const MultiTouchInput& aEvent
case PANNING:
case PANNING_LOCKED_X:
case PANNING_LOCKED_Y:
case PANNING_LOCKED_X_SMOOTH_SCROLL:
case PANNING_LOCKED_Y_SMOOTH_SCROLL:
case CROSS_SLIDING_X:
case CROSS_SLIDING_Y:
case PINCHING:
@ -1257,6 +1259,8 @@ nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent)
case PANNING:
case PANNING_LOCKED_X:
case PANNING_LOCKED_Y:
case PANNING_LOCKED_X_SMOOTH_SCROLL:
case PANNING_LOCKED_Y_SMOOTH_SCROLL:
case PAN_MOMENTUM:
TrackTouch(aEvent);
return nsEventStatus_eConsumeNoDefault;
@ -1318,6 +1322,10 @@ nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent)
}
return nsEventStatus_eIgnore;
case PANNING_LOCKED_X_SMOOTH_SCROLL:
case PANNING_LOCKED_Y_SMOOTH_SCROLL:
CancelAnimation();
MOZ_FALLTHROUGH;
case PANNING:
case PANNING_LOCKED_X:
case PANNING_LOCKED_Y:
@ -2116,6 +2124,7 @@ void AsyncPanZoomController::HandlePanning(double aAngle) {
mY.SetAxisLocked(true);
if (canScrollHorizontal) {
SetState(PANNING_LOCKED_X);
overscrollHandoffChain->RequestSnapOnLock(Layer::VERTICAL);
} else {
SetState(CROSS_SLIDING_X);
mX.SetAxisLocked(true);
@ -2124,6 +2133,7 @@ void AsyncPanZoomController::HandlePanning(double aAngle) {
mX.SetAxisLocked(true);
if (canScrollVertical) {
SetState(PANNING_LOCKED_Y);
overscrollHandoffChain->RequestSnapOnLock(Layer::HORIZONTAL);
} else {
SetState(CROSS_SLIDING_Y);
mY.SetAxisLocked(true);
@ -2140,6 +2150,19 @@ void AsyncPanZoomController::HandlePanningUpdate(const ScreenPoint& aPanDistance
double angle = atan2(aPanDistance.y, aPanDistance.x); // range [-pi, pi]
angle = fabs(angle); // range [0, pi]
{
// If we can scroll on both axes, we want to allow breaking axis-lock. If
// we can only scroll on one axis, we want to always enable entering to
// axis-lock.
ReentrantMonitorAutoEnter lock(mMonitor);
if (!mX.CanScroll() || !mY.CanScroll()) {
if (mState == PANNING) {
HandlePanning(angle);
}
return;
}
}
float breakThreshold = gfxPrefs::APZAxisBreakoutThreshold() * APZCTreeManager::GetDPI();
if (fabs(aPanDistance.x) > breakThreshold || fabs(aPanDistance.y) > breakThreshold) {
@ -2409,7 +2432,20 @@ void AsyncPanZoomController::HandleSmoothScrollOverscroll(const ParentLayerPoint
}
void AsyncPanZoomController::StartSmoothScroll(ScrollSource aSource) {
SetState(SMOOTH_SCROLL);
// Only cancel animation and change state if the user isn't pan-locked.
// Snapping is requested during panning if the opposing axis of an
// unscrollable axis is locked.
if (mState == PANNING_LOCKED_X) {
mY.SetAxisLocked(false);
SetState(PANNING_LOCKED_X_SMOOTH_SCROLL);
} else if (mState == PANNING_LOCKED_Y) {
mX.SetAxisLocked(false);
SetState(PANNING_LOCKED_Y_SMOOTH_SCROLL);
} else {
CancelAnimation();
SetState(SMOOTH_SCROLL);
}
nsPoint initialPosition = CSSPoint::ToAppUnits(mFrameMetrics.GetScrollOffset());
// Cast velocity from ParentLayerPoints/ms to CSSPoints/ms then convert to
// appunits/second
@ -2812,7 +2848,15 @@ bool AsyncPanZoomController::UpdateAnimation(const TimeStamp& aSampleTime,
}
} else {
mAnimation = nullptr;
SetState(NOTHING);
if (mState == PANNING_LOCKED_X_SMOOTH_SCROLL) {
mY.SetAxisLocked(true);
SetState(PANNING_LOCKED_X);
} else if (mState == PANNING_LOCKED_Y_SMOOTH_SCROLL) {
mX.SetAxisLocked(true);
SetState(PANNING_LOCKED_Y);
} else {
SetState(NOTHING);
}
RequestContentRepaint();
}
UpdateSharedCompositorFrameMetrics();
@ -3148,8 +3192,6 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri
Stringify(mFrameMetrics.GetScrollOffset()).c_str(),
Stringify(aLayerMetrics.GetSmoothScrollOffset()).c_str());
CancelAnimation();
// It's important to not send repaint requests between this
// CopySmoothScrollInfo call and the sending of the scroll update
// acknowledgement below, otherwise that repaint request will get rejected
@ -3380,7 +3422,10 @@ bool AsyncPanZoomController::IsTransformingState(PanZoomState aState) {
}
bool AsyncPanZoomController::IsInPanningState() const {
return (mState == PANNING || mState == PANNING_LOCKED_X || mState == PANNING_LOCKED_Y);
return (mState == PANNING ||
mState == PANNING_LOCKED_X || mState == PANNING_LOCKED_Y ||
mState == PANNING_LOCKED_X_SMOOTH_SCROLL ||
mState == PANNING_LOCKED_Y_SMOOTH_SCROLL);
}
void AsyncPanZoomController::UpdateZoomConstraints(const ZoomConstraints& aConstraints) {
@ -3497,6 +3542,7 @@ void AsyncPanZoomController::ShareCompositorFrameMetrics() {
void AsyncPanZoomController::RequestSnap() {
if (RefPtr<GeckoContentController> controller = GetGeckoContentController()) {
ReentrantMonitorAutoEnter lock(mMonitor);
APZC_LOG("%p requesting snap near %s\n", this,
Stringify(mFrameMetrics.GetScrollOffset()).c_str());
controller->RequestFlingSnap(mFrameMetrics.GetScrollId(),

View File

@ -382,6 +382,11 @@ public:
void NotifyMozMouseScrollEvent(const nsString& aString) const;
// This is called to request that the main thread snap the scroll position
// to a nearby snap position if appropriate. The current scroll position is
// used as the final destination.
void RequestSnap();
protected:
// Protected destructor, to discourage deletion outside of Release():
virtual ~AsyncPanZoomController();
@ -633,11 +638,6 @@ protected:
// Common processing at the end of a touch block.
void OnTouchEndOrCancel();
// This is called to request that the main thread snap the scroll position
// to a nearby snap position if appropriate. The current scroll position is
// used as the final destination.
void RequestSnap();
uint64_t mLayersId;
RefPtr<CompositorParent> mCompositorParent;
RefPtr<TaskThrottler> mPaintThrottler;
@ -751,6 +751,12 @@ protected:
the finger is lifted. */
SMOOTH_SCROLL, /* Smooth scrolling to destination. Used by
CSSOM-View smooth scroll-behavior */
PANNING_LOCKED_X_SMOOTH_SCROLL, /* Smooth scrolling animation initiated
while simultaneously panning the frame
with the X axis locked. */
PANNING_LOCKED_Y_SMOOTH_SCROLL, /* as above for Y axis. */
WHEEL_SCROLL /* Smooth scrolling to a destination for a wheel event. */
};

View File

@ -112,6 +112,30 @@ OverscrollHandoffChain::SnapBackOverscrolledApzc(const AsyncPanZoomController* a
}
}
}
void
OverscrollHandoffChain::RequestSnapOnLock(Layer::ScrollDirection aAxis) const
{
for (uint32_t i = 0; i < Length(); ++i) {
AsyncPanZoomController* apzc = mChain[i];
if (!apzc->IsDestroyed()) {
switch (aAxis) {
case Layer::HORIZONTAL:
if (!apzc->CanScroll(Layer::VERTICAL)) {
apzc->RequestSnap();
}
break;
case Layer::VERTICAL:
if (!apzc->CanScroll(Layer::HORIZONTAL)) {
apzc->RequestSnap();
}
break;
default:
MOZ_ASSERT(false);
break;
}
}
}
}
bool
OverscrollHandoffChain::CanBePanned(const AsyncPanZoomController* aApzc) const

View File

@ -71,6 +71,9 @@ public:
// |aStart| onwards, if any.
void SnapBackOverscrolledApzc(const AsyncPanZoomController* aStart) const;
// Request snap on APZCs that cannot scroll on the opposing axis to |aAxis|.
void RequestSnapOnLock(Layer::ScrollDirection aAxis) const;
// Determine whether the given APZC, or any APZC further in the chain,
// has room to be panned.
bool CanBePanned(const AsyncPanZoomController* aApzc) const;