Back out bug 772679 for crashes.

This commit is contained in:
Ms2ger 2012-08-04 15:10:45 +02:00
parent 6d930fb447
commit 434ae84f40
7 changed files with 92 additions and 148 deletions

View File

@ -2505,50 +2505,44 @@ FrameLayerBuilder::GetDedicatedLayer(nsIFrame* aFrame, PRUint32 aDisplayItemKey)
return nullptr;
}
static gfxSize
PredictScaleForContent(nsIFrame* aFrame, nsIFrame* aAncestorWithScale,
const gfxSize& aScale)
bool
FrameLayerBuilder::GetThebesLayerResolutionForFrame(nsIFrame* aFrame,
double* aXres, double* aYres,
gfxPoint* aPoint)
{
gfx3DMatrix transform =
gfx3DMatrix::ScalingMatrix(aScale.width, aScale.height, 1.0);
// aTransform is applied first, then the scale is applied to the result
transform = nsLayoutUtils::GetTransformToAncestor(aFrame, aAncestorWithScale)*transform;
gfxMatrix transform2d;
if (transform.CanDraw2D(&transform2d)) {
return transform2d.ScaleFactors(true);
}
return gfxSize(1.0, 1.0);
}
gfxSize
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));
}
}
nsTArray<DisplayItemData> *array = GetDisplayItemDataArrayForFrame(aFrame);
if (array) {
for (PRUint32 i = 0; i < array->Length(); ++i) {
Layer* layer = array->ElementAt(i).mLayer;
if (layer->HasUserData(&gThebesDisplayItemLayerUserData)) {
ThebesDisplayItemLayerUserData* data =
static_cast<ThebesDisplayItemLayerUserData*>
(layer->GetUserData(&gThebesDisplayItemLayerUserData));
*aXres = data->mXScale;
*aYres = data->mYScale;
*aPoint = data->mActiveScrolledRootPosition;
return true;
}
}
}
return PredictScaleForContent(aFrame, last,
last->PresContext()->PresShell()->GetResolution());
nsIFrame::ChildListIterator lists(aFrame);
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

View File

@ -369,13 +369,15 @@ public:
nsIntPoint GetLastPaintOffset(ThebesLayer* aLayer);
/**
* Return the resolution at which we expect to render aFrame's contents,
* assuming they are being painted to retained layers. This takes into account
* the resolution the contents of the ContainerLayer containing aFrame are
* being rendered at, as well as any currently-inactive transforms between
* aFrame and that container layer.
* Return resolution and scroll offset of ThebesLayer content associated
* with aFrame's subtree.
* Returns true if some ThebesLayer was found.
* This just looks for the first ThebesLayer and returns its data. There
* 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

View File

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

View File

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

View File

@ -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>

View File

@ -34,7 +34,11 @@ function startTest() {
t.scrollTop = 33;
waitForAllPaintsFlushed(function () {
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();
});
});

View File

@ -1967,34 +1967,38 @@ void nsGfxScrollFrameInner::ScrollVisual(nsPoint aOldScrolledFramePos)
}
/**
* Return an appunit value close to aDesired and between aLower and aUpper
* such that (aDesired - aCurrent)*aRes/aAppUnitsPerPixel is an integer (or
* as close as we can get modulo rounding to appunits). If that
* can't be done, just returns aDesired.
* Adjust the desired scroll value in given range
* in order to get resulting scroll by whole amount of layer pixels.
* Current implementation is not checking that result value is the best.
* 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
AlignWithLayerPixels(nscoord aDesired, nscoord aLower,
nscoord aUpper, nscoord aAppUnitsPerPixel,
double aRes, nscoord aCurrent)
RestrictToLayerPixels(nscoord aDesired, nscoord aLower,
nscoord aUpper, nscoord aAppUnitsPerPixel,
double aRes, double aCurrentLayerOffset)
{
double currentLayerVal = (aRes*aCurrent)/aAppUnitsPerPixel;
double desiredLayerVal = (aRes*aDesired)/aAppUnitsPerPixel;
double delta = desiredLayerVal - currentLayerVal;
double nearestVal = NS_round(delta) + currentLayerVal;
// convert the result to layer pixels
double layerVal = aRes * double(aDesired) / aAppUnitsPerPixel;
// Convert back from ThebesLayer space to appunits relative to the top-left
// of the scrolled frame.
// Correct value using current layer offset
layerVal -= aCurrentLayerOffset;
// Try nearest pixel bound first
double nearestVal = NS_round(layerVal);
nscoord nearestAppUnitVal =
NSToCoordRoundWithClamp(nearestVal*aAppUnitsPerPixel/aRes);
NSToCoordRoundWithClamp(nearestVal * aAppUnitsPerPixel / aRes);
// Check if nearest layer pixel result fit into allowed and scroll range
if (nearestAppUnitVal >= aLower && nearestAppUnitVal <= aUpper) {
return nearestAppUnitVal;
} else if (nearestVal != desiredLayerVal) {
} else if (nearestVal != layerVal) {
// 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 =
NSToCoordRoundWithClamp(oppositeVal*aAppUnitsPerPixel/aRes);
NSToCoordRoundWithClamp(oppositeVal * aAppUnitsPerPixel / aRes);
if (oppositeAppUnitVal >= aLower && oppositeAppUnitVal <= aUpper) {
return oppositeAppUnitVal;
}
@ -2003,17 +2007,17 @@ AlignWithLayerPixels(nscoord aDesired, nscoord aLower,
}
/**
* Clamp desired scroll position aPt to aBounds and then snap
* it to the same layer pixel edges as aCurrent, keeping it within aRange
* during snapping. aCurrent is the current scroll position.
* Clamp desired scroll position aPt to aBounds (if aBounds is non-null) and then snap
* it to the nearest layer pixel edges, keeping it within aRange during snapping
* (if aRange is non-null). aCurrScroll is the current scroll position.
*/
static nsPoint
ClampAndAlignWithLayerPixels(const nsPoint& aPt,
const nsRect& aBounds,
const nsRect& aRange,
const nsPoint& aCurrent,
nscoord aAppUnitsPerPixel,
const gfxSize& aScale)
ClampAndRestrictToLayerPixels(const nsPoint& aPt,
const nsRect& aBounds,
nscoord aAppUnitsPerPixel,
const nsRect& aRange,
double aXRes, double aYRes,
const gfxPoint& aCurrScroll)
{
nsPoint pt = aBounds.ClampPoint(aPt);
// 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 rangeBottomRight = aBounds.ClampPoint(aRange.BottomRight());
return nsPoint(AlignWithLayerPixels(pt.x, rangeTopLeft.x, rangeBottomRight.x,
aAppUnitsPerPixel, aScale.width, aCurrent.x),
AlignWithLayerPixels(pt.y, rangeTopLeft.y, rangeBottomRight.y,
aAppUnitsPerPixel, aScale.height, aCurrent.y));
return nsPoint(RestrictToLayerPixels(pt.x, rangeTopLeft.x, rangeBottomRight.x,
aAppUnitsPerPixel, aXRes, aCurrScroll.x),
RestrictToLayerPixels(pt.y, rangeTopLeft.y, rangeBottomRight.y,
aAppUnitsPerPixel, aYRes, aCurrScroll.y));
}
/* static */ void
@ -2057,28 +2061,19 @@ nsGfxScrollFrameInner::ScrollToImpl(nsPoint aPt, const nsRect& aRange)
{
nsPresContext* presContext = mOuter->PresContext();
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) {
return;
}