Back out bug 772679 for crashes.

This commit is contained in:
Ms2ger 2012-08-04 15:10:45 +02:00
Родитель 52324b00e5
Коммит fbb42e3f19
7 изменённых файлов: 92 добавлений и 148 удалений

Просмотреть файл

@ -2505,50 +2505,44 @@ FrameLayerBuilder::GetDedicatedLayer(nsIFrame* aFrame, PRUint32 aDisplayItemKey)
return nullptr; return nullptr;
} }
static gfxSize bool
PredictScaleForContent(nsIFrame* aFrame, nsIFrame* aAncestorWithScale, FrameLayerBuilder::GetThebesLayerResolutionForFrame(nsIFrame* aFrame,
const gfxSize& aScale) double* aXres, double* aYres,
gfxPoint* aPoint)
{ {
gfx3DMatrix transform = nsTArray<DisplayItemData> *array = GetDisplayItemDataArrayForFrame(aFrame);
gfx3DMatrix::ScalingMatrix(aScale.width, aScale.height, 1.0); if (array) {
// aTransform is applied first, then the scale is applied to the result for (PRUint32 i = 0; i < array->Length(); ++i) {
transform = nsLayoutUtils::GetTransformToAncestor(aFrame, aAncestorWithScale)*transform; Layer* layer = array->ElementAt(i).mLayer;
gfxMatrix transform2d; if (layer->HasUserData(&gThebesDisplayItemLayerUserData)) {
if (transform.CanDraw2D(&transform2d)) { ThebesDisplayItemLayerUserData* data =
return transform2d.ScaleFactors(true); static_cast<ThebesDisplayItemLayerUserData*>
} (layer->GetUserData(&gThebesDisplayItemLayerUserData));
return gfxSize(1.0, 1.0); *aXres = data->mXScale;
} *aYres = data->mYScale;
*aPoint = data->mActiveScrolledRootPosition;
gfxSize return true;
FrameLayerBuilder::GetThebesLayerScaleForFrame(nsIFrame* aFrame)
{
nsIFrame* last;
for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
last = f;
if (f->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER) {
nsTArray<DisplayItemData>* array = GetDisplayItemDataArrayForFrame(f);
NS_ASSERTION(array, "Must have display item data for container");
for (PRUint32 i = 0; i < array->Length(); ++i) {
Layer* layer = array->ElementAt(i).mLayer;
ContainerLayer* container = layer->AsContainerLayer();
if (!container) {
continue;
}
for (Layer* l = container->GetFirstChild(); l; l = l->GetNextSibling()) {
ThebesDisplayItemLayerUserData* data =
static_cast<ThebesDisplayItemLayerUserData*>
(l->GetUserData(&gThebesDisplayItemLayerUserData));
if (data) {
return PredictScaleForContent(aFrame, f, gfxSize(data->mXScale, data->mYScale));
}
}
} }
} }
} }
return PredictScaleForContent(aFrame, last, nsIFrame::ChildListIterator lists(aFrame);
last->PresContext()->PresShell()->GetResolution()); for (; !lists.IsDone(); lists.Next()) {
if (lists.CurrentID() == nsIFrame::kPopupList ||
lists.CurrentID() == nsIFrame::kSelectPopupList) {
continue;
}
nsFrameList::Enumerator childFrames(lists.CurrentList());
for (; !childFrames.AtEnd(); childFrames.Next()) {
if (GetThebesLayerResolutionForFrame(childFrames.get(),
aXres, aYres, aPoint)) {
return true;
}
}
}
return false;
} }
#ifdef MOZ_DUMP_PAINTING #ifdef MOZ_DUMP_PAINTING

Просмотреть файл

