Bug 1289432 - Allow the CurrentBlock() and CurrentXXXBlock() functions to return null, and guard/assert at the callsites. r?botond draft
authorKartikaya Gupta <kgupta@mozilla.com>
Mon, 12 Sep 2016 22:42:18 -0400
changeset 412859 0269e458a6a663761bf75be2a306e071dda28e55
parent 412858 cd4a6dd405544674ef45e856e6cfc6c9f3a9c0e7
child 412860 3a1c93931eaebe50464eae618328a73a17f22877
push id29274
push userkgupta@mozilla.com
push dateTue, 13 Sep 2016 02:44:31 +0000
reviewersbotond
bugs1289432
milestone51.0a1
Bug 1289432 - Allow the CurrentBlock() and CurrentXXXBlock() functions to return null, and guard/assert at the callsites. r?botond MozReview-Commit-ID: 364NTVfTFgQ
gfx/layers/apz/src/AsyncPanZoomController.cpp
gfx/layers/apz/src/AsyncPanZoomController.h
gfx/layers/apz/src/GestureEventListener.cpp
gfx/layers/apz/src/InputQueue.cpp
gfx/layers/apz/src/InputQueue.h
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -1082,25 +1082,27 @@ nsEventStatus AsyncPanZoomController::On
 
   switch (mState) {
     case FLING:
     case ANIMATING_ZOOM:
     case SMOOTH_SCROLL:
     case OVERSCROLL_ANIMATION:
     case WHEEL_SCROLL:
     case PAN_MOMENTUM:
-      CurrentTouchBlock()->GetOverscrollHandoffChain()->CancelAnimations(ExcludeOverscroll);
+      MOZ_ASSERT(GetCurrentTouchBlock());
+      GetCurrentTouchBlock()->GetOverscrollHandoffChain()->CancelAnimations(ExcludeOverscroll);
       MOZ_FALLTHROUGH;
     case NOTHING: {
       mX.StartTouch(point.x, aEvent.mTime);
       mY.StartTouch(point.y, aEvent.mTime);
       if (RefPtr<GeckoContentController> controller = GetGeckoContentController()) {
+        MOZ_ASSERT(GetCurrentTouchBlock());
         controller->NotifyAPZStateChange(
             GetGuid(), APZStateChange::eStartTouch,
-            CurrentTouchBlock()->GetOverscrollHandoffChain()->CanBePanned(this));
+            GetCurrentTouchBlock()->GetOverscrollHandoffChain()->CanBePanned(this));
       }
       SetState(TOUCHING);
       break;
     }
     case TOUCHING:
     case PANNING:
     case PANNING_LOCKED_X:
     case PANNING_LOCKED_Y:
