Bug 1101628 - Have the APZCTM tell the input queue what the allowed touch behaviours are, if it has the information. r=botond
authorKartikaya Gupta <kgupta@mozilla.com>
Wed, 01 Jun 2016 15:48:05 -0400
changeset 339005 c8011fc5c80b24911c1aabfd0de37f004eb7f587
parent 339004 2e253d272ceb1514b3932342a1532c4bb9e287ac
child 339006 274c6d39f9635a7ef4844930043a9d28c13130b5
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond
bugs1101628
milestone49.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 1101628 - Have the APZCTM tell the input queue what the allowed touch behaviours are, if it has the information. r=botond MozReview-Commit-ID: CUgJm5ObVFV
gfx/layers/apz/src/APZCTreeManager.cpp
gfx/layers/apz/src/APZCTreeManager.h
gfx/layers/apz/src/InputQueue.cpp
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -885,43 +885,80 @@ APZCTreeManager::ReceiveInputEvent(Input
         tapInput.mPoint = *untransformedPoint;
       }
       break;
     }
   }
   return result;
 }
 
+static TouchBehaviorFlags
+ConvertToTouchBehavior(HitTestResult result)
+{
+  switch (result) {
+    case HitNothing:
+      return AllowedTouchBehavior::NONE;
+    case HitLayer:
+      return AllowedTouchBehavior::VERTICAL_PAN
+           | AllowedTouchBehavior::HORIZONTAL_PAN
+           | AllowedTouchBehavior::PINCH_ZOOM
+           | AllowedTouchBehavior::DOUBLE_TAP_ZOOM;
+    case HitLayerTouchActionNone:
+      return AllowedTouchBehavior::NONE;
+    case HitLayerTouchActionPanX:
+      return AllowedTouchBehavior::HORIZONTAL_PAN;
+    case HitLayerTouchActionPanY:
+      return AllowedTouchBehavior::VERTICAL_PAN;
+    case HitDispatchToContentRegion:
+    default:
+      return AllowedTouchBehavior::UNKNOWN;
+  }
+}
+
 already_AddRefed<AsyncPanZoomController>
 APZCTreeManager::GetTouchInputBlockAPZC(const MultiTouchInput& aEvent,
+                                        nsTArray<TouchBehaviorFlags>* aOutTouchBehaviors,
                                         HitTestResult* aOutHitResult)
 {
   RefPtr<AsyncPanZoomController> apzc;
   if (aEvent.mTouches.Length() == 0) {
     return apzc.forget();
   }
 
   FlushRepaintsToClearScreenToGeckoTransform();
 
-  apzc = GetTargetAPZC(aEvent.mTouches[0].mScreenPoint, aOutHitResult);
+  HitTestResult hitResult;
+  apzc = GetTargetAPZC(aEvent.mTouches[0].mScreenPoint, &hitResult);
+  if (aOutTouchBehaviors) {
+    aOutTouchBehaviors->AppendElement(ConvertToTouchBehavior(hitResult));
+  }
   for (size_t i = 1; i < aEvent.mTouches.Length(); i++) {
-    RefPtr<AsyncPanZoomController> apzc2 = GetTargetAPZC(aEvent.mTouches[i].mScreenPoint, aOutHitResult);
+    RefPtr<AsyncPanZoomController> apzc2 = GetTargetAPZC(aEvent.mTouches[i].mScreenPoint, &hitResult);
+    if (aOutTouchBehaviors) {
+      aOutTouchBehaviors->AppendElement(ConvertToTouchBehavior(hitResult));
+    }
     apzc = GetMultitouchTarget(apzc, apzc2);
     APZCTM_LOG("Using APZC %p as the root APZC for multi-touch\n", apzc.get());
   }
 
+  if (aOutHitResult) {
+    // XXX we should probably be combining the hit results from the different
+    // touch points somehow, instead of just using the last one.
+    *aOutHitResult = hitResult;
+  }
   return apzc.forget();
 }
 
 nsEventStatus
 APZCTreeManager::ProcessTouchInput(MultiTouchInput& aInput,
                                    ScrollableLayerGuid* aOutTargetGuid,
                                    uint64_t* aOutInputBlockId)
 {
   aInput.mHandledByAPZ = true;
+  nsTArray<TouchBehaviorFlags> touchBehaviors;
   if (aInput.mType == MultiTouchInput::MULTITOUCH_START) {
     // If we are panned into overscroll and a second finger goes down,
     // ignore that second touch point completely. The touch-start for it is
     // dropped completely; subsequent touch events until the touch-end for it
     // will have this touch point filtered out.
     // (By contrast, if we're in overscroll but not panning, such as after
     // putting two fingers down during an overscroll animation, we process the
     // second touch and proceed to pinch.)
@@ -930,17 +967,27 @@ APZCTreeManager::ProcessTouchInput(Multi
         BuildOverscrollHandoffChain(mApzcForInputBlock)->HasOverscrolledApzc()) {
       if (mRetainedTouchIdentifier == -1) {
         mRetainedTouchIdentifier = mApzcForInputBlock->GetLastTouchIdentifier();
       }
       return nsEventStatus_eConsumeNoDefault;
     }
 
     mHitResultForInputBlock = HitNothing;
-    mApzcForInputBlock = GetTouchInputBlockAPZC(aInput, &mHitResultForInputBlock);
+    mApzcForInputBlock = GetTouchInputBlockAPZC(aInput, &touchBehaviors, &mHitResultForInputBlock);
+    MOZ_ASSERT(touchBehaviors.Length() == aInput.mTouches.Length());
+    for (size_t i = 0; i < touchBehaviors.Length(); i++) {
+      APZCTM_LOG("Touch point has allowed behaviours 0x%02x\n", touchBehaviors[i]);
+      if (touchBehaviors[i] == AllowedTouchBehavior::UNKNOWN) {
+        // If there's any unknown items in the list, throw it out and we'll
+        // wait for the main thread to send us a notification.
+        touchBehaviors.Clear();
+        break;
+      }
+    }
   } else if (mApzcForInputBlock) {
     APZCTM_LOG("Re-using APZC %p as continuation of event block\n", mApzcForInputBlock.get());
   }
 
   // If we receive a touch-cancel, it means all touches are finished, so we
   // can stop ignoring any that we were ignoring.
   if (aInput.mType == MultiTouchInput::MULTITOUCH_CANCEL) {
     mRetainedTouchIdentifier = -1;
@@ -949,32 +996,39 @@ APZCTreeManager::ProcessTouchInput(Multi
   // If we are currently ignoring any touch points, filter them out from the
   // set of touch points included in this event. Note that we modify aInput
   // itself, so that the touch points are also filtered out when the caller
   // passes the event on to content.
   if (mRetainedTouchIdentifier != -1) {
     for (size_t j = 0; j < aInput.mTouches.Length(); ++j) {
       if (aInput.mTouches[j].mIdentifier != mRetainedTouchIdentifier) {
         aInput.mTouches.RemoveElementAt(j);
+        if (!touchBehaviors.IsEmpty()) {
+          MOZ_ASSERT(touchBehaviors.Length() > j);
+          touchBehaviors.RemoveElementAt(j);
+        }
         --j;
       }
     }
     if (aInput.mTouches.IsEmpty()) {
       return nsEventStatus_eConsumeNoDefault;
     }
   }
 
   nsEventStatus result = nsEventStatus_eIgnore;
   if (mApzcForInputBlock) {
     MOZ_ASSERT(mHitResultForInputBlock != HitNothing);
 
     mApzcForInputBlock->GetGuid(aOutTargetGuid);
     result = mInputQueue->ReceiveInputEvent(mApzcForInputBlock,
         /* aTargetConfirmed = */ mHitResultForInputBlock != HitDispatchToContentRegion,
         aInput, aOutInputBlockId);
+    if (!touchBehaviors.IsEmpty()) {
+      mInputQueue->SetAllowedTouchBehavior(*aOutInputBlockId, touchBehaviors);
+    }
 
     // For computing the event to pass back to Gecko, use up-to-date transforms
     // (i.e. not anything cached in an input block).
     // This ensures that transformToApzc and transformToGecko are in sync.
     ScreenToParentLayerMatrix4x4 transformToApzc = GetScreenToApzcTransform(mApzcForInputBlock);
     ParentLayerToScreenMatrix4x4 transformToGecko = GetApzcToGeckoTransform(mApzcForInputBlock);
     ScreenToScreenMatrix4x4 outTransform = transformToApzc * transformToGecko;
     
--- a/gfx/layers/apz/src/APZCTreeManager.h
+++ b/gfx/layers/apz/src/APZCTreeManager.h
@@ -468,16 +468,17 @@ private:
                                          HitTestResult* aOutHitResult,
                                          bool* aOutHitScrollbar);
   AsyncPanZoomController* FindRootApzcForLayersId(uint64_t aLayersId) const;
   AsyncPanZoomController* FindRootContentApzcForLayersId(uint64_t aLayersId) const;
   AsyncPanZoomController* FindRootContentOrRootApzc() const;
   already_AddRefed<AsyncPanZoomController> GetMultitouchTarget(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2) const;
   already_AddRefed<AsyncPanZoomController> CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2) const;
   already_AddRefed<AsyncPanZoomController> GetTouchInputBlockAPZC(const MultiTouchInput& aEvent,
+                                                                  nsTArray<TouchBehaviorFlags>* aOutTouchBehaviors,
                                                                   HitTestResult* aOutHitResult);
   nsEventStatus ProcessTouchInput(MultiTouchInput& aInput,
                                   ScrollableLayerGuid* aOutTargetGuid,
                                   uint64_t* aOutInputBlockId);
   nsEventStatus ProcessWheelEvent(WidgetWheelEvent& aEvent,
                                   ScrollableLayerGuid* aOutTargetGuid,
                                   uint64_t* aOutInputBlockId);
   nsEventStatus ProcessEvent(WidgetInputEvent& inputEvent,
--- a/gfx/layers/apz/src/InputQueue.cpp
+++ b/gfx/layers/apz/src/InputQueue.cpp
@@ -402,19 +402,22 @@ InputQueue::MaybeRequestContentResponse(
   if (aBlock->IsTargetConfirmed()) {
     // Content won't prevent-default this, so we can just set the flag directly.
     INPQ_LOG("not waiting for content response on block %p\n", aBlock);
     aBlock->SetContentResponse(false);
   } else {
     waitForMainThread = true;
   }
   if (aBlock->AsTouchBlock() && gfxPrefs::TouchActionEnabled()) {
-    // TODO: once bug 1101628 is fixed, waitForMainThread should only be set
-    // to true if the APZCTM didn't know the touch-action behaviours for this
-    // block.
+    // waitForMainThread is set to true unconditionally here, but if the APZCTM
+    // has the touch-action behaviours for this block, it will set it
+    // immediately after we unwind out of this ReceiveInputEvent call. So even
+    // though we are scheduling the main-thread timeout, we might end up not
+    // waiting.
+    INPQ_LOG("waiting for main thread touch-action info on block %p\n", aBlock);
     waitForMainThread = true;
   }
   if (waitForMainThread) {
     // We either don't know for sure if aTarget is the right APZC, or we may
     // need to wait to give content the opportunity to prevent-default the
     // touch events. Either way we schedule a timeout so the main thread stuff
     // can run.
     ScheduleMainThreadTimeout(aTarget, aBlock);