@ -369,13 +369,15 @@ public:
nsIntPoint GetLastPaintOffset(ThebesLayer* aLayer); nsIntPoint GetLastPaintOffset(ThebesLayer* aLayer);
/** /**
* Return the resolution at which we expect to render aFrame's contents, * Return resolution and scroll offset of ThebesLayer content associated
* assuming they are being painted to retained layers. This takes into account * with aFrame's subtree.
* the resolution the contents of the ContainerLayer containing aFrame are * Returns true if some ThebesLayer was found.
* being rendered at, as well as any currently-inactive transforms between * This just looks for the first ThebesLayer and returns its data. There
* aFrame and that container layer. * could be other ThebesLayers with different resolution and offsets.
*/ */
static gfxSize GetThebesLayerScaleForFrame(nsIFrame* aFrame); static bool GetThebesLayerResolutionForFrame(nsIFrame* aFrame,
double* aXRes, double* aYRes,
gfxPoint* aPoint);
/** /**
* Clip represents the intersection of an optional rectangle with a * Clip represents the intersection of an optional rectangle with a

Просмотреть файл

@ -1196,7 +1196,6 @@ public:
* The resolution defaults to 1.0. * The resolution defaults to 1.0.
*/ */
virtual nsresult SetResolution(float aXResolution, float aYResolution) = 0; virtual nsresult SetResolution(float aXResolution, float aYResolution) = 0;
gfxSize GetResolution() { return gfxSize(mXResolution, mYResolution); }
float GetXResolution() { return mXResolution; } float GetXResolution() { return mXResolution; }
float GetYResolution() { return mYResolution; } float GetYResolution() { return mYResolution; }

Просмотреть файл

@ -40,7 +40,6 @@ MOCHITEST_CHROME_FILES = \
printpreview_bug396024_helper.xul \ printpreview_bug396024_helper.xul \
test_printpreview_bug482976.xul \ test_printpreview_bug482976.xul \
printpreview_bug482976_helper.xul \ printpreview_bug482976_helper.xul \
test_scrolling_repaints.html \
test_transformed_scrolling_repaints.html \ test_transformed_scrolling_repaints.html \
test_transformed_scrolling_repaints_2.html \ test_transformed_scrolling_repaints_2.html \
$(NULL) $(NULL)

Просмотреть файл

@ -1,49 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test that we don't get unnecessary repaints due to subpixel shifts</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="paint_listener.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<!-- Need a timeout here to allow paint unsuppression before we start the test -->
<body onload="setTimeout(startTest,0)">
<div id="t" style="width:400px; height:100px; background:yellow; overflow:hidden">
<div style="height:40px;"></div>
<div id="e" style="height:30px; background:lime"></div>
<div style="height:60.4px; background:pink"></div>
</div>
<pre id="test">
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
var t = document.getElementById("t");
var e = document.getElementById("e");
var utils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
getInterface(Components.interfaces.nsIDOMWindowUtils);
function startTest() {
// Do a scroll to ensure we trigger activity heuristics.
waitForAllPaintsFlushed(function () {
t.scrollTop = 5;
// Scroll down as far as we can, to put our rendering layer at a subpixel offset within the layer
waitForAllPaintsFlushed(function () {
t.scrollTop = 1000;
waitForAllPaintsFlushed(function () {
// Clear paint state now and scroll again.
utils.checkAndClearPaintedState(e);
// scroll up a little bit. This should not cause anything to be repainted.
t.scrollTop = t.scrollTop - 10;
waitForAllPaintsFlushed(function () {
var painted = utils.checkAndClearPaintedState(e);
is(painted, false, "Fully-visible scrolled element should not have been painted");
SimpleTest.finish();
});
});
});
});
}
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -34,7 +34,11 @@ function startTest() {
t.scrollTop = 33; t.scrollTop = 33;
waitForAllPaintsFlushed(function () { waitForAllPaintsFlushed(function () {
var painted = utils.checkAndClearPaintedState(e); var painted = utils.checkAndClearPaintedState(e);
is(painted, false, "Fully-visible scrolled element should not have been painted"); if (navigator.platform.indexOf("Mac") >= 0) {
todo_is(painted, false, "Fully-visible scrolled element should not have been painted (disabled on Mac, see bug 753497)");
} else {
is(painted, false, "Fully-visible scrolled element should not have been painted");
}
SimpleTest.finish(); SimpleTest.finish();
}); });
}); });

