mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
Bug 637852. Part 22: Detect when the contents of a ThebesLayer have shifted by a subpixel amount and repaint the entire layer when that happens. r=tnikkel
This fixes artifacts when we're scrolling inside scaled content, and includes a test for that (which fails without this code change).
This commit is contained in:
parent
612c9f5ad3
commit
6965db4c13
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
25
layout/reftests/scrolling/transformed-1.html
Normal file
25
layout/reftests/scrolling/transformed-1.html
Normal file
@ -0,0 +1,25 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
<div class="scrollTop" style="height:100px; width:100px; overflow:hidden;
|
||||
-moz-transform:scale(2.7); transform:scale(2.7); -moz-transform-origin:top left; transform-origin:top left;">
|
||||
<div style="background:yellow;">
|
||||
<div>Hello Kitty</div>
|
||||
<div>Hello Kitty</div>
|
||||
<div>Hello Kitty</div>
|
||||
<div>Hello Kitty</div>
|
||||
<div>Hello Kitty</div>
|
||||
<div>Hello Kitty</div>
|
||||
<div>Hello Kitty</div>
|
||||
<div>Hello Kitty</div>
|
||||
<div>Hello Kitty</div>
|
||||
<div>Hello Kitty</div>
|
||||
<div>Hello Kitty</div>
|
||||
<div>Hello Kitty</div>
|
||||
<div>Hello Kitty</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>document.body.getBoundingClientRect();</script>
|
||||
<script src="scrolling.js"></script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user