зеркало из https://github.com/mozilla/gecko-dev.git
Back out bug 772679 for crashes.
This commit is contained in:
Родитель
52324b00e5
Коммит
fbb42e3f19
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче