Bug 1349750 - Have APZ initiate async scrollbar dragging when possible. r=kats draft
authorBotond Ballo <botond@mozilla.com>
Wed, 10 May 2017 19:29:46 -0400
changeset 577150 dce1353e5ccebfacd5d100719ebb684dfa0f516b
parent 577149 25183e22cb7ffb9995a2594d6aea106cdef7924a
child 577151 dabc4a4b72210133d8b62256510213183312f18f
push id58627
push userbballo@mozilla.com
push dateFri, 12 May 2017 22:26:26 +0000
reviewerskats
bugs1349750
milestone55.0a1
Bug 1349750 - Have APZ initiate async scrollbar dragging when possible. r=kats MozReview-Commit-ID: 1snCEl6H9bN
gfx/layers/apz/src/APZCTreeManager.cpp
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -776,17 +776,18 @@ APZCTreeManager::ReceiveInputEvent(Input
     case MULTITOUCH_INPUT: {
       MultiTouchInput& touchInput = aEvent.AsMultiTouchInput();
       result = ProcessTouchInput(touchInput, aOutTargetGuid, aOutInputBlockId);
       break;
     } case MOUSE_INPUT: {
       MouseInput& mouseInput = aEvent.AsMouseInput();
       mouseInput.mHandledByAPZ = true;
 
-      if (DragTracker::StartsDrag(mouseInput)) {
+      bool startsDrag = DragTracker::StartsDrag(mouseInput);
+      if (startsDrag) {
         // If this is the start of a drag we need to unambiguously know if it's
         // going to land on a scrollbar or not. We can't apply an untransform
         // here without knowing that, so we need to ensure the untransform is
         // a no-op.
         FlushRepaintsToClearScreenToGeckoTransform();
       }
 
       HitTestingTreeNode* hitScrollbarNode = nullptr;
@@ -800,26 +801,55 @@ APZCTreeManager::ReceiveInputEvent(Input
         MutexAutoLock lock(mTreeLock);
         if (!apzc && mRootNode) {
           apzc = mRootNode->GetApzc();
         }
       }
 
       if (apzc) {
         bool targetConfirmed = (hitResult != HitNothing && hitResult != HitDispatchToContentRegion);
-        if (gfxPrefs::APZDragEnabled() && hitScrollbar) {
+        bool apzDragEnabled = gfxPrefs::APZDragEnabled();
+        if (apzDragEnabled && hitScrollbar) {
           // If scrollbar dragging is enabled and we hit a scrollbar, wait
           // for the main-thread confirmation because it contains drag metrics
           // that we need.
           targetConfirmed = false;
         }
         result = mInputQueue->ReceiveInputEvent(
           apzc, targetConfirmed,
           mouseInput, aOutInputBlockId);
 
+        // Under some conditions, we can confirm the drag block right away.
+        // Otherwise, we have to wait for a main-thread confirmation.
+        if (apzDragEnabled && startsDrag && hitScrollbarNode &&
+            hitScrollbarNode->IsScrollThumbNode() &&
+            hitScrollbarNode->GetScrollThumbData().mIsAsyncDraggable &&
+            // check that the scrollbar's target scroll frame is layerized
+            hitScrollbarNode->GetScrollTargetId() == apzc->GetGuid().mScrollId &&
+            !apzc->IsScrollInfoLayer() && mInputQueue->GetCurrentDragBlock()) {
+          uint64_t dragBlockId = mInputQueue->GetCurrentDragBlock()->GetBlockId();
+          const ScrollThumbData& thumbData = hitScrollbarNode->GetScrollThumbData();
+          // AsyncPanZoomController::HandleInputEvent() will call
+          // TransformToLocal() on the event, but we need its mLocalOrigin now
+          // to compute a drag start offset for the AsyncDragMetrics.
+          mouseInput.TransformToLocal(apzc->GetTransformToThis());
+          CSSCoord dragStart = apzc->ConvertScrollbarPoint(
+              mouseInput.mLocalOrigin, thumbData);
+          // ConvertScrollbarPoint() got the drag start offset relative to
+          // the scroll track. Now get it relative to the thumb.
+          dragStart -= thumbData.mThumbStart;
+          mInputQueue->ConfirmDragBlock(
+              dragBlockId, apzc,
+              AsyncDragMetrics(apzc->GetGuid().mScrollId,
+                               apzc->GetGuid().mPresShellId,
+                               dragBlockId,
+                               dragStart,
+                               thumbData.mDirection));
+        }
+
         if (result == nsEventStatus_eConsumeDoDefault) {
           // This input event is part of a drag block, so whether or not it is
           // directed at a scrollbar depends on whether the drag block started
           // on a scrollbar.
           hitScrollbar = mInputQueue->IsDragOnScrollbar(hitScrollbar);
         }
 
         // Update the out-parameters so they are what the caller expects.