@@ -1129,17 +1131,18 @@ nsEventStatus AsyncPanZoomController::On
     case TOUCHING: {
       ScreenCoord panThreshold = GetTouchStartTolerance();
       UpdateWithTouchAtDevicePoint(aEvent);
 
       if (PanDistance() < panThreshold) {
         return nsEventStatus_eIgnore;
       }
 
-      if (gfxPrefs::TouchActionEnabled() && CurrentTouchBlock()->TouchActionAllowsPanningXY()) {
+      MOZ_ASSERT(GetCurrentTouchBlock());
+      if (gfxPrefs::TouchActionEnabled() && GetCurrentTouchBlock()->TouchActionAllowsPanningXY()) {
         // User tries to trigger a touch behavior. If allowed touch behavior is vertical pan
         // + horizontal pan (touch-action value is equal to AUTO) we can return ConsumeNoDefault
         // status immediately to trigger cancel event further. It should happen independent of
         // the parent type (whether it is scrolling or not).
         StartPanning(aEvent);
         return nsEventStatus_eConsumeNoDefault;
       }
 
@@ -1201,43 +1204,45 @@ nsEventStatus AsyncPanZoomController::On
     // second tap. Ignore if this happens.
     return nsEventStatus_eIgnore;
 
   case TOUCHING:
     // We may have some velocity stored on the axis from move events
     // that were not big enough to trigger scrolling. Clear that out.
     mX.SetVelocity(0);
     mY.SetVelocity(0);
+    MOZ_ASSERT(GetCurrentTouchBlock());
     APZC_LOG("%p still has %u touch points active\n", this,
-        CurrentTouchBlock()->GetActiveTouchCount());
+        GetCurrentTouchBlock()->GetActiveTouchCount());
     // In cases where the user is panning, then taps the second finger without
     // entering a pinch, we will arrive here when the second finger is lifted.
     // However the first finger is still down so we want to remain in state
     // TOUCHING.
-    if (CurrentTouchBlock()->GetActiveTouchCount() == 0) {
+    if (GetCurrentTouchBlock()->GetActiveTouchCount() == 0) {
       // It's possible we may be overscrolled if the user tapped during a
       // previous overscroll pan. Make sure to snap back in this situation.
       // An ancestor APZC could be overscrolled instead of this APZC, so
       // walk the handoff chain as well.
-      CurrentTouchBlock()->GetOverscrollHandoffChain()->SnapBackOverscrolledApzc(this);
+      GetCurrentTouchBlock()->GetOverscrollHandoffChain()->SnapBackOverscrolledApzc(this);
       // SnapBackOverscrolledApzc() will put any APZC it causes to snap back
       // into the OVERSCROLL_ANIMATION state. If that's not us, since we're
       // done TOUCHING enter the NOTHING state.
       if (mState != OVERSCROLL_ANIMATION) {
         SetState(NOTHING);
       }
     }
     return nsEventStatus_eIgnore;
 
   case PANNING:
   case PANNING_LOCKED_X:
   case PANNING_LOCKED_Y:
   case PAN_MOMENTUM:
   {
-    CurrentTouchBlock()->GetOverscrollHandoffChain()->FlushRepaints();
+    MOZ_ASSERT(GetCurrentTouchBlock());
+    GetCurrentTouchBlock()->GetOverscrollHandoffChain()->FlushRepaints();
     mX.EndTouch(aEvent.mTime);
     mY.EndTouch(aEvent.mTime);
     ParentLayerPoint flingVelocity = GetVelocityVector();
     // Clear our velocities; if DispatchFling() gives the fling to us,
     // the fling velocity gets *added* to our existing velocity in
     // AcceptFling().
     mX.SetVelocity(0);
     mY.SetVelocity(0);
@@ -1255,19 +1260,19 @@ nsEventStatus AsyncPanZoomController::On
       return nsEventStatus_eConsumeNoDefault;
     }
 
     // Make a local copy of the tree manager pointer and check that it's not
     // null before calling DispatchFling(). This is necessary because Destroy(),
     // which nulls out mTreeManager, could be called concurrently.
     if (APZCTreeManager* treeManagerLocal = GetApzcTreeManager()) {
       FlingHandoffState handoffState{flingVelocity,
-                                     CurrentTouchBlock()->GetOverscrollHandoffChain(),
+                                     GetCurrentTouchBlock()->GetOverscrollHandoffChain(),
                                      false /* not handoff */,
-                                     CurrentTouchBlock()->GetScrolledApzc()};
+                                     GetCurrentTouchBlock()->GetScrolledApzc()};
       treeManagerLocal->DispatchFling(this, handoffState);
     }
     return nsEventStatus_eConsumeNoDefault;
   }
   case PINCHING:
     SetState(NOTHING);
     // Scale gesture listener should have handled this.
     NS_WARNING("Gesture listener should have handled pinching in OnTouchEnd.");