Просмотреть файл

@ -1967,34 +1967,38 @@ void nsGfxScrollFrameInner::ScrollVisual(nsPoint aOldScrolledFramePos)
} }
/** /**
* Return an appunit value close to aDesired and between aLower and aUpper * Adjust the desired scroll value in given range
* such that (aDesired - aCurrent)*aRes/aAppUnitsPerPixel is an integer (or * in order to get resulting scroll by whole amount of layer pixels.
* as close as we can get modulo rounding to appunits). If that * Current implementation is not checking that result value is the best.
* can't be done, just returns aDesired. * Ideally it's would be possible to find best value by implementing
* test function which is repeating last part of CreateOrRecycleThebesLayer,
* and checking other points in allowed range, but that may cause another perf hit.
* Let's keep it as TODO.
*/ */
static nscoord static nscoord
AlignWithLayerPixels(nscoord aDesired, nscoord aLower, RestrictToLayerPixels(nscoord aDesired, nscoord aLower,
nscoord aUpper, nscoord aAppUnitsPerPixel, nscoord aUpper, nscoord aAppUnitsPerPixel,
double aRes, nscoord aCurrent) double aRes, double aCurrentLayerOffset)
{ {
double currentLayerVal = (aRes*aCurrent)/aAppUnitsPerPixel; // convert the result to layer pixels
double desiredLayerVal = (aRes*aDesired)/aAppUnitsPerPixel; double layerVal = aRes * double(aDesired) / aAppUnitsPerPixel;
double delta = desiredLayerVal - currentLayerVal;
double nearestVal = NS_round(delta) + currentLayerVal;
// Convert back from ThebesLayer space to appunits relative to the top-left // Correct value using current layer offset
// of the scrolled frame. layerVal -= aCurrentLayerOffset;
// Try nearest pixel bound first
double nearestVal = NS_round(layerVal);
nscoord nearestAppUnitVal = nscoord nearestAppUnitVal =
NSToCoordRoundWithClamp(nearestVal*aAppUnitsPerPixel/aRes); NSToCoordRoundWithClamp(nearestVal * aAppUnitsPerPixel / aRes);
// Check if nearest layer pixel result fit into allowed and scroll range // Check if nearest layer pixel result fit into allowed and scroll range
if (nearestAppUnitVal >= aLower && nearestAppUnitVal <= aUpper) { if (nearestAppUnitVal >= aLower && nearestAppUnitVal <= aUpper) {
return nearestAppUnitVal; return nearestAppUnitVal;
} else if (nearestVal != desiredLayerVal) { } else if (nearestVal != layerVal) {
// Check if opposite pixel boundary fit into scroll range // Check if opposite pixel boundary fit into scroll range
double oppositeVal = nearestVal + ((nearestVal < desiredLayerVal) ? 1 : -1); double oppositeVal = nearestVal + ((nearestVal < layerVal) ? 1 : -1);
nscoord oppositeAppUnitVal = nscoord oppositeAppUnitVal =
NSToCoordRoundWithClamp(oppositeVal*aAppUnitsPerPixel/aRes); NSToCoordRoundWithClamp(oppositeVal * aAppUnitsPerPixel / aRes);
if (oppositeAppUnitVal >= aLower && oppositeAppUnitVal <= aUpper) { if (oppositeAppUnitVal >= aLower && oppositeAppUnitVal <= aUpper) {
return oppositeAppUnitVal; return oppositeAppUnitVal;
} }
@ -2003,17 +2007,17 @@ AlignWithLayerPixels(nscoord aDesired, nscoord aLower,
} }
/** /**
* Clamp desired scroll position aPt to aBounds and then snap * Clamp desired scroll position aPt to aBounds (if aBounds is non-null) and then snap
* it to the same layer pixel edges as aCurrent, keeping it within aRange * it to the nearest layer pixel edges, keeping it within aRange during snapping
* during snapping. aCurrent is the current scroll position. * (if aRange is non-null). aCurrScroll is the current scroll position.
*/ */
static nsPoint static nsPoint
ClampAndAlignWithLayerPixels(const nsPoint& aPt, ClampAndRestrictToLayerPixels(const nsPoint& aPt,
const nsRect& aBounds, const nsRect& aBounds,
const nsRect& aRange, nscoord aAppUnitsPerPixel,
const nsPoint& aCurrent, const nsRect& aRange,
nscoord aAppUnitsPerPixel, double aXRes, double aYRes,
const gfxSize& aScale) const gfxPoint& aCurrScroll)
{ {
nsPoint pt = aBounds.ClampPoint(aPt); nsPoint pt = aBounds.ClampPoint(aPt);
// Intersect scroll range with allowed range, by clamping the corners // Intersect scroll range with allowed range, by clamping the corners
@ -2021,10 +2025,10 @@ ClampAndAlignWithLayerPixels(const nsPoint& aPt,
nsPoint rangeTopLeft = aBounds.ClampPoint(aRange.TopLeft()); nsPoint rangeTopLeft = aBounds.ClampPoint(aRange.TopLeft());
nsPoint rangeBottomRight = aBounds.ClampPoint(aRange.BottomRight()); nsPoint rangeBottomRight = aBounds.ClampPoint(aRange.BottomRight());
return nsPoint(AlignWithLayerPixels(pt.x, rangeTopLeft.x, rangeBottomRight.x, return nsPoint(RestrictToLayerPixels(pt.x, rangeTopLeft.x, rangeBottomRight.x,
aAppUnitsPerPixel, aScale.width, aCurrent.x), aAppUnitsPerPixel, aXRes, aCurrScroll.x),
AlignWithLayerPixels(pt.y, rangeTopLeft.y, rangeBottomRight.y, RestrictToLayerPixels(pt.y, rangeTopLeft.y, rangeBottomRight.y,
aAppUnitsPerPixel, aScale.height, aCurrent.y)); aAppUnitsPerPixel, aYRes, aCurrScroll.y));
} }
/* static */ void /* static */ void
@ -2057,28 +2061,19 @@ nsGfxScrollFrameInner::ScrollToImpl(nsPoint aPt, const nsRect& aRange)
{ {
nsPresContext* presContext = mOuter->PresContext(); nsPresContext* presContext = mOuter->PresContext();
nscoord appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel(); nscoord appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
// 'scale' is our estimate of the scale factor that will be applied
// when rendering the scrolled content to its own ThebesLayer.
gfxSize scale = FrameLayerBuilder::GetThebesLayerScaleForFrame(mScrolledFrame);
nsPoint curPos = GetScrollPosition();
// Try to align aPt with curPos so they have an integer number of layer
// pixels between them. This gives us the best chance of scrolling without
// having to invalidate due to changes in subpixel rendering.
// Note that when we actually draw into a ThebesLayer, the coordinates
// that get mapped onto the layer buffer pixels are from the display list,
// which are relative to the display root frame's top-left increasing down,
// whereas here our coordinates are scroll positions which increase upward
// and are relative to the scrollport top-left. This difference doesn't actually
// matter since all we are about is that there be an integer number of
// layer pixels between pt and curPos.
nsPoint pt =
ClampAndAlignWithLayerPixels(aPt,
GetScrollRangeForClamping(),
aRange,
curPos,
appUnitsPerDevPixel,
scale);
double xres = 1.0, yres = 1.0;
gfxPoint activeScrolledRootPosition;
FrameLayerBuilder::GetThebesLayerResolutionForFrame(mScrolledFrame, &xres, &yres,
&activeScrolledRootPosition);
nsPoint pt =
ClampAndRestrictToLayerPixels(aPt,
GetScrollRangeForClamping(),
appUnitsPerDevPixel,
aRange, xres, yres,
activeScrolledRootPosition);
nsPoint curPos = GetScrollPosition();
if (pt == curPos) { if (pt == curPos) {
return; return;
} }