Bug 1249710: fix unit mismatch calculating scroll range during async scrollbar drag r=botond
When calculating the max scroll position, the size of mCompositionBounds is
subtracted from the size of mScrollableRectangle. Unfortunately, the former is
in ParentLayer units and the latter is in CSS units. This causes the final
scroll position to become staggered relative to the mouse when user zoom is not
100%.
Use cssCompositionBounds, mCompositionBounds transformed to CSSRect, which
changes based on zoom. Additionally, refactor GetAxis* functions to return
typed units, where possible.
MozReview-Commit-ID: Ec9cOMP1cdT
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -828,45 +828,63 @@ AsyncPanZoomController::ArePointerEvents
bool consumable = (aTouchPoints == 1 ? pannable : zoomable);
if (!consumable) {
return false;
}
return true;
}
-template <typename T>
-static float GetAxisStart(AsyncDragMetrics::DragDirection aDir, T aValue) {
+template <typename Units>
+static CoordTyped<Units> GetAxisStart(AsyncDragMetrics::DragDirection aDir, const PointTyped<Units>& aValue) {
+ if (aDir == AsyncDragMetrics::HORIZONTAL) {
+ return aValue.x;
+ } else {
+ return aValue.y;
+ }
+}
+
+template <typename Units>
+static CoordTyped<Units> GetAxisStart(AsyncDragMetrics::DragDirection aDir, const RectTyped<Units>& aValue) {
if (aDir == AsyncDragMetrics::HORIZONTAL) {
return aValue.x;
} else {
return aValue.y;
}
}
-template <typename T>
-static float GetAxisEnd(AsyncDragMetrics::DragDirection aDir, T aValue) {
+template <typename Units>
+static IntCoordTyped<Units> GetAxisStart(AsyncDragMetrics::DragDirection aDir, const IntRectTyped<Units>& aValue) {
+ if (aDir == AsyncDragMetrics::HORIZONTAL) {
+ return aValue.x;
+ } else {
+ return aValue.y;
+ }
+}
+
+template <typename Units>
+static IntCoordTyped<Units> GetAxisEnd(AsyncDragMetrics::DragDirection aDir, const IntRectTyped<Units>& aValue) {
if (aDir == AsyncDragMetrics::HORIZONTAL) {
return aValue.x + aValue.width;
} else {
return aValue.y + aValue.height;
}
}
-template <typename T>
-static float GetAxisSize(AsyncDragMetrics::DragDirection aDir, T aValue) {
+template <typename Units>
+static CoordTyped<Units> GetAxisSize(AsyncDragMetrics::DragDirection aDir, const RectTyped<Units>& aValue) {
if (aDir == AsyncDragMetrics::HORIZONTAL) {
return aValue.width;
} else {
return aValue.height;
}
}
-template <typename T>
-static float GetAxisScale(AsyncDragMetrics::DragDirection aDir, T aValue) {
+template <typename FromUnits, typename ToUnits>
+static float GetAxisScale(AsyncDragMetrics::DragDirection aDir, const ScaleFactors2D<FromUnits, ToUnits>& aValue) {
if (aDir == AsyncDragMetrics::HORIZONTAL) {
return aValue.xScale;
} else {
return aValue.yScale;
}
}
nsEventStatus AsyncPanZoomController::HandleDragEvent(const MouseInput& aEvent,
@@ -891,34 +909,34 @@ nsEventStatus AsyncPanZoomController::Ha
ReentrantMonitorAutoEnter lock(mMonitor);
CSSPoint scrollFramePoint = aEvent.mLocalOrigin / GetFrameMetrics().GetZoom();
// The scrollbar can be transformed with the frame but the pres shell
// resolution is only applied to the scroll frame.
CSSPoint scrollbarPoint = scrollFramePoint * mFrameMetrics.GetPresShellResolution();
CSSRect cssCompositionBound = mFrameMetrics.CalculateCompositedRectInCssPixels();
- float mousePosition = GetAxisStart(aDragMetrics.mDirection, scrollbarPoint) -
- aDragMetrics.mScrollbarDragOffset -
+ CSSCoord mousePosition = GetAxisStart(aDragMetrics.mDirection, scrollbarPoint) -
+ CSSCoord(aDragMetrics.mScrollbarDragOffset) -
GetAxisStart(aDragMetrics.mDirection, cssCompositionBound) -
- GetAxisStart(aDragMetrics.mDirection, aDragMetrics.mScrollTrack);
-
- float scrollMax = GetAxisEnd(aDragMetrics.mDirection, aDragMetrics.mScrollTrack);
+ CSSCoord(GetAxisStart(aDragMetrics.mDirection, aDragMetrics.mScrollTrack));
+
+ CSSCoord scrollMax = CSSCoord(GetAxisEnd(aDragMetrics.mDirection, aDragMetrics.mScrollTrack));
scrollMax -= node->GetScrollSize() /
GetAxisScale(aDragMetrics.mDirection, mFrameMetrics.GetZoom()) *
mFrameMetrics.GetPresShellResolution();
float scrollPercent = mousePosition / scrollMax;
- float minScrollPosition =
+ CSSCoord minScrollPosition =
GetAxisStart(aDragMetrics.mDirection, mFrameMetrics.GetScrollableRect().TopLeft());
- float maxScrollPosition =
+ CSSCoord maxScrollPosition =
GetAxisSize(aDragMetrics.mDirection, mFrameMetrics.GetScrollableRect()) -
- GetAxisSize(aDragMetrics.mDirection, mFrameMetrics.GetCompositionBounds());
- float scrollPosition = scrollPercent * maxScrollPosition;
+ GetAxisSize(aDragMetrics.mDirection, cssCompositionBound);
+ CSSCoord scrollPosition = scrollPercent * maxScrollPosition;
scrollPosition = std::max(scrollPosition, minScrollPosition);
scrollPosition = std::min(scrollPosition, maxScrollPosition);
CSSPoint scrollOffset = mFrameMetrics.GetScrollOffset();
if (aDragMetrics.mDirection == AsyncDragMetrics::HORIZONTAL) {
scrollOffset.x = scrollPosition;
} else {