@@ -1293,32 +1298,32 @@ nsEventStatus AsyncPanZoomController::On
 }
 
 nsEventStatus AsyncPanZoomController::OnScaleBegin(const PinchGestureInput& aEvent) {
   APZC_LOG("%p got a scale-begin in state %d\n", this, mState);
 
   mPinchPaintTimerSet = false;
   // Note that there may not be a touch block at this point, if we received the
   // PinchGestureEvent directly from widget code without any touch events.
-  if (HasReadyTouchBlock() && !CurrentTouchBlock()->TouchActionAllowsPinchZoom()) {
+  if (HasReadyTouchBlock() && !GetCurrentTouchBlock()->TouchActionAllowsPinchZoom()) {
     return nsEventStatus_eIgnore;
   }
 
   SetState(PINCHING);
   mX.SetVelocity(0);
   mY.SetVelocity(0);
   mLastZoomFocus = aEvent.mLocalFocusPoint - mFrameMetrics.GetCompositionBounds().TopLeft();
 
   return nsEventStatus_eConsumeNoDefault;
 }
 
 nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
   APZC_LOG("%p got a scale in state %d\n", this, mState);
-
-  if (HasReadyTouchBlock() && !CurrentTouchBlock()->TouchActionAllowsPinchZoom()) {
+ 
+  if (HasReadyTouchBlock() && !GetCurrentTouchBlock()->TouchActionAllowsPinchZoom()) {
     return nsEventStatus_eIgnore;
   }
 
   if (mState != PINCHING) {
     return nsEventStatus_eConsumeNoDefault;
   }
 
   // Only the root APZC is zoomable, and the root APZC is not allowed to have
@@ -1414,17 +1419,17 @@ nsEventStatus AsyncPanZoomController::On
   return nsEventStatus_eConsumeNoDefault;
 }
 
 nsEventStatus AsyncPanZoomController::OnScaleEnd(const PinchGestureInput& aEvent) {
   APZC_LOG("%p got a scale-end in state %d\n", this, mState);
 
   mPinchPaintTimerSet = false;
 
-  if (HasReadyTouchBlock() && !CurrentTouchBlock()->TouchActionAllowsPinchZoom()) {
+  if (HasReadyTouchBlock() && !GetCurrentTouchBlock()->TouchActionAllowsPinchZoom()) {
     return nsEventStatus_eIgnore;
   }
 
   SetState(NOTHING);
 
   {
     ReentrantMonitorAutoEnter lock(mMonitor);
     ScheduleComposite();
@@ -1446,17 +1451,17 @@ nsEventStatus AsyncPanZoomController::On
     // pinch if we go into overscroll with a two-finger pan, and then turn
     // that into a pinch by increasing the span sufficiently. In such a case,
     // there is no snap-back animation to get us out of overscroll, so we need
     // to get out of it somehow.
     // Moreover, in cases of scroll handoff, the overscroll can be on an APZC
     // further up in the handoff chain rather than on the current APZC, so
     // we need to clear overscroll along the entire handoff chain.
     if (HasReadyTouchBlock()) {
-      CurrentTouchBlock()->GetOverscrollHandoffChain()->ClearOverscroll();
+      GetCurrentTouchBlock()->GetOverscrollHandoffChain()->ClearOverscroll();
     } else {
       ClearOverscroll();
     }
     // Along with clearing the overscroll, we also want to snap to the nearest
     // snap point as appropriate.
     ScrollSnap();
   }
 
@@ -1620,17 +1625,17 @@ AsyncPanZoomController::CanScroll(Layer:
   }
 }
 
 bool
 AsyncPanZoomController::AllowScrollHandoffInCurrentBlock() const
 {
   bool result = mInputQueue->AllowScrollHandoff();
   if (!gfxPrefs::APZAllowImmediateHandoff()) {
-    if (InputBlockState* currentBlock = CurrentInputBlock()) {
+    if (InputBlockState* currentBlock = GetCurrentInputBlock()) {
       // Do not allow handoff beyond the first APZC to scroll.
       if (currentBlock->GetScrolledApzc() == this) {
         result = false;
       }
     }
   }
   return result;
 }
@@ -1699,18 +1704,19 @@ nsEventStatus AsyncPanZoomController::On
       CSSPoint startPosition = mFrameMetrics.GetScrollOffset();
       MaybeAdjustDeltaForScrollSnapping(aEvent, delta, startPosition);
 
       ScreenPoint distance = ToScreenCoordinates(
         ParentLayerPoint(fabs(delta.x), fabs(delta.y)), aEvent.mLocalOrigin);
 
       CancelAnimation();
 
+      MOZ_ASSERT(mInputQueue->GetCurrentWheelBlock());
       OverscrollHandoffState handoffState(
-          *mInputQueue->CurrentWheelBlock()->GetOverscrollHandoffChain(),
+          *mInputQueue->GetCurrentWheelBlock()->GetOverscrollHandoffChain(),
           distance,
           ScrollSource::Wheel);
       ParentLayerPoint startPoint = aEvent.mLocalOrigin;
       ParentLayerPoint endPoint = aEvent.mLocalOrigin - delta;
       CallDispatchScroll(startPoint, endPoint, handoffState);
 
       SetState(NOTHING);
 
@@ -1789,17 +1795,18 @@ AsyncPanZoomController::NotifyMozMouseSc
   controller->NotifyMozMouseScrollEvent(mFrameMetrics.GetScrollId(), aString);
 }
 
 nsEventStatus AsyncPanZoomController::OnPanMayBegin(const PanGestureInput& aEvent) {
   APZC_LOG("%p got a pan-maybegin in state %d\n", this, mState);
 
   mX.StartTouch(aEvent.mLocalPanStartPoint.x, aEvent.mTime);
   mY.StartTouch(aEvent.mLocalPanStartPoint.y, aEvent.mTime);
-  CurrentPanGestureBlock()->GetOverscrollHandoffChain()->CancelAnimations();
+  MOZ_ASSERT(GetCurrentPanGestureBlock());
+  GetCurrentPanGestureBlock()->GetOverscrollHandoffChain()->CancelAnimations();
 
   return nsEventStatus_eConsumeNoDefault;
 }
 
 nsEventStatus AsyncPanZoomController::OnPanCancelled(const PanGestureInput& aEvent) {
   APZC_LOG("%p got a pan-cancelled in state %d\n", this, mState);
 
   mX.CancelGesture();
@@ -1886,18 +1893,19 @@ nsEventStatus AsyncPanZoomController::On
   mY.UpdateWithTouchAtDevicePoint(aEvent.mLocalPanStartPoint.y, logicalPanDisplacement.y, aEvent.mTime);
 
   HandlePanningUpdate(physicalPanDisplacement);
 
   mozilla::Telemetry::Accumulate(mozilla::Telemetry::SCROLL_INPUT_METHODS,
       (uint32_t) ScrollInputMethod::ApzPanGesture);
 
   ScreenPoint panDistance(fabs(physicalPanDisplacement.x), fabs(physicalPanDisplacement.y));
+  MOZ_ASSERT(GetCurrentPanGestureBlock());
   OverscrollHandoffState handoffState(
-      *CurrentPanGestureBlock()->GetOverscrollHandoffChain(),
+      *GetCurrentPanGestureBlock()->GetOverscrollHandoffChain(),
       panDistance,
       ScrollSource::Wheel);
 
   // Create fake "touch" positions that will result in the desired scroll motion.
   // Note that the pan displacement describes the change in scroll position:
   // positive displacement values mean that the scroll position increases.
   // However, an increase in scroll position means that the scrolled contents
   // are moved to the left / upwards. Since our simulated "touches" determine
@@ -1917,18 +1925,19 @@ nsEventStatus AsyncPanZoomController::On
   OnPan(aEvent, true);
 
   mX.EndTouch(aEvent.mTime);
   mY.EndTouch(aEvent.mTime);
 
   // Drop any velocity on axes where we don't have room to scroll anyways
   // (in this APZC, or an APZC further in the handoff chain).
   // This ensures that we don't enlarge the display port unnecessarily.
+  MOZ_ASSERT(GetCurrentPanGestureBlock());
   RefPtr<const OverscrollHandoffChain> overscrollHandoffChain =
-    CurrentPanGestureBlock()->GetOverscrollHandoffChain();
+    GetCurrentPanGestureBlock()->GetOverscrollHandoffChain();
   if (!overscrollHandoffChain->CanScrollInDirection(this, Layer::HORIZONTAL)) {
     mX.SetVelocity(0);
   }
   if (!overscrollHandoffChain->CanScrollInDirection(this, Layer::VERTICAL)) {
     mY.SetVelocity(0);
   }
 
   SetState(NOTHING);
@@ -1977,23 +1986,22 @@ nsEventStatus AsyncPanZoomController::On
 }
 
 nsEventStatus AsyncPanZoomController::OnLongPress(const TapGestureInput& aEvent) {
   APZC_LOG("%p got a long-press in state %d\n", this, mState);
   RefPtr<GeckoContentController> controller = GetGeckoContentController();
   if (controller) {
     LayoutDevicePoint geckoScreenPoint;
     if (ConvertToGecko(aEvent.mPoint, &geckoScreenPoint)) {
-      CancelableBlockState* block = CurrentInputBlock();
-      MOZ_ASSERT(block);
-      if (!block->AsTouchBlock()) {
+      TouchBlockState* touch = GetCurrentTouchBlock();
+      if (!touch) {
         APZC_LOG("%p dropping long-press because some non-touch block interrupted it\n", this);
         return nsEventStatus_eIgnore;
       }
-      if (block->AsTouchBlock()->IsDuringFastFling()) {
+      if (touch->IsDuringFastFling()) {
         APZC_LOG("%p dropping long-press because of fast fling\n", this);
         return nsEventStatus_eIgnore;
       }
       uint64_t blockId = GetInputQueue()->InjectNewTouchBlock(this);
       controller->HandleTap(TapType::eLongTap, geckoScreenPoint, aEvent.modifiers, GetGuid(), blockId);
       return nsEventStatus_eConsumeNoDefault;
     }
   }
@@ -2006,20 +2014,18 @@ nsEventStatus AsyncPanZoomController::On
 }
 
 nsEventStatus AsyncPanZoomController::GenerateSingleTap(TapType aType,
       const ScreenIntPoint& aPoint, mozilla::Modifiers aModifiers) {
   RefPtr<GeckoContentController> controller = GetGeckoContentController();
   if (controller) {
     LayoutDevicePoint geckoScreenPoint;
     if (ConvertToGecko(aPoint, &geckoScreenPoint)) {
-      CancelableBlockState* block = CurrentInputBlock();
-      MOZ_ASSERT(block);
-      TouchBlockState* touch = block->AsTouchBlock();
-      // |block| may be a non-touch block in the case where this function is
+      TouchBlockState* touch = GetCurrentTouchBlock();
+      // |touch| may be null in the case where this function is
       // invoked by GestureEventListener on a timeout. In that case we already
       // verified that the single tap is allowed so we let it through.
       // XXX there is a bug here that in such a case the touch block that
       // generated this tap will not get its mSingleTapOccurred flag set.
       // See https://bugzilla.mozilla.org/show_bug.cgi?id=1256344#c6
       if (touch) {
         if (touch->IsDuringFastFling()) {
           APZC_LOG("%p dropping single-tap because it was during a fast-fling\n", this);
@@ -2044,45 +2050,48 @@ nsEventStatus AsyncPanZoomController::Ge
       return nsEventStatus_eConsumeNoDefault;
     }
   }
   return nsEventStatus_eIgnore;
 }
 
 void AsyncPanZoomController::OnTouchEndOrCancel() {
   if (RefPtr<GeckoContentController> controller = GetGeckoContentController()) {
+    MOZ_ASSERT(GetCurrentTouchBlock());
     controller->NotifyAPZStateChange(
-        GetGuid(), APZStateChange::eEndTouch, CurrentTouchBlock()->SingleTapOccurred());
+        GetGuid(), APZStateChange::eEndTouch, GetCurrentTouchBlock()->SingleTapOccurred());
   }
 }
 
 nsEventStatus AsyncPanZoomController::OnSingleTapUp(const TapGestureInput& aEvent) {
   APZC_LOG("%p got a single-tap-up in state %d\n", this, mState);
   // If mZoomConstraints.mAllowDoubleTapZoom is true we wait for a call to OnSingleTapConfirmed before
   // sending event to content
-  if (!(mZoomConstraints.mAllowDoubleTapZoom && CurrentTouchBlock()->TouchActionAllowsDoubleTapZoom())) {
+  MOZ_ASSERT(GetCurrentTouchBlock());
+  if (!(mZoomConstraints.mAllowDoubleTapZoom && GetCurrentTouchBlock()->TouchActionAllowsDoubleTapZoom())) {
     return GenerateSingleTap(TapType::eSingleTap, aEvent.mPoint, aEvent.modifiers);
   }
   return nsEventStatus_eIgnore;
 }
 
 nsEventStatus AsyncPanZoomController::OnSingleTapConfirmed(const TapGestureInput& aEvent) {
   APZC_LOG("%p got a single-tap-confirmed in state %d\n", this, mState);
   return GenerateSingleTap(TapType::eSingleTap, aEvent.mPoint, aEvent.modifiers);
 }
 
 nsEventStatus AsyncPanZoomController::OnDoubleTap(const TapGestureInput& aEvent) {
   APZC_LOG("%p got a double-tap in state %d\n", this, mState);
   RefPtr<GeckoContentController> controller = GetGeckoContentController();
   if (controller) {
-    if (mZoomConstraints.mAllowDoubleTapZoom && CurrentTouchBlock()->TouchActionAllowsDoubleTapZoom()) {
+    MOZ_ASSERT(GetCurrentTouchBlock());
+    if (mZoomConstraints.mAllowDoubleTapZoom && GetCurrentTouchBlock()->TouchActionAllowsDoubleTapZoom()) {
       LayoutDevicePoint geckoScreenPoint;
       if (ConvertToGecko(aEvent.mPoint, &geckoScreenPoint)) {
         controller->HandleTap(TapType::eDoubleTap, geckoScreenPoint,
-            aEvent.modifiers, GetGuid(), CurrentTouchBlock()->GetBlockId());
+            aEvent.modifiers, GetGuid(), GetCurrentTouchBlock()->GetBlockId());
       }
     }
     return nsEventStatus_eConsumeNoDefault;
   }
   return nsEventStatus_eIgnore;
 }
 
 nsEventStatus AsyncPanZoomController::OnCancelTap(const TapGestureInput& aEvent) {
@@ -2148,45 +2157,46 @@ const ParentLayerPoint AsyncPanZoomContr
 void AsyncPanZoomController::SetVelocityVector(const ParentLayerPoint& aVelocityVector) {
   mX.SetVelocity(aVelocityVector.x);
   mY.SetVelocity(aVelocityVector.y);
 }
 
 void AsyncPanZoomController::HandlePanningWithTouchAction(double aAngle) {
   // Handling of cross sliding will need to be added in this method after touch-action released
   // enabled by default.
-  if (CurrentTouchBlock()->TouchActionAllowsPanningXY()) {
+  MOZ_ASSERT(GetCurrentTouchBlock());
+  if (GetCurrentTouchBlock()->TouchActionAllowsPanningXY()) {
     if (mX.CanScrollNow() && mY.CanScrollNow()) {
       if (IsCloseToHorizontal(aAngle, gfxPrefs::APZAxisLockAngle())) {
         mY.SetAxisLocked(true);
         SetState(PANNING_LOCKED_X);
       } else if (IsCloseToVertical(aAngle, gfxPrefs::APZAxisLockAngle())) {
         mX.SetAxisLocked(true);
         SetState(PANNING_LOCKED_Y);
       } else {
         SetState(PANNING);
       }
     } else if (mX.CanScrollNow() || mY.CanScrollNow()) {
       SetState(PANNING);
     } else {
       SetState(NOTHING);
     }
-  } else if (CurrentTouchBlock()->TouchActionAllowsPanningX()) {
+  } else if (GetCurrentTouchBlock()->TouchActionAllowsPanningX()) {
     // Using bigger angle for panning to keep behavior consistent
     // with IE.
     if (IsCloseToHorizontal(aAngle, gfxPrefs::APZAllowedDirectPanAngle())) {
       mY.SetAxisLocked(true);
       SetState(PANNING_LOCKED_X);
       mPanDirRestricted = true;
     } else {
       // Don't treat these touches as pan/zoom movements since 'touch-action' value
       // requires it.
       SetState(NOTHING);
     }
-  } else if (CurrentTouchBlock()->TouchActionAllowsPanningY()) {
+  } else if (GetCurrentTouchBlock()->TouchActionAllowsPanningY()) {
     if (IsCloseToVertical(aAngle, gfxPrefs::APZAllowedDirectPanAngle())) {
       mX.SetAxisLocked(true);
       SetState(PANNING_LOCKED_Y);
       mPanDirRestricted = true;
     } else {
       SetState(NOTHING);
     }
   } else {
@@ -2198,18 +2208,19 @@ void AsyncPanZoomController::HandlePanni
     // touchmoves.
     mX.SetVelocity(0);
     mY.SetVelocity(0);
   }
 }
 
 void AsyncPanZoomController::HandlePanning(double aAngle) {
   ReentrantMonitorAutoEnter lock(mMonitor);
+  MOZ_ASSERT(GetCurrentInputBlock());
   RefPtr<const OverscrollHandoffChain> overscrollHandoffChain =
-    CurrentInputBlock()->GetOverscrollHandoffChain();
+    GetCurrentInputBlock()->GetOverscrollHandoffChain();
   bool canScrollHorizontal = !mX.IsAxisLocked() &&
     overscrollHandoffChain->CanScrollInDirection(this, Layer::HORIZONTAL);
   bool canScrollVertical = !mY.IsAxisLocked() &&
     overscrollHandoffChain->CanScrollInDirection(this, Layer::VERTICAL);
 
   if (!canScrollHorizontal || !canScrollVertical) {
     SetState(PANNING);
   } else if (IsCloseToHorizontal(aAngle, gfxPrefs::APZAxisLockAngle())) {
@@ -2300,17 +2311,17 @@ bool AsyncPanZoomController::AttemptScro
   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).
   // We want to disallow this.
   bool scrollThisApzc = false;
-  if (InputBlockState* block = CurrentInputBlock()) {
+  if (InputBlockState* block = GetCurrentInputBlock()) {
     scrollThisApzc = !block->GetScrolledApzc() || block->IsDownchainOfScrolledApzc(this);
   }
 
   if (scrollThisApzc) {
     ReentrantMonitorAutoEnter lock(mMonitor);
 
     ParentLayerPoint adjustedDisplacement;
     bool forceVerticalOverscroll =
@@ -2321,17 +2332,17 @@ 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 (CancelableBlockState* block = CurrentInputBlock()) {
+      if (CancelableBlockState* block = GetCurrentInputBlock()) {
         if (block->AsTouchBlock() && (block->GetScrolledApzc() != this)) {
           RefPtr<GeckoContentController> controller = GetGeckoContentController();
           if (controller) {
             controller->SetScrollingRootContent(IsRootContent());
           }
         }
         block->SetScrolledApzc(this);
       }
@@ -2540,18 +2551,19 @@ void AsyncPanZoomController::TrackTouch(
       PanStart());
   HandlePanningUpdate(panDistance);
 
   UpdateWithTouchAtDevicePoint(aEvent);
 
   if (prevTouchPoint != touchPoint) {
     mozilla::Telemetry::Accumulate(mozilla::Telemetry::SCROLL_INPUT_METHODS,
         (uint32_t) ScrollInputMethod::ApzTouch);
+    MOZ_ASSERT(GetCurrentTouchBlock());
     OverscrollHandoffState handoffState(
-        *CurrentTouchBlock()->GetOverscrollHandoffChain(),
+        *GetCurrentTouchBlock()->GetOverscrollHandoffChain(),
         panDistance,
         ScrollSource::Touch);
     CallDispatchScroll(prevTouchPoint, touchPoint, handoffState);
   }
 }
 
 ParentLayerPoint AsyncPanZoomController::GetFirstTouchPoint(const MultiTouchInput& aEvent) {
   return ((SingleTouchData&)aEvent.mTouches[0]).mLocalScreenPoint;
@@ -3606,45 +3618,45 @@ void AsyncPanZoomController::ZoomToRect(
       controller->DispatchToRepaintThread(
           NewRunnableMethod<FrameMetrics, ParentLayerPoint>(
               this, func, endZoomToMetrics, velocity));
     }
   }
 }
 
 CancelableBlockState*
-AsyncPanZoomController::CurrentInputBlock() const
+AsyncPanZoomController::GetCurrentInputBlock() const
 {
-  return GetInputQueue()->CurrentBlock();
+  return GetInputQueue()->GetCurrentBlock();
 }
 
 TouchBlockState*
-AsyncPanZoomController::CurrentTouchBlock() const
+AsyncPanZoomController::GetCurrentTouchBlock() const
 {
-  return GetInputQueue()->CurrentTouchBlock();
+  return GetInputQueue()->GetCurrentTouchBlock();
 }
 
 PanGestureBlockState*
-AsyncPanZoomController::CurrentPanGestureBlock() const
+AsyncPanZoomController::GetCurrentPanGestureBlock() const
 {
-  return GetInputQueue()->CurrentPanGestureBlock();
+  return GetInputQueue()->GetCurrentPanGestureBlock();
 }
 
 void
 AsyncPanZoomController::ResetTouchInputState()
 {
   MultiTouchInput cancel(MultiTouchInput::MULTITOUCH_CANCEL, 0, TimeStamp::Now(), 0);
   RefPtr<GestureEventListener> listener = GetGestureEventListener();
   if (listener) {
     listener->HandleInputEvent(cancel);
   }
   CancelAnimationAndGestureState();
   // Clear overscroll along the entire handoff chain, in case an APZC
   // later in the chain is overscrolled.
-  if (TouchBlockState* block = CurrentInputBlock()->AsTouchBlock()) {
+  if (TouchBlockState* block = GetCurrentTouchBlock()) {
     block->GetOverscrollHandoffChain()->ClearOverscroll();
   }
 }
 
 void
 AsyncPanZoomController::CancelAnimationAndGestureState()
 {
   mX.CancelGesture();
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -856,21 +856,21 @@ public:
    * Gets a ref to the input queue that is shared across the entire tree manager.
    */
   const RefPtr<InputQueue>& GetInputQueue() const;
 
 private:
   void CancelAnimationAndGestureState();
 
   RefPtr<InputQueue> mInputQueue;
-  CancelableBlockState* CurrentInputBlock() const;
-  TouchBlockState* CurrentTouchBlock() const;
+  CancelableBlockState* GetCurrentInputBlock() const;
+  TouchBlockState* GetCurrentTouchBlock() const;
   bool HasReadyTouchBlock() const;
 
-  PanGestureBlockState* CurrentPanGestureBlock() const;
+  PanGestureBlockState* GetCurrentPanGestureBlock() const;
 
 private:
   /* ===================================================================
    * The functions and members in this section are used to manage
    * fling animations, smooth scroll animations, and overscroll
    * during a fling or smooth scroll.
    */
 public:
--- a/gfx/layers/apz/src/GestureEventListener.cpp
+++ b/gfx/layers/apz/src/GestureEventListener.cpp
@@ -521,17 +521,18 @@ void GestureEventListener::CancelMaxTapT
     mMaxTapTimeoutTask = nullptr;
   }
 }
 
 void GestureEventListener::CreateMaxTapTimeoutTask()
 {
   mLastTapInput = mLastTouchInput;
 
-  TouchBlockState* block = mAsyncPanZoomController->GetInputQueue()->CurrentTouchBlock();
+  TouchBlockState* block = mAsyncPanZoomController->GetInputQueue()->GetCurrentTouchBlock();
+  MOZ_ASSERT(block);
   RefPtr<CancelableRunnable> task =
     NewCancelableRunnableMethod<bool>(this,
                                       &GestureEventListener::HandleInputTimeoutMaxTap,
                                       block->IsDuringFastFling());
 
   mMaxTapTimeoutTask = task;
   mAsyncPanZoomController->PostDelayedTask(
     task.forget(),
--- a/gfx/layers/apz/src/InputQueue.cpp
+++ b/gfx/layers/apz/src/InputQueue.cpp
@@ -453,66 +453,69 @@ InputQueue::SweepDepletedBlocks()
 TouchBlockState*
 InputQueue::StartNewTouchBlock(const RefPtr<AsyncPanZoomController>& aTarget,
                                bool aTargetConfirmed,
                                bool aCopyPropertiesFromCurrent)
 {
   TouchBlockState* newBlock = new TouchBlockState(aTarget, aTargetConfirmed,
       mTouchCounter);
   if (aCopyPropertiesFromCurrent) {
-    newBlock->CopyPropertiesFrom(*CurrentTouchBlock());
+    // We should never enter here without a current touch block, because this
+    // codepath is invoked from the OnLongPress handler in
+    // AsyncPanZoomController, which should bail out if there is no current
+    // touch block.
+    MOZ_ASSERT(GetCurrentTouchBlock());
+    newBlock->CopyPropertiesFrom(*GetCurrentTouchBlock());
   }
 
   SweepDepletedBlocks();
 
   // Add the new block to the queue.
   mInputBlockQueue.AppendElement(newBlock);
   mActiveTouchBlock = newBlock;
   return newBlock;
 }
 
 CancelableBlockState*
-InputQueue::CurrentBlock() const
+InputQueue::GetCurrentBlock() const
 {
   APZThreadUtils::AssertOnControllerThread();
 
-  MOZ_ASSERT(!mInputBlockQueue.IsEmpty());
+  if (mInputBlockQueue.IsEmpty()) {
+    return nullptr;
+  }
   return mInputBlockQueue[0].get();
 }
 
 TouchBlockState*
-InputQueue::CurrentTouchBlock() const
+InputQueue::GetCurrentTouchBlock() const
 {
-  TouchBlockState* block = CurrentBlock()->AsTouchBlock();
-  MOZ_ASSERT(block);
-  return block;
+  CancelableBlockState* block = GetCurrentBlock();
+  return block ? block->AsTouchBlock() : mActiveTouchBlock.get();
 }
 
 WheelBlockState*
-InputQueue::CurrentWheelBlock() const
+InputQueue::GetCurrentWheelBlock() const
 {
-  WheelBlockState* block = CurrentBlock()->AsWheelBlock();
-  MOZ_ASSERT(block);
-  return block;
+  CancelableBlockState* block = GetCurrentBlock();
+  return block ? block->AsWheelBlock() : mActiveWheelBlock.get();
 }
 
 DragBlockState*
-InputQueue::CurrentDragBlock() const
+InputQueue::GetCurrentDragBlock() const
 {
-  DragBlockState* block = CurrentBlock()->AsDragBlock();
-  MOZ_ASSERT(block);
-  return block;
+  CancelableBlockState* block = GetCurrentBlock();
+  return block ? block->AsDragBlock() : mActiveDragBlock.get();
 }
 
 PanGestureBlockState*
-InputQueue::CurrentPanGestureBlock() const
+InputQueue::GetCurrentPanGestureBlock() const
 {
-  PanGestureBlockState* block = CurrentBlock()->AsPanGestureBlock();
-  MOZ_ASSERT(block);
-  return block;
+  CancelableBlockState* block = GetCurrentBlock();
+  return block ? block->AsPanGestureBlock() : mActivePanGestureBlock.get();
 }
 
 WheelBlockState*
 InputQueue::GetCurrentWheelTransaction() const
 {
   WheelBlockState* block = mActiveWheelBlock.get();
   if (!block || !block->InTransaction()) {
     return nullptr;
@@ -526,22 +529,21 @@ InputQueue::HasReadyTouchBlock() const
   return !mInputBlockQueue.IsEmpty() &&
          mInputBlockQueue[0]->AsTouchBlock() &&
          mInputBlockQueue[0]->IsReadyForHandling();
 }
 
 bool
 InputQueue::AllowScrollHandoff() const
 {
-  MOZ_ASSERT(CurrentBlock());
-  if (CurrentBlock()->AsWheelBlock()) {
-    return CurrentBlock()->AsWheelBlock()->AllowScrollHandoff();
+  if (GetCurrentWheelBlock()) {
+    return GetCurrentWheelBlock()->AllowScrollHandoff();
   }
-  if (CurrentBlock()->AsPanGestureBlock()) {
-    return CurrentBlock()->AsPanGestureBlock()->AllowScrollHandoff();
+  if (GetCurrentPanGestureBlock()) {
+    return GetCurrentPanGestureBlock()->AllowScrollHandoff();
   }
   return true;
 }
 
 bool
 InputQueue::IsDragOnScrollbar(bool aHitScrollbar)
 {
   if (!mDragTracker.InDrag()) {
@@ -675,18 +677,18 @@ InputQueue::SetAllowedTouchBehavior(uint
   }
 }
 
 void
 InputQueue::ProcessInputBlocks() {
   APZThreadUtils::AssertOnControllerThread();
 
   do {
-    CancelableBlockState* curBlock = CurrentBlock();
-    if (!curBlock->IsReadyForHandling()) {
+    CancelableBlockState* curBlock = GetCurrentBlock();
+    if (!curBlock || !curBlock->IsReadyForHandling()) {
       break;
     }
 
     INPQ_LOG("processing input block %p; preventDefault %d target %p\n",
         curBlock, curBlock->IsDefaultPrevented(),
         curBlock->GetTargetApzc().get());
     RefPtr<AsyncPanZoomController> target = curBlock->GetTargetApzc();
     // target may be null here if the initial target was unconfirmed and then
--- a/gfx/layers/apz/src/InputQueue.h
+++ b/gfx/layers/apz/src/InputQueue.h
@@ -86,28 +86,31 @@ public:
    * Adds a new touch block at the end of the input queue that has the same
    * allowed touch behaviour flags as the the touch block currently being
    * processed. This should only be called when processing of a touch block
    * triggers the creation of a new touch block. Returns the input block id
    * of the the newly-created block.
    */
   uint64_t InjectNewTouchBlock(AsyncPanZoomController* aTarget);
   /**
-   * Returns the pending input block at the head of the queue.
+   * Returns the pending input block at the head of the queue, if there is one.
+   * This may return null if there all input events have been processed.
    */
-  CancelableBlockState* CurrentBlock() const;
-  /**
-   * Returns the current pending input block as a specific kind of block.
-   * These methods must only be called if the current pending block is of the
-   * requested type.
+  CancelableBlockState* GetCurrentBlock() const;
+  /*
+   * Returns the current pending input block as a specific kind of block. If
+   * GetCurrentBlock() returns null, these functions additionally check the
+   * mActiveXXXBlock field of the corresponding input type to see if there is
+   * a depleted but still active input block, and returns that if found. These
+   * functions may return null if no block is found.
    */
-  TouchBlockState* CurrentTouchBlock() const;
-  WheelBlockState* CurrentWheelBlock() const;
-  DragBlockState* CurrentDragBlock() const;
-  PanGestureBlockState* CurrentPanGestureBlock() const;
+  TouchBlockState* GetCurrentTouchBlock() const;
+  WheelBlockState* GetCurrentWheelBlock() const;
+  DragBlockState* GetCurrentDragBlock() const;
+  PanGestureBlockState* GetCurrentPanGestureBlock() const;
   /**
    * Returns true iff the pending block at the head of the queue is ready for
    * handling.
    */
   bool HasReadyTouchBlock() const;
   /**
    * If there is a wheel transaction, returns the WheelBlockState representing
    * the transaction. Otherwise, returns null.