Bug 1260588 - C++ APZ should only allow handoff to ancestor APZC r=botond
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -2355,21 +2355,21 @@ bool AsyncPanZoomController::AttemptScro
ParentLayerPoint displacement = aStartPoint - aEndPoint;
ParentLayerPoint overscroll; // will be used outside monitor block
// If the direction of panning is reversed within the same input block,
// a later event in the block could potentially scroll an APZC earlier
// in the handoff chain, than an earlier event in the block (because
// the earlier APZC was scrolled to its extent in the original direction).
- // If immediate handoff is disallowed, we want to disallow this (to
- // preserve the property that a single input block only scrolls one APZC),
- // so we skip the earlier APZC.
- bool scrollThisApzc = gfxPrefs::APZAllowImmediateHandoff() ||
- (CurrentInputBlock() && (!CurrentInputBlock()->GetScrolledApzc() || this == CurrentInputBlock()->GetScrolledApzc()));
+ // We want to disallow this.
+ bool scrollThisApzc = false;
+ if (InputBlockState* block = CurrentInputBlock()) {
+ scrollThisApzc = !block->GetScrolledApzc() || block->IsDownchainOfScrolledApzc(this);
+ }
if (scrollThisApzc) {
ReentrantMonitorAutoEnter lock(mMonitor);
ParentLayerPoint adjustedDisplacement;
bool forceVerticalOverscroll =
(aOverscrollHandoffState.mScrollSource == ScrollSource::Wheel &&
!mFrameMetrics.AllowVerticalScrollWithWheel());
@@ -2378,31 +2378,29 @@ bool AsyncPanZoomController::AttemptScro
bool xChanged = mX.AdjustDisplacement(displacement.x, adjustedDisplacement.x, overscroll.x);
if (xChanged || yChanged) {
ScheduleComposite();
}
if (!IsZero(adjustedDisplacement)) {
ScrollBy(adjustedDisplacement / mFrameMetrics.GetZoom());
- if (!gfxPrefs::APZAllowImmediateHandoff()) {
- if (InputBlockState* block = CurrentInputBlock()) {
- block->SetScrolledApzc(this);
- }
+ if (InputBlockState* block = CurrentInputBlock()) {
+ block->SetScrolledApzc(this);
}
ScheduleCompositeAndMaybeRepaint();
UpdateSharedCompositorFrameMetrics();
}
+
+ // Adjust the start point to reflect the consumed portion of the scroll.
+ aStartPoint = aEndPoint + overscroll;
} else {
overscroll = displacement;
}
- // Adjust the start point to reflect the consumed portion of the scroll.
- aStartPoint = aEndPoint + overscroll;
-
// If we consumed the entire displacement as a normal scroll, great.
if (IsZero(overscroll)) {
return true;
}
if (AllowScrollHandoffInCurrentBlock()) {
// If there is overscroll, first try to hand it off to an APZC later
// in the handoff chain to consume (either as a normal scroll or as
--- a/gfx/layers/apz/src/InputBlockState.cpp
+++ b/gfx/layers/apz/src/InputBlockState.cpp
@@ -83,17 +83,17 @@ InputBlockState::GetBlockId() const
bool
InputBlockState::IsTargetConfirmed() const
{
return mTargetConfirmed;
}
bool
-InputBlockState::IsAncestorOf(AsyncPanZoomController* aA, AsyncPanZoomController* aB)
+InputBlockState::IsDownchainOf(AsyncPanZoomController* aA, AsyncPanZoomController* aB) const
{
if (aA == aB) {
return true;
}
bool seenA = false;
for (size_t i = 0; i < mOverscrollHandoffChain->Length(); ++i) {
AsyncPanZoomController* apzc = mOverscrollHandoffChain->GetApzcAtIndex(i);
@@ -107,27 +107,35 @@ InputBlockState::IsAncestorOf(AsyncPanZo
return false;
}
void
InputBlockState::SetScrolledApzc(AsyncPanZoomController* aApzc)
{
// An input block should only have one scrolled APZC.
- MOZ_ASSERT(!mScrolledApzc || mScrolledApzc == aApzc);
+ MOZ_ASSERT(!mScrolledApzc || (gfxPrefs::APZAllowImmediateHandoff() ? IsDownchainOf(mScrolledApzc, aApzc) : mScrolledApzc == aApzc));
mScrolledApzc = aApzc;
}
AsyncPanZoomController*
InputBlockState::GetScrolledApzc() const
{
return mScrolledApzc;
}
+bool
+InputBlockState::IsDownchainOfScrolledApzc(AsyncPanZoomController* aApzc) const
+{
+ MOZ_ASSERT(aApzc && mScrolledApzc);
+
+ return IsDownchainOf(mScrolledApzc, aApzc);
+}
+
CancelableBlockState::CancelableBlockState(const RefPtr<AsyncPanZoomController>& aTargetApzc,
bool aTargetConfirmed)
: InputBlockState(aTargetApzc, aTargetConfirmed)
, mPreventDefault(false)
, mContentResponded(false)
, mContentResponseTimerExpired(false)
{
}
--- a/gfx/layers/apz/src/InputBlockState.h
+++ b/gfx/layers/apz/src/InputBlockState.h
@@ -47,24 +47,25 @@ public:
const RefPtr<AsyncPanZoomController>& GetTargetApzc() const;
const RefPtr<const OverscrollHandoffChain>& GetOverscrollHandoffChain() const;
uint64_t GetBlockId() const;
bool IsTargetConfirmed() const;
void SetScrolledApzc(AsyncPanZoomController* aApzc);
AsyncPanZoomController* GetScrolledApzc() const;
+ bool IsDownchainOfScrolledApzc(AsyncPanZoomController* aApzc) const;
protected:
virtual void UpdateTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc);
private:
// Checks whether |aA| is an ancestor of |aB| (or the same as |aB|) in
// |mOverscrollHandoffChain|.
- bool IsAncestorOf(AsyncPanZoomController* aA, AsyncPanZoomController* aB);
+ bool IsDownchainOf(AsyncPanZoomController* aA, AsyncPanZoomController* aB) const;
private:
RefPtr<AsyncPanZoomController> mTargetApzc;
bool mTargetConfirmed;
const uint64_t mBlockId;
// The APZC that was actually scrolled by events in this input block.
// This is used in configurations where a single input block is only