diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp index 7e1709c7a4df..f942f8954458 100644 --- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -2133,11 +2133,8 @@ nsGenericElement::SetScrollTop(PRInt32 aScrollTop) nsIScrollableFrame* sf = GetScrollFrame(); if (sf) { nsPoint pt = sf->GetScrollPosition(); - pt.y = nsPresContext::CSSPixelsToAppUnits(aScrollTop); - nscoord halfPixel = nsPresContext::CSSPixelsToAppUnits(0.5f); - // Don't allow pt.y + halfPixel since that would round up to the next CSS pixel. - nsRect range(pt.x, pt.y - halfPixel, 0, halfPixel*2 - 1); - sf->ScrollTo(pt, nsIScrollableFrame::INSTANT, &range); + sf->ScrollToCSSPixels(nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x), + aScrollTop)); } return NS_OK; } @@ -2166,11 +2163,8 @@ nsGenericElement::SetScrollLeft(PRInt32 aScrollLeft) nsIScrollableFrame* sf = GetScrollFrame(); if (sf) { nsPoint pt = sf->GetScrollPosition(); - pt.x = nsPresContext::CSSPixelsToAppUnits(aScrollLeft); - nscoord halfPixel = nsPresContext::CSSPixelsToAppUnits(0.5f); - // Don't allow pt.x + halfPixel since that would round up to the next CSS pixel. - nsRect range(pt.x - halfPixel, pt.y, halfPixel*2 - 1, 0); - sf->ScrollTo(pt, nsIScrollableFrame::INSTANT, &range); + sf->ScrollToCSSPixels(nsIntPoint(aScrollLeft, + nsPresContext::AppUnitsToIntCSSPixels(pt.y))); } return NS_OK; } diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index a3e3eadeda99..374a68797cb5 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -5328,12 +5328,7 @@ nsGlobalWindow::ScrollTo(PRInt32 aXScroll, PRInt32 aYScroll) if (aYScroll > maxpx) { aYScroll = maxpx; } - nsPoint pt(nsPresContext::CSSPixelsToAppUnits(aXScroll), - nsPresContext::CSSPixelsToAppUnits(aYScroll)); - nscoord halfPixel = nsPresContext::CSSPixelsToAppUnits(0.5f); - // Don't allow pt.x/y + halfPixel since that would round up to the next CSS pixel. - nsRect range(pt.x - halfPixel, pt.y - halfPixel, halfPixel*2 - 1, halfPixel*2 - 1); - sf->ScrollTo(pt, nsIScrollableFrame::INSTANT, &range); + sf->ScrollToCSSPixels(nsIntPoint(aXScroll, aYScroll)); } return NS_OK; diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 0c1ac592a41c..096078a71efb 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -1724,6 +1724,31 @@ nsGfxScrollFrameInner::AsyncScrollCallback(void* anInstance, mozilla::TimeStamp self->ScrollToImpl(self->mDestination, range); } +void +nsGfxScrollFrameInner::ScrollToCSSPixels(nsIntPoint aScrollPosition) +{ + nsPoint current = GetScrollPosition(); + nsPoint pt(nsPresContext::CSSPixelsToAppUnits(aScrollPosition.x), + nsPresContext::CSSPixelsToAppUnits(aScrollPosition.y)); + nscoord halfPixel = nsPresContext::CSSPixelsToAppUnits(0.5f); + nsRect range(pt.x - halfPixel, pt.y - halfPixel, 2*halfPixel - 1, 2*halfPixel - 1); + if (nsPresContext::AppUnitsToIntCSSPixels(current.x) == aScrollPosition.x) { + pt.x = current.x; + range.x = pt.x; + range.width = 0; + } else { + // current.x must be outside 'range', so we must move in the correct direction. + } + if (nsPresContext::AppUnitsToIntCSSPixels(current.y) == aScrollPosition.y) { + pt.y = current.y; + range.y = pt.y; + range.height = 0; + } else { + // current.y must be outside 'range', so we must move in the correct direction. + } + ScrollTo(pt, nsIScrollableFrame::INSTANT, &range); +} + /* * this method wraps calls to ScrollToImpl(), either in one shot or incrementally, * based on the setting of the smoothness scroll pref diff --git a/layout/generic/nsGfxScrollFrame.h b/layout/generic/nsGfxScrollFrame.h index 63caddef8a0b..1fa67f832a91 100644 --- a/layout/generic/nsGfxScrollFrame.h +++ b/layout/generic/nsGfxScrollFrame.h @@ -195,6 +195,7 @@ public: const nsRect* aRange = nsnull) { ScrollToWithOrigin(aScrollPosition, aMode, nsGkAtoms::other, aRange); } + void ScrollToCSSPixels(nsIntPoint aScrollPosition); void ScrollToImpl(nsPoint aScrollPosition, const nsRect& aRange); void ScrollVisual(nsPoint aOldScrolledFramePosition); void ScrollBy(nsIntPoint aDelta, nsIScrollableFrame::ScrollUnit aUnit, @@ -505,6 +506,9 @@ public: const nsRect* aRange = nsnull) { mInner.ScrollTo(aScrollPosition, aMode, aRange); } + virtual void ScrollToCSSPixels(nsIntPoint aScrollPosition) { + mInner.ScrollToCSSPixels(aScrollPosition); + } virtual void ScrollBy(nsIntPoint aDelta, ScrollUnit aUnit, ScrollMode aMode, nsIntPoint* aOverflow, nsIAtom *aOrigin = nsnull) { mInner.ScrollBy(aDelta, aUnit, aMode, aOverflow, aOrigin); @@ -747,6 +751,9 @@ public: const nsRect* aRange = nsnull) { mInner.ScrollTo(aScrollPosition, aMode, aRange); } + virtual void ScrollToCSSPixels(nsIntPoint aScrollPosition) { + mInner.ScrollToCSSPixels(aScrollPosition); + } virtual void ScrollBy(nsIntPoint aDelta, ScrollUnit aUnit, ScrollMode aMode, nsIntPoint* aOverflow, nsIAtom *aOrigin = nsnull) { mInner.ScrollBy(aDelta, aUnit, aMode, aOverflow, aOrigin); diff --git a/layout/generic/nsIScrollableFrame.h b/layout/generic/nsIScrollableFrame.h index 1c07921835fc..cbbccdf4c856 100644 --- a/layout/generic/nsIScrollableFrame.h +++ b/layout/generic/nsIScrollableFrame.h @@ -156,6 +156,15 @@ public: */ virtual void ScrollTo(nsPoint aScrollPosition, ScrollMode aMode, const nsRect* aRange = nsnull) = 0; + /** + * Scrolls to a particular position in integer CSS pixels. + * Keeps the exact current horizontal or vertical position if the current + * position, rounded to CSS pixels, matches aScrollPosition. If + * aScrollPosition.x/y is different from the current CSS pixel position, + * makes sure we only move in the direction given by the difference. + * The scroll mode is INSTANT. + */ + virtual void ScrollToCSSPixels(nsIntPoint aScrollPosition) = 0; /** * When scrolling by a relative amount, we can choose various units. */ diff --git a/layout/reftests/scrolling/reftest.list b/layout/reftests/scrolling/reftest.list index 6b0f62cc55ae..98a2581aca06 100644 --- a/layout/reftests/scrolling/reftest.list +++ b/layout/reftests/scrolling/reftest.list @@ -8,6 +8,7 @@ random-if(Android) HTTP == image-1.html image-1.html?ref HTTP == opacity-mixed-scrolling-1.html opacity-mixed-scrolling-1.html?ref random-if(cocoaWidget) HTTP == opacity-mixed-scrolling-2.html opacity-mixed-scrolling-2.html?ref # see bug 625357 HTTP == simple-1.html simple-1.html?ref +HTTP == subpixel-1.html#d subpixel-1-ref.html#d HTTP == text-1.html text-1.html?ref HTTP == text-2.html?up text-2.html?ref HTTP == transformed-1.html transformed-1.html?ref diff --git a/layout/reftests/scrolling/subpixel-1-ref.html b/layout/reftests/scrolling/subpixel-1-ref.html new file mode 100644 index 000000000000..52ec2c54a579 --- /dev/null +++ b/layout/reftests/scrolling/subpixel-1-ref.html @@ -0,0 +1,7 @@ + + + +
+
+ + diff --git a/layout/reftests/scrolling/subpixel-1.html b/layout/reftests/scrolling/subpixel-1.html new file mode 100644 index 000000000000..a0bac5f6a660 --- /dev/null +++ b/layout/reftests/scrolling/subpixel-1.html @@ -0,0 +1,12 @@ + + + +
+
+ + +