Bug 1352863 - Record the position of the scrollbar thumb at the start of a scrollbar drag. r=kats
MozReview-Commit-ID: JqEi1zJZOJa
--- 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
{