Bug 1352863 - Record the position of the scrollbar thumb at the start of a scrollbar drag. r=kats draft
authorBotond Ballo <botond@mozilla.com>
Fri, 19 May 2017 20:14:14 -0400
changeset 583909 8e7c2255c1cf2661489cc7fee0013bb8297c8d06
parent 583908 4c63269480154a95d5faedf1b4972f7d3373cb5a
child 583910 47ecaffe037579a590e00727f36b1caf2e00aaa6
push id60596
push userbballo@mozilla.com
push dateWed, 24 May 2017 19:49:24 +0000
reviewerskats
bugs1352863
milestone55.0a1
Bug 1352863 - Record the position of the scrollbar thumb at the start of a scrollbar drag. r=kats MozReview-Commit-ID: JqEi1zJZOJa
gfx/layers/apz/src/APZCTreeManager.cpp
gfx/layers/apz/src/InputBlockState.cpp
gfx/layers/apz/src/InputBlockState.h
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -929,61 +929,70 @@ APZCTreeManager::ReceiveInputEvent(Input
           // 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 && gfxPrefs::APZDragInitiationEnabled() &&
-            startsDrag && hitScrollbarNode &&
+        // If we're starting an async scrollbar drag
+        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()) {
+            mInputQueue->GetCurrentDragBlock()) {
           DragBlockState* dragBlock = mInputQueue->GetCurrentDragBlock();
-          uint64_t dragBlockId = dragBlock->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.
-          // ScrollThumbData::mThumbStart stores the offset of the thumb
-          // relative to the scroll track at the time of the last paint.
-          // Since that paint, the thumb may have acquired an async transform
-          // due to async scrolling, so look that up and apply it.
-          LayerToParentLayerMatrix4x4 thumbTransform;
-          {
-            MutexAutoLock lock(mTreeLock);
-            thumbTransform = ComputeTransformForNode(hitScrollbarNode);
+
+          // Record the thumb's position at the start of the drag.
+          // We snap back to this position if, during the drag, the mouse
+          // gets sufficiently far away from the scrollbar.
+          dragBlock->SetInitialThumbPos(thumbData.mThumbStart);
+
+          // Under some conditions, we can confirm the drag block right away.
+          // Otherwise, we have to wait for a main-thread confirmation.
+          if (gfxPrefs::APZDragInitiationEnabled() &&
+              // check that the scrollbar's target scroll frame is layerized
+              hitScrollbarNode->GetScrollTargetId() == apzc->GetGuid().mScrollId &&
+              !apzc->IsScrollInfoLayer()) {
+            uint64_t dragBlockId = dragBlock->GetBlockId();
+            // 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.
+            // ScrollThumbData::mThumbStart stores the offset of the thumb
+            // relative to the scroll track at the time of the last paint.
+            // Since that paint, the thumb may have acquired an async transform
+            // due to async scrolling, so look that up and apply it.
+            LayerToParentLayerMatrix4x4 thumbTransform;
+            {
+              MutexAutoLock lock(mTreeLock);
+              thumbTransform = ComputeTransformForNode(hitScrollbarNode);
+            }
+            // Only consider the translation, since we do not support both
+            // zooming and scrollbar dragging on any platform.
+            CSSCoord thumbStart = thumbData.mThumbStart
+                                + ((thumbData.mDirection == ScrollDirection::HORIZONTAL)
+                                   ? thumbTransform._41 : thumbTransform._42);
+            dragStart -= thumbStart;
+            mInputQueue->ConfirmDragBlock(
+                dragBlockId, apzc,
+                AsyncDragMetrics(apzc->GetGuid().mScrollId,
+                                 apzc->GetGuid().mPresShellId,
+                                 dragBlockId,
+                                 dragStart,
+                                 thumbData.mDirection));
+            // Content can't prevent scrollbar dragging with preventDefault(),
+            // so we don't need to wait for a content response.
+            dragBlock->SetContentResponse(false);
           }
-          // Only consider the translation, since we do not support both
-          // zooming and scrollbar dragging on any platform.
-          CSSCoord thumbStart = thumbData.mThumbStart
-                              + ((thumbData.mDirection == ScrollDirection::HORIZONTAL)
-                                 ? thumbTransform._41 : thumbTransform._42);
-          dragStart -= thumbStart;
-          mInputQueue->ConfirmDragBlock(
-              dragBlockId, apzc,
-              AsyncDragMetrics(apzc->GetGuid().mScrollId,
-                               apzc->GetGuid().mPresShellId,
-                               dragBlockId,
-                               dragStart,
-                               thumbData.mDirection));
-          // Content can't prevent scrollbar dragging with preventDefault(),
-          // so we don't need to wait for a content response.
-          dragBlock->SetContentResponse(false);
         }
 
         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);
         }
--- a/gfx/layers/apz/src/InputBlockState.cpp
+++ b/gfx/layers/apz/src/InputBlockState.cpp
@@ -267,16 +267,22 @@ DragBlockState::HasReceivedMouseUp()
 
 void
 DragBlockState::MarkMouseUpReceived()
 {
   mReceivedMouseUp = true;
 }
 
 void
+DragBlockState::SetInitialThumbPos(CSSCoord aThumbPos)
+{
+  mInitialThumbPos = aThumbPos;
+}
+
+void
 DragBlockState::SetDragMetrics(const AsyncDragMetrics& aDragMetrics)
 {
   mDragMetrics = aDragMetrics;
 }
 
 void
 DragBlockState::DispatchEvent(const InputData& aEvent) const
 {
--- a/gfx/layers/apz/src/InputBlockState.h
+++ b/gfx/layers/apz/src/InputBlockState.h
@@ -296,21 +296,23 @@ public:
 
   bool HasReceivedMouseUp();
   void MarkMouseUpReceived();
 
   DragBlockState *AsDragBlock() override {
     return this;
   }
 
+  void SetInitialThumbPos(CSSCoord aThumbPos);
   void SetDragMetrics(const AsyncDragMetrics& aDragMetrics);
 
   void DispatchEvent(const InputData& aEvent) const override;
 private:
   AsyncDragMetrics mDragMetrics;
+  CSSCoord mInitialThumbPos;
   bool mReceivedMouseUp;
 };
 
 /**
  * A single block of pan gesture events.
  */
 class PanGestureBlockState : public CancelableBlockState
 {