Bug 1289432 - Stop relying on the mEvents array inside the SetConfirmedTargetApzc implementations. r?botond draft
authorKartikaya Gupta <kgupta@mozilla.com>
Mon, 12 Sep 2016 22:42:18 -0400
changeset 412861 f076794d81b97f5ed7be68ff05ecf696970157d0
parent 412860 3a1c93931eaebe50464eae618328a73a17f22877
child 412862 30f3663070cb0998b904d167acfb0f3377cfb7e6
push id29274
push userkgupta@mozilla.com
push dateTue, 13 Sep 2016 02:44:31 +0000
reviewersbotond
bugs1289432
milestone51.0a1
Bug 1289432 - Stop relying on the mEvents array inside the SetConfirmedTargetApzc implementations. r?botond MozReview-Commit-ID: JBJNZFiZhDm
gfx/layers/apz/src/InputBlockState.cpp
gfx/layers/apz/src/InputBlockState.h
gfx/layers/apz/src/InputQueue.cpp
gfx/layers/apz/src/InputQueue.h
--- a/gfx/layers/apz/src/InputBlockState.cpp
+++ b/gfx/layers/apz/src/InputBlockState.cpp
@@ -33,17 +33,18 @@ InputBlockState::InputBlockState(const R
 {
   // We should never be constructed with a nullptr target.
   MOZ_ASSERT(mTargetApzc);
   mOverscrollHandoffChain = mTargetApzc->BuildOverscrollHandoffChain();
 }
 
 bool
 InputBlockState::SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc,
-                                        TargetConfirmationState aState)
+                                        TargetConfirmationState aState,
+                                        InputData* aFirstInput)
 {
   MOZ_ASSERT(aState == TargetConfirmationState::eConfirmed
           || aState == TargetConfirmationState::eTimedOut);
 
   if (mTargetConfirmed == TargetConfirmationState::eTimedOut &&
       aState == TargetConfirmationState::eConfirmed) {
     // The main thread finally responded. We had already timed out the
     // confirmation, but we want to update the state internally so that we
@@ -377,28 +378,28 @@ WheelBlockState::SetContentResponse(bool
   if (aPreventDefault) {
     EndTransaction();
   }
   return CancelableBlockState::SetContentResponse(aPreventDefault);
 }
 
 bool
 WheelBlockState::SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc,
-                                        TargetConfirmationState aState)
+                                        TargetConfirmationState aState,
+                                        InputData* aFirstInput)
 {
   // The APZC that we find via APZCCallbackHelpers may not be the same APZC
   // ESM or OverscrollHandoff would have computed. Make sure we get the right
   // one by looking for the first apzc the next pending event can scroll.
   RefPtr<AsyncPanZoomController> apzc = aTargetApzc;
-  if (apzc && mEvents.Length() > 0) {
-    const ScrollWheelInput& event = mEvents.ElementAt(0);
-    apzc = apzc->BuildOverscrollHandoffChain()->FindFirstScrollable(event);
+  if (apzc && aFirstInput) {
+    apzc = apzc->BuildOverscrollHandoffChain()->FindFirstScrollable(*aFirstInput);
   }
 
-  InputBlockState::SetConfirmedTargetApzc(apzc, aState);
+  InputBlockState::SetConfirmedTargetApzc(apzc, aState, aFirstInput);
   return true;
 }
 
 void
 WheelBlockState::Update(ScrollWheelInput& aEvent)
 {
   // We might not be in a transaction if the block never started in a
   // transaction - for example, if nothing was scrollable.
@@ -632,32 +633,32 @@ PanGestureBlockState::PanGestureBlockSta
     if (apzc && apzc != GetTargetApzc()) {
       UpdateTargetApzc(apzc);
     }
   }
 }
 
 bool
 PanGestureBlockState::SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc,
-                                             TargetConfirmationState aState)
+                                             TargetConfirmationState aState,
+                                             InputData* aFirstInput)
 {
   // The APZC that we find via APZCCallbackHelpers may not be the same APZC
   // ESM or OverscrollHandoff would have computed. Make sure we get the right
   // one by looking for the first apzc the next pending event can scroll.
   RefPtr<AsyncPanZoomController> apzc = aTargetApzc;
-  if (apzc && mEvents.Length() > 0) {
-    const PanGestureInput& event = mEvents.ElementAt(0);
+  if (apzc && aFirstInput) {
     RefPtr<AsyncPanZoomController> scrollableApzc =
-      apzc->BuildOverscrollHandoffChain()->FindFirstScrollable(event);
+      apzc->BuildOverscrollHandoffChain()->FindFirstScrollable(*aFirstInput);
     if (scrollableApzc) {
       apzc = scrollableApzc;
     }
   }
 
-  InputBlockState::SetConfirmedTargetApzc(apzc, aState);
+  InputBlockState::SetConfirmedTargetApzc(apzc, aState, aFirstInput);
   return true;
 }
 
 void
 PanGestureBlockState::AddEvent(const PanGestureInput& aEvent)
 {
   mEvents.AppendElement(aEvent);
 }
--- a/gfx/layers/apz/src/InputBlockState.h
+++ b/gfx/layers/apz/src/InputBlockState.h
@@ -50,17 +50,18 @@ public:
   };
 
   explicit InputBlockState(const RefPtr<AsyncPanZoomController>& aTargetApzc,
                            bool aTargetConfirmed);
   virtual ~InputBlockState()
   {}
 
   virtual bool SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc,
-                                      TargetConfirmationState aState);
+                                      TargetConfirmationState aState,
+                                      InputData* aFirstInput);
   const RefPtr<AsyncPanZoomController>& GetTargetApzc() const;
   const RefPtr<const OverscrollHandoffChain>& GetOverscrollHandoffChain() const;
   uint64_t GetBlockId() const;
 
   bool IsTargetConfirmed() const;
   bool HasReceivedRealConfirmedTarget() const;
 
   void SetScrolledApzc(AsyncPanZoomController* aApzc);
@@ -228,17 +229,18 @@ public:
 
   bool SetContentResponse(bool aPreventDefault) override;
   bool HasEvents() const override;
   void DropEvents(nsTArray<UniquePtr<QueuedInput>>* aQueued) override;
   void HandleEvents(nsTArray<UniquePtr<QueuedInput>>* aQueued) override;
   bool MustStayActive() override;
   const char* Type() override;
   bool SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc,
-                              TargetConfirmationState aState) override;
+                              TargetConfirmationState aState,
+                              InputData* aFirstInput) override;
 
   void AddEvent(const ScrollWheelInput& aEvent);
 
   WheelBlockState *AsWheelBlock() override {
     return this;
   }
 
   /**
@@ -350,17 +352,18 @@ public:
   bool HasReceivedAllContentNotifications() const override;
   bool IsReadyForHandling() const override;
   bool HasEvents() const override;
   void DropEvents(nsTArray<UniquePtr<QueuedInput>>* aQueued) override;
   void HandleEvents(nsTArray<UniquePtr<QueuedInput>>* aQueued) override;
   bool MustStayActive() override;
   const char* Type() override;
   bool SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc,
-                              TargetConfirmationState aState) override;
+                              TargetConfirmationState aState,
+                              InputData* aFirstInput) override;
 
   void AddEvent(const PanGestureInput& aEvent);
 
   PanGestureBlockState *AsPanGestureBlock() override {
     return this;
   }
 
   /**
--- a/gfx/layers/apz/src/InputQueue.cpp
+++ b/gfx/layers/apz/src/InputQueue.cpp
@@ -99,17 +99,18 @@ InputQueue::ReceiveTouchInput(const RefP
         haveBehaviors) {
       // If we're already in a fast fling, and a single finger goes down, then
       // we want special handling for the touch event, because it shouldn't get
       // delivered to content. Note that we don't set this flag when going
       // from a fast fling to a pinch state (i.e. second finger goes down while
       // the first finger is moving).
       block->SetDuringFastFling();
       block->SetConfirmedTargetApzc(aTarget,
-          InputBlockState::TargetConfirmationState::eConfirmed);
+          InputBlockState::TargetConfirmationState::eConfirmed,
+          nullptr /* the block was just created so it has no events */);
       if (gfxPrefs::TouchActionEnabled()) {
         block->SetAllowedTouchBehaviors(currentBehaviors);
       }
       INPQ_LOG("block %p tagged as fast-motion\n", block);
     }
 
     CancelAnimationsForNewBlock(block);
 
@@ -541,33 +542,65 @@ InputQueue::ScheduleMainThreadTimeout(co
   INPQ_LOG("scheduling main thread timeout for target %p\n", aTarget.get());
   aBlock->StartContentResponseTimer();
   aTarget->PostDelayedTask(NewRunnableMethod<uint64_t>(this,
                                                        &InputQueue::MainThreadTimeout,
                                                        aBlock->GetBlockId()),
                            gfxPrefs::APZContentResponseTimeout());
 }
 
+CancelableBlockState*
+InputQueue::FindBlockForId(const uint64_t& aInputBlockId,
+                           InputData** aOutFirstInput)
+{
+  for (size_t i = 0; i < mQueuedInputs.Length(); i++) {
+    if (mQueuedInputs[i]->Block()->GetBlockId() == aInputBlockId) {
+      if (aOutFirstInput) {
+        *aOutFirstInput = mQueuedInputs[i]->Input();
+      }
+      return mQueuedInputs[i]->Block();
+    }
+  }
+
+  CancelableBlockState* block = nullptr;
+  if (mActiveTouchBlock && mActiveTouchBlock->GetBlockId() == aInputBlockId) {
+    block = mActiveTouchBlock.get();
+  } else if (mActiveWheelBlock && mActiveWheelBlock->GetBlockId() == aInputBlockId) {
+    block = mActiveWheelBlock.get();
+  } else if (mActiveDragBlock && mActiveDragBlock->GetBlockId() == aInputBlockId) {
+    block = mActiveDragBlock.get();
+  } else if (mActivePanGestureBlock && mActivePanGestureBlock->GetBlockId() == aInputBlockId) {
+    block = mActivePanGestureBlock.get();
+  }
+  // Since we didn't encounter this block while iterating through mQueuedInputs,
+  // it must have no events associated with it at the moment.
+  MOZ_ASSERT(!block || !block->HasEvents());
+  if (aOutFirstInput) {
+    *aOutFirstInput = nullptr;
+  }
+  return block;
+}
+
 void
 InputQueue::MainThreadTimeout(const uint64_t& aInputBlockId) {
   APZThreadUtils::AssertOnControllerThread();
 
   INPQ_LOG("got a main thread timeout; block=%" PRIu64 "\n", aInputBlockId);
   bool success = false;
-  for (size_t i = 0; i < mInputBlockQueue.Length(); i++) {
-    if (mInputBlockQueue[i]->GetBlockId() == aInputBlockId) {
-      // time out the touch-listener response and also confirm the existing
-      // target apzc in the case where the main thread doesn't get back to us
-      // fast enough.
-      success = mInputBlockQueue[i]->TimeoutContentResponse();
-      success |= mInputBlockQueue[i]->SetConfirmedTargetApzc(
-          mInputBlockQueue[i]->GetTargetApzc(),
-          InputBlockState::TargetConfirmationState::eTimedOut);
-      break;
-    }
+  InputData* firstInput = nullptr;
+  CancelableBlockState* block = FindBlockForId(aInputBlockId, &firstInput);
+  if (block) {
+    // time out the touch-listener response and also confirm the existing
+    // target apzc in the case where the main thread doesn't get back to us
+    // fast enough.
+    success = block->TimeoutContentResponse();
+    success |= block->SetConfirmedTargetApzc(
+        block->GetTargetApzc(),
+        InputBlockState::TargetConfirmationState::eTimedOut,
+        firstInput);
   }
   if (success) {
     ProcessInputBlocks();
   }
 }
 
 void
 InputQueue::ContentReceivedInputBlock(uint64_t aInputBlockId, bool aPreventDefault) {
@@ -590,48 +623,46 @@ InputQueue::ContentReceivedInputBlock(ui
 
 void
 InputQueue::SetConfirmedTargetApzc(uint64_t aInputBlockId, const RefPtr<AsyncPanZoomController>& aTargetApzc) {
   APZThreadUtils::AssertOnControllerThread();
 
   INPQ_LOG("got a target apzc; block=%" PRIu64 " guid=%s\n",
     aInputBlockId, aTargetApzc ? Stringify(aTargetApzc->GetGuid()).c_str() : "");
   bool success = false;
-  for (size_t i = 0; i < mInputBlockQueue.Length(); i++) {
-    CancelableBlockState* block = mInputBlockQueue[i].get();
-    if (block->GetBlockId() == aInputBlockId) {
-      success = block->SetConfirmedTargetApzc(aTargetApzc,
-          InputBlockState::TargetConfirmationState::eConfirmed);
-      block->RecordContentResponseTime();
-      break;
-    }
+  InputData* firstInput = nullptr;
+  CancelableBlockState* block = FindBlockForId(aInputBlockId, &firstInput);
+  if (block) {
+    success = block->SetConfirmedTargetApzc(aTargetApzc,
+        InputBlockState::TargetConfirmationState::eConfirmed,
+        firstInput);
+    block->RecordContentResponseTime();
   }
   if (success) {
     ProcessInputBlocks();
   }
 }
 
 void
 InputQueue::ConfirmDragBlock(uint64_t aInputBlockId, const RefPtr<AsyncPanZoomController>& aTargetApzc,
                                    const AsyncDragMetrics& aDragMetrics)
 {
   APZThreadUtils::AssertOnControllerThread();
 
   INPQ_LOG("got a target apzc; block=%" PRIu64 " guid=%s\n",
     aInputBlockId, aTargetApzc ? Stringify(aTargetApzc->GetGuid()).c_str() : "");
   bool success = false;
-  for (size_t i = 0; i < mInputBlockQueue.Length(); i++) {
-    DragBlockState* block = mInputBlockQueue[i]->AsDragBlock();
-    if (block && block->GetBlockId() == aInputBlockId) {
-      block->SetDragMetrics(aDragMetrics);
-      success = block->SetConfirmedTargetApzc(aTargetApzc,
-          InputBlockState::TargetConfirmationState::eConfirmed);
-      block->RecordContentResponseTime();
-      break;
-    }
+  InputData* firstInput = nullptr;
+  CancelableBlockState* block = FindBlockForId(aInputBlockId, &firstInput);
+  if (block && block->AsDragBlock()) {
+    block->AsDragBlock()->SetDragMetrics(aDragMetrics);
+    success = block->SetConfirmedTargetApzc(aTargetApzc,
+        InputBlockState::TargetConfirmationState::eConfirmed,
+        firstInput);
+    block->RecordContentResponseTime();
   }
   if (success) {
     ProcessInputBlocks();
   }
 }
 
 void
 InputQueue::SetAllowedTouchBehavior(uint64_t aInputBlockId, const nsTArray<TouchBehaviorFlags>& aBehaviors) {
--- a/gfx/layers/apz/src/InputQueue.h
+++ b/gfx/layers/apz/src/InputQueue.h
@@ -167,16 +167,27 @@ private:
                                         const PanGestureInput& aEvent,
                                         uint64_t* aOutInputBlockId);
 
   /**
    * Remove any blocks that are inactive - not ready, and having no events.
    */
   void SweepDepletedBlocks();
 
+  /**
+   * Helper function that searches mQueuedInputs for the first block matching
+   * the given id, and returns it. If |aOutFirstInput| is non-null, it is
+   * populated with a pointer to the first input in mQueuedInputs that
+   * corresponds to the block, or null if no such input was found. Note that
+   * even if there are no inputs in mQueuedInputs, this function can return
+   * non-null if the block id provided matches one of the depleted-but-still-
+   * active blocks (mActiveTouchBlock, mActiveWheelBlock, etc.).
+   */
+  CancelableBlockState* FindBlockForId(const uint64_t& aInputBlockId,
+                                       InputData** aOutFirstInput);
   void ScheduleMainThreadTimeout(const RefPtr<AsyncPanZoomController>& aTarget,
                                  CancelableBlockState* aBlock);
   void MainThreadTimeout(const uint64_t& aInputBlockId);
   void ProcessInputBlocks();
   void ClearActiveBlock(CancelableBlockState* aBlock);
   void UpdateActiveApzc(const RefPtr<AsyncPanZoomController>& aNewActive);
 
 private: