Bug 1289432 - Allow the CurrentBlock() and CurrentXXXBlock() functions to return null, and guard/assert at the callsites. r=botond
authorKartikaya Gupta <kgupta@mozilla.com>
Wed, 14 Sep 2016 07:54:36 -0400
changeset 355214 4284c891813dafaaacc329ca931997d16532817a
parent 355213 525c3eceb1060ec39de57c45f2b8923f5518dcb9
child 355215 b40d59513ee6954ab7fff73689fa834727b4a0fa
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-beta@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond
bugs1289432
milestone51.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1289432 - Allow the CurrentBlock() and CurrentXXXBlock() functions to return null, and guard/assert at the callsites. r=botond MozReview-Commit-ID: 77LWZBtAB9Y
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.