diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index f23cb45c5dbe..4272d8df3fc5 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -393,7 +393,9 @@ class ThebesDisplayItemLayerUserData : public LayerUserData { public: ThebesDisplayItemLayerUserData() : - mForcedBackgroundColor(NS_RGBA(0,0,0,0)) {} + mForcedBackgroundColor(NS_RGBA(0,0,0,0)), + mXScale(1.f), mYScale(1.f), + mActiveScrolledRootPosition(0, 0) {} /** * A color that should be painted over the bounds of the layer's visible @@ -404,6 +406,17 @@ public: * The resolution scale used. */ float mXScale, mYScale; + /** + * We try to make 0,0 of the ThebesLayer be the top-left of the + * border-box of the "active scrolled root" frame (i.e. the nearest ancestor + * frame for the display items that is being actively scrolled). But + * we force the ThebesLayer transform to be an integer translation, and we may + * have a resolution scale, so we have to snap the ThebesLayer transform, so + * 0,0 may not be exactly the top-left of the active scrolled root. Here we + * store the coordinates in ThebesLayer space of the top-left of the + * active scrolled root. + */ + gfxPoint mActiveScrolledRootPosition; }; /** @@ -854,17 +867,28 @@ ContainerState::CreateOrRecycleThebesLayer(nsIFrame* aActiveScrolledRoot) // Set up transform so that 0,0 in the Thebes layer corresponds to the // (pixel-snapped) top-left of the aActiveScrolledRoot. - // XXX if the transform has changed, and the difference between the old and - // new offsets (not transforms!) is not an integer number of pixels after - // scaling, we need to invalidate the entire layer. nsPoint offset = mBuilder->ToReferenceFrame(aActiveScrolledRoot); - nsIntPoint pixOffset = offset.ScaleToNearestPixels( - mParameters.mXScale, mParameters.mYScale, - aActiveScrolledRoot->PresContext()->AppUnitsPerDevPixel()); + nscoord appUnitsPerDevPixel = aActiveScrolledRoot->PresContext()->AppUnitsPerDevPixel(); + gfxPoint scaledOffset( + NSAppUnitsToDoublePixels(offset.x, appUnitsPerDevPixel)*mParameters.mXScale, + NSAppUnitsToDoublePixels(offset.y, appUnitsPerDevPixel)*mParameters.mYScale); + nsIntPoint pixOffset(NSToIntRoundUp(scaledOffset.x), NSToIntRoundUp(scaledOffset.y)); gfxMatrix matrix; matrix.Translate(gfxPoint(pixOffset.x, pixOffset.y)); layer->SetTransform(gfx3DMatrix::From2D(matrix)); + // Calculate exact position of the top-left of the active scrolled root. + // This might not be 0,0 due to the snapping in ScaleToNearestPixels. + gfxPoint activeScrolledRootTopLeft = scaledOffset - matrix.GetTranslation(); + // If it has changed, then we need to invalidate the entire layer since the + // pixels in the layer buffer have the content at a (subpixel) offset + // from what we need. + if (activeScrolledRootTopLeft != data->mActiveScrolledRootPosition) { + data->mActiveScrolledRootPosition = activeScrolledRootTopLeft; + nsIntRect invalidate = layer->GetValidRegion().GetBounds(); + layer->InvalidateRegion(invalidate); + } + return layer.forget(); } diff --git a/layout/reftests/scrolling/reftest.list b/layout/reftests/scrolling/reftest.list index 720bfc151e5c..a0564e56b51b 100644 --- a/layout/reftests/scrolling/reftest.list +++ b/layout/reftests/scrolling/reftest.list @@ -7,5 +7,7 @@ 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 == text-1.html text-1.html?ref +HTTP == transformed-1.html transformed-1.html?ref +HTTP == transformed-1.html?up transformed-1.html?ref == uncovering-1.html uncovering-1-ref.html == uncovering-2.html uncovering-2-ref.html diff --git a/layout/reftests/scrolling/scrolling.js b/layout/reftests/scrolling/scrolling.js index c01369abe519..e2346abe6650 100644 --- a/layout/reftests/scrolling/scrolling.js +++ b/layout/reftests/scrolling/scrolling.js @@ -24,6 +24,13 @@ function doScroll(d) if (document.location.search == '?ref') { doScroll(20); +} else if (document.location.search == '?up') { + doScroll(40); + document.documentElement.setAttribute("class", "reftest-wait"); + window.addEventListener("MozReftestInvalidate", function() { + document.documentElement.removeAttribute("class"); + doScroll(20); + }, false); } else { doScroll(1); document.documentElement.setAttribute("class", "reftest-wait"); diff --git a/layout/reftests/scrolling/transformed-1.html b/layout/reftests/scrolling/transformed-1.html new file mode 100644 index 000000000000..cbc9b7ad4a26 --- /dev/null +++ b/layout/reftests/scrolling/transformed-1.html @@ -0,0 +1,25 @@ + + +
+ + + + +