Backout 61fd66629c4f, 7c8121f8d3af & 2a2e9cf8fd41 (bug 539356), e31a5e6545d3 (bug 761884), 85fa80bd9792, a284ccb25b83, 2865904db9fc, 34e07b09c426, e9b3d41e0360, cef00ebcd6c8, f943b729ac14 & 783f298401b6 (bug 539356), 330a086f1570 (bug 741682), d80219c8842c (bug 739671), e8c96b4fd4da, 313af486e68d, 0adc41ff56dc, 0cd288a38085, f1d43208825c, 4859876972f3, eec8ef3ebe48, f7f29fcd1845, 6079b229d306, f23c3a7e7ce0, 9824458a41e2 & 6748b5496059 (bug 539356) for mochitest-4 orange & talos regressions on multiple platforms

This commit is contained in:
Ed Morley 2012-06-11 10:08:32 +01:00
parent 772ec44784
commit a73fc227f9
179 changed files with 3309 additions and 4328 deletions

View File

@ -41,9 +41,7 @@ let WindowEventHandler = {
// Sends an asynchronous message when the "onMozAfterPaint" event
// is fired.
onMozAfterPaint: function WEH_onMozAfterPaint(event) {
if (event.clientRects.length > 0) {
sendAsyncMessage("Panorama:MozAfterPaint");
}
sendAsyncMessage("Panorama:MozAfterPaint");
}
};

View File

@ -294,9 +294,7 @@ LayoutView.prototype = {
let clientRect = node.getBoundingClientRect();
let width = Math.round(clientRect.width);
let height = Math.round(clientRect.height);
if (this.doc.querySelector("#element-size").textContent != width + "x" + height) {
this.doc.querySelector("#element-size").textContent = width + "x" + height;
}
this.doc.querySelector("#element-size").textContent = width + "x" + height;
// If the view is closed, no need to do anything more.
if (!this.isOpen) return;

View File

@ -107,6 +107,14 @@ public:
nsRefPtr<nsIDocShell> mDocShell;
};
static void InvalidateFrame(nsIFrame* aFrame, PRUint32 aFlags)
{
if (!aFrame)
return;
nsRect rect = nsRect(nsPoint(0, 0), aFrame->GetRect().Size());
aFrame->InvalidateWithFlags(rect, aFlags);
}
NS_IMPL_ISUPPORTS1(nsContentView, nsIContentView)
bool
@ -141,6 +149,13 @@ nsContentView::Update(const ViewConfig& aConfig)
rfp->ContentViewScaleChanged(this);
}
// XXX could be clever here and compute a smaller invalidation
// rect
// NB: we pass INVALIDATE_NO_THEBES_LAYERS here to keep view
// semantics the same for both in-process and out-of-process
// <browser>. This is just a transform of the layer subtree in
// both.
InvalidateFrame(mFrameLoader->GetPrimaryFrameOfOwningContent(), nsIFrame::INVALIDATE_NO_THEBES_LAYERS);
return NS_OK;
}
@ -1708,6 +1723,11 @@ nsFrameLoader::SetRenderMode(PRUint32 aRenderMode)
}
mRenderMode = aRenderMode;
// NB: we pass INVALIDATE_NO_THEBES_LAYERS here to keep view
// semantics the same for both in-process and out-of-process
// <browser>. This is just a transform of the layer subtree in
// both.
InvalidateFrame(GetPrimaryFrameOfOwningContent(), nsIFrame::INVALIDATE_NO_THEBES_LAYERS);
return NS_OK;
}
@ -1738,7 +1758,7 @@ nsFrameLoader::SetClipSubdocument(bool aClip)
mClipSubdocument = aClip;
nsIFrame* frame = GetPrimaryFrameOfOwningContent();
if (frame) {
frame->InvalidateFrame();
InvalidateFrame(frame, 0);
frame->PresContext()->PresShell()->
FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
nsSubDocumentFrame* subdocFrame = do_QueryFrame(frame);

View File

@ -505,8 +505,8 @@ nsresult nsObjectLoadingContent::IsPluginEnabledForType(const nsCString& aMIMETy
nsCOMPtr<nsIPermissionManager> permissionManager = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
PRUint32 permission;
rv = permissionManager->TestPermission(topUri,
"plugins",
rv = permissionManager->TestPermission(topUri,
"plugins",
&permission);
NS_ENSURE_SUCCESS(rv, rv);
if (permission == nsIPermissionManager::ALLOW_ACTION) {
@ -1100,7 +1100,7 @@ nsObjectLoadingContent::HasNewFrame(nsIObjectFrame* aFrame)
// Set up new frame to draw.
objFrame->FixupWindow(objFrame->GetContentRectRelativeToSelf().Size());
objFrame->InvalidateFrame();
objFrame->Invalidate(objFrame->GetContentRectRelativeToSelf());
return NS_OK;
}

View File

@ -39,10 +39,12 @@ nsRegion
nsDOMNotifyPaintEvent::GetRegion()
{
nsRegion r;
if (!nsContentUtils::IsCallerTrustedForRead()) {
return r;
}
bool isTrusted = nsContentUtils::IsCallerTrustedForRead();
for (PRUint32 i = 0; i < mInvalidateRequests.Length(); ++i) {
if (!isTrusted &&
(mInvalidateRequests[i].mFlags & nsIFrame::INVALIDATE_CROSS_DOC))
continue;
r.Or(r, mInvalidateRequests[i].mRect);
r.SimplifyOutward(10);
}
@ -96,15 +98,17 @@ nsDOMNotifyPaintEvent::GetPaintRequests(nsIDOMPaintRequestList** aResult)
if (!requests)
return NS_ERROR_OUT_OF_MEMORY;
if (nsContentUtils::IsCallerTrustedForRead()) {
for (PRUint32 i = 0; i < mInvalidateRequests.Length(); ++i) {
nsRefPtr<nsPaintRequest> r = new nsPaintRequest();
if (!r)
return NS_ERROR_OUT_OF_MEMORY;
r->SetRequest(mInvalidateRequests[i]);
requests->Append(r);
}
bool isTrusted = nsContentUtils::IsCallerTrustedForRead();
for (PRUint32 i = 0; i < mInvalidateRequests.Length(); ++i) {
if (!isTrusted &&
(mInvalidateRequests[i].mFlags & nsIFrame::INVALIDATE_CROSS_DOC))
continue;
nsRefPtr<nsPaintRequest> r = new nsPaintRequest();
if (!r)
return NS_ERROR_OUT_OF_MEMORY;
r->SetRequest(mInvalidateRequests[i]);
requests->Append(r);
}
requests.forget(aResult);

View File

@ -35,7 +35,17 @@ nsPaintRequest::GetClientRect(nsIDOMClientRect** aResult)
NS_IMETHODIMP
nsPaintRequest::GetReason(nsAString& aResult)
{
aResult.AssignLiteral("repaint");
switch (mRequest.mFlags & nsIFrame::INVALIDATE_REASON_MASK) {
case nsIFrame::INVALIDATE_REASON_SCROLL_BLIT:
aResult.AssignLiteral("scroll copy");
break;
case nsIFrame::INVALIDATE_REASON_SCROLL_REPAINT:
aResult.AssignLiteral("scroll repaint");
break;
default:
aResult.Truncate();
break;
}
return NS_OK;
}

View File

@ -36,7 +36,6 @@ _TEST_FILES = \
test_bug409604.html \
test_bug412567.html \
test_bug426082.html \
bug426082.html \
test_bug427537.html \
test_bug432698.html \
test_bug443985.html \
@ -71,7 +70,6 @@ _TEST_FILES = \
test_bug648573.html \
test_bug615597.html \
test_bug656379-1.html \
bug656379-1.html \
test_bug656379-2.html \
test_bug656954.html \
test_bug659350.html \

View File

@ -1,182 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=426082
-->
<head>
<title>Test for Bug 426082</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style>
canvas {
display: none;
}
</style>
</head>
<body onload="runTests()">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=426082">Mozilla Bug 426082</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<p><input type="button" value="Button" id="button"></p>
<p><label for="button" id="label">Label</label></p>
<p id="outside">Something under the label</p>
<pre id="test">
<script type="application/javascript;version=1.8">
/** Test for Bug 426082 **/
var normalButtonCanvas, pressedButtonCanvas, normalFocusedButtonCanvas,
pressedFocusedButtonCanvas, currentSnapshot, button, label, outside;
function runTests() {
normalButtonCanvas = document.getElementById("normalButtonCanvas");
pressedButtonCanvas = document.getElementById("pressedButtonCanvas");
normalFocusedButtonCanvas = document.getElementById("normalFocusedButtonCanvas");
pressedFocusedButtonCanvas = document.getElementById("pressedFocusedButtonCanvas");
currentSnapshot = document.getElementById("currentSnapshot");
button = document.getElementById("button");
label = document.getElementById("label");
outside = document.getElementById("outside");
SimpleTest.executeSoon(executeTests);
}
function isRectContainedInRectFromRegion(rect, region) {
console.log("Button rect: " + rect.left + " " + rect.top + " " + rect.right + " " + rect.bottom);
return Array.some(region, function (r) {
console.log("Region rect: " + r.left + " " + r.top + " " + r.right + " " + r.bottom);
return rect.left >= r.left &&
rect.top >= r.top &&
rect.right <= r.right &&
rect.bottom <= r.bottom;
});
}
function paintListener(e) {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
console.log("paint");
if (isRectContainedInRectFromRegion(buttonRect(), e.clientRects)) {
console.log("painted");
gNeedsPaint = false;
takeSnapshot(currentSnapshot);
}
}
var gNeedsPaint = false;
function executeTests() {
var testYielder = tests();
function execNext() {
try {
console.log("check painted");
if (!gNeedsPaint) {
testYielder.next();
button.getBoundingClientRect(); // Flush.
gNeedsPaint = true;
}
SimpleTest.executeSoon(execNext);
} catch (e) {}
}
execNext();
}
function tests() {
window.addEventListener("MozAfterPaint", paintListener, false);
takeSnapshot(normalButtonCanvas);
// Press the button.
sendMouseEvent("mousemove", button);
sendMouseEvent("mousedown", button);
yield;
takeSnapshot(pressedFocusedButtonCanvas);
compareSnapshots_(normalButtonCanvas, pressedFocusedButtonCanvas, false, "Pressed focused buttons should look different from normal buttons.");
// Release.
sendMouseEvent("mouseup", button);
yield;
// make sure the button is focused as this doesn't happen on click on Mac
button.focus();
takeSnapshot(normalFocusedButtonCanvas);
compareSnapshots_(normalFocusedButtonCanvas, pressedFocusedButtonCanvas, false, "Pressed focused buttons should look different from normal focused buttons.");
// Unfocus the button.
sendMouseEvent("mousedown", outside);
sendMouseEvent("mouseup", outside);
yield;
// Press the label.
sendMouseEvent("mousemove", label);
sendMouseEvent("mousedown", label);
yield;
compareSnapshots_(normalButtonCanvas, currentSnapshot, false, "Pressing the label should have pressed the button.");
takeSnapshot(pressedButtonCanvas);
// Move the mouse down from the label.
sendMouseEvent("mousemove", outside);
yield;
compareSnapshots_(normalButtonCanvas, currentSnapshot, true, "Moving the mouse down from the label should have unpressed the button.");
// ... and up again.
sendMouseEvent("mousemove", label);
yield;
compareSnapshots_(pressedButtonCanvas, currentSnapshot, true, "Moving the mouse back on top of the label should have pressed the button.");
// Release.
sendMouseEvent("mouseup", label);
yield;
compareSnapshots_(normalFocusedButtonCanvas, currentSnapshot, true, "Releasing the mouse over the label should have unpressed (and focused) the button.");
// Press the label and remove it.
sendMouseEvent("mousemove", label);
sendMouseEvent("mousedown", label);
yield;
label.parentNode.removeChild(label);
yield;
compareSnapshots_(normalButtonCanvas, currentSnapshot, true, "Removing the label should have unpressed the button.");
sendMouseEvent("mouseup", label);
window.removeEventListener("MozAfterPaint", paintListener, false);
window.opener.finishTests();
}
function sendMouseEvent(t, elem) {
var r = elem.getBoundingClientRect();
synthesizeMouse(elem, r.width / 2, r.height / 2, {type: t});
}
function compareSnapshots_(c1, c2, shouldBeIdentical, msg) {
var [correct, c1url, c2url] = compareSnapshots(c1, c2, shouldBeIdentical);
if (correct) {
if (shouldBeIdentical) {
window.opener.ok(true, msg + " - expected " + c1url);
} else {
window.opener.ok(true, msg + " - got " + c1url + " and " + c2url);
}
} else {
if (shouldBeIdentical) {
window.opener.ok(false, msg + " - expected " + c1url + " but got " + c2url);
} else {
window.opener.ok(false, msg + " - expected something other than " + c1url);
}
}
}
function takeSnapshot(canvas) {
var r = buttonRect();
var ctx = canvas.getContext("2d");
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
canvas.width = r.width + 4;
canvas.height = r.height + 4;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawWindow(window, r.left - 2, r.top - 2, r.width + 4, r.height + 4, "#FFF");
}
function buttonRect() {
return button.getBoundingClientRect();
}
</script>
</pre>
<canvas id="normalButtonCanvas"></canvas>
<canvas id="pressedButtonCanvas"></canvas>
<canvas id="normalFocusedButtonCanvas"></canvas>
<canvas id="pressedFocusedButtonCanvas"></canvas>
<canvas id="currentSnapshot"></canvas>
</body>
</html>

View File

@ -1,208 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=656379
-->
<head>
<title>Test for Bug 656379</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style>
canvas {
display: none;
}
input[type=button] {
-moz-appearance: none;
padding: 0;
border: none;
color: black;
background: white;
}
input[type=button]::-moz-focus-inner { border: none; }
/* Make sure that normal, focused, hover+active, focused+hover+active
buttons all have different styles so that the test keeps moving along. */
input[type=button]:hover:active {
background: red;
}
input[type=button]:focus {
background: green;
}
input[type=button]:focus:hover:active {
background: purple;
}
</style>
</head>
<body onload="runTests()">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=656379">Mozilla Bug 656379</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript;version=1.8">
var normalButtonCanvas, pressedButtonCanvas, normalFocusedButtonCanvas,
pressedFocusedButtonCanvas, currentSnapshot, button, label, outside;
function runTests() {
normalButtonCanvas = $("normalButtonCanvas");
pressedButtonCanvas = $("pressedButtonCanvas");
normalFocusedButtonCanvas = $("normalFocusedButtonCanvas");
pressedFocusedButtonCanvas = $("pressedFocusedButtonCanvas");
currentSnapshot = $("currentSnapshot");
button = $("button");
label = $("label");
outside = $("outside");
SimpleTest.executeSoon(executeTests);
}
function isRectContainedInRectFromRegion(rect, region) {
return Array.some(region, function (r) {
return rect.left >= r.left &&
rect.top >= r.top &&
rect.right <= r.right &&
rect.bottom <= r.bottom;
});
}
function paintListener(e) {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
window.opener.ok(true, "Paint");
if (isRectContainedInRectFromRegion(buttonRect(), e.clientRects)) {
window.opener.ok(true, "Painted button");
gNeedsPaint = false;
takeSnapshot(currentSnapshot);
}
}
var gNeedsPaint = false;
function executeTests() {
var testYielder = tests();
function execNext() {
try {
if (!gNeedsPaint) {
testYielder.next();
button.getBoundingClientRect(); // Flush.
gNeedsPaint = true;
}
SimpleTest.executeSoon(execNext);
} catch (e) {}
}
execNext();
}
function tests() {
window.addEventListener("MozAfterPaint", paintListener, false);
takeSnapshot(normalButtonCanvas);
// Press the button.
sendMouseEvent("mousemove", button);
sendMouseEvent("mousedown", button);
yield;
window.opener.ok(true, "1");
takeSnapshot(pressedFocusedButtonCanvas);
compareSnapshots_(normalButtonCanvas, pressedFocusedButtonCanvas, false, "Pressed focused buttons should look different from normal buttons.");
// Release.
sendMouseEvent("mouseup", button);
yield;
window.opener.ok(true, "2");
// make sure the button is focused as this doesn't happen on click on Mac
button.focus();
takeSnapshot(normalFocusedButtonCanvas);
compareSnapshots_(normalFocusedButtonCanvas, pressedFocusedButtonCanvas, false, "Pressed focused buttons should look different from normal focused buttons.");
// Unfocus the button.
sendMouseEvent("mousedown", outside);
sendMouseEvent("mouseup", outside);
yield;
window.opener.ok(true, "3");
// Press the label.
sendMouseEvent("mousemove", label);
sendMouseEvent("mousedown", label);
yield;
window.opener.ok(true, "4");
compareSnapshots_(normalButtonCanvas, currentSnapshot, false, "Pressing the label should have pressed the button.");
takeSnapshot(pressedButtonCanvas);
// Move the mouse down from the label.
sendMouseEvent("mousemove", outside);
yield;
window.opener.ok(true, "5");
compareSnapshots_(normalButtonCanvas, currentSnapshot, true, "Moving the mouse down from the label should have unpressed the button.");
// ... and up again.
sendMouseEvent("mousemove", label);
yield;
window.opener.ok(true, "6");
compareSnapshots_(pressedButtonCanvas, currentSnapshot, true, "Moving the mouse back on top of the label should have pressed the button.");
// Release.
sendMouseEvent("mouseup", label);
yield;
window.opener.ok(true, "7");
compareSnapshots_(normalFocusedButtonCanvas, currentSnapshot, true, "Releasing the mouse over the label should have unpressed (and focused) the button.");
// Press the label and remove it.
sendMouseEvent("mousemove", label);
sendMouseEvent("mousedown", label);
yield;
window.opener.ok(true, "8");
label.parentNode.removeChild(label);
yield;
window.opener.ok(true, "9");
compareSnapshots_(normalButtonCanvas, currentSnapshot, true, "Removing the label should have unpressed the button.");
sendMouseEvent("mouseup", label);
window.removeEventListener("MozAfterPaint", paintListener, false);
window.opener.finishTests();
}
function sendMouseEvent(t, elem) {
var r = elem.getBoundingClientRect();
synthesizeMouse(elem, r.width / 2, r.height / 2, {type: t});
}
function compareSnapshots_(c1, c2, shouldBeIdentical, msg) {
var [correct, c1url, c2url] = compareSnapshots(c1, c2, shouldBeIdentical);
if (correct) {
if (shouldBeIdentical) {
window.opener.ok(true, msg + " - expected " + c1url);
} else {
window.opener.ok(true, msg + " - got " + c1url + " and " + c2url);
}
} else {
if (shouldBeIdentical) {
window.opener.ok(false, msg + " - expected " + c1url + " but got " + c2url);
} else {
window.opener.ok(false, msg + " - expected something other than " + c1url);
}
}
}
function takeSnapshot(canvas) {
var r = buttonRect();
var ctx = canvas.getContext("2d");
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
canvas.width = r.width + 4;
canvas.height = r.height + 4;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawWindow(window, r.left - 2, r.top - 2, r.width + 4, r.height + 4, "#FFF");
}
function buttonRect() {
return button.getBoundingClientRect();
}
</script>
</pre>
<p><input type="button" value="Button" id="button"></p>
<p><label for="button" id="label">Label</label></p>
<p id="outside">Something under the label</p>
<canvas id="normalButtonCanvas"></canvas>
<canvas id="pressedButtonCanvas"></canvas>
<canvas id="normalFocusedButtonCanvas"></canvas>
<canvas id="pressedFocusedButtonCanvas"></canvas>
<canvas id="currentSnapshot"></canvas>
</body>
</html>

View File

@ -9,22 +9,170 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=426082
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style>
canvas {
display: none;
}
</style>
</head>
<body>
<body onload="runTests()">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=426082">Mozilla Bug 426082</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript;version=1.8">
/** Test for Bug 426082 **/
SimpleTest.waitForExplicitFinish();
var subwindow = window.open("./bug426082.html", "bug426082", "width=800,height=1000");
function finishTests() {
subwindow.close();
var normalButtonCanvas, pressedButtonCanvas, normalFocusedButtonCanvas,
pressedFocusedButtonCanvas, currentSnapshot, button, label, outside;
function runTests() {
normalButtonCanvas = $("normalButtonCanvas");
pressedButtonCanvas = $("pressedButtonCanvas");
normalFocusedButtonCanvas = $("normalFocusedButtonCanvas");
pressedFocusedButtonCanvas = $("pressedFocusedButtonCanvas");
currentSnapshot = $("currentSnapshot");
button = $("button");
label = $("label");
outside = $("outside");
SimpleTest.executeSoon(executeTests);
}
function isRectContainedInRectFromRegion(rect, region) {
return Array.some(region, function (r) {
return rect.left >= r.left &&
rect.top >= r.top &&
rect.right <= r.right &&
rect.bottom <= r.bottom;
});
}
function paintListener(e) {
if (isRectContainedInRectFromRegion(buttonRect(), e.clientRects)) {
gNeedsPaint = false;
takeSnapshot(currentSnapshot);
}
}
var gNeedsPaint = false;
function executeTests() {
var testYielder = tests();
function execNext() {
try {
if (!gNeedsPaint) {
testYielder.next();
button.getBoundingClientRect(); // Flush.
gNeedsPaint = true;
}
SimpleTest.executeSoon(execNext);
} catch (e) {}
}
execNext();
}
function tests() {
window.addEventListener("MozAfterPaint", paintListener, false);
takeSnapshot(normalButtonCanvas);
// Press the button.
sendMouseEvent("mousemove", button);
sendMouseEvent("mousedown", button);
yield;
takeSnapshot(pressedFocusedButtonCanvas);
compareSnapshots_(normalButtonCanvas, pressedFocusedButtonCanvas, false, "Pressed focused buttons should look different from normal buttons.");
// Release.
sendMouseEvent("mouseup", button);
yield;
// make sure the button is focused as this doesn't happen on click on Mac
button.focus();
takeSnapshot(normalFocusedButtonCanvas);
compareSnapshots_(normalFocusedButtonCanvas, pressedFocusedButtonCanvas, false, "Pressed focused buttons should look different from normal focused buttons.");
// Unfocus the button.
sendMouseEvent("mousedown", outside);
sendMouseEvent("mouseup", outside);
yield;
// Press the label.
sendMouseEvent("mousemove", label);
sendMouseEvent("mousedown", label);
yield;
compareSnapshots_(normalButtonCanvas, currentSnapshot, false, "Pressing the label should have pressed the button.");
takeSnapshot(pressedButtonCanvas);
// Move the mouse down from the label.
sendMouseEvent("mousemove", outside);
yield;
compareSnapshots_(normalButtonCanvas, currentSnapshot, true, "Moving the mouse down from the label should have unpressed the button.");
// ... and up again.
sendMouseEvent("mousemove", label);
yield;
compareSnapshots_(pressedButtonCanvas, currentSnapshot, true, "Moving the mouse back on top of the label should have pressed the button.");
// Release.
sendMouseEvent("mouseup", label);
yield;
compareSnapshots_(normalFocusedButtonCanvas, currentSnapshot, true, "Releasing the mouse over the label should have unpressed (and focused) the button.");
// Press the label and remove it.
sendMouseEvent("mousemove", label);
sendMouseEvent("mousedown", label);
yield;
label.parentNode.removeChild(label);
yield;
compareSnapshots_(normalButtonCanvas, currentSnapshot, true, "Removing the label should have unpressed the button.");
sendMouseEvent("mouseup", label);
window.removeEventListener("MozAfterPaint", paintListener, false);
SimpleTest.finish();
}
function sendMouseEvent(t, elem) {
var r = elem.getBoundingClientRect();
synthesizeMouse(elem, r.width / 2, r.height / 2, {type: t});
}
function compareSnapshots_(c1, c2, shouldBeIdentical, msg) {
var [correct, c1url, c2url] = compareSnapshots(c1, c2, shouldBeIdentical);
if (correct) {
if (shouldBeIdentical) {
ok(true, msg + " - expected " + c1url);
} else {
ok(true, msg + " - got " + c1url + " and " + c2url);
}
} else {
if (shouldBeIdentical) {
ok(false, msg + " - expected " + c1url + " but got " + c2url);
} else {
ok(false, msg + " - expected something other than " + c1url);
}
}
}
function takeSnapshot(canvas) {
var r = buttonRect();
var ctx = canvas.getContext("2d");
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
canvas.width = r.width + 4;
canvas.height = r.height + 4;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawWindow(window, r.left - 2, r.top - 2, r.width + 4, r.height + 4, "#FFF");
}
function buttonRect() {
return button.getBoundingClientRect();
}
</script>
</pre>
<p><input type="button" value="Button" id="button"></p>
<p><label for="button" id="label">Label</label></p>
<p id="outside">Something under the label</p>
<canvas id="normalButtonCanvas"></canvas>
<canvas id="pressedButtonCanvas"></canvas>
<canvas id="normalFocusedButtonCanvas"></canvas>
<canvas id="pressedFocusedButtonCanvas"></canvas>
<canvas id="currentSnapshot"></canvas>
</body>
</html>

View File

@ -9,22 +9,190 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=656379
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<style>
canvas {
display: none;
}
input[type=button] {
-moz-appearance: none;
padding: 0;
border: none;
color: black;
background: white;
}
input[type=button]::-moz-focus-inner { border: none; }
/* Make sure that normal, focused, hover+active, focused+hover+active
buttons all have different styles so that the test keeps moving along. */
input[type=button]:hover:active {
background: red;
}
input[type=button]:focus {
background: green;
}
input[type=button]:focus:hover:active {
background: purple;
}
</style>
</head>
<body onload="runTests()">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=426082">Mozilla Bug 426082</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript;version=1.8">
/** Test for Bug 656379 **/
/** Test for Bug 426082 **/
SimpleTest.waitForExplicitFinish();
var subwindow = window.open("./bug656379-1.html", "bug656379", "width=800,height=1000");
function finishTests() {
subwindow.close();
var normalButtonCanvas, pressedButtonCanvas, normalFocusedButtonCanvas,
pressedFocusedButtonCanvas, currentSnapshot, button, label, outside;
function runTests() {
normalButtonCanvas = $("normalButtonCanvas");
pressedButtonCanvas = $("pressedButtonCanvas");
normalFocusedButtonCanvas = $("normalFocusedButtonCanvas");
pressedFocusedButtonCanvas = $("pressedFocusedButtonCanvas");
currentSnapshot = $("currentSnapshot");
button = $("button");
label = $("label");
outside = $("outside");
SimpleTest.executeSoon(executeTests);
}
function isRectContainedInRectFromRegion(rect, region) {
return Array.some(region, function (r) {
return rect.left >= r.left &&
rect.top >= r.top &&
rect.right <= r.right &&
rect.bottom <= r.bottom;
});
}
function paintListener(e) {
if (isRectContainedInRectFromRegion(buttonRect(), e.clientRects)) {
gNeedsPaint = false;
takeSnapshot(currentSnapshot);
}
}
var gNeedsPaint = false;
function executeTests() {
var testYielder = tests();
function execNext() {
try {
if (!gNeedsPaint) {
testYielder.next();
button.getBoundingClientRect(); // Flush.
gNeedsPaint = true;
}
SimpleTest.executeSoon(execNext);
} catch (e) {}
}
execNext();
}
function tests() {
window.addEventListener("MozAfterPaint", paintListener, false);
takeSnapshot(normalButtonCanvas);
// Press the button.
sendMouseEvent("mousemove", button);
sendMouseEvent("mousedown", button);
yield;
takeSnapshot(pressedFocusedButtonCanvas);
compareSnapshots_(normalButtonCanvas, pressedFocusedButtonCanvas, false, "Pressed focused buttons should look different from normal buttons.");
// Release.
sendMouseEvent("mouseup", button);
yield;
// make sure the button is focused as this doesn't happen on click on Mac
button.focus();
takeSnapshot(normalFocusedButtonCanvas);
compareSnapshots_(normalFocusedButtonCanvas, pressedFocusedButtonCanvas, false, "Pressed focused buttons should look different from normal focused buttons.");
// Unfocus the button.
sendMouseEvent("mousedown", outside);
sendMouseEvent("mouseup", outside);
yield;
// Press the label.
sendMouseEvent("mousemove", label);
sendMouseEvent("mousedown", label);
yield;
compareSnapshots_(normalButtonCanvas, currentSnapshot, false, "Pressing the label should have pressed the button.");
takeSnapshot(pressedButtonCanvas);
// Move the mouse down from the label.
sendMouseEvent("mousemove", outside);
yield;
compareSnapshots_(normalButtonCanvas, currentSnapshot, true, "Moving the mouse down from the label should have unpressed the button.");
// ... and up again.
sendMouseEvent("mousemove", label);
yield;
compareSnapshots_(pressedButtonCanvas, currentSnapshot, true, "Moving the mouse back on top of the label should have pressed the button.");
// Release.
sendMouseEvent("mouseup", label);
yield;
compareSnapshots_(normalFocusedButtonCanvas, currentSnapshot, true, "Releasing the mouse over the label should have unpressed (and focused) the button.");
// Press the label and remove it.
sendMouseEvent("mousemove", label);
sendMouseEvent("mousedown", label);
yield;
label.parentNode.removeChild(label);
yield;
compareSnapshots_(normalButtonCanvas, currentSnapshot, true, "Removing the label should have unpressed the button.");
sendMouseEvent("mouseup", label);
window.removeEventListener("MozAfterPaint", paintListener, false);
SimpleTest.finish();
}
function sendMouseEvent(t, elem) {
var r = elem.getBoundingClientRect();
synthesizeMouse(elem, r.width / 2, r.height / 2, {type: t});
}
function compareSnapshots_(c1, c2, shouldBeIdentical, msg) {
var [correct, c1url, c2url] = compareSnapshots(c1, c2, shouldBeIdentical);
if (correct) {
if (shouldBeIdentical) {
ok(true, msg + " - expected " + c1url);
} else {
ok(true, msg + " - got " + c1url + " and " + c2url);
}
} else {
if (shouldBeIdentical) {
ok(false, msg + " - expected " + c1url + " but got " + c2url);
} else {
ok(false, msg + " - expected something other than " + c1url);
}
}
}
function takeSnapshot(canvas) {
var r = buttonRect();
var ctx = canvas.getContext("2d");
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
canvas.width = r.width + 4;
canvas.height = r.height + 4;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawWindow(window, r.left - 2, r.top - 2, r.width + 4, r.height + 4, "#FFF");
}
function buttonRect() {
return button.getBoundingClientRect();
}
</script>
</pre>
<p><input type="button" value="Button" id="button"></p>
<p><label for="button" id="label">Label</label></p>
<p id="outside">Something under the label</p>
<canvas id="normalButtonCanvas"></canvas>
<canvas id="pressedButtonCanvas"></canvas>
<canvas id="normalFocusedButtonCanvas"></canvas>
<canvas id="pressedFocusedButtonCanvas"></canvas>
<canvas id="currentSnapshot"></canvas>
</body>
</html>

View File

@ -650,22 +650,32 @@ nsHTMLCanvasElement::InvalidateCanvasContent(const gfxRect* damageRect)
frame->MarkLayersActive(nsChangeHint(0));
Layer* layer;
nsRect invalRect;
nsRect contentArea = frame->GetContentRect();
if (damageRect) {
nsIntSize size = GetWidthHeight();
if (size.width != 0 && size.height != 0) {
// damageRect and size are in CSS pixels; contentArea is in appunits
// We want a rect in appunits; so avoid doing pixels-to-appunits and
// vice versa conversion here.
gfxRect realRect(*damageRect);
realRect.Scale(contentArea.width / gfxFloat(size.width),
contentArea.height / gfxFloat(size.height));
realRect.RoundOut();
nsIntRect invalRect(realRect.X(), realRect.Y(),
realRect.Width(), realRect.Height());
// then make it a nsRect
invalRect = nsRect(realRect.X(), realRect.Y(),
realRect.Width(), realRect.Height());
layer = frame->InvalidateLayer(nsDisplayItem::TYPE_CANVAS, &invalRect);
invalRect = invalRect.Intersect(nsRect(nsPoint(0,0), contentArea.Size()));
}
} else {
layer = frame->InvalidateLayer(nsDisplayItem::TYPE_CANVAS);
invalRect = nsRect(nsPoint(0, 0), contentArea.Size());
}
invalRect.MoveBy(contentArea.TopLeft() - frame->GetPosition());
Layer* layer = frame->InvalidateLayer(invalRect, nsDisplayItem::TYPE_CANVAS);
if (layer) {
static_cast<CanvasLayer*>(layer)->Updated();
}
@ -680,7 +690,7 @@ nsHTMLCanvasElement::InvalidateCanvas()
if (!frame)
return;
frame->InvalidateFrame();
frame->Invalidate(frame->GetContentRect() - frame->GetPosition());
}
PRInt32

View File

@ -79,10 +79,11 @@ void VideoFrameContainer::Invalidate()
}
if (frame) {
nsRect contentRect = frame->GetContentRect() - frame->GetPosition();
if (invalidateFrame) {
frame->InvalidateFrame();
frame->Invalidate(contentRect);
} else {
frame->InvalidateLayer(nsDisplayItem::TYPE_VIDEO);
frame->InvalidateLayer(contentRect, nsDisplayItem::TYPE_VIDEO);
}
}

View File

@ -206,10 +206,12 @@ nsDOMWindowUtils::Redraw(PRUint32 aCount, PRUint32 *aDurationOut)
nsIFrame *rootFrame = presShell->GetRootFrame();
if (rootFrame) {
nsRect r(nsPoint(0, 0), rootFrame->GetSize());
PRIntervalTime iStart = PR_IntervalNow();
for (PRUint32 i = 0; i < aCount; i++)
rootFrame->InvalidateFrame();
rootFrame->InvalidateWithFlags(r, nsIFrame::INVALIDATE_IMMEDIATE);
#if defined(MOZ_X11) && defined(MOZ_WIDGET_GTK2)
XSync(GDK_DISPLAY(), False);
@ -354,7 +356,14 @@ nsDOMWindowUtils::SetDisplayPortForElement(float aXPx, float aYPx,
nsIFrame* rootFrame = presShell->FrameManager()->GetRootFrame();
if (rootFrame) {
rootFrame->InvalidateFrame();
nsIContent* rootContent =
rootScrollFrame ? rootScrollFrame->GetContent() : nsnull;
nsRect rootDisplayport;
bool usingDisplayport = rootContent &&
nsLayoutUtils::GetDisplayPort(rootContent, &rootDisplayport);
rootFrame->InvalidateWithFlags(
usingDisplayport ? rootDisplayport : rootFrame->GetVisualOverflowRect(),
nsIFrame::INVALIDATE_NO_THEBES_LAYERS);
// If we are hiding something that is a display root then send empty paint
// transaction in order to release retained layers because it won't get

View File

@ -633,11 +633,23 @@ NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRect(NPRect *invalidRect)
}
#endif
nsIntRect rect(invalidRect->left,
invalidRect->top,
invalidRect->right - invalidRect->left,
invalidRect->bottom - invalidRect->top);
mObjectFrame->InvalidateLayer(nsDisplayItem::TYPE_PLUGIN, &rect);
nsPresContext* presContext = mObjectFrame->PresContext();
nsRect rect(presContext->DevPixelsToAppUnits(invalidRect->left),
presContext->DevPixelsToAppUnits(invalidRect->top),
presContext->DevPixelsToAppUnits(invalidRect->right - invalidRect->left),
presContext->DevPixelsToAppUnits(invalidRect->bottom - invalidRect->top));
if (container) {
gfxIntSize newSize = container->GetCurrentSize();
if (newSize != oldSize) {
// The image size has changed - invalidate the old area too, bug 635405.
nsRect oldRect = nsRect(0, 0,
presContext->DevPixelsToAppUnits(oldSize.width),
presContext->DevPixelsToAppUnits(oldSize.height));
rect.UnionRect(rect, oldRect);
}
}
rect.MoveBy(mObjectFrame->GetContentRectRelativeToSelf().TopLeft());
mObjectFrame->InvalidateLayer(rect, nsDisplayItem::TYPE_PLUGIN);
return NS_OK;
}
@ -650,7 +662,7 @@ NS_IMETHODIMP
nsPluginInstanceOwner::RedrawPlugin()
{
if (mObjectFrame) {
mObjectFrame->InvalidateLayer(nsDisplayItem::TYPE_PLUGIN);
mObjectFrame->InvalidateLayer(mObjectFrame->GetContentRectRelativeToSelf(), nsDisplayItem::TYPE_PLUGIN);
}
return NS_OK;
}
@ -3752,7 +3764,7 @@ void nsPluginInstanceOwner::SetFrame(nsObjectFrame *aFrame)
mObjectFrame->PrepForDrawing(mWidget);
}
mObjectFrame->FixupWindow(mObjectFrame->GetContentRectRelativeToSelf().Size());
mObjectFrame->InvalidateFrame();
mObjectFrame->Invalidate(mObjectFrame->GetContentRectRelativeToSelf());
// Scroll position listening is only required for Carbon event model plugins on Mac OS X.
#if defined(XP_MACOSX) && !defined(NP_NO_QUICKDRAW)

View File

@ -94,9 +94,8 @@ function done() {
function waitForPaint(func) {
paint_waiter.last_paint_count = paint_waiter.getPaintCount();
// Ensure the waiter has had a style change, so that this will
// Ensure the waiter has been reflowed with zero height, so that this will
// change its size and cause a paint.
paint_waiter.style.backgroundColor = paint_waiter.style.backgroundColor == "blue" ? "yellow" : "blue";
var flush = paint_waiter.offsetHeight;
paint_waiter.style.height = "1px";
waitForPaintHelper(func);

View File

@ -25,6 +25,6 @@ load 615450-1.html
load 639736-1.xhtml
load 643786-1.html
load 682650-1.html
asserts(0-1) load 716456-1.html
load 716456-1.html
load 759748.html
load 761861.html

View File

@ -45,7 +45,7 @@ fails-if(Android) != spellcheck-input-property-dynamic-override-inherit.html spe
random-if(Android) != spellcheck-textarea-attr.html spellcheck-textarea-ref.html
needs-focus == spellcheck-textarea-focused.html spellcheck-textarea-ref.html
needs-focus == spellcheck-textarea-focused-reframe.html spellcheck-textarea-ref.html
needs-focus == spellcheck-textarea-focused-notreadonly.html spellcheck-textarea-ref2.html
needs-focus == spellcheck-textarea-focused-notreadonly.html spellcheck-textarea-ref.html
random-if(Android) != spellcheck-textarea-nofocus.html spellcheck-textarea-ref.html
random-if(Android) != spellcheck-textarea-disabled.html spellcheck-textarea-ref.html
random-if(Android) != spellcheck-textarea-attr-inherit.html spellcheck-textarea-ref.html

View File

@ -1,19 +1,19 @@
<!DOCTYPE html>
<html>
<body>
<textarea id="testBox" style="padding:2px;" readonly></textarea>
<script type="text/javascript">
//Adding focus to the textbox should trigger a spellcheck
var textbox = document.getElementById("testBox");
addEventListener("load", function() {
textbox.readOnly = false;
textbox.focus();
textbox.value = "blahblahblah";
textbox.selectionStart = textbox.selectionEnd = 0;
textbox.blur();
}, false);
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<body>
<textarea id="testBox" readonly></textarea>
<script type="text/javascript">
//Adding focus to the textbox should trigger a spellcheck
var textbox = document.getElementById("testBox");
addEventListener("load", function() {
textbox.readOnly = false;
textbox.focus();
textbox.value = "blahblahblah";
textbox.selectionStart = textbox.selectionEnd = 0;
textbox.blur();
}, false);
</script>
</body>
</html>

View File

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<textarea spellcheck="true" style="padding:2px;">blahblahblah</textarea>
<script type="text/javascript">
var box = document.getElementsByTagName("textarea")[0];
box.focus(); //Bring the textbox into focus, triggering a spellcheck
box.blur(); //Blur in order to make things similar to other tests otherwise
</script>
</body>
</html>

View File

@ -26,16 +26,8 @@ public:
/* Attaches untyped userData associated with key. destroy is called on destruction */
void Add(UserDataKey *key, void *userData, destroyFunc destroy)
{
for (int i=0; i<count; i++) {
if (key == entries[i].key) {
if (entries[i].destroy) {
entries[i].destroy(entries[i].userData);
}
entries[i].userData = userData;
entries[i].destroy = destroy;
return;
}
}
// XXX we should really warn if user data with key has already been added,
// since in that case Get() will return the old user data!
// We could keep entries in a std::vector instead of managing it by hand
// but that would propagate an stl dependency out which we'd rather not
@ -82,21 +74,12 @@ public:
return NULL;
}
void Destroy()
{
for (int i=0; i<count; i++) {
if (entries[i].destroy) {
entries[i].destroy(entries[i].userData);
}
}
free(entries);
entries = NULL;
count = 0;
}
~UserData()
{
Destroy();
for (int i=0; i<count; i++) {
entries[i].destroy(entries[i].userData);
}
free(entries);
}
private:

View File

@ -605,10 +605,9 @@ public:
mScaleMode = aMode;
}
ImageContainer* GetContainer() { return mContainer; }
gfxPattern::GraphicsFilter GetFilter() { return mFilter; }
const gfxIntSize& GetScaleToSize() { return mScaleToSize; }
ScaleMode GetScaleMode() { return mScaleMode; }
MOZ_LAYER_DECL_NAME("ImageLayer", TYPE_IMAGE)

View File

@ -1,331 +0,0 @@
/*-*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "LayerTreeInvalidation.h"
#include "gfxUtils.h"
namespace mozilla {
namespace layers {
struct LayerPropertiesBase;
LayerPropertiesBase* CloneLayerTreePropertiesInternal(Layer* aRoot);
static nsIntRect
TransformRect(const nsIntRect& aRect, const gfx3DMatrix& aTransform)
{
if (aRect.IsEmpty()) {
return nsIntRect();
}
gfxRect rect(aRect.x, aRect.y, aRect.width, aRect.height);
rect = aTransform.TransformBounds(rect);
rect.RoundOut();
nsIntRect intRect;
if (!gfxUtils::GfxRectToIntRect(rect, &intRect)) {
return nsIntRect();
}
return intRect;
}
/**
* Walks over this layer, and all descendant layers.
* If any of these are a ContainerLayer that reports invalidations to a PresShell,
* then report that the entire bounds have changed.
*/
static void
NotifySubdocumentInvalidationRecursive(Layer* aLayer, NotifySubDocInvalidationFunc aCallback)
{
aLayer->ClearInvalidRect();
ContainerLayer* container = aLayer->AsContainerLayer();
if (aLayer->GetMaskLayer()) {
NotifySubdocumentInvalidationRecursive(aLayer->GetMaskLayer(), aCallback);
}
if (!container) {
return;
}
for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
NotifySubdocumentInvalidationRecursive(child, aCallback);
}
aCallback(container, container->GetVisibleRegion());
}
struct LayerPropertiesBase : public LayerProperties
{
LayerPropertiesBase(Layer* aLayer)
: mLayer(aLayer)
, mMaskLayer(nsnull)
, mVisibleBounds(aLayer->GetVisibleRegion().GetBounds())
, mTransform(aLayer->GetTransform())
, mOpacity(aLayer->GetOpacity())
, mUseClipRect(!!aLayer->GetClipRect())
{
MOZ_COUNT_CTOR(LayerPropertiesBase);
if (aLayer->GetMaskLayer()) {
mMaskLayer = CloneLayerTreePropertiesInternal(aLayer->GetMaskLayer());
}
if (mUseClipRect) {
mClipRect = *aLayer->GetClipRect();
}
}
LayerPropertiesBase()
: mLayer(nsnull)
, mMaskLayer(nsnull)
{
MOZ_COUNT_CTOR(LayerPropertiesBase);
}
~LayerPropertiesBase()
{
MOZ_COUNT_DTOR(LayerPropertiesBase);
}
virtual nsIntRect ComputeDifferences(Layer* aRoot,
NotifySubDocInvalidationFunc aCallback);
nsIntRect ComputeChange(NotifySubDocInvalidationFunc aCallback)
{
bool transformChanged = mTransform != mLayer->GetTransform();
Layer* otherMask = mLayer->GetMaskLayer();
const nsIntRect* otherClip = mLayer->GetClipRect();
nsIntRect result;
if ((mMaskLayer ? mMaskLayer->mLayer : nsnull) != otherMask ||
(mUseClipRect != !!otherClip) ||
mLayer->GetOpacity() != mOpacity ||
transformChanged)
{
result = OldTransformedBounds();
if (transformChanged) {
result = result.Union(NewTransformedBounds());
}
// If we don't have to generate invalidations separately for child
// layers then we can just stop here since we've already invalidated the entire
// old and new bounds.
if (!aCallback) {
ClearInvalidations(mLayer);
return result;
}
}
result = result.Union(ComputeChangeInternal(aCallback));
result = result.Union(TransformRect(mLayer->GetInvalidRegion().GetBounds(), mTransform));
if (mMaskLayer && otherMask) {
nsIntRect maskDiff = mMaskLayer->ComputeChange(aCallback);
result = result.Union(TransformRect(maskDiff, mTransform));
}
if (mUseClipRect && otherClip) {
if (!mClipRect.IsEqualInterior(*otherClip)) {
nsIntRegion tmp;
tmp.Xor(mClipRect, *otherClip);
result = result.Union(tmp.GetBounds());
}
}
mLayer->ClearInvalidRect();
return result;
}
nsIntRect NewTransformedBounds()
{
return TransformRect(mLayer->GetVisibleRegion().GetBounds(), mLayer->GetTransform());
}
nsIntRect OldTransformedBounds()
{
return TransformRect(mVisibleBounds, mTransform);
}
virtual nsIntRect ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback) { return nsIntRect(); }
Layer* mLayer;
nsAutoPtr<LayerPropertiesBase> mMaskLayer;
nsIntRect mVisibleBounds;
gfx3DMatrix mTransform;
float mOpacity;
nsIntRect mClipRect;
bool mUseClipRect;
};
struct ContainerLayerProperties : public LayerPropertiesBase
{
ContainerLayerProperties(ContainerLayer* aLayer)
: LayerPropertiesBase(aLayer)
{
for (Layer* child = aLayer->GetFirstChild(); child; child = child->GetNextSibling()) {
mChildren.AppendElement(CloneLayerTreePropertiesInternal(child));
}
}
virtual nsIntRect ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback)
{
ContainerLayer* container = mLayer->AsContainerLayer();
nsIntRegion result;
PRUint32 i = 0;
for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
if (i >= mChildren.Length() || child != mChildren[i]->mLayer) {
// Child change. Invalidate the full areas.
// TODO: We could be smarter here if non-overlapping children
// swap order.
result.Or(result, TransformRect(child->GetVisibleRegion().GetBounds(), child->GetTransform()));
if (i < mChildren.Length()) {
result.Or(result, mChildren[i]->OldTransformedBounds());
}
if (aCallback) {
NotifySubdocumentInvalidationRecursive(child, aCallback);
} else {
ClearInvalidations(child);
}
} else {
// Same child, check for differences within the child
result.Or(result, mChildren[i]->ComputeChange(aCallback));
}
i++;
}
// Process remaining removed children.
while (i < mChildren.Length()) {
result.Or(result, mChildren[i]->OldTransformedBounds());
i++;
}
if (aCallback) {
aCallback(container, result);
}
return TransformRect(result.GetBounds(), mLayer->GetTransform());
}
nsAutoTArray<nsAutoPtr<LayerPropertiesBase>,1> mChildren;
};
struct ColorLayerProperties : public LayerPropertiesBase
{
ColorLayerProperties(ColorLayer *aLayer)
: LayerPropertiesBase(aLayer)
, mColor(aLayer->GetColor())
{ }
virtual nsIntRect ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback)
{
ColorLayer* color = static_cast<ColorLayer*>(mLayer);
if (mColor != color->GetColor()) {
return NewTransformedBounds();
}
return nsIntRect();
}
gfxRGBA mColor;
};
struct ImageLayerProperties : public LayerPropertiesBase
{
ImageLayerProperties(ImageLayer* aImage)
: LayerPropertiesBase(aImage)
, mVisibleRegion(aImage->GetVisibleRegion())
, mContainer(aImage->GetContainer())
, mFilter(aImage->GetFilter())
, mScaleToSize(aImage->GetScaleToSize())
, mScaleMode(aImage->GetScaleMode())
{ }
virtual nsIntRect ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback)
{
ImageLayer* image = static_cast<ImageLayer*>(mLayer);
if (!image->GetVisibleRegion().IsEqual(mVisibleRegion)) {
nsIntRect result = NewTransformedBounds();
result = result.Union(OldTransformedBounds());
return result;
}
if (mContainer != image->GetContainer() ||
mFilter != image->GetFilter() ||
mScaleToSize != image->GetScaleToSize() ||
mScaleMode != image->GetScaleMode()) {
return NewTransformedBounds();
}
return nsIntRect();
}
nsIntRegion mVisibleRegion;
nsRefPtr<ImageContainer> mContainer;
gfxPattern::GraphicsFilter mFilter;
gfxIntSize mScaleToSize;
ImageLayer::ScaleMode mScaleMode;
};
LayerPropertiesBase*
CloneLayerTreePropertiesInternal(Layer* aRoot)
{
if (!aRoot) {
return new LayerPropertiesBase();
}
switch (aRoot->GetType()) {
case Layer::TYPE_CONTAINER: return new ContainerLayerProperties(aRoot->AsContainerLayer());
case Layer::TYPE_COLOR: return new ColorLayerProperties(static_cast<ColorLayer*>(aRoot));
case Layer::TYPE_IMAGE: return new ImageLayerProperties(static_cast<ImageLayer*>(aRoot));
default: return new LayerPropertiesBase(aRoot);
}
return nsnull;
}
/* static */ LayerProperties*
LayerProperties::CloneFrom(Layer* aRoot)
{
return CloneLayerTreePropertiesInternal(aRoot);
}
/* static */ void
LayerProperties::ClearInvalidations(Layer *aLayer)
{
aLayer->ClearInvalidRect();
if (aLayer->GetMaskLayer()) {
ClearInvalidations(aLayer->GetMaskLayer());
}
ContainerLayer* container = aLayer->AsContainerLayer();
if (!container) {
return;
}
for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
ClearInvalidations(child);
}
}
nsIntRect
LayerPropertiesBase::ComputeDifferences(Layer* aRoot, NotifySubDocInvalidationFunc aCallback)
{
NS_ASSERTION(aRoot, "Must have a layer tree to compare against!");
if (mLayer != aRoot) {
if (aCallback) {
NotifySubdocumentInvalidationRecursive(aRoot, aCallback);
} else {
ClearInvalidations(aRoot);
}
nsIntRect result = TransformRect(aRoot->GetVisibleRegion().GetBounds(), aRoot->GetTransform());
result = result.Union(OldTransformedBounds());
return result;
} else {
return ComputeChange(aCallback);
}
}
} // namespace layers
} // namespace mozilla

View File

@ -1,64 +0,0 @@
/*-*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GFX_LAYER_TREE_INVALIDATION_H
#define GFX_LAYER_TREE_INVALIDATION_H
#include "Layers.h"
class nsPresContext;
namespace mozilla {
namespace layers {
/**
* Callback for ContainerLayer invalidations.
*
* @param aContainer ContainerLayer being invalidated.
* @param aRegion Invalidated region in the ContainerLayer's coordinate
* space.
*/
typedef void (*NotifySubDocInvalidationFunc)(ContainerLayer* aLayer,
const nsIntRegion& aRegion);
/**
* A set of cached layer properties (including those of child layers),
* used for comparing differences in layer trees.
*/
struct LayerProperties
{
virtual ~LayerProperties() {}
/**
* Copies the current layer tree properties into
* a new LayerProperties object.
*
* @param Layer tree to copy, or nsnull if we have no
* initial layer tree.
*/
static LayerProperties* CloneFrom(Layer* aRoot);
/**
* Clear all invalidation status from this layer tree.
*/
static void ClearInvalidations(Layer* aRoot);
/**
* Compares a set of existing layer tree properties to the current layer
* tree and generates the changed rectangle.
*
* @param aRoot Root layer of the layer tree to compare against.
* @param aCallback If specified, callback to call when ContainerLayers
* are invalidated.
* @return Painted area changed by the layer tree changes.
*/
virtual nsIntRect ComputeDifferences(Layer* aRoot,
NotifySubDocInvalidationFunc aCallback) = 0;
};
} // namespace layers
} // namespace mozilla
#endif /* GFX_LAYER_TREE_INVALIDATON_H */

View File

@ -167,10 +167,60 @@ public:
* BasicLayerManager for such an implementation.
*/
static void LayerManagerUserDataDestroy(void *data)
{
delete static_cast<LayerUserData*>(data);
}
/**
* Helper class to manage user data for layers and LayerManagers.
*/
class THEBES_API LayerUserDataSet {
public:
LayerUserDataSet() : mKey(nsnull) {}
void Set(void* aKey, LayerUserData* aValue)
{
NS_ASSERTION(!mKey || mKey == aKey,
"Multiple LayerUserData objects not supported");
mKey = aKey;
mValue = aValue;
}
/**
* This can be used anytime. Ownership passes to the caller!
*/
LayerUserData* Remove(void* aKey)
{
if (mKey == aKey) {
mKey = nsnull;
LayerUserData* d = mValue.forget();
return d;
}
return nsnull;
}
/**
* This getter can be used anytime.
*/
bool Has(void* aKey)
{
return mKey == aKey;
}
/**
* This getter can be used anytime. Ownership is retained by this object.
*/
LayerUserData* Get(void* aKey)
{
return mKey == aKey ? mValue.get() : nsnull;
}
/**
* Clear out current user data.
*/
void Clear()
{
mKey = nsnull;
mValue = nsnull;
}
private:
void* mKey;
nsAutoPtr<LayerUserData> mValue;
};
/**
* A LayerManager controls a tree of layers. All layers in the tree
@ -220,7 +270,7 @@ public:
* for its widget going away. After this call, only user data calls
* are valid on the layer manager.
*/
virtual void Destroy() { mDestroyed = true; mUserData.Destroy(); }
virtual void Destroy() { mDestroyed = true; mUserData.Clear(); }
bool IsDestroyed() { return mDestroyed; }
virtual ShadowLayerForwarder* AsShadowForwarder()
@ -229,12 +279,6 @@ public:
virtual ShadowLayerManager* AsShadowManager()
{ return nsnull; }
/**
* Returns true if this LayerManager is owned by an nsIWidget,
* and is used for drawing into the widget.
*/
virtual bool IsWidgetLayerManager() { return true; }
/**
* Start a new transaction. Nested transactions are not allowed so
* there must be no transaction currently in progress.
@ -294,8 +338,7 @@ public:
enum EndTransactionFlags {
END_DEFAULT = 0,
END_NO_IMMEDIATE_REDRAW = 1 << 0, // Do not perform the drawing phase
END_NO_COMPOSITE = 1 << 1 // Do not composite after drawing thebes layer contents.
END_NO_IMMEDIATE_REDRAW = 1 << 0 // Do not perform the drawing phase
};
/**
@ -309,18 +352,8 @@ public:
void* aCallbackData,
EndTransactionFlags aFlags = END_DEFAULT) = 0;
virtual bool HasShadowManagerInternal() const { return false; }
bool HasShadowManager() const { return HasShadowManagerInternal(); }
bool IsSnappingEffectiveTransforms() { return mSnapEffectiveTransforms; }
/**
* Returns true if this LayerManager can properly support layers with
* SURFACE_COMPONENT_ALPHA. This can include disabling component
* alpha if required.
*/
virtual bool AreComponentAlphaLayersEnabled() { return true; }
/**
* CONSTRUCTION PHASE ONLY
* Set the root layer. The root layer is initially null. If there is
@ -428,32 +461,23 @@ public:
* initially null. Ownership pases to the layer manager.
*/
void SetUserData(void* aKey, LayerUserData* aData)
{
mUserData.Add(static_cast<gfx::UserDataKey*>(aKey), aData, LayerManagerUserDataDestroy);
}
{ mUserData.Set(aKey, aData); }
/**
* This can be used anytime. Ownership passes to the caller!
*/
nsAutoPtr<LayerUserData> RemoveUserData(void* aKey)
{
nsAutoPtr<LayerUserData> d(static_cast<LayerUserData*>(mUserData.Remove(static_cast<gfx::UserDataKey*>(aKey))));
return d;
}
{ nsAutoPtr<LayerUserData> d(mUserData.Remove(aKey)); return d; }
/**
* This getter can be used anytime.
*/
bool HasUserData(void* aKey)
{
return GetUserData(aKey);
}
{ return mUserData.Has(aKey); }
/**
* This getter can be used anytime. Ownership is retained by the layer
* manager.
*/
LayerUserData* GetUserData(void* aKey)
{
return static_cast<LayerUserData*>(mUserData.Get(static_cast<gfx::UserDataKey*>(aKey)));
}
{ return mUserData.Get(aKey); }
/**
* Flag the next paint as the first for a document.
@ -503,7 +527,7 @@ public:
protected:
nsRefPtr<Layer> mRoot;
gfx::UserData mUserData;
LayerUserDataSet mUserData;
bool mDestroyed;
bool mSnapEffectiveTransforms;
@ -753,32 +777,23 @@ public:
* initially null. Ownership pases to the layer manager.
*/
void SetUserData(void* aKey, LayerUserData* aData)
{
mUserData.Add(static_cast<gfx::UserDataKey*>(aKey), aData, LayerManagerUserDataDestroy);
}
{ mUserData.Set(aKey, aData); }
/**
* This can be used anytime. Ownership passes to the caller!
*/
nsAutoPtr<LayerUserData> RemoveUserData(void* aKey)
{
nsAutoPtr<LayerUserData> d(static_cast<LayerUserData*>(mUserData.Remove(static_cast<gfx::UserDataKey*>(aKey))));
return d;
}
{ nsAutoPtr<LayerUserData> d(mUserData.Remove(aKey)); return d; }
/**
* This getter can be used anytime.
*/
bool HasUserData(void* aKey)
{
return GetUserData(aKey);
}
{ return mUserData.Has(aKey); }
/**
* This getter can be used anytime. Ownership is retained by the layer
* manager.
*/
LayerUserData* GetUserData(void* aKey)
{
return static_cast<LayerUserData*>(mUserData.Get(static_cast<gfx::UserDataKey*>(aKey)));
}
{ return mUserData.Get(aKey); }
/**
* |Disconnect()| is used by layers hooked up over IPC. It may be
@ -907,29 +922,6 @@ public:
static bool IsLogEnabled() { return LayerManager::IsLogEnabled(); }
/**
* Returns the current area of the layer (in layer-space coordinates)
* marked as needed to be recomposited.
*/
const nsIntRegion& GetInvalidRegion() { return mInvalidRegion; }
/**
* Mark the entirety of the layer's visible region as being invalid.
*/
void SetInvalidRectToVisibleRegion() { mInvalidRegion = GetVisibleRegion(); }
/**
* Adds to the current invalid rect.
*/
void AddInvalidRect(const nsIntRect& aRect) { mInvalidRegion.Or(mInvalidRegion, aRect); }
/**
* Clear the invalid rect, marking the layer as being identical to what is currently
* composited.
*/
void ClearInvalidRect() { mInvalidRegion.SetEmpty(); }
#ifdef DEBUG
void SetDebugColorIndex(PRUint32 aIndex) { mDebugColorIndex = aIndex; }
PRUint32 GetDebugColorIndex() { return mDebugColorIndex; }
@ -987,7 +979,7 @@ protected:
Layer* mPrevSibling;
void* mImplData;
nsRefPtr<Layer> mMaskLayer;
gfx::UserData mUserData;
LayerUserDataSet mUserData;
nsIntRegion mVisibleRegion;
gfx3DMatrix mTransform;
gfx3DMatrix mEffectiveTransform;
@ -999,7 +991,6 @@ protected:
bool mUseTileSourceRect;
bool mIsFixedPosition;
DebugOnly<PRUint32> mDebugColorIndex;
nsIntRegion mInvalidRegion;
};
/**
@ -1316,7 +1307,7 @@ public:
* Notify this CanvasLayer that the canvas surface contents have
* changed (or will change) before the next transaction.
*/
void Updated() { mDirty = true; SetInvalidRectToVisibleRegion(); }
void Updated() { mDirty = true; }
/**
* Register a callback to be called at the end of each transaction.

View File

@ -38,7 +38,6 @@ EXPORTS = \
LayerManagerOGLProgram.h \
ReadbackLayer.h \
LayerSorter.h \
LayerTreeInvalidation.h \
$(NULL)
CPPSRCS = \
@ -59,7 +58,6 @@ CPPSRCS = \
ReusableTileStoreOGL.cpp \
LayerManagerOGLProgram.cpp \
LayerSorter.cpp \
LayerTreeInvalidation.cpp \
ImageLayers.cpp \
$(NULL)

View File

@ -59,11 +59,19 @@ public:
* effective visible region (snapped or unsnapped, it doesn't matter).
*/
virtual void PaintThebes(gfxContext* aContext,
Layer* aMasklayer,
Layer* aMasklayer,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData,
ReadbackProcessor* aReadback) {}
/**
* Implementations return true here if they *must* retain their
* layer contents. This is true of shadowable layers with shadows,
* because there's no target on which to composite directly in the
* layer-publishing child process.
*/
virtual bool MustRetainContent() { return false; }
/**
* Layers will get this call when their layer manager is destroyed, this
* indicates they should clear resources they don't really need after their
@ -90,14 +98,14 @@ public:
mOperator = aOperator;
}
gfxContext::GraphicsOperator GetOperator() const { return mOperator; }
/**
* Return a surface for this layer. Will use an existing surface, if
* possible, or may create a temporary surface.
* Implement this method for any layers that might be used as a mask.
* Should only return null if a surface cannor be created.
*/
virtual already_AddRefed<gfxASurface> GetAsSurface() { return nsnull; }
/**
* Return a surface for this layer. Will use an existing surface, if
* possible, or may create a temporary surface.
* Implement this method for any layers that might be used as a mask.
* Should only return null if a surface cannor be created.
*/
virtual already_AddRefed<gfxASurface> GetAsSurface() { return nsnull; }
bool GetClipToVisibleRegion() { return mClipToVisibleRegion; }
void SetClipToVisibleRegion(bool aClip) { mClipToVisibleRegion = aClip; }

View File

@ -11,7 +11,6 @@
#include "mozilla/layers/PLayersChild.h"
#include "mozilla/layers/PLayersParent.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/Preferences.h"
#include "ipc/ShadowLayerChild.h"
@ -445,9 +444,7 @@ public:
{
NS_ASSERTION(BasicManager()->InConstruction(),
"Can only set properties in construction phase");
mInvalidRegion.Or(mInvalidRegion, aRegion);
mInvalidRegion.SimplifyOutward(10);
mValidRegion.Sub(mValidRegion, mInvalidRegion);
mValidRegion.Sub(mValidRegion, aRegion);
}
virtual void PaintThebes(gfxContext* aContext,
@ -468,7 +465,9 @@ public:
referenceSurface = defaultTarget->CurrentSurface();
} else {
nsIWidget* widget = BasicManager()->GetRetainerWidget();
if (!widget || !(referenceSurface = widget->GetThebesSurface())) {
if (widget) {
referenceSurface = widget->GetThebesSurface();
} else {
referenceSurface = BasicManager()->GetTarget()->CurrentSurface();
}
}
@ -647,7 +646,10 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext,
gfxASurface::CONTENT_COLOR_ALPHA;
float opacity = GetEffectiveOpacity();
if (!BasicManager()->IsRetained()) {
if (!BasicManager()->IsRetained() ||
(!canUseOpaqueSurface &&
(mContentFlags & CONTENT_COMPONENT_ALPHA) &&
!MustRetainContent())) {
NS_ASSERTION(readbackUpdates.IsEmpty(), "Can't do readback for non-retained layer");
mValidRegion.SetEmpty();
@ -1334,7 +1336,9 @@ ToInsideIntRect(const gfxRect& aRect)
}
BasicLayerManager::BasicLayerManager(nsIWidget* aWidget) :
#ifdef DEBUG
mPhase(PHASE_NONE),
#endif
mWidget(aWidget)
, mDoubleBuffering(BUFFER_NONE), mUsingDefaultTarget(false)
, mCachedSurfaceInUse(false)
@ -1345,7 +1349,9 @@ BasicLayerManager::BasicLayerManager(nsIWidget* aWidget) :
}
BasicLayerManager::BasicLayerManager() :
#ifdef DEBUG
mPhase(PHASE_NONE),
#endif
mWidget(nsnull)
, mDoubleBuffering(BUFFER_NONE), mUsingDefaultTarget(false)
, mCachedSurfaceInUse(false)
@ -1446,7 +1452,9 @@ BasicLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
#endif
NS_ASSERTION(!InTransaction(), "Nested transactions not allowed");
#ifdef DEBUG
mPhase = PHASE_CONSTRUCTION;
#endif
mTarget = aTarget;
}
@ -1639,19 +1647,15 @@ BasicLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback,
#endif
NS_ASSERTION(InConstruction(), "Should be in construction phase");
#ifdef DEBUG
mPhase = PHASE_DRAWING;
#endif
Layer* aLayer = GetRoot();
RenderTraceLayers(aLayer, "FF00");
mTransactionIncomplete = false;
if (aFlags & END_NO_COMPOSITE) {
// TODO: We should really just set mTarget to null and make sure we can handle that further down the call chain
nsRefPtr<gfxASurface> surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(1, 1), gfxASurface::CONTENT_COLOR);
mTarget = new gfxContext(surf);
}
if (mTarget && mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
nsIntRect clipRect;
if (HasShadowManager()) {
@ -1681,20 +1685,7 @@ BasicLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback,
}
}
if (aFlags & END_NO_COMPOSITE) {
if (IsRetained()) {
// Clip the destination out so that we don't draw to it, and
// only end up validating ThebesLayers.
mTarget->Clip(gfxRect(0, 0, 0, 0));
PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nsnull);
}
// If we're not retained, then don't composite means do nothing at all.
} else {
PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nsnull);
if (mWidget) {
FlashWidgetUpdateArea(mTarget);
}
}
PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nsnull);
if (!mTransactionIncomplete) {
// Clear out target if we have a complete transaction.
@ -1707,9 +1698,11 @@ BasicLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback,
MOZ_LAYERS_LOG(("]----- EndTransaction"));
#endif
#ifdef DEBUG
// Go back to the construction phase if the transaction isn't complete.
// Layout will update the layer tree and call EndTransaction().
mPhase = mTransactionIncomplete ? PHASE_CONSTRUCTION : PHASE_NONE;
#endif
if (!mTransactionIncomplete) {
// This is still valid if the transaction was incomplete.
@ -1725,27 +1718,6 @@ BasicLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback,
return !mTransactionIncomplete;
}
void
BasicLayerManager::FlashWidgetUpdateArea(gfxContext *aContext)
{
static bool sWidgetFlashingEnabled;
static bool sWidgetFlashingPrefCached = false;
if (!sWidgetFlashingPrefCached) {
sWidgetFlashingPrefCached = true;
mozilla::Preferences::AddBoolVarCache(&sWidgetFlashingEnabled,
"nglayout.debug.widget_update_flashing");
}
if (sWidgetFlashingEnabled) {
float r = float(rand()) / RAND_MAX;
float g = float(rand()) / RAND_MAX;
float b = float(rand()) / RAND_MAX;
aContext->SetColor(gfxRGBA(r, g, b, 0.2));
aContext->Paint();
}
}
bool
BasicLayerManager::EndEmptyTransaction()
{
@ -2330,6 +2302,7 @@ public:
virtual Layer* AsLayer() { return this; }
virtual ShadowableLayer* AsShadowableLayer() { return this; }
virtual bool MustRetainContent() { return HasShadow(); }
void SetBackBufferAndAttrs(const OptionalThebesBuffer& aBuffer,
const nsIntRegion& aValidRegion,
@ -3590,7 +3563,9 @@ void
BasicShadowLayerManager::ForwardTransaction()
{
RenderTraceScope rendertrace("Foward Transaction", "000090");
#ifdef DEBUG
mPhase = PHASE_FORWARD;
#endif
// forward this transaction's changeset to our ShadowLayerManager
AutoInfallibleTArray<EditReply, 10> replies;
@ -3655,7 +3630,9 @@ BasicShadowLayerManager::ForwardTransaction()
NS_WARNING("failed to forward Layers transaction");
}
#ifdef DEBUG
mPhase = PHASE_NONE;
#endif
// this may result in Layers being deleted, which results in
// PLayer::Send__delete__() and DeallocShmem()

View File

@ -86,8 +86,6 @@ public:
nsIWidget* GetRetainerWidget() { return mWidget; }
void ClearRetainerWidget() { mWidget = nsnull; }
virtual bool IsWidgetLayerManager() { return mWidget != nsnull; }
virtual void BeginTransaction();
virtual void BeginTransactionWithTarget(gfxContext* aTarget);
virtual bool EndEmptyTransaction();
@ -95,8 +93,6 @@ public:
void* aCallbackData,
EndTransactionFlags aFlags = END_DEFAULT);
virtual bool AreComponentAlphaLayersEnabled() { return HasShadowManager(); }
virtual void SetRoot(Layer* aLayer);
virtual already_AddRefed<ThebesLayer> CreateThebesLayer();
@ -125,11 +121,9 @@ public:
bool InConstruction() { return mPhase == PHASE_CONSTRUCTION; }
bool InDrawing() { return mPhase == PHASE_DRAWING; }
bool InForward() { return mPhase == PHASE_FORWARD; }
#endif
bool InTransaction() { return mPhase != PHASE_NONE; }
#endif
gfxContext* GetTarget() { return mTarget; }
void SetTarget(gfxContext* aTarget) { mUsingDefaultTarget = false; mTarget = aTarget; }
bool IsRetained() { return mWidget != nsnull; }
#ifdef MOZ_LAYERS_HAVE_LOG
@ -150,13 +144,17 @@ public:
void PopGroupToSourceWithCachedSurface(gfxContext *aTarget, gfxContext *aPushed);
virtual bool IsCompositingCheap() { return false; }
virtual bool HasShadowManagerInternal() const { return false; }
bool HasShadowManager() const { return HasShadowManagerInternal(); }
virtual PRInt32 GetMaxTextureSize() const { return PR_INT32_MAX; }
protected:
#ifdef DEBUG
enum TransactionPhase {
PHASE_NONE, PHASE_CONSTRUCTION, PHASE_DRAWING, PHASE_FORWARD
};
TransactionPhase mPhase;
#endif
// Paints aLayer to mTarget.
void PaintLayer(gfxContext* aTarget,
@ -172,8 +170,6 @@ protected:
void* aCallbackData,
EndTransactionFlags aFlags = END_DEFAULT);
void FlashWidgetUpdateArea(gfxContext* aContext);
// Widget whose surface should be used as the basis for ThebesLayer
// buffers.
nsIWidget* mWidget;

View File

@ -168,11 +168,12 @@ public:
// Thebes Layer
virtual Layer* AsLayer() { return this; }
virtual void InvalidateRegion(const nsIntRegion& aRegion) {
mInvalidRegion.Or(mInvalidRegion, aRegion);
mInvalidRegion.SimplifyOutward(10);
mValidRegion.Sub(mValidRegion, mInvalidRegion);
mValidRegion.Sub(mValidRegion, aRegion);
}
// BasicImplData
virtual bool MustRetainContent() { return HasShadow(); }
// Shadow methods
virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs);
virtual ShadowableLayer* AsShadowableLayer() { return this; }
@ -183,7 +184,7 @@ public:
}
virtual void PaintThebes(gfxContext* aContext,
Layer* aMaskLayer,
Layer* aMaskLayer,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData,
ReadbackProcessor* aReadback);

View File

@ -199,7 +199,7 @@ LayerManagerD3D10::Initialize(bool force)
mInputLayout = attachments->mInputLayout;
}
if (LayerManager::HasShadowManager()) {
if (HasShadowManager()) {
reporter.SetSuccessful();
return true;
}
@ -320,7 +320,7 @@ LayerManagerD3D10::EndTransaction(DrawThebesLayerCallback aCallback,
Log();
#endif
Render(aFlags);
Render();
mCurrentCallbackInfo.Callback = nsnull;
mCurrentCallbackInfo.CallbackData = nsnull;
}
@ -649,14 +649,10 @@ LayerManagerD3D10::EnsureReadbackManager()
}
void
LayerManagerD3D10::Render(EndTransactionFlags aFlags)
LayerManagerD3D10::Render()
{
static_cast<LayerD3D10*>(mRoot->ImplData())->Validate();
if (aFlags & END_NO_COMPOSITE) {
return;
}
SetupPipeline();
float black[] = { 0, 0, 0, 0 };
@ -876,7 +872,7 @@ LayerD3D10::LoadMaskTexture()
gfxMatrix maskTransform;
bool maskIs2D = maskLayer->GetEffectiveTransform().CanDraw2D(&maskTransform);
NS_ASSERTION(maskIs2D, "How did we end up with a 3D transform here?!");
NS_ASSERTION(maskIs2D, "How did we end up with a 3D transform here?!");
gfxRect bounds = gfxRect(gfxPoint(), size);
bounds = maskTransform.TransformBounds(bounds);

View File

@ -177,7 +177,7 @@ private:
void VerifyBufferSize();
void EnsureReadbackManager();
void Render(EndTransactionFlags aFlags);
void Render();
nsRefPtr<ID3D10Device1> mDevice;

View File

@ -53,9 +53,7 @@ void
ThebesLayerD3D10::InvalidateRegion(const nsIntRegion &aRegion)
{
mInvalidRegion.Or(mInvalidRegion, aRegion);
mInvalidRegion.SimplifyOutward(10);
mValidRegion.Sub(mValidRegion, mInvalidRegion);
mValidRegion.Sub(mValidRegion, aRegion);
}
void ThebesLayerD3D10::CopyRegion(ID3D10Texture2D* aSrc, const nsIntPoint &aSrcOffset,

View File

@ -192,9 +192,6 @@ void
CanvasLayerD3D9::RenderLayer()
{
UpdateSurface();
if (mD3DManager->CompositingDisabled()) {
return;
}
FireDidTransactionCallback();
if (!mTexture)
@ -364,7 +361,7 @@ ShadowCanvasLayerD3D9::GetLayer()
void
ShadowCanvasLayerD3D9::RenderLayer()
{
if (!mBuffer || mD3DManager->CompositingDisabled()) {
if (!mBuffer) {
return;
}

View File

@ -19,9 +19,6 @@ RenderColorLayerD3D9(ColorLayer* aLayer, LayerManagerD3D9 *aManager)
{
// XXX we might be able to improve performance by using
// IDirect3DDevice9::Clear
if (aManager->CompositingDisabled()) {
return;
}
nsIntRect visibleRect = aLayer->GetEffectiveVisibleRegion().GetBounds();

View File

@ -147,24 +147,21 @@ ContainerRender(Container* aContainer,
aContainer->mSupportsComponentAlphaChildren = false;
if (useIntermediate) {
nsRefPtr<IDirect3DSurface9> renderSurface;
if (!aManager->CompositingDisabled()) {
aManager->device()->GetRenderTarget(0, getter_AddRefs(previousRenderTarget));
HRESULT hr = aManager->device()->CreateTexture(visibleRect.width, visibleRect.height, 1,
D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT, getter_AddRefs(renderTexture),
NULL);
if (FAILED(hr)) {
aManager->ReportFailure(NS_LITERAL_CSTRING("ContainerLayerD3D9::ContainerRender(): Failed to create texture"),
hr);
return;
}
nsRefPtr<IDirect3DSurface9> renderSurface;
renderTexture->GetSurfaceLevel(0, getter_AddRefs(renderSurface));
aManager->device()->SetRenderTarget(0, renderSurface);
aManager->device()->GetRenderTarget(0, getter_AddRefs(previousRenderTarget));
HRESULT hr = aManager->device()->CreateTexture(visibleRect.width, visibleRect.height, 1,
D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT, getter_AddRefs(renderTexture),
NULL);
if (FAILED(hr)) {
aManager->ReportFailure(NS_LITERAL_CSTRING("ContainerLayerD3D9::ContainerRender(): Failed to create texture"),
hr);
return;
}
nsRefPtr<IDirect3DSurface9> renderSurface;
renderTexture->GetSurfaceLevel(0, getter_AddRefs(renderSurface));
aManager->device()->SetRenderTarget(0, renderSurface);
if (aContainer->mVisibleRegion.GetNumRects() == 1 &&
(aContainer->GetContentFlags() & aContainer->CONTENT_OPAQUE)) {
// don't need a background, we're going to paint all opaque stuff
@ -185,14 +182,12 @@ ContainerRender(Container* aContainer,
::OffsetRect(&src,
visibleRect.x + PRInt32(transform.x0),
visibleRect.y + PRInt32(transform.y0));
if (!aManager->CompositingDisabled()) {
hr = aManager->device()->
StretchRect(previousRenderTarget, &src, renderSurface, &dest, D3DTEXF_NONE);
}
hr = aManager->device()->
StretchRect(previousRenderTarget, &src, renderSurface, &dest, D3DTEXF_NONE);
}
if (hr == S_OK) {
aContainer->mSupportsComponentAlphaChildren = true;
} else if (!aManager->CompositingDisabled()) {
} else {
aManager->device()->
Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 0), 0, 0);
}
@ -261,7 +256,7 @@ ContainerRender(Container* aContainer,
aManager->device()->SetScissorRect(&containerD3D9ClipRect);
if (useIntermediate && !aManager->CompositingDisabled()) {
if (useIntermediate) {
aManager->device()->SetRenderTarget(0, previousRenderTarget);
aManager->device()->SetVertexShaderConstantF(CBvRenderTargetOffset, previousRenderTargetOffset, 1);
aManager->device()->SetVertexShaderConstantF(CBmProjection, &oldViewMatrix[0][0], 4);

View File

@ -343,7 +343,7 @@ void
ImageLayerD3D9::RenderLayer()
{
ImageContainer *container = GetContainer();
if (!container || mD3DManager->CompositingDisabled()) {
if (!container) {
return;
}
@ -594,10 +594,6 @@ ShadowImageLayerD3D9::GetLayer()
void
ShadowImageLayerD3D9::RenderLayer()
{
if (mD3DManager->CompositingDisabled()) {
return;
}
if (mBuffer) {
mBuffer->RenderTo(mD3DManager, GetEffectiveVisibleRegion());
} else if (mYCbCrImage) {

View File

@ -149,7 +149,6 @@ LayerManagerD3D9::EndTransaction(DrawThebesLayerCallback aCallback,
// so we don't need to pass any global transform here.
mRoot->ComputeEffectiveTransforms(gfx3DMatrix());
SetCompositingDisabled(aFlags & END_NO_COMPOSITE);
Render();
/* Clean this out for sanity */
mCurrentCallbackInfo.Callback = NULL;
@ -285,12 +284,6 @@ LayerManagerD3D9::Render()
deviceManager()->SetupRenderState();
SetupPipeline();
if (CompositingDisabled()) {
static_cast<LayerD3D9*>(mRoot->ImplData())->RenderLayer();
return;
}
nsIntRect rect;
mWidget->GetClientBounds(rect);

View File

@ -179,9 +179,6 @@ public:
void ReportFailure(const nsACString &aMsg, HRESULT aCode);
bool CompositingDisabled() { return mCompositingDisabled; }
void SetCompositingDisabled(bool aCompositingDisabled) { mCompositingDisabled = aCompositingDisabled; }
private:
/* Default device manager instance */
static DeviceManagerD3D9 *mDefaultDeviceManager;
@ -214,12 +211,6 @@ private:
*/
PRUint32 mDeviceResetCount;
/*
* True if we should only be drawing layer contents, not
* compositing them to the target.
*/
bool mCompositingDisabled;
/*
* Render the current layer tree to the active target.
*/

View File

@ -47,9 +47,7 @@ ThebesLayerD3D9::~ThebesLayerD3D9()
void
ThebesLayerD3D9::InvalidateRegion(const nsIntRegion &aRegion)
{
mInvalidRegion.Or(mInvalidRegion, aRegion);
mInvalidRegion.SimplifyOutward(10);
mValidRegion.Sub(mValidRegion, mInvalidRegion);
mValidRegion.Sub(mValidRegion, aRegion);
}
void
@ -238,10 +236,6 @@ ThebesLayerD3D9::RenderThebesLayer(ReadbackProcessor* aReadback)
mValidRegion = neededRegion;
}
if (mD3DManager->CompositingDisabled()) {
return;
}
SetShaderTransformAndOpacity();
if (mode == SURFACE_COMPONENT_ALPHA) {
@ -660,7 +654,7 @@ ShadowThebesLayerD3D9::IsEmpty()
void
ShadowThebesLayerD3D9::RenderThebesLayer()
{
if (!mBuffer || mD3DManager->CompositingDisabled()) {
if (!mBuffer) {
return;
}
NS_ABORT_IF_FALSE(mBuffer, "should have a buffer here");

View File

@ -194,9 +194,6 @@ CanvasLayerOGL::RenderLayer(int aPreviousDestination,
const nsIntPoint& aOffset)
{
UpdateSurface();
if (mOGLManager->CompositingDisabled()) {
return;
}
FireDidTransactionCallback();
mOGLManager->MakeCurrent();
@ -368,9 +365,6 @@ void
ShadowCanvasLayerOGL::RenderLayer(int aPreviousFrameBuffer,
const nsIntPoint& aOffset)
{
if (mOGLManager->CompositingDisabled()) {
return;
}
mOGLManager->MakeCurrent();
ShaderProgramOGL *program =

View File

@ -12,10 +12,6 @@ static void
RenderColorLayer(ColorLayer* aLayer, LayerManagerOGL *aManager,
const nsIntPoint& aOffset)
{
if (aManager->CompositingDisabled()) {
return;
}
aManager->MakeCurrent();
// XXX we might be able to improve performance by using glClear

View File

@ -179,14 +179,12 @@ ContainerRender(Container* aContainer,
}
aContainer->gl()->PushViewportRect();
framebufferRect -= childOffset;
if (!aManager->CompositingDisabled()) {
aManager->CreateFBOWithTexture(framebufferRect,
mode,
aPreviousFrameBuffer,
&frameBuffer,
&containerSurface);
}
framebufferRect -= childOffset;
aManager->CreateFBOWithTexture(framebufferRect,
mode,
aPreviousFrameBuffer,
&frameBuffer,
&containerSurface);
childOffset.x = visibleRect.x;
childOffset.y = visibleRect.y;
} else {
@ -241,47 +239,45 @@ ContainerRender(Container* aContainer,
aManager->SetupPipeline(viewport.width, viewport.height,
LayerManagerOGL::ApplyWorldTransform);
aContainer->gl()->PopScissorRect();
aContainer->gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer);
aContainer->gl()->fDeleteFramebuffers(1, &frameBuffer);
if (!aManager->CompositingDisabled()) {
aContainer->gl()->fDeleteFramebuffers(1, &frameBuffer);
aContainer->gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
aContainer->gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
aContainer->gl()->fBindTexture(aManager->FBOTextureTarget(), containerSurface);
aContainer->gl()->fBindTexture(aManager->FBOTextureTarget(), containerSurface);
MaskType maskType = MaskNone;
if (aContainer->GetMaskLayer()) {
if (!aContainer->GetTransform().CanDraw2D()) {
maskType = Mask3d;
} else {
maskType = Mask2d;
}
MaskType maskType = MaskNone;
if (aContainer->GetMaskLayer()) {
if (!aContainer->GetTransform().CanDraw2D()) {
maskType = Mask3d;
} else {
maskType = Mask2d;
}
ShaderProgramOGL *rgb =
aManager->GetFBOLayerProgram(maskType);
rgb->Activate();
rgb->SetLayerQuadRect(visibleRect);
rgb->SetLayerTransform(transform);
rgb->SetLayerOpacity(opacity);
rgb->SetRenderOffset(aOffset);
rgb->SetTextureUnit(0);
rgb->LoadMask(aContainer->GetMaskLayer());
if (rgb->GetTexCoordMultiplierUniformLocation() != -1) {
// 2DRect case, get the multiplier right for a sampler2DRect
rgb->SetTexCoordMultiplier(visibleRect.width, visibleRect.height);
}
// Drawing is always flipped, but when copying between surfaces we want to avoid
// this. Pass true for the flip parameter to introduce a second flip
// that cancels the other one out.
aManager->BindAndDrawQuad(rgb, true);
// Clean up resources. This also unbinds the texture.
aContainer->gl()->fDeleteTextures(1, &containerSurface);
}
ShaderProgramOGL *rgb =
aManager->GetFBOLayerProgram(maskType);
rgb->Activate();
rgb->SetLayerQuadRect(visibleRect);
rgb->SetLayerTransform(transform);
rgb->SetLayerOpacity(opacity);
rgb->SetRenderOffset(aOffset);
rgb->SetTextureUnit(0);
rgb->LoadMask(aContainer->GetMaskLayer());
if (rgb->GetTexCoordMultiplierUniformLocation() != -1) {
// 2DRect case, get the multiplier right for a sampler2DRect
rgb->SetTexCoordMultiplier(visibleRect.width, visibleRect.height);
}
// Drawing is always flipped, but when copying between surfaces we want to avoid
// this. Pass true for the flip parameter to introduce a second flip
// that cancels the other one out.
aManager->BindAndDrawQuad(rgb, true);
// Clean up resources. This also unbinds the texture.
aContainer->gl()->fDeleteTextures(1, &containerSurface);
} else {
aContainer->gl()->PopScissorRect();
}

View File

@ -186,7 +186,7 @@ ImageLayerOGL::RenderLayer(int,
{
nsRefPtr<ImageContainer> container = GetContainer();
if (!container || mOGLManager->CompositingDisabled())
if (!container)
return;
mOGLManager->MakeCurrent();
@ -772,9 +772,6 @@ void
ShadowImageLayerOGL::RenderLayer(int aPreviousFrameBuffer,
const nsIntPoint& aOffset)
{
if (mOGLManager->CompositingDisabled()) {
return;
}
mOGLManager->MakeCurrent();
if (mTexImage) {

View File

@ -410,7 +410,6 @@ LayerManagerOGL::EndTransaction(DrawThebesLayerCallback aCallback,
mThebesLayerCallback = aCallback;
mThebesLayerCallbackData = aCallbackData;
SetCompositingDisabled(aFlags & END_NO_COMPOSITE);
Render();
@ -763,13 +762,6 @@ LayerManagerOGL::Render()
mGLContext->fScissor(0, 0, width, height);
}
if (CompositingDisabled()) {
RootLayer()->RenderLayer(mGLContext->IsDoubleBuffered() ? 0 : mBackBufferFBO,
nsIntPoint(0, 0));
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
return;
}
mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST);
// If the Java compositor is being used, this clear will be done in

View File

@ -350,9 +350,6 @@ public:
*/
void SetSurfaceSize(int width, int height);
bool CompositingDisabled() { return mCompositingDisabled; }
void SetCompositingDisabled(bool aCompositingDisabled) { mCompositingDisabled = aCompositingDisabled; }
private:
/** Widget associated with this layer manager */
nsIWidget *mWidget;
@ -394,7 +391,6 @@ private:
/** Misc */
bool mHasBGRA;
bool mCompositingDisabled;
/**
* When rendering to an EGL surface (e.g. on Android), we rely on being told

View File

@ -83,8 +83,6 @@ public:
void RenderTo(const nsIntPoint& aOffset, LayerManagerOGL* aManager,
PRUint32 aFlags);
void EndUpdate();
nsIntSize GetSize() {
if (mTexImage)
return mTexImage->GetSize();
@ -105,17 +103,6 @@ protected:
bool mInitialised;
};
void ThebesLayerBufferOGL::EndUpdate()
{
if (mTexImage && mTexImage->InUpdate()) {
mTexImage->EndUpdate();
}
if (mTexImageOnWhite && mTexImageOnWhite->InUpdate()) {
mTexImageOnWhite->EndUpdate();
}
}
void
ThebesLayerBufferOGL::RenderTo(const nsIntPoint& aOffset,
LayerManagerOGL* aManager,
@ -126,7 +113,13 @@ ThebesLayerBufferOGL::RenderTo(const nsIntPoint& aOffset,
if (!mTexImage || !Initialised())
return;
EndUpdate();
if (mTexImage->InUpdate()) {
mTexImage->EndUpdate();
}
if (mTexImageOnWhite && mTexImageOnWhite->InUpdate()) {
mTexImageOnWhite->EndUpdate();
}
#ifdef MOZ_DUMP_PAINTING
if (gfxUtils::sDumpPainting) {
@ -784,9 +777,7 @@ ThebesLayerOGL::SetVisibleRegion(const nsIntRegion &aRegion)
void
ThebesLayerOGL::InvalidateRegion(const nsIntRegion &aRegion)
{
mInvalidRegion.Or(mInvalidRegion, aRegion);
mInvalidRegion.SimplifyOutward(10);
mValidRegion.Sub(mValidRegion, mInvalidRegion);
mValidRegion.Sub(mValidRegion, aRegion);
}
void
@ -842,11 +833,6 @@ ThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer,
}
}
if (mOGLManager->CompositingDisabled()) {
mBuffer->EndUpdate();
return;
}
// Drawing thebes layers can change the current context, reset it.
gl()->MakeCurrent();
@ -1277,7 +1263,7 @@ void
ShadowThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer,
const nsIntPoint& aOffset)
{
if (!mBuffer || mOGLManager->CompositingDisabled()) {
if (!mBuffer) {
return;
}
NS_ABORT_IF_FALSE(mBuffer, "should have a buffer here");

View File

@ -112,13 +112,6 @@ gfx3DMatrix::operator==(const gfx3DMatrix& o) const
_41 == o._41 && _42 == o._42 && _43 == o._43 && _44 == o._44;
}
bool
gfx3DMatrix::operator!=(const gfx3DMatrix& o) const
{
return !((*this) == o);
}
gfx3DMatrix&
gfx3DMatrix::operator/=(const gfxFloat scalar)
{

View File

@ -56,7 +56,6 @@ public:
* Return true if this matrix and |aMatrix| are the same matrix.
*/
bool operator==(const gfx3DMatrix& aMatrix) const;
bool operator!=(const gfx3DMatrix& aMatrix) const;
/**
* Divide all values in the matrix by a scalar value

View File

@ -487,13 +487,6 @@ gfxASurface::MovePixels(const nsIntRect& aSourceRect,
nsRefPtr<gfxASurface> tmp =
CreateSimilarSurface(GetContentType(),
gfxIntSize(aSourceRect.width, aSourceRect.height));
// CreateSimilarSurface can return nsnull if the current surface is
// in an error state. This isn't good, but its better to carry
// on with the error surface instead of crashing.
NS_ASSERTION(tmp, "Must have temporary surface to move pixels!");
if (!tmp) {
return;
}
nsRefPtr<gfxContext> ctx = new gfxContext(tmp);
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->SetSource(this, gfxPoint(-aSourceRect.x, -aSourceRect.y));

View File

@ -55,7 +55,6 @@ function takeReferenceSnapshot() {
function myOnStopFrame(aRequest, aFrame) {
gOnStopFrameCounter++;
ok(true, "myOnStopFrame called");
let currentSnapshot = snapshotWindow(window, false);
if (compareSnapshots(currentSnapshot, gReferenceSnapshot, true)[0]) {
// SUCCESS!
@ -63,7 +62,6 @@ function myOnStopFrame(aRequest, aFrame) {
"at call #" + gOnStopFrameCounter + " to onStopFrame");
cleanUpAndFinish();
}
setTimeout(function() { myOnStopFrame(0, 0); }, 1000);
}
function failTest() {

File diff suppressed because it is too large Load Diff

View File

@ -12,8 +12,6 @@
#include "nsRegion.h"
#include "nsIFrame.h"
#include "Layers.h"
#include "nsDisplayListInvalidation.h"
#include "LayerTreeInvalidation.h"
class nsDisplayListBuilder;
class nsDisplayList;
@ -23,9 +21,6 @@ class nsRootPresContext;
namespace mozilla {
class FrameLayerBuilder;
class LayerManagerData;
enum LayerState {
LAYER_NONE,
LAYER_INACTIVE,
@ -34,15 +29,7 @@ enum LayerState {
// when the layer has rounded rect clips.
LAYER_ACTIVE_FORCE,
// Special layer that is metadata only.
LAYER_ACTIVE_EMPTY,
// Inactive style layer for rendering SVG effects.
LAYER_SVG_EFFECTS
};
extern PRUint8 gLayerManagerLayerBuilder;
extern PRUint8 gLayerManagerSecondary;
class LayerManagerSecondary : public layers::LayerUserData {
LAYER_ACTIVE_EMPTY
};
/**
@ -84,7 +71,7 @@ class LayerManagerSecondary : public layers::LayerUserData {
* integer types (nsIntPoint/nsIntSize/nsIntRect/nsIntRegion) are all in layer
* coordinates, post-scaling, whereas appunit types are all pre-scaling.
*/
class FrameLayerBuilder : public layers::LayerUserData {
class FrameLayerBuilder {
public:
typedef layers::ContainerLayer ContainerLayer;
typedef layers::Layer Layer;
@ -94,18 +81,11 @@ public:
FrameLayerBuilder() :
mRetainingManager(nsnull),
mDetectedDOMModification(false),
mInvalidateAllLayers(false),
mContainerLayerGeneration(0),
mMaxContainerLayerGeneration(0)
mInvalidateAllLayers(false)
{
MOZ_COUNT_CTOR(FrameLayerBuilder);
mNewDisplayItemData.Init();
mThebesLayerItems.Init();
}
~FrameLayerBuilder()
{
MOZ_COUNT_DTOR(FrameLayerBuilder);
}
void Init(nsDisplayListBuilder* aBuilder);
@ -120,7 +100,14 @@ public:
* is not the retained layer manager then it must be a temporary layer
* manager that will not be used again.
*/
void WillEndTransaction();
void WillEndTransaction(LayerManager* aManager);
/**
* Call this after we end a transaction on aManager. If aManager
* is not the retained layer manager then it must be a temporary layer
* manager that will not be used again.
*/
void DidEndTransaction(LayerManager* aManager);
struct ContainerParameters {
ContainerParameters() :
@ -193,8 +180,26 @@ public:
* region.
*/
Layer* GetLeafLayerFor(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
nsDisplayItem* aItem);
/**
* Call this during invalidation if aFrame has
* the NS_FRAME_HAS_CONTAINER_LAYER state bit. Only the nearest
* ancestor frame of the damaged frame that has
* NS_FRAME_HAS_CONTAINER_LAYER needs to be invalidated this way.
*/
static void InvalidateThebesLayerContents(nsIFrame* aFrame,
const nsRect& aRect);
/**
* For any descendant frame of aFrame (including across documents) that
* has an associated container layer, invalidate all the contents of
* all ThebesLayer children of the container. Useful when aFrame is
* being moved and we need to invalidate everything in aFrame's subtree.
*/
static void InvalidateThebesLayersInSubtree(nsIFrame* aFrame);
/**
* Call this to force all retained layers to be discarded and recreated at
* the next paint.
@ -207,7 +212,7 @@ public:
* otherwise we return the layer.
*/
static Layer* GetDedicatedLayer(nsIFrame* aFrame, PRUint32 aDisplayItemKey);
/**
* This callback must be provided to EndTransaction. The callback data
* must be the nsDisplayListBuilder containing this FrameLayerBuilder.
@ -223,7 +228,7 @@ public:
* Dumps this FrameLayerBuilder's retained layer manager's retained
* layer tree to stderr.
*/
static void DumpRetainedLayerTree(LayerManager* aManager, FILE* aFile = stdout);
void DumpRetainedLayerTree(FILE* aFile = stdout);
#endif
/******* PRIVATE METHODS to FrameLayerBuilder.cpp ********/
@ -233,17 +238,10 @@ public:
/**
* Record aItem as a display item that is rendered by aLayer.
*
* @param aLayer Layer that the display item will be rendered into
* @param aItem Display item to be drawn.
* @param aLayerState What LayerState the item is using.
* @param aManager If the layer is in the LAYER_INACTIVE state,
* then this is the temporary layer manager to draw with.
*/
void AddLayerDisplayItem(Layer* aLayer,
nsDisplayItem* aItem,
LayerState aLayerState,
LayerManager* aManager = nsnull);
LayerState aLayerState);
/**
* Record aItem as a display item that is rendered by the ThebesLayer
@ -258,47 +256,6 @@ public:
nsIFrame* aContainerLayerFrame,
LayerState aLayerState);
/**
* Set the current top-level LayerManager for the widget being
* painted.
*/
static void SetWidgetLayerManager(LayerManager* aManager)
{
LayerManagerSecondary* secondary =
static_cast<LayerManagerSecondary*>(aManager->GetUserData(&gLayerManagerSecondary));
sWidgetManagerSecondary = !!secondary;
}
/**
* Gets the frame property descriptor for the given manager, or for the current
* widget layer manager if nsnull is passed.
*/
static const FramePropertyDescriptor* GetDescriptorForManager(LayerManager* aManager);
/**
* Get the LayerManagerData for a given frame and layer manager. If no layer manager
* is passed, then the current widget layer manager is used.
*/
static LayerManagerData* GetManagerData(nsIFrame* aFrame, LayerManager* aManager = nsnull);
/**
* Set the LayerManagerData for a given frame and current widget layer manager.
* This replaces any existing data for the same frame/layer manager pair.
*/
static void SetManagerData(nsIFrame* aFrame, LayerManagerData* aData);
/**
* Clears the current LayerManagerData for the given frame and current widget
* layer manager.
*/
static void ClearManagerData(nsIFrame* aFrame);
/**
* Clears any references to the given LayerManagerData for the given frame
* and belonging to any layer manager.
*/
static void ClearManagerData(nsIFrame* aFrame, LayerManagerData* aData);
/**
* Given a frame and a display item key that uniquely identifies a
* display item for the frame, find the layer that was last used to
@ -306,16 +263,7 @@ public:
* This could be a dedicated layer for the display item, or a ThebesLayer
* that renders many display items.
*/
Layer* GetOldLayerFor(nsIFrame* aFrame, PRUint32 aDisplayItemKey, nsDisplayItemGeometry** aOldGeometry = nsnull);
static Layer* GetDebugOldLayerFor(nsIFrame* aFrame, PRUint32 aDisplayItemKey);
/**
* If the display item was previously drawn as an inactive layer,
* then return the layer manager used for the inactive transaction.
* Returns nsnull if no manager could be found.
*/
LayerManager* GetInactiveLayerManagerFor(nsDisplayItem* aItem);
Layer* GetOldLayerFor(nsIFrame* aFrame, PRUint32 aDisplayItemKey);
/**
* Try to determine whether the ThebesLayer aLayer paints an opaque
@ -329,7 +277,10 @@ public:
* Destroy any stored LayerManagerDataProperty and the associated data for
* aFrame.
*/
static void DestroyDisplayItemDataFor(nsIFrame* aFrame);
static void DestroyDisplayItemDataFor(nsIFrame* aFrame)
{
aFrame->Properties().Delete(LayerManagerDataProperty());
}
LayerManager* GetRetainingLayerManager() { return mRetainingManager; }
@ -348,11 +299,8 @@ public:
* into a retained layer.
* Returns false if it was rendered into a temporary layer manager and then
* into a retained layer.
*
* Since display items can belong to multiple retained LayerManagers, we need to
* specify which LayerManager to check.
*/
static bool HasRetainedLayerFor(nsIFrame* aFrame, PRUint32 aDisplayItemKey, LayerManager* aManager);
static bool HasRetainedLayerFor(nsIFrame* aFrame, PRUint32 aDisplayItemKey);
/**
* Save transform that was in aLayer when we last painted. It must be an integer
@ -458,12 +406,6 @@ public:
return !(*this == aOther);
}
};
NS_DECLARE_FRAME_PROPERTY_WITH_FRAME_IN_DTOR(LayerManagerDataProperty,
RemoveFrameFromLayerManager)
NS_DECLARE_FRAME_PROPERTY_WITH_FRAME_IN_DTOR(LayerManagerSecondaryDataProperty,
RemoveFrameFromLayerManager)
protected:
/**
@ -473,50 +415,19 @@ protected:
*/
class DisplayItemData {
public:
DisplayItemData(Layer* aLayer, PRUint32 aKey, LayerState aLayerState, PRUint32 aGeneration)
: mLayer(aLayer)
, mDisplayItemKey(aKey)
, mContainerLayerGeneration(aGeneration)
, mLayerState(aLayerState)
, mUsed(false)
{}
DisplayItemData()
: mUsed(false)
{}
DisplayItemData(DisplayItemData &toCopy)
{
// This isn't actually a copy-constructor; notice that it steals toCopy's
// mGeometry pointer. Be careful.
mLayer = toCopy.mLayer;
mInactiveManager = toCopy.mInactiveManager;
mGeometry = toCopy.mGeometry;
mDisplayItemKey = toCopy.mDisplayItemKey;
mContainerLayerGeneration = toCopy.mContainerLayerGeneration;
mLayerState = toCopy.mLayerState;
mUsed = toCopy.mUsed;
}
DisplayItemData(Layer* aLayer, PRUint32 aKey, LayerState aLayerState)
: mLayer(aLayer), mDisplayItemKey(aKey), mLayerState(aLayerState) {}
nsRefPtr<Layer> mLayer;
nsRefPtr<LayerManager> mInactiveManager;
nsAutoPtr<nsDisplayItemGeometry> mGeometry;
PRUint32 mDisplayItemKey;
PRUint32 mContainerLayerGeneration;
LayerState mLayerState;
/**
* Used to track if data currently stored in mFramesWithLayers (from an existing
* paint) is also used in the current paint and has an equivalent data object
* in mNewDisplayItemData.
*/
bool mUsed;
};
// LayerManagerData needs to see DisplayItemDataEntry.
friend class LayerManagerData;
static void RemoveFrameFromLayerManager(nsIFrame* aFrame, void* aPropertyValue);
NS_DECLARE_FRAME_PROPERTY_WITH_FRAME_IN_DTOR(LayerManagerDataProperty,
RemoveFrameFromLayerManager)
/**
* We accumulate DisplayItemData elements in a hashtable during
* the paint process, and store them in the frame property only when
@ -524,31 +435,25 @@ protected:
*/
class DisplayItemDataEntry : public nsPtrHashKey<nsIFrame> {
public:
DisplayItemDataEntry(const nsIFrame *key) : nsPtrHashKey<nsIFrame>(key) { MOZ_COUNT_CTOR(DisplayItemDataEntry); }
DisplayItemDataEntry(const nsIFrame *key) : nsPtrHashKey<nsIFrame>(key), mIsSharingContainerLayer(false) {}
DisplayItemDataEntry(DisplayItemDataEntry &toCopy) :
nsPtrHashKey<nsIFrame>(toCopy.mKey)
nsPtrHashKey<nsIFrame>(toCopy.mKey), mIsSharingContainerLayer(toCopy.mIsSharingContainerLayer)
{
MOZ_COUNT_CTOR(DisplayItemDataEntry);
// This isn't actually a copy-constructor; notice that it steals toCopy's
// array. Be careful.
mData.SwapElements(toCopy.mData);
mContainerLayerGeneration = toCopy.mContainerLayerGeneration;
}
~DisplayItemDataEntry() { MOZ_COUNT_DTOR(DisplayItemDataEntry); }
bool HasNonEmptyContainerLayer();
nsAutoTArray<DisplayItemData, 1> mData;
PRUint32 mContainerLayerGeneration;
bool mIsSharingContainerLayer;
enum { ALLOW_MEMMOVE = false };
};
/**
* Stores DisplayItemData associated with aFrame, stores the data in
* mNewDisplayItemData.
*/
void StoreDataForFrame(nsIFrame* aFrame, DisplayItemData& data);
// LayerManagerData needs to see DisplayItemDataEntry.
friend class LayerManagerData;
// Flash the area within the context clip if paint flashing is enabled.
static void FlashPaint(gfxContext *aContext);
@ -560,16 +465,7 @@ protected:
* Note that the pointer returned here is only valid so long as you don't
* poke the LayerManagerData's mFramesWithLayers hashtable.
*/
nsTArray<DisplayItemData>* GetDisplayItemDataArrayForFrame(nsIFrame *aFrame);
/*
* Get the DisplayItemData associated with this frame / display item pair,
* using the LayerManager instead of FrameLayerBuilder.
*/
static DisplayItemData* GetDisplayItemDataForManager(nsIFrame* aFrame,
PRUint32 aDisplayItemKey,
LayerManager* aManager);
static DisplayItemData* GetDisplayItemDataForManager(nsDisplayItem* aItem, LayerManager* aManager);
static nsTArray<DisplayItemData>* GetDisplayItemDataArrayForFrame(nsIFrame *aFrame);
/**
* A useful hashtable iteration function that removes the
@ -578,7 +474,10 @@ protected:
* aClosure is ignored.
*/
static PLDHashOperator RemoveDisplayItemDataForFrame(DisplayItemDataEntry* aEntry,
void* aClosure);
void* aClosure)
{
return UpdateDisplayItemDataForFrame(aEntry, nsnull);
}
/**
* We store one of these for each display item associated with a
@ -591,24 +490,14 @@ protected:
* mItem always has an underlying frame.
*/
struct ClippedDisplayItem {
ClippedDisplayItem(nsDisplayItem* aItem, const Clip& aClip, PRUint32 aGeneration)
: mItem(aItem), mClip(aClip), mContainerLayerGeneration(aGeneration)
ClippedDisplayItem(nsDisplayItem* aItem, const Clip& aClip)
: mItem(aItem), mClip(aClip)
{
}
~ClippedDisplayItem();
nsDisplayItem* mItem;
/**
* If the display item is being rendered as an inactive
* layer, then this stores the layer manager being
* used for the inactive transaction.
*/
nsRefPtr<LayerManager> mInactiveLayer;
Clip mClip;
PRUint32 mContainerLayerGeneration;
bool mInactiveLayer;
};
/**
@ -632,7 +521,6 @@ public:
// The translation set on this ThebesLayer before we started updating the
// layer tree.
nsIntPoint mLastPaintOffset;
PRUint32 mContainerLayerGeneration;
bool mHasExplicitLastPaintOffset;
/**
* The first mCommonClipCount rounded rectangle clips are identical for
@ -652,23 +540,14 @@ public:
return mThebesLayerItems.GetEntry(aLayer);
}
static PLDHashOperator ProcessRemovedDisplayItems(DisplayItemDataEntry* aEntry,
void* aUserArg);
protected:
void RemoveThebesItemsForLayerSubtree(Layer* aLayer);
static PLDHashOperator UpdateDisplayItemDataForFrame(DisplayItemDataEntry* aEntry,
void* aUserArg);
static PLDHashOperator StoreNewDisplayItemData(DisplayItemDataEntry* aEntry,
void* aUserArg);
static PLDHashOperator RestoreDisplayItemData(DisplayItemDataEntry* aEntry,
void *aUserArg);
static PLDHashOperator RestoreThebesLayerItemEntries(ThebesLayerItemsEntry* aEntry,
void *aUserArg);
/**
* Returns true if the DOM has been modified since we started painting,
* in which case we should bail out and not paint anymore. This should
@ -685,11 +564,6 @@ protected:
* The root prescontext for the display list builder reference frame
*/
nsRootPresContext* mRootPresContext;
/**
* The display list builder being used.
*/
nsDisplayListBuilder* mDisplayListBuilder;
/**
* A map from frames to a list of (display item key, layer) pairs that
* describes what layers various parts of the frame are assigned to.
@ -714,22 +588,8 @@ protected:
* during this paint.
*/
bool mInvalidateAllLayers;
PRUint32 mContainerLayerGeneration;
PRUint32 mMaxContainerLayerGeneration;
/**
* True if the current top-level LayerManager for the widget being
* painted is marked as being a 'secondary' LayerManager.
*/
static bool sWidgetManagerSecondary;
};
static inline FrameLayerBuilder *GetLayerBuilderForManager(layers::LayerManager* aManager)
{
return static_cast<FrameLayerBuilder*>(aManager->GetUserData(&gLayerManagerLayerBuilder));
}
}
#endif /* FRAMELAYERBUILDER_H_ */

View File

@ -37,7 +37,6 @@ EXPORTS = \
nsCompatibility.h \
nsDisplayItemTypes.h \
nsDisplayList.h \
nsDisplayListInvalidation.h \
nsFrameManager.h \
nsFrameManagerBase.h \
nsFrameTraversal.h \

View File

@ -7559,6 +7559,11 @@ UpdateViewsForTree(nsIFrame* aFrame,
DoApplyRenderingChangeToTree(child, aFrameManager,
aChange);
} else { // regular frame
if ((child->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER) &&
(aChange & nsChangeHint_RepaintFrame)) {
FrameLayerBuilder::InvalidateThebesLayerContents(child,
child->GetVisualOverflowRectRelativeToSelf());
}
UpdateViewsForTree(child, aFrameManager, aChange);
}
}
@ -7599,17 +7604,21 @@ DoApplyRenderingChangeToTree(nsIFrame* aFrame,
nsSVGUtils::InvalidateBounds(aFrame);
}
} else {
aFrame->InvalidateFrameSubtree();
aFrame->InvalidateOverflowRect();
}
}
if (aChange & nsChangeHint_UpdateOpacityLayer) {
aFrame->MarkLayersActive(nsChangeHint_UpdateOpacityLayer);
aFrame->InvalidateLayer(aFrame->GetVisualOverflowRectRelativeToSelf(),
nsDisplayItem::TYPE_OPACITY);
}
if (aChange & nsChangeHint_UpdateTransformLayer) {
aFrame->MarkLayersActive(nsChangeHint_UpdateTransformLayer);
// Invalidate the old transformed area. The new transformed area
// will be invalidated by nsFrame::FinishAndStoreOverflowArea.
aFrame->InvalidateTransformLayer();
}
aFrame->SchedulePaint();
}
}
@ -11927,8 +11936,6 @@ nsCSSFrameConstructor::RecomputePosition(nsIFrame* aFrame)
return true;
}
aFrame->SchedulePaint();
// For relative positioning, we can simply update the frame rect
if (display->mPosition == NS_STYLE_POSITION_RELATIVE) {
nsIFrame* cb = aFrame->GetContainingBlock();
@ -11936,6 +11943,9 @@ nsCSSFrameConstructor::RecomputePosition(nsIFrame* aFrame)
const nsPoint oldOffsets = aFrame->GetRelativeOffset();
nsMargin newOffsets;
// Invalidate the old rect
aFrame->InvalidateOverflowRect();
// Move the frame
nsHTMLReflowState::ComputeRelativeOffsets(
cb->GetStyleVisibility()->mDirection,
@ -11946,6 +11956,9 @@ nsCSSFrameConstructor::RecomputePosition(nsIFrame* aFrame)
aFrame->SetPosition(aFrame->GetPosition() - oldOffsets +
nsPoint(newOffsets.left, newOffsets.top));
// Invalidate the new rect
aFrame->InvalidateOverflowRect();
return true;
}
@ -12017,6 +12030,9 @@ nsCSSFrameConstructor::RecomputePosition(nsIFrame* aFrame)
reflowState.mComputedMargin.top;
}
// Invalidate the old rect
aFrame->InvalidateOverflowRect();
// Move the frame
nsPoint pos(parentBorder.left + reflowState.mComputedOffsets.left +
reflowState.mComputedMargin.left,
@ -12024,6 +12040,9 @@ nsCSSFrameConstructor::RecomputePosition(nsIFrame* aFrame)
reflowState.mComputedMargin.top);
aFrame->SetPosition(pos);
// Invalidate the new rect
aFrame->InvalidateOverflowRect();
return true;
}

View File

@ -483,9 +483,8 @@ void nsCaret::InvalidateOutsideCaret()
nsIFrame *frame = GetCaretFrame();
// Only invalidate if we are not fully contained by our frame's rect.
if (frame && !frame->GetVisualOverflowRect().Contains(GetCaretRect())) {
frame->SchedulePaint();
}
if (frame && !frame->GetVisualOverflowRect().Contains(GetCaretRect()))
InvalidateRects(mCaretRect, GetHookRect(), frame);
}
void nsCaret::UpdateCaretPosition()
@ -614,9 +613,31 @@ nsresult nsCaret::PrimeTimer()
return NS_OK;
}
void nsCaret::InvalidateTextOverflowBlock()
{
// If the nearest block has a potential 'text-overflow' marker then
// invalidate it.
if (mLastContent) {
nsIFrame* caretFrame = mLastContent->GetPrimaryFrame();
if (caretFrame) {
nsIFrame* block = nsLayoutUtils::GetAsBlock(caretFrame) ? caretFrame :
nsLayoutUtils::FindNearestBlockAncestor(caretFrame);
if (block) {
const nsStyleTextReset* style = block->GetStyleTextReset();
if (style->mTextOverflow.mLeft.mType != NS_STYLE_TEXT_OVERFLOW_CLIP ||
style->mTextOverflow.mRight.mType != NS_STYLE_TEXT_OVERFLOW_CLIP) {
block->InvalidateOverflowRect();
}
}
}
}
}
//-----------------------------------------------------------------------------
void nsCaret::StartBlinking()
{
InvalidateTextOverflowBlock();
if (mReadOnly) {
// Make sure the one draw command we use for a readonly caret isn't
// done until the selection is set
@ -640,6 +661,8 @@ void nsCaret::StartBlinking()
//-----------------------------------------------------------------------------
void nsCaret::StopBlinking()
{
InvalidateTextOverflowBlock();
if (mDrawn) // erase the caret if necessary
DrawCaret(true);
@ -698,7 +721,7 @@ nsCaret::DrawAtPositionWithHint(nsIDOMNode* aNode,
}
if (aInvalidate)
theFrame->SchedulePaint();
InvalidateRects(mCaretRect, mHookRect, theFrame);
return true;
}
@ -1114,6 +1137,16 @@ nsCaret::UpdateCaretRects(nsIFrame* aFrame, PRInt32 aFrameOffset)
return true;
}
// static
void nsCaret::InvalidateRects(const nsRect &aRect, const nsRect &aHook,
nsIFrame *aFrame)
{
NS_ASSERTION(aFrame, "Must have a frame to invalidate");
nsRect rect;
rect.UnionRect(aRect, aHook);
aFrame->Invalidate(rect);
}
//-----------------------------------------------------------------------------
/* static */
void nsCaret::CaretBlinkCallback(nsITimer *aTimer, void *aClosure)

View File

@ -173,6 +173,10 @@ protected:
void StartBlinking();
void StopBlinking();
// If the nearest block has a potential 'text-overflow' marker then
// invalidate it.
void InvalidateTextOverflowBlock();
bool DrawAtPositionWithHint(nsIDOMNode* aNode,
PRInt32 aOffset,
nsFrameSelection::HINT aFrameHint,
@ -199,6 +203,8 @@ protected:
void DrawCaret(bool aInvalidate);
void DrawCaretAfterBriefDelay();
bool UpdateCaretRects(nsIFrame* aFrame, PRInt32 aFrameOffset);
static void InvalidateRects(const nsRect &aRect, const nsRect &aHook,
nsIFrame *aFrame);
nsRect GetHookRect()
{
#ifdef IBMBIDI

View File

@ -26,7 +26,6 @@
#include "nsLayoutUtils.h"
#include "nsIScrollableFrame.h"
#include "nsThemeConstants.h"
#include "LayerTreeInvalidation.h"
#include "imgIContainer.h"
#include "nsIInterfaceRequestorUtils.h"
@ -36,7 +35,6 @@
#include "nsSVGEffects.h"
#include "nsSVGClipPathFrame.h"
#include "sampler.h"
#include "nsIViewManager.h"
#include "mozilla/StandardInteger.h"
@ -88,6 +86,8 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
}
}
LayerBuilder()->Init(this);
PR_STATIC_ASSERT(nsDisplayItem::TYPE_MAX < (1 << nsDisplayItem::TYPE_BITS));
}
@ -564,13 +564,10 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder,
"Must call ComputeVisibility before calling Paint");
nsRefPtr<LayerManager> layerManager;
bool widgetTransaction = false;
bool allowRetaining = false;
bool doBeginTransaction = true;
nsIView *view = nsnull;
if (aFlags & PAINT_USE_WIDGET_LAYERS) {
nsIFrame* referenceFrame = aBuilder->ReferenceFrame();
view = referenceFrame->GetView();
NS_ASSERTION(referenceFrame == nsLayoutUtils::GetDisplayRootFrame(referenceFrame),
"Reference frame must be a display root for us to use the layer manager");
nsIWidget* window = referenceFrame->GetNearestWidget();
@ -578,8 +575,6 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder,
layerManager = window->GetLayerManager(&allowRetaining);
if (layerManager) {
doBeginTransaction = !(aFlags & PAINT_EXISTING_TRANSACTION);
FrameLayerBuilder::SetWidgetLayerManager(layerManager);
widgetTransaction = true;
}
}
}
@ -591,10 +586,6 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder,
layerManager = new BasicLayerManager();
}
FrameLayerBuilder *layerBuilder = new FrameLayerBuilder();
layerBuilder->Init(aBuilder);
layerManager->SetUserData(&gLayerManagerLayerBuilder, layerBuilder);
if (aFlags & PAINT_FLUSH_LAYERS) {
FrameLayerBuilder::InvalidateAllLayers(layerManager);
}
@ -607,36 +598,19 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder,
}
}
if (allowRetaining) {
layerBuilder->DidBeginRetainedLayerTransaction(layerManager);
aBuilder->LayerBuilder()->DidBeginRetainedLayerTransaction(layerManager);
}
nsPresContext* presContext = aForFrame->PresContext();
nsIPresShell* presShell = presContext->GetPresShell();
NotifySubDocInvalidationFunc computeInvalidFunc =
presContext->MayHavePaintEventListenerInSubDocument() ? nsPresContext::NotifySubDocInvalidation : 0;
bool computeInvalidRect = (computeInvalidFunc ||
(layerManager->GetBackendType() == LayerManager::LAYERS_BASIC)) &&
widgetTransaction;
nsAutoPtr<LayerProperties> props(computeInvalidRect ?
LayerProperties::CloneFrom(layerManager->GetRoot()) :
nsnull);
nsDisplayItem::ContainerParameters containerParameters
(presShell->GetXResolution(), presShell->GetYResolution());
nsRefPtr<ContainerLayer> root = layerBuilder->
nsRefPtr<ContainerLayer> root = aBuilder->LayerBuilder()->
BuildContainerLayerFor(aBuilder, layerManager, aForFrame, nsnull, *this,
containerParameters, nsnull);
if (widgetTransaction) {
aForFrame->ClearInvalidationStateBits();
}
if (!root) {
layerManager->RemoveUserData(&gLayerManagerLayerBuilder);
if (!root)
return;
}
// Root is being scaled up by the X/Y resolution. Scale it back down.
gfx3DMatrix rootTransform = root->GetTransform()*
gfx3DMatrix::ScalingMatrix(1.0f/containerParameters.mXScale,
@ -667,38 +641,16 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder,
}
layerManager->SetRoot(root);
layerBuilder->WillEndTransaction();
aBuilder->LayerBuilder()->WillEndTransaction(layerManager);
layerManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer,
aBuilder, (aFlags & PAINT_NO_COMPOSITE) ? LayerManager::END_NO_COMPOSITE : LayerManager::END_DEFAULT);
nsIntRect invalid;
if (props) {
invalid = props->ComputeDifferences(root, computeInvalidFunc);
} else if (widgetTransaction) {
LayerProperties::ClearInvalidations(root);
}
if (view) {
if (props) {
if (!invalid.IsEmpty()) {
nsRect rect(presContext->DevPixelsToAppUnits(invalid.x),
presContext->DevPixelsToAppUnits(invalid.y),
presContext->DevPixelsToAppUnits(invalid.width),
presContext->DevPixelsToAppUnits(invalid.height));
view->GetViewManager()->InvalidateViewNoSuppression(view, rect);
presContext->NotifyInvalidation(invalid, 0);
}
} else {
view->GetViewManager()->InvalidateView(view);
}
}
aBuilder);
aBuilder->LayerBuilder()->DidEndTransaction(layerManager);
if (aFlags & PAINT_FLUSH_LAYERS) {
FrameLayerBuilder::InvalidateAllLayers(layerManager);
}
nsCSSRendering::DidPaint();
layerManager->RemoveUserData(&gLayerManagerLayerBuilder);
}
PRUint32 nsDisplayList::Count() const {
@ -1352,7 +1304,7 @@ nsDisplayBackground::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
// theme background overrides any other background
if (mIsThemed) {
if (mThemeTransparency == nsITheme::eOpaque) {
result = nsRect(ToReferenceFrame(), mFrame->GetSize());
result = GetBounds(aBuilder, aSnap);
}
return result;
}
@ -1453,36 +1405,6 @@ nsDisplayBackground::IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuild
nsLayoutUtils::IsProperAncestorFrame(aFrame, mFrame));
}
bool
nsDisplayBackground::RenderingMightDependOnFrameSize()
{
// theme background overrides any other background and we don't know what to do here
if (mIsThemed)
return true;
// We could be smarter with rounded corners and only invalidate the new area + the piece that was previously
// clipped out.
nscoord radii[8];
if (mFrame->GetBorderRadii(radii))
return true;
nsPresContext* presContext = mFrame->PresContext();
nsStyleContext *bgSC;
bool hasBG =
nsCSSRendering::FindBackground(presContext, mFrame, &bgSC);
if (!hasBG)
return false;
const nsStyleBackground* bg = bgSC->GetStyleBackground();
NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
const nsStyleBackground::Layer &layer = bg->mLayers[i];
if (layer.RenderingMightDependOnFrameSize()) {
return true;
}
}
return false;
}
bool
nsDisplayBackground::ShouldFixToViewport(nsDisplayListBuilder* aBuilder)
{
@ -1540,28 +1462,6 @@ nsDisplayBackground::Paint(nsDisplayListBuilder* aBuilder,
flags);
}
void nsDisplayBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
{
const nsDisplayBackgroundGeometry* geometry = static_cast<const nsDisplayBackgroundGeometry*>(aGeometry);
if (ShouldFixToViewport(aBuilder)) {
// This is incorrect, We definitely need to check more things here.
return;
}
bool snap;
if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) ||
!geometry->mPaddingRect.IsEqualInterior(GetPaddingRect()) ||
!geometry->mContentRect.IsEqualInterior(GetContentRect())) {
if (!RenderingMightDependOnFrameSize() && geometry->mBounds.TopLeft() == GetBounds(aBuilder, &snap).TopLeft()) {
aInvalidRegion->Xor(GetBounds(aBuilder, &snap), geometry->mBounds);
} else {
aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds);
}
}
}
nsRect
nsDisplayBackground::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
nsRect r(nsPoint(0,0), mFrame->GetSize());
@ -1571,10 +1471,6 @@ nsDisplayBackground::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
presContext->GetTheme()->
GetWidgetOverflow(presContext->DeviceContext(), mFrame,
mFrame->GetStyleDisplay()->mAppearance, &r);
#ifdef XP_MACOSX
// Bug 748219
r.Inflate(mFrame->PresContext()->AppUnitsPerDevPixel());
#endif
}
*aSnap = true;
@ -1669,33 +1565,7 @@ nsDisplayBorder::ComputeVisibility(nsDisplayListBuilder* aBuilder,
return true;
}
nsDisplayItemGeometry*
nsDisplayBorder::AllocateGeometry(nsDisplayListBuilder* aBuilder)
{
bool snap;
nsDisplayBorderGeometry* geometry = new nsDisplayBorderGeometry;
geometry->mBounds = GetBounds(aBuilder, &snap);
geometry->mPaddingRect = GetContentRect();
return geometry;
}
void
nsDisplayBorder::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
{
const nsDisplayBorderGeometry* geometry = static_cast<const nsDisplayBorderGeometry*>(aGeometry);
bool snap;
if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) ||
!geometry->mPaddingRect.IsEqualInterior(GetContentRect())) {
// We can probably get away with only invalidating the difference
// between the border and padding rects, but the XUL ui at least
// is apparently painting a background with this?
aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds);
}
}
void
nsDisplayBorder::Paint(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx) {
@ -2040,7 +1910,7 @@ already_AddRefed<Layer>
nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aContainerParameters) {
nsRefPtr<Layer> layer = GetLayerBuilderForManager(aManager)->
nsRefPtr<Layer> layer = aBuilder->LayerBuilder()->
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
aContainerParameters, nsnull);
if (!layer)
@ -2110,10 +1980,8 @@ bool nsDisplayOpacity::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* a
}
nsDisplayOwnLayer::nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
PRUint32 aFlags)
: nsDisplayWrapList(aBuilder, aFrame, aList)
, mFlags(aFlags) {
nsIFrame* aFrame, nsDisplayList* aList)
: nsDisplayWrapList(aBuilder, aFrame, aList) {
MOZ_COUNT_CTOR(nsDisplayOwnLayer);
}
@ -2128,15 +1996,9 @@ already_AddRefed<Layer>
nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aContainerParameters) {
nsRefPtr<Layer> layer = GetLayerBuilderForManager(aManager)->
nsRefPtr<Layer> layer = aBuilder->LayerBuilder()->
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
aContainerParameters, nsnull);
if (mFlags & GENERATE_SUBDOC_INVALIDATIONS) {
ContainerLayerPresContext* pres = new ContainerLayerPresContext;
pres->mPresContext = mFrame->PresContext();
layer->SetUserData(&gNotifySubDocInvalidationData, pres);
}
return layer.forget();
}
@ -2201,7 +2063,7 @@ already_AddRefed<Layer>
nsDisplayScrollLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aContainerParameters) {
nsRefPtr<ContainerLayer> layer = GetLayerBuilderForManager(aManager)->
nsRefPtr<ContainerLayer> layer = aBuilder->LayerBuilder()->
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
aContainerParameters, nsnull);
@ -2384,7 +2246,7 @@ already_AddRefed<Layer>
nsDisplaySimpleScrollLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aContainerParameters) {
nsRefPtr<ContainerLayer> layer = GetLayerBuilderForManager(aManager)->
nsRefPtr<ContainerLayer> layer = aBuilder->LayerBuilder()->
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
aContainerParameters, nsnull);
@ -2593,10 +2455,9 @@ bool nsDisplayClipRoundedRect::TryMerge(nsDisplayListBuilder* aBuilder, nsDispla
nsDisplayZoom::nsDisplayZoom(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList,
PRInt32 aAPD, PRInt32 aParentAPD,
PRUint32 aFlags)
: nsDisplayOwnLayer(aBuilder, aFrame, aList, aFlags)
, mAPD(aAPD), mParentAPD(aParentAPD) {
PRInt32 aAPD, PRInt32 aParentAPD)
: nsDisplayOwnLayer(aBuilder, aFrame, aList), mAPD(aAPD),
mParentAPD(aParentAPD) {
MOZ_COUNT_CTOR(nsDisplayZoom);
}
@ -3020,7 +2881,7 @@ already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBu
return nsnull;
}
nsRefPtr<ContainerLayer> container = GetLayerBuilderForManager(aManager)->
nsRefPtr<ContainerLayer> container = aBuilder->LayerBuilder()->
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, *mStoredList.GetList(),
aContainerParameters, &newTransformMatrix);
@ -3395,52 +3256,11 @@ nsDisplaySVGEffects::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect
}
}
void
nsDisplaySVGEffects::PaintAsLayer(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx,
LayerManager* aManager)
void nsDisplaySVGEffects::Paint(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx)
{
nsSVGIntegrationUtils::PaintFramesWithEffects(aCtx, mFrame,
mVisibleRect,
aBuilder, aManager);
}
LayerState
nsDisplaySVGEffects::GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aParameters)
{
return LAYER_SVG_EFFECTS;
}
already_AddRefed<Layer>
nsDisplaySVGEffects::BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aContainerParameters)
{
float opacity = mFrame->GetStyleDisplay()->mOpacity;
if (opacity == 0.0f)
return nsnull;
nsIFrame* firstFrame =
nsLayoutUtils::GetFirstContinuationOrSpecialSibling(mFrame);
nsSVGEffects::EffectProperties effectProperties =
nsSVGEffects::GetEffectProperties(firstFrame);
bool isOK = true;
nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
nsSVGMaskFrame *maskFrame = effectProperties.GetMaskFrame(&isOK);
nsSVGFilterFrame *filterFrame = effectProperties.GetFilterFrame(&isOK);
if (!isOK) {
return nsnull;
}
nsRefPtr<ContainerLayer> container = GetLayerBuilderForManager(aManager)->
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
aContainerParameters, nsnull);
return container.forget();
nsSVGIntegrationUtils::PaintFramesWithEffects(aCtx,
mFrame, mVisibleRect, aBuilder, &mList);
}
bool nsDisplaySVGEffects::ComputeVisibility(nsDisplayListBuilder* aBuilder,

View File

@ -25,8 +25,6 @@
#include "FrameLayerBuilder.h"
#include "nsThemeConstants.h"
#include "ImageLayers.h"
#include "nsLayoutUtils.h"
#include "nsDisplayListInvalidation.h"
#include "mozilla/StandardInteger.h"
@ -331,6 +329,11 @@ public:
*/
void MarkPreserve3DFramesForDisplayList(nsIFrame* aDirtyFrame, const nsRect& aDirtyRect);
/**
* Return the FrameLayerBuilder.
*/
FrameLayerBuilder* LayerBuilder() { return &mLayerBuilder; }
/**
* Get the area of the final transparent region.
*/
@ -500,6 +503,7 @@ private:
return &mPresShellStates[mPresShellStates.Length() - 1];
}
FrameLayerBuilder mLayerBuilder;
nsIFrame* mReferenceFrame;
nsIFrame* mIgnoreScrollFrame;
PLArenaPool mPool;
@ -678,72 +682,6 @@ public:
*aSnap = false;
return nsRect(ToReferenceFrame(), GetUnderlyingFrame()->GetSize());
}
nsRect GetBorderRect() {
return nsRect(ToReferenceFrame(), GetUnderlyingFrame()->GetSize());
}
nsRect GetPaddingRect() {
return GetUnderlyingFrame()->GetPaddingRectRelativeToSelf() + ToReferenceFrame();
}
nsRect GetContentRect() {
return GetUnderlyingFrame()->GetContentRectRelativeToSelf() + ToReferenceFrame();
}
/**
* Checks if the frame(s) owning this display item have been marked as invalid,
* and needing repainting.
*/
virtual bool IsInvalid() { return mFrame ? mFrame->IsInvalid() : false; }
/**
* Creates and initializes an nsDisplayItemGeometry object that retains the current
* areas covered by this display item. These need to retain enough information
* such that they can be compared against a future nsDisplayItem of the same type,
* and determine if repainting needs to happen.
*
* Subclasses wishing to store more information need to override both this
* and ComputeInvalidationRegion, as well as implementing an nsDisplayItemGeometry
* subclass.
*
* The default implementation tracks both the display item bounds, and the frame's
* border rect.
*/
virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder)
{
nsDisplayItemGenericGeometry* geometry = new nsDisplayItemGenericGeometry();
bool snap;
geometry->mBounds = GetBounds(aBuilder, &snap);
geometry->mBorderRect = GetBorderRect();
return geometry;
}
/**
* Compares an nsDisplayItemGeometry object from a previous paint against the
* current item. Computes if the geometry of the item has changed, and the
* invalidation area required for correct repainting.
*
* The existing geometry will have been created from a display item with a
* matching GetPerFrameKey()/mFrame pair to the current item.
*
* The default implementation compares the display item bounds, and the frame's
* border rect, and invalidates the entire bounds if either rect changes.
*
* @param aGeometry The geometry of the matching display item from the
* previous paint.
* @param aInvalidRegion Output param, the region to invalidate, or
* unchanged if none.
*/
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
{
const nsDisplayItemGenericGeometry* geometry = static_cast<const nsDisplayItemGenericGeometry*>(aGeometry);
bool snap;
if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) ||
!geometry->mBorderRect.IsEqualInterior(GetBorderRect())) {
aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds);
}
}
/**
* @param aSnap set to true if the edges of the rectangles of the opaque
* region would be snapped to device pixels when drawing
@ -1223,8 +1161,7 @@ public:
PAINT_DEFAULT = 0,
PAINT_USE_WIDGET_LAYERS = 0x01,
PAINT_FLUSH_LAYERS = 0x02,
PAINT_EXISTING_TRANSACTION = 0x04,
PAINT_NO_COMPOSITE = 0x08
PAINT_EXISTING_TRANSACTION = 0x04
};
void PaintRoot(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx,
PRUint32 aFlags) const;
@ -1576,12 +1513,6 @@ public:
nsRegion* aVisibleRegion,
const nsRect& aAllowVisibleRegionExpansion);
NS_DISPLAY_DECL_NAME("Border", TYPE_BORDER)
virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder);
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion);
};
/**
@ -1674,27 +1605,6 @@ public:
// Returns the value of GetUnderlyingFrame()->IsThemed(), but cached
bool IsThemed() { return mIsThemed; }
/**
* Returns true if existing rendered pixels of this display item may need
* to be redrawn if the frame size changes.
* If false, only the changed area needs to be redrawn.
*/
bool RenderingMightDependOnFrameSize();
virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder)
{
bool snap;
nsDisplayBackgroundGeometry* geometry = new nsDisplayBackgroundGeometry;
geometry->mBounds = GetBounds(aBuilder, &snap);
geometry->mPaddingRect = GetPaddingRect();
geometry->mContentRect = GetContentRect();
return geometry;
}
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion);
protected:
typedef class mozilla::layers::ImageContainer ImageContainer;
typedef class mozilla::layers::ImageLayer ImageLayer;
@ -1735,21 +1645,6 @@ public:
nsRegion* aVisibleRegion,
const nsRect& aAllowVisibleRegionExpansion);
NS_DISPLAY_DECL_NAME("BoxShadowOuter", TYPE_BOX_SHADOW_OUTER)
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
{
const nsDisplayItemGenericGeometry* geometry = static_cast<const nsDisplayItemGenericGeometry*>(aGeometry);
bool snap;
if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) ||
!geometry->mBorderRect.IsEqualInterior(GetBorderRect())) {
nsRegion oldShadow, newShadow;
oldShadow = oldShadow.Sub(geometry->mBounds, geometry->mBorderRect);
newShadow = newShadow.Sub(GetBounds(aBuilder, &snap), GetBorderRect());
aInvalidRegion->Or(oldShadow, newShadow);
}
}
private:
nsRegion mVisibleRegion;
@ -1775,28 +1670,6 @@ public:
nsRegion* aVisibleRegion,
const nsRect& aAllowVisibleRegionExpansion);
NS_DISPLAY_DECL_NAME("BoxShadowInner", TYPE_BOX_SHADOW_INNER)
virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder)
{
nsDisplayBoxShadowInnerGeometry* geometry = new nsDisplayBoxShadowInnerGeometry;
bool snap;
geometry->mBounds = GetBounds(aBuilder, &snap);
geometry->mPaddingRect = GetPaddingRect();
return geometry;
}
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
{
const nsDisplayBoxShadowInnerGeometry* geometry = static_cast<const nsDisplayBoxShadowInnerGeometry*>(aGeometry);
if (!geometry->mPaddingRect.IsEqualInterior(GetPaddingRect())) {
// nsDisplayBoxShadowInner is based around the padding rect, but it can
// touch pixels outside of this. We should invalidate the entire bounds.
bool snap;
aInvalidRegion->Or(geometry->mBounds, GetBounds(aBuilder, &snap));
}
}
private:
nsRegion mVisibleRegion;
@ -1903,18 +1776,6 @@ public:
{
aFrames->AppendElements(mMergedFrames);
}
virtual bool IsInvalid()
{
if (mFrame->IsInvalid()) {
return true;
}
for (PRUint32 i = 0; i < mMergedFrames.Length(); i++) {
if (mMergedFrames[i]->IsInvalid()) {
return true;
}
}
return false;
}
NS_DISPLAY_DECL_NAME("WrapList", TYPE_WRAP_LIST)
virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder);
@ -2025,21 +1886,8 @@ public:
*/
class nsDisplayOwnLayer : public nsDisplayWrapList {
public:
/**
* nsDisplayOwnLayer constructor flags
*/
enum {
GENERATE_SUBDOC_INVALIDATIONS = 0x01
};
/**
* @param aFlags GENERATE_SUBDOC_INVALIDATIONS :
* Add UserData to the created ContainerLayer, so that invalidations
* for this layer are send to our nsPresContext.
*/
nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayList* aList, PRUint32 aFlags = 0);
nsDisplayList* aList);
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplayOwnLayer();
#endif
@ -2051,7 +1899,7 @@ public:
LayerManager* aManager,
const ContainerParameters& aParameters)
{
return mozilla::LAYER_ACTIVE_FORCE;
return mozilla::LAYER_ACTIVE;
}
virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem)
{
@ -2059,8 +1907,6 @@ public:
return false;
}
NS_DISPLAY_DECL_NAME("OwnLayer", TYPE_OWN_LAYER)
private:
PRUint32 mFlags;
};
/**
@ -2295,14 +2141,10 @@ public:
* @param aAPD is the app units per dev pixel ratio of the subdocument.
* @param aParentAPD is the app units per dev pixel ratio of the parent
* document.
* @param aFlags GENERATE_SUBDOC_INVALIDATIONS :
* Add UserData to the created ContainerLayer, so that invalidations
* for this layer are send to our nsPresContext.
*/
nsDisplayZoom(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
nsDisplayList* aList,
PRInt32 aAPD, PRInt32 aParentAPD,
PRUint32 aFlags = 0);
PRInt32 aAPD, PRInt32 aParentAPD);
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplayZoom();
#endif
@ -2345,24 +2187,13 @@ public:
*aSnap = false;
return mEffectsBounds + ToReferenceFrame();
}
virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx);
virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion,
const nsRect& aAllowVisibleRegionExpansion);
virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem);
NS_DISPLAY_DECL_NAME("SVGEffects", TYPE_SVG_EFFECTS)
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aParameters);
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aContainerParameters);
void PaintAsLayer(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx,
LayerManager* aManager);
#ifdef MOZ_DUMP_PAINTING
void PrintEffects(FILE* aOutput);
#endif

View File

@ -1,118 +0,0 @@
/*-*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef NSDISPLAYLISTINVALIDATION_H_
#define NSDISPLAYLISTINVALIDATION_H_
/**
* This stores the geometry of an nsDisplayItem, and the area
* that will be affected when painting the item.
*
* It is used to retain information about display items so they
* can be compared against new display items in the next paint.
*/
class nsDisplayItemGeometry
{
public:
nsDisplayItemGeometry()
{
MOZ_COUNT_CTOR(nsDisplayItemGeometry);
}
virtual ~nsDisplayItemGeometry()
{
MOZ_COUNT_DTOR(nsDisplayItemGeometry);
}
/**
* Compute the area required to be invalidated if this
* display item is removed.
*/
nsRegion ComputeInvalidationRegion() { return mBounds; }
/**
* Shifts all retained areas of the nsDisplayItemGeometry by the given offset.
*
* This is used to compensate for scrolling, since the destination buffer
* can scroll without requiring a full repaint.
*
* @param aOffset Offset to shift by.
*/
virtual void MoveBy(const nsPoint& aOffset) = 0;
/**
* The appunits per dev pixel for the item's frame.
*/
nscoord mAppUnitsPerDevPixel;
/**
* The offset (in pixels) of the TopLeft() of the ThebesLayer
* this display item was drawn into.
*/
nsIntPoint mPaintOffset;
gfxPoint mActiveScrolledRootPosition;
/**
* Bounds of the display item
*/
nsRect mBounds;
};
/**
* A default geometry implementation, used by nsDisplayItem. Retains
* and compares the bounds, and border rect.
*
* This should be sufficient for the majority of display items.
*/
class nsDisplayItemGenericGeometry : public nsDisplayItemGeometry
{
public:
virtual void MoveBy(const nsPoint& aOffset)
{
mBounds.MoveBy(aOffset);
mBorderRect.MoveBy(aOffset);
}
nsRect mBorderRect;
};
class nsDisplayBorderGeometry : public nsDisplayItemGeometry
{
public:
virtual void MoveBy(const nsPoint& aOffset)
{
mBounds.MoveBy(aOffset);
mPaddingRect.MoveBy(aOffset);
}
nsRect mPaddingRect;
};
class nsDisplayBackgroundGeometry : public nsDisplayItemGeometry
{
public:
virtual void MoveBy(const nsPoint& aOffset)
{
mBounds.MoveBy(aOffset);
mPaddingRect.MoveBy(aOffset);
mContentRect.MoveBy(aOffset);
}
nsRect mPaddingRect;
nsRect mContentRect;
};
class nsDisplayBoxShadowInnerGeometry : public nsDisplayItemGeometry
{
public:
virtual void MoveBy(const nsPoint& aOffset)
{
mBounds.MoveBy(aOffset);
mPaddingRect.MoveBy(aOffset);
}
nsRect mPaddingRect;
};
#endif /*NSDISPLAYLISTINVALIDATION_H_*/

View File

@ -2883,7 +2883,8 @@ DocumentViewerImpl::SetFullZoom(float aFullZoom)
nsIFrame* rootFrame = shell->GetRootFrame();
if (rootFrame) {
rootFrame->InvalidateFrame();
nsRect rect(nsPoint(0, 0), rootFrame->GetSize());
rootFrame->Invalidate(rect);
}
return NS_OK;
}

View File

@ -468,11 +468,22 @@ nsFrameManager::InsertFrames(nsIFrame* aParentFrame,
nsresult
nsFrameManager::RemoveFrame(ChildListID aListID,
nsIFrame* aOldFrame)
nsIFrame* aOldFrame,
bool aInvalidate /* = true */)
{
bool wasDestroyingFrames = mIsDestroyingFrames;
mIsDestroyingFrames = true;
// In case the reflow doesn't invalidate anything since it just leaves
// a gap where the old frame was, we invalidate it here. (This is
// reasonably likely to happen when removing a last child in a way
// that doesn't change the size of the parent.)
// This has to sure to invalidate the entire overflow rect; this
// is important in the presence of absolute positioning
if (aInvalidate) {
aOldFrame->InvalidateFrameSubtree();
}
NS_ASSERTION(!aOldFrame->GetPrevContinuation() ||
// exception for nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames
aOldFrame->GetType() == nsGkAtoms::textFrame,

View File

@ -95,7 +95,8 @@ public:
nsFrameList& aFrameList);
NS_HIDDEN_(nsresult) RemoveFrame(ChildListID aListID,
nsIFrame* aOldFrame);
nsIFrame* aOldFrame,
bool aInvalidate = true);
/*
* Notification that a frame is about to be destroyed. This allows any

View File

@ -1207,12 +1207,9 @@ public:
*/
virtual void SynthesizeMouseMove(bool aFromScroll) = 0;
enum PaintType {
PaintType_Composite,
PaintType_NoComposite
};
virtual void Paint(nsIView* aViewToPaint, const nsRegion& aDirtyRegion,
PaintType aType, bool aWillSendDidPaint) = 0;
virtual void Paint(nsIView* aViewToPaint, nsIWidget* aWidget,
const nsRegion& aDirtyRegion, const nsIntRegion& aIntDirtyRegion,
bool aWillSendDidPaint) = 0;
virtual nsresult HandleEvent(nsIFrame* aFrame,
nsGUIEvent* aEvent,
bool aDontRetargetEvents,
@ -1228,16 +1225,7 @@ public:
* root pres shell.
*/
virtual void DidPaint() = 0;
/**
* Ensures that the refresh driver is running, and schedules a view
* manager flush on the next tick.
*
* @param aFlags nsIFrame::PAINT_COMPOSITE_ONLY : No changes have
* been made that require a layer tree update, so only schedule a
* layer tree composite.
*/
virtual void ScheduleViewManagerFlush(PRUint32 aFlags = 0) = 0;
virtual void ScheduleViewManagerFlush() = 0;
virtual void ClearMouseCaptureOnView(nsIView* aView) = 0;
virtual bool IsVisible() = 0;
virtual void DispatchSynthMouseMove(nsGUIEvent *aEvent, bool aFlushOnHoverChange) = 0;

View File

@ -213,7 +213,39 @@ nsImageLoader::DoRedraw(const nsRect* aDamageRect)
//
// Invalidate the entire frame
// XXX We really only need to invalidate the client area of the frame...
nsRect bounds(nsPoint(0, 0), mFrame->GetSize());
if (mFrame->GetType() == nsGkAtoms::canvasFrame) {
// The canvas's background covers the whole viewport.
bounds = mFrame->GetVisualOverflowRect();
}
// XXX this should be ok, but there is some crappy ass bug causing it not to work
// XXX seems related to the "body fixup rule" dealing with the canvas and body frames...
#if 0
// Invalidate the entire frame only if the frame has a tiled background
// image, otherwise just invalidate the intersection of the frame's bounds
// with the damaged rect.
nsStyleContext* styleContext;
mFrame->GetStyleContext(&styleContext);
const nsStyleBackground* bg = styleContext->GetStyleBackground();
if ((bg->mBackgroundFlags & NS_STYLE_BG_IMAGE_NONE) ||
(bg->mBackgroundRepeat == NS_STYLE_BG_REPEAT_OFF)) {
// The frame does not have a background image so we are free
// to invalidate only the intersection of the damage rect and
// the frame's bounds.
if (aDamageRect) {
bounds.IntersectRect(*aDamageRect, bounds);
}
}
#endif
if (mFrame->GetStyleVisibility()->IsVisible()) {
mFrame->InvalidateFrame();
mFrame->Invalidate(bounds);
}
}

View File

@ -180,7 +180,7 @@ PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList,
}
if (f) {
PRUint32 key = i->GetPerFrameKey();
Layer* layer = mozilla::FrameLayerBuilder::GetDebugOldLayerFor(f, key);
Layer* layer = aBuilder->LayerBuilder()->GetOldLayerFor(f, key);
if (layer) {
fprintf(aOutput, " <a href=\"#%p\">layer=%p</a>", layer, layer);
}

View File

@ -1783,9 +1783,6 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
if (aFlags & PAINT_EXISTING_TRANSACTION) {
flags |= nsDisplayList::PAINT_EXISTING_TRANSACTION;
}
if (aFlags & PAINT_NO_COMPOSITE) {
flags |= nsDisplayList::PAINT_NO_COMPOSITE;
}
list.PaintRoot(&builder, aRenderingContext, flags);
@ -1809,13 +1806,7 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
nsFrame::PrintDisplayList(&builder, list, gfxUtils::sDumpPaintFile);
fprintf(gfxUtils::sDumpPaintFile, "Painting --- retained layer tree:\n");
nsIWidget* widget = aFrame->GetNearestWidget();
if (widget) {
nsRefPtr<LayerManager> layerManager = widget->GetLayerManager();
if (layerManager) {
FrameLayerBuilder::DumpRetainedLayerTree(layerManager, gfxUtils::sDumpPaintFile);
}
}
builder.LayerBuilder()->DumpRetainedLayerTree(gfxUtils::sDumpPaintFile);
fprintf(gfxUtils::sDumpPaintFile, "</body></html>");
if (gfxUtils::sDumpPaintingToFile) {
@ -3953,8 +3944,6 @@ nsLayoutUtils::IsPopup(nsIFrame* aFrame)
/* static */ nsIFrame*
nsLayoutUtils::GetDisplayRootFrame(nsIFrame* aFrame)
{
// We could use GetRootPresContext() here if the
// NS_FRAME_IN_POPUP frame bit is set.
nsIFrame* f = aFrame;
for (;;) {
if (IsPopup(f))

View File

@ -596,8 +596,7 @@ public:
PAINT_HIDE_CARET = 0x20,
PAINT_ALL_CONTINUATIONS = 0x40,
PAINT_TO_WINDOW = 0x80,
PAINT_EXISTING_TRANSACTION = 0x100,
PAINT_NO_COMPOSITE = 0x200
PAINT_EXISTING_TRANSACTION = 0x100
};
/**

View File

@ -83,8 +83,6 @@
using namespace mozilla;
using namespace mozilla::dom;
PRUint8 gNotifySubDocInvalidationData;
namespace {
class CharSetChangingRunnable : public nsRunnable
@ -138,21 +136,6 @@ nsPresContext::PrefChangedCallback(const char* aPrefName, void* instance_data)
return 0; // PREF_OK
}
bool
nsPresContext::IsDOMPaintEventPending()
{
if (!mInvalidateRequests.mRequests.IsEmpty()) {
return true;
}
if (GetRootPresContext()->mRefreshDriver->ViewManagerFlushIsPending()) {
// Since we're promising that there will be a MozAfterPaint event
// fired, we record an empty invalidation in case display list
// invalidation doesn't invalidate anything further.
NotifyInvalidation(nsRect(0, 0, 0, 0), 0);
return true;
}
return false;
}
void
nsPresContext::PrefChangedUpdateTimerCallback(nsITimer *aTimer, void *aClosure)
@ -818,7 +801,7 @@ nsPresContext::InvalidateThebesLayers()
// FrameLayerBuilder caches invalidation-related values that depend on the
// appunits-per-dev-pixel ratio, so ensure that all ThebesLayer drawing
// is completely flushed.
rootFrame->InvalidateFrameSubtree();
FrameLayerBuilder::InvalidateThebesLayersInSubtree(rootFrame);
}
}
@ -1197,18 +1180,6 @@ nsPresContext::GetParentPresContext()
return f->PresContext();
}
}
// Not sure if this is always strictly the parent, but it works for GetRootPresContext
// where the current pres context has no frames.
nsIDocument *doc = Document();
if (doc) {
doc = doc->GetParentDocument();
if (doc) {
shell = doc->GetShell();
if (shell) {
return shell->GetPresContext();
}
}
}
return nsnull;
}
@ -1233,7 +1204,7 @@ nsPresContext::GetRootPresContext()
nsPresContext* pc = this;
for (;;) {
nsPresContext* parent = pc->GetParentPresContext();
if (!parent || parent == pc)
if (!parent)
break;
pc = parent;
}
@ -2076,14 +2047,29 @@ nsPresContext::FireDOMPaintEvent()
nsCOMPtr<nsIDOMEventTarget> dispatchTarget = do_QueryInterface(ourWindow);
nsCOMPtr<nsIDOMEventTarget> eventTarget = dispatchTarget;
if (!IsChrome() && !mSendAfterPaintToContent) {
// Don't tell the window about this event, it should not know that
// something happened in a subdocument. Tell only the chrome event handler.
// (Events sent to the window get propagated to the chrome event handler
// automatically.)
dispatchTarget = do_QueryInterface(ourWindow->GetParentTarget());
if (!dispatchTarget) {
return;
if (!IsChrome()) {
bool notifyContent = mSendAfterPaintToContent;
if (notifyContent) {
// If the pref is set, we still don't post events when they're
// entirely cross-doc.
notifyContent = false;
for (PRUint32 i = 0; i < mInvalidateRequests.mRequests.Length(); ++i) {
if (!(mInvalidateRequests.mRequests[i].mFlags &
nsIFrame::INVALIDATE_CROSS_DOC)) {
notifyContent = true;
}
}
}
if (!notifyContent) {
// Don't tell the window about this event, it should not know that
// something happened in a subdocument. Tell only the chrome event handler.
// (Events sent to the window get propagated to the chrome event handler
// automatically.)
dispatchTarget = do_QueryInterface(ourWindow->GetParentTarget());
if (!dispatchTarget) {
return;
}
}
}
// Events sent to the window get propagated to the chrome event handler
@ -2107,24 +2093,6 @@ nsPresContext::FireDOMPaintEvent()
nsEventDispatcher::DispatchDOMEvent(dispatchTarget, nsnull, event, this, nsnull);
}
static bool
MayHavePaintEventListenerSubdocumentCallback(nsIDocument* aDocument, void* aData)
{
bool *result = static_cast<bool*>(aData);
nsIPresShell* shell = aDocument->GetShell();
if (shell) {
nsPresContext* pc = shell->GetPresContext();
if (pc) {
*result = pc->MayHavePaintEventListenerInSubDocument();
// If we found a paint event listener, then we can stop enumerating
// sub documents.
return !*result;
}
}
return true;
}
static bool
MayHavePaintEventListener(nsPIDOMWindow* aInnerWindow)
{
@ -2176,28 +2144,6 @@ nsPresContext::MayHavePaintEventListener()
return ::MayHavePaintEventListener(mDocument->GetInnerWindow());
}
bool
nsPresContext::MayHavePaintEventListenerInSubDocument()
{
if (MayHavePaintEventListener()) {
return true;
}
bool result = false;
mDocument->EnumerateSubDocuments(MayHavePaintEventListenerSubdocumentCallback, &result);
return result;
}
void
nsPresContext::NotifyInvalidation(const nsIntRect& aRect, PRUint32 aFlags)
{
nsRect rect(DevPixelsToAppUnits(aRect.x),
DevPixelsToAppUnits(aRect.y),
DevPixelsToAppUnits(aRect.width),
DevPixelsToAppUnits(aRect.height));
NotifyInvalidation(rect, aFlags);
}
void
nsPresContext::NotifyInvalidation(const nsRect& aRect, PRUint32 aFlags)
{
@ -2206,6 +2152,8 @@ nsPresContext::NotifyInvalidation(const nsRect& aRect, PRUint32 aFlags)
// MayHavePaintEventListener is pretty cheap and we could make it
// even cheaper by providing a more efficient
// nsPIDOMWindow::GetListenerManager.
if (aRect.IsEmpty() || !MayHavePaintEventListener())
return;
nsPresContext* pc;
for (pc = this; pc; pc = pc->GetParentPresContext()) {
@ -2229,30 +2177,6 @@ nsPresContext::NotifyInvalidation(const nsRect& aRect, PRUint32 aFlags)
request->mFlags = aFlags;
}
/* static */ void
nsPresContext::NotifySubDocInvalidation(ContainerLayer* aContainer,
const nsIntRegion& aRegion)
{
ContainerLayerPresContext *data =
static_cast<ContainerLayerPresContext*>(
aContainer->GetUserData(&gNotifySubDocInvalidationData));
if (!data) {
return;
}
nsIntPoint topLeft = aContainer->GetVisibleRegion().GetBounds().TopLeft();
nsIntRegionRectIterator iter(aRegion);
while (const nsIntRect* r = iter.Next()) {
nsIntRect rect = *r;
//PresContext coordinate space is relative to the start of our visible
// region. Is this really true? This feels like the wrong way to get the right
// answer.
rect.MoveBy(-topLeft);
data->mPresContext->NotifyInvalidation(rect, 0);
}
}
static bool
NotifyDidPaintSubdocumentCallback(nsIDocument* aDocument, void* aData)
{
@ -2269,18 +2193,19 @@ NotifyDidPaintSubdocumentCallback(nsIDocument* aDocument, void* aData)
void
nsPresContext::NotifyDidPaintForSubtree()
{
if (IsRoot()) {
if (!mFireAfterPaintEvents)
return;
if (!mFireAfterPaintEvents)
return;
mFireAfterPaintEvents = false;
if (IsRoot()) {
static_cast<nsRootPresContext*>(this)->CancelDidPaintTimer();
}
mFireAfterPaintEvents = false;
nsCOMPtr<nsIRunnable> ev =
NS_NewRunnableMethod(this, &nsPresContext::FireDOMPaintEvent);
nsContentUtils::AddScriptRunner(ev);
if (!mInvalidateRequests.mRequests.IsEmpty()) {
nsCOMPtr<nsIRunnable> ev =
NS_NewRunnableMethod(this, &nsPresContext::FireDOMPaintEvent);
nsContentUtils::AddScriptRunner(ev);
}
mDocument->EnumerateSubDocuments(NotifyDidPaintSubdocumentCallback, nsnull);
}

View File

@ -116,17 +116,6 @@ public:
nsTArray<Request> mRequests;
};
/**
* Layer UserData for ContainerLayers that want to be notified
* of local invalidations of them and their descendant layers.
* Pass a callback to ComputeDifferences to have these called.
*/
class ContainerLayerPresContext : public mozilla::layers::LayerUserData {
public:
nsPresContext* mPresContext;
};
extern PRUint8 gNotifySubDocInvalidationData;
/* Used by nsPresContext::HasAuthorSpecifiedRules */
#define NS_AUTHOR_SPECIFIED_BACKGROUND (1 << 0)
#define NS_AUTHOR_SPECIFIED_BORDER (1 << 1)
@ -851,16 +840,12 @@ public:
bool EnsureSafeToHandOutCSSRules();
void NotifyInvalidation(const nsRect& aRect, PRUint32 aFlags);
// aRect is in device pixels
void NotifyInvalidation(const nsIntRect& aRect, PRUint32 aFlags);
void NotifyDidPaintForSubtree();
void FireDOMPaintEvent();
// Callback for catching invalidations in ContainerLayers
// Passed to LayerProperties::ComputeDifference
static void NotifySubDocInvalidation(mozilla::layers::ContainerLayer* aContainer,
const nsIntRegion& aRegion);
bool IsDOMPaintEventPending();
bool IsDOMPaintEventPending() {
return !mInvalidateRequests.mRequests.IsEmpty();
}
void ClearMozAfterPaintEvents() {
mInvalidateRequests.mRequests.Clear();
}
@ -1075,22 +1060,12 @@ protected:
public:
void DoChangeCharSet(const nsCString& aCharSet);
/**
* Checks for MozAfterPaint listeners on the document
*/
bool MayHavePaintEventListener();
/**
* Checks for MozAfterPaint listeners on the document and
* any subdocuments, except for subdocuments that are non-top-level
* content documents.
*/
bool MayHavePaintEventListenerInSubDocument();
protected:
void InvalidateThebesLayers();
void AppUnitsPerDevPixelChanged();
bool MayHavePaintEventListener();
void HandleRebuildUserFontSet() {
mPostedFlushUserFontSet = false;
FlushUserFontSet();

View File

@ -170,7 +170,6 @@
#include "sampler.h"
#include "Layers.h"
#include "LayerTreeInvalidation.h"
#include "nsAsyncDOMEvent.h"
#ifdef NS_FUNCTION_TIMER
@ -1635,10 +1634,6 @@ PresShell::InitialReflow(nscoord aWidth, nscoord aHeight)
return NS_ERROR_OUT_OF_MEMORY;
}
for (nsIFrame* f = rootFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
f->RemoveStateBits(NS_FRAME_NO_COMPONENT_ALPHA);
}
Element *root = mDocument->GetRootElement();
if (root) {
@ -3379,14 +3374,11 @@ PresShell::GetRectVisibility(nsIFrame* aFrame,
}
void
PresShell::ScheduleViewManagerFlush(PRUint32 aFlags)
PresShell::ScheduleViewManagerFlush()
{
nsPresContext* presContext = GetPresContext();
if (presContext) {
presContext->RefreshDriver()->ScheduleViewManagerFlush();
if (!(aFlags & nsIFrame::PAINT_COMPOSITE_ONLY)) {
mPaintRequired = true;
}
}
if (mDocument) {
mDocument->SetNeedLayoutFlush();
@ -3558,7 +3550,8 @@ PresShell::UnsuppressAndInvalidate()
nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
if (rootFrame) {
// let's assume that outline on a root frame is not supported
rootFrame->InvalidateFrame();
nsRect rect(nsPoint(0, 0), rootFrame->GetSize());
rootFrame->Invalidate(rect);
if (mCaretEnabled && mCaret) {
mCaret->CheckCaretDrawingState();
@ -3956,7 +3949,12 @@ PresShell::DocumentStatesChanged(nsIDocument* aDocument,
VERIFY_STYLE_TREE;
}
ScheduleViewManagerFlush();
if (aStateMask.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE)) {
nsIFrame* root = mFrameConstructor->GetRootFrame();
if (root) {
root->InvalidateFrameSubtree();
}
}
}
void
@ -5204,8 +5202,9 @@ private:
void
PresShell::Paint(nsIView* aViewToPaint,
nsIWidget* aWidgetToPaint,
const nsRegion& aDirtyRegion,
PaintType aType,
const nsIntRegion& aIntDirtyRegion,
bool aWillSendDidPaint)
{
#ifdef NS_FUNCTION_TIMER
@ -5222,6 +5221,7 @@ PresShell::Paint(nsIView* aViewToPaint,
SAMPLE_LABEL("Paint", "PresShell::Paint");
NS_ASSERTION(!mIsDestroying, "painting a destroyed PresShell");
NS_ASSERTION(aViewToPaint, "null view");
NS_ASSERTION(aWidgetToPaint, "Can't paint without a widget");
nsAutoNotifyDidPaint notifyDidPaint(aWillSendDidPaint);
@ -5232,82 +5232,37 @@ PresShell::Paint(nsIView* aViewToPaint,
bool isRetainingManager;
LayerManager* layerManager =
aViewToPaint->GetWidget()->GetLayerManager(&isRetainingManager);
aWidgetToPaint->GetLayerManager(&isRetainingManager);
NS_ASSERTION(layerManager, "Must be in paint event");
if (mIsFirstPaint) {
layerManager->SetIsFirstPaint();
mIsFirstPaint = false;
}
layerManager->BeginTransaction();
if (frame && isRetainingManager) {
// Try to do an empty transaction, if the frame tree does not
// need to be updated. Do not try to do an empty transaction on
// a non-retained layer manager (like the BasicLayerManager that
// draws the window title bar on Mac), because a) it won't work
// and b) below we don't want to clear mPaintRequired,
// and b) below we don't want to clear NS_FRAME_UPDATE_LAYER_TREE,
// that will cause us to forget to update the real layer manager!
if (aType == PaintType_Composite) {
if (layerManager->HasShadowManager()) {
return;
}
layerManager->BeginTransaction();
if (!(frame->GetStateBits() & NS_FRAME_UPDATE_LAYER_TREE)) {
if (layerManager->EndEmptyTransaction()) {
return;
}
NS_WARNING("Must complete empty transaction when compositing!");
} else {
layerManager->BeginTransaction();
}
if (!mPaintRequired) {
NotifySubDocInvalidationFunc computeInvalidFunc =
presContext->MayHavePaintEventListenerInSubDocument() ? nsPresContext::NotifySubDocInvalidation : 0;
bool computeInvalidRect = computeInvalidFunc ||
(layerManager->GetBackendType() == LayerManager::LAYERS_BASIC);
nsAutoPtr<LayerProperties> props(computeInvalidRect ?
LayerProperties::CloneFrom(layerManager->GetRoot()) :
nsnull);
if (layerManager->EndEmptyTransaction()) {
nsIntRect invalid;
if (props) {
invalid = props->ComputeDifferences(layerManager->GetRoot(), computeInvalidFunc);
} else {
LayerProperties::ClearInvalidations(layerManager->GetRoot());
}
if (!invalid.IsEmpty()) {
if (props) {
nsRect rect(presContext->DevPixelsToAppUnits(invalid.x),
presContext->DevPixelsToAppUnits(invalid.y),
presContext->DevPixelsToAppUnits(invalid.width),
presContext->DevPixelsToAppUnits(invalid.height));
aViewToPaint->GetViewManager()->InvalidateViewNoSuppression(aViewToPaint, rect);
presContext->NotifyInvalidation(invalid, 0);
} else {
aViewToPaint->GetViewManager()->InvalidateView(aViewToPaint);
}
}
frame->UpdatePaintCountForPaintedPresShells();
presContext->NotifyDidPaintForSubtree();
return;
}
}
mPaintRequired = false;
} else {
layerManager->BeginTransaction();
frame->RemoveStateBits(NS_FRAME_UPDATE_LAYER_TREE);
}
if (frame) {
frame->ClearPresShellsFromLastPaint();
}
nscolor bgcolor = ComputeBackstopColor(aViewToPaint);
PRUint32 flags = nsLayoutUtils::PAINT_WIDGET_LAYERS | nsLayoutUtils::PAINT_EXISTING_TRANSACTION;
if (aType == PaintType_NoComposite) {
flags |= nsLayoutUtils::PAINT_NO_COMPOSITE;
}
if (frame) {
// Defer invalidates that are triggered during painting, and discard
@ -5317,12 +5272,12 @@ PresShell::Paint(nsIView* aViewToPaint,
frame->BeginDeferringInvalidatesForDisplayRoot(aDirtyRegion);
// We can paint directly into the widget using its layer manager.
nsLayoutUtils::PaintFrame(nsnull, frame, aDirtyRegion, bgcolor, flags);
nsLayoutUtils::PaintFrame(nsnull, frame, aDirtyRegion, bgcolor,
nsLayoutUtils::PAINT_WIDGET_LAYERS |
nsLayoutUtils::PAINT_EXISTING_TRANSACTION);
frame->EndDeferringInvalidatesForDisplayRoot();
if (aType != PaintType_Composite) {
presContext->NotifyDidPaintForSubtree();
}
presContext->NotifyDidPaintForSubtree();
return;
}
@ -5336,13 +5291,9 @@ PresShell::Paint(nsIView* aViewToPaint,
root->SetVisibleRegion(bounds);
layerManager->SetRoot(root);
}
layerManager->EndTransaction(NULL, NULL, aType == PaintType_NoComposite ?
LayerManager::END_NO_COMPOSITE :
LayerManager::END_DEFAULT);
layerManager->EndTransaction(NULL, NULL);
if (aType != PaintType_Composite) {
presContext->NotifyDidPaintForSubtree();
}
presContext->NotifyDidPaintForSubtree();
}
// static
@ -6130,11 +6081,13 @@ PresShell::ShowEventTargetDebug()
if (nsFrame::GetShowEventTargetFrameBorder() &&
GetCurrentEventFrame()) {
if (mDrawEventTargetFrame) {
mDrawEventTargetFrame->InvalidateFrame();
mDrawEventTargetFrame->Invalidate(
nsRect(nsPoint(0, 0), mDrawEventTargetFrame->GetSize()));
}
mDrawEventTargetFrame = mCurrentEventFrame;
mDrawEventTargetFrame->InvalidateFrame();
mDrawEventTargetFrame->Invalidate(
nsRect(nsPoint(0, 0), mDrawEventTargetFrame->GetSize()));
}
}
#endif
@ -7342,8 +7295,6 @@ PresShell::DoReflow(nsIFrame* target, bool aInterruptible)
NS_TIME_FUNCTION_WITH_DOCURL;
SAMPLE_LABEL("layout", "DoReflow");
target->SchedulePaint();
if (mReflowContinueTimer) {
mReflowContinueTimer->Cancel();
mReflowContinueTimer = nsnull;
@ -7369,6 +7320,11 @@ PresShell::DoReflow(nsIFrame* target, bool aInterruptible)
nsSize size;
if (target == rootFrame) {
size = mPresContext->GetVisibleArea().Size();
// target->GetRect() has the old size of the frame,
// mPresContext->GetVisibleArea() has the new size.
target->InvalidateRectDifference(mPresContext->GetVisibleArea(),
target->GetRect());
} else {
size = target->GetSize();
}

View File

@ -183,8 +183,9 @@ public:
//nsIViewObserver interface
virtual void Paint(nsIView* aViewToPaint, const nsRegion& aDirtyRegion,
PaintType aType, bool aWillSendDidPaint);
virtual void Paint(nsIView* aViewToPaint, nsIWidget* aWidget,
const nsRegion& aDirtyRegion, const nsIntRegion& aIntDirtyRegion,
bool aWillSendDidPaint);
virtual nsresult HandleEvent(nsIFrame* aFrame,
nsGUIEvent* aEvent,
bool aDontRetargetEvents,
@ -198,7 +199,7 @@ public:
virtual bool ShouldIgnoreInvalidation();
virtual void WillPaint(bool aWillSendDidPaint);
virtual void DidPaint();
virtual void ScheduleViewManagerFlush(PRUint32 aFlags = 0);
virtual void ScheduleViewManagerFlush();
virtual void DispatchSynthMouseMove(nsGUIEvent *aEvent, bool aFlushOnHoverChange);
virtual void ClearMouseCaptureOnView(nsIView* aView);
virtual bool IsVisible();
@ -766,12 +767,6 @@ protected:
bool mNoDelayedMouseEvents : 1;
bool mNoDelayedKeyEvents : 1;
// False if calls to Paint with the retaining manager can be handled
// with an empty transaction, True if we require painting and a layer
// tree update.
bool mPaintRequired : 1;
// We've been disconnected from the document. We will refuse to paint the
// document until either our timer fires or all frames are constructed.
bool mIsDocumentGone : 1;

View File

@ -411,15 +411,8 @@ nsRefreshDriver::Notify(nsITimer *aTimer)
}
if (mViewManagerFlushIsPending) {
#ifdef DEBUG_INVALIDATIONS
printf("Starting ProcessPendingUpdates\n");
#endif
mViewManagerFlushIsPending = false;
bool skippedFlush = mPresContext->GetPresShell()->GetViewManager()->ProcessPendingUpdates();
mViewManagerFlushIsPending |= skippedFlush;
#ifdef DEBUG_INVALIDATIONS
printf("Ending ProcessPendingUpdates\n");
#endif
mPresContext->GetPresShell()->GetViewManager()->ProcessPendingUpdates();
}
if (mThrottled ||

View File

@ -154,9 +154,6 @@ public:
void RevokeViewManagerFlush() {
mViewManagerFlushIsPending = false;
}
bool ViewManagerFlushIsPending() {
return mViewManagerFlushIsPending;
}
/**
* Add a document for which we have nsIFrameRequestCallbacks

View File

@ -59,7 +59,6 @@ _TEST_FILES = \
test_bug423523.html \
test_bug449781.html \
test_bug450930.xhtml \
bug450930.xhtml \
test_bug458898.html \
test_bug465448.xul \
test_bug469170.html \
@ -354,7 +353,7 @@ endif
ifeq (,$(filter cocoa,$(MOZ_WIDGET_TOOLKIT)))
# THESE TESTS (BELOW) DO NOT RUN ON MAC
_TEST_FILES += \
$(warning test_flush_on_paint.html disabled due to random orange; see bug 539356) \
test_flush_on_paint.html \
$(NULL)
# THESE TESTS (ABOVE) DO NOT RUN ON MAC
endif

View File

@ -1,192 +0,0 @@
<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=450930
-->
<head>
<title>Test for Bug 450930 (MozAfterPaint)</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body onload="runNext()">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=450930">Mozilla Bug 450930</a>
<div id="display">
<div id="d" style="width:400px; height:200px;"></div>
<iframe id="iframe" style="width:400px; height:200px;"
src="data:text/html,&lt;div id='d'&gt;&lt;span style='margin-left:3px;'&gt;Hello&lt;/span&gt;
&lt;/div&gt;&lt;div style='margin-top:500px' id='d2'&gt;
&lt;span style='margin-left:3px;'&gt;Goodbye&lt;/span&gt;&lt;/div>"></iframe>
<svg:svg style="width:410px; height:210px;" id="svg">
<svg:foreignObject width="100%" height="100%">
<iframe id="iframe2" style="width:400px; height:200px;"
src="data:text/html,&lt;div id='d'&gt;&lt;span style='margin-left:3px;'&gt;Hello&lt;/span&gt;
&lt;/div&gt;&lt;div style='margin-top:500px' id='d2'&gt;
&lt;span style='margin-left:3px;'&gt;Goodbye&lt;/span&gt;&lt;/div>"></iframe>
</svg:foreignObject>
</svg:svg>
</div>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript"><![CDATA[
function flash(doc, name) {
var d = doc.getElementById(name);
d.style.backgroundColor = d.style.backgroundColor == "blue" ? "yellow" : "blue";
// Now flush out style changes in that document, since our event listeners
// seem to assume that things will work that way.
d.getBoundingClientRect();
}
function le(v1, v2, s) {
window.opener.ok(v1 <= v2, s + " (" + v1 + "," + v2 + ")");
}
function checkContains(r1, r2, s) {
le(Math.round(r1.left), Math.round(r2.left), "Left edges out" + s);
le(Math.round(r2.right), Math.round(r1.right), "Right edges out" + s);
le(Math.round(r1.top), Math.round(r2.top), "Top edges out" + s);
le(Math.round(r2.bottom), Math.round(r1.bottom), "Bottom edges out" + s);
}
function isRect(r1, r2) {
return (Math.abs(r1.left - r2.left) <= 1 ||
Math.abs(r1.right - r2.right) <= 1 ||
Math.abs(r1.top - r2.top) <= 1 ||
Math.abs(r1.bottom - r2.bottom) <= 1);
}
function isRectInList(r, list) {
for (var i = 0; i < list.length; ++i) {
if (isRect(r, list[i]))
return true;
}
return false;
}
function doesRectContain(r1, r2) {
return Math.floor(r1.left) <= r2.left && r2.right <= Math.ceil(r1.right) &&
Math.floor(r1.top) <= r2.top && r2.bottom <= Math.ceil(r1.bottom);
}
function rectToString(r) {
return "(" + r.left + "," + r.top + "," + r.right + "," + r.bottom + ")";
}
function doesRectContainListElement(r, list) {
dump("Incoming rect: " + rectToString(r) + "\n");
for (var i = 0; i < list.length; ++i) {
dump("List rect " + i + ": " + rectToString(list[i]));
if (doesRectContain(r, list[i])) {
dump(" FOUND\n");
return true;
}
dump("\n");
}
dump("NOT FOUND\n");
return false;
}
function checkGotSubdoc(list, container) {
var r = container.getBoundingClientRect();
return doesRectContainListElement(r, list);
}
function runTest1() {
// test basic functionality
var iterations = 0;
var foundExactRect = false;
function listener(event) {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var r = event.boundingClientRect;
var bounds = document.getElementById('d').getBoundingClientRect();
checkContains(r, bounds, "");
if (isRectInList(bounds, event.clientRects)) {
foundExactRect = true;
}
window.removeEventListener("MozAfterPaint", listener, false);
++iterations;
if (iterations < 4) {
setTimeout(triggerPaint, 100);
} else {
window.opener.ok(foundExactRect, "Found exact rect");
runNext();
}
}
function triggerPaint() {
window.addEventListener("MozAfterPaint", listener, false);
flash(document, 'd');
window.opener.ok(true, "trigger test1 paint");
}
triggerPaint();
}
function runTest2(frameID, containerID) {
// test reporting of painting in subdocuments
var fired = 0;
var gotSubdocPrivileged = false;
var gotSubdocNonprivileged = false;
var iframe = document.getElementById(frameID);
var container = document.getElementById(containerID);
function listener(event) {
if (checkGotSubdoc(event.clientRects, container))
gotSubdocNonprivileged = true;
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
if (checkGotSubdoc(event.clientRects, container))
gotSubdocPrivileged = true;
if (event.clientRects.length > 0) {
fired++;
if (fired == 1)
setTimeout(check, 100);
}
}
function check() {
window.opener.is(fired, 1, "Wrong event count (" + frameID + ")");
window.opener.ok(!gotSubdocNonprivileged, "Got subdoc invalidation while not privileged (" + frameID + ")");
window.opener.ok(gotSubdocPrivileged, "Didn't get subdoc invalidation while we were privileged (" + frameID + ")");
window.removeEventListener("MozAfterPaint", listener, false);
runNext();
}
function triggerPaint() {
window.addEventListener("MozAfterPaint", listener, false);
document.body.offsetTop;
flash(iframe.contentDocument, 'd');
}
triggerPaint();
}
var test = 0;
var tests = [runTest1,
function() { runTest2("iframe", "iframe") },
function() { runTest2("iframe2", "svg") }];
function runNext() {
var CI = Components.interfaces;
var utils = window.QueryInterface(CI.nsIInterfaceRequestor)
.getInterface(CI.nsIDOMWindowUtils);
if (utils.isMozAfterPaintPending) {
// Wait until there are no pending paints before trying to run tests
setTimeout(runNext, 100);
return;
}
if (test < tests.length) {
++test;
tests[test - 1]();
} else {
window.opener.finishTests();
}
}
]]></script>
</pre>
</body>
</html>

View File

@ -46,13 +46,10 @@ _CHROME_FILES = \
$(NULL)
ifdef MOZ_DEBUG
# Disabled on Mac because of Bug 748219
ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT))
_CHROME_FILES += \
test_leaf_layers_partition_browser_window.xul \
$(NULL)
endif
endif
libs:: $(_CHROME_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)

View File

@ -1,47 +1,47 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test that scaled elements with scrolled contents don't repaint unnecessarily when we scroll inside them</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="-moz-transform: scale(1.2, 1.2); -moz-transform-origin:top left; width:200px; height:100px; background:yellow; overflow:hidden">
<div style="height:40px;">Hello</div>
<div id="e" style="height:30px; background:lime">Kitty</div>
<div style="height:300px; background:yellow">Kitty</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 couple of scrolls to ensure we've triggered activity heuristics.
waitForAllPaintsFlushed(function () {
t.scrollTop = 5;
waitForAllPaintsFlushed(function () {
t.scrollTop = 10;
waitForAllPaintsFlushed(function () {
// Clear paint state now and scroll again.
utils.checkAndClearPaintedState(e);
t.scrollTop = 15;
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>
<!DOCTYPE HTML>
<html>
<head>
<title>Test that scaled elements with scrolled contents don't repaint unnecessarily when we scroll inside them</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="-moz-transform: scale(1.2, 1.2); -moz-transform-origin:top left; width:200px; height:100px; background:yellow; overflow:hidden">
<div style="height:40px;">Hello</div>
<div id="e" style="height:30px; background:lime">Kitty</div>
<div style="height:300px; background:yellow">Kitty</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 couple of scrolls to ensure we've triggered activity heuristics.
waitForAllPaintsFlushed(function () {
t.scrollTop = 5;
waitForAllPaintsFlushed(function () {
t.scrollTop = 10;
waitForAllPaintsFlushed(function () {
// Clear paint state now and scroll again.
utils.checkAndClearPaintedState(e);
t.scrollTop = 33;
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

@ -1,47 +1,51 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test that scaled elements with scrolled contents don't repaint unnecessarily when we scroll inside them (1.1 scale)</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="-moz-transform: scale(1.1, 1.1); -moz-transform-origin:top left; width:200px; height:100px; background:yellow; overflow:hidden">
<div style="height:40px;"></div>
<div id="e" style="height:30px; background:lime"></div>
<div style="height:300px; background:yellow"></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 couple of scrolls to ensure we've triggered activity heuristics
waitForAllPaintsFlushed(function () {
t.scrollTop = 5;
waitForAllPaintsFlushed(function () {
t.scrollTop = 10;
waitForAllPaintsFlushed(function () {
// Clear paint state now and scroll again.
utils.checkAndClearPaintedState(e);
t.scrollTop = 20;
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>
<!DOCTYPE HTML>
<html>
<head>
<title>Test that scaled elements with scrolled contents don't repaint unnecessarily when we scroll inside them (1.1 scale)</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="-moz-transform: scale(1.1, 1.1); -moz-transform-origin:top left; width:200px; height:100px; background:yellow; overflow:hidden">
<div style="height:40px;">Hello</div>
<div id="e" style="height:30px; background:lime">Kitty</div>
<div style="height:300px; background:yellow">Kitty</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 couple of scrolls to ensure we've triggered activity heuristics
waitForAllPaintsFlushed(function () {
t.scrollTop = 5;
waitForAllPaintsFlushed(function () {
t.scrollTop = 10;
waitForAllPaintsFlushed(function () {
// Clear paint state now and scroll again.
utils.checkAndClearPaintedState(e);
t.scrollTop = 33;
waitForAllPaintsFlushed(function () {
var painted = utils.checkAndClearPaintedState(e);
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();
});
});
});
});
}
</script>
</pre>
</body>
</html>

View File

@ -48,7 +48,6 @@ function print_event(event) {
function step0(event) {
// Wait until we get the MozAfterPaint following the load event
// before starting.
ok(true, "loaded");
window.addEventListener("MozAfterPaint", step1, false);
// Ensure a MozAfterPaint event is fired

View File

@ -9,18 +9,208 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=450930
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=450930">Mozilla Bug 450930</a>
<div id="display">
<div id="d" style="width:400px; height:200px;"></div>
<iframe id="iframe" style="width:400px; height:200px;"
src="data:text/html,&lt;div id='d'&gt;&lt;span style='margin-left:3px;'&gt;Hello&lt;/span&gt;
&lt;/div&gt;&lt;div style='margin-top:500px' id='d2'&gt;
&lt;span style='margin-left:3px;'&gt;Goodbye&lt;/span&gt;&lt;/div>"></iframe>
<svg:svg style="width:410px; height:210px;" id="svg">
<svg:foreignObject width="100%" height="100%">
<iframe id="iframe2" style="width:400px; height:200px;"
src="data:text/html,&lt;div id='d'&gt;&lt;span style='margin-left:3px;'&gt;Hello&lt;/span&gt;
&lt;/div&gt;&lt;div style='margin-top:500px' id='d2'&gt;
&lt;span style='margin-left:3px;'&gt;Goodbye&lt;/span&gt;&lt;/div>"></iframe>
</svg:foreignObject>
</svg:svg>
</div>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript"><![CDATA[
/** Test for Bug 450930 **/
SimpleTest.waitForExplicitFinish();
var subwindow = window.open("./bug450930.xhtml", "bug450930", "width=800,height=1000");
function finishTests() {
subwindow.close();
SimpleTest.finish();
function flash(doc, name) {
var d = doc.getElementById(name);
d.style.backgroundColor = d.style.backgroundColor == "blue" ? "yellow" : "blue";
// Now flush out style changes in that document, since our event listeners
// seem to assume that things will work that way.
d.getBoundingClientRect();
}
function le(v1, v2, s) {
ok(v1 <= v2, s + " (" + v1 + "," + v2 + ")");
}
function checkContains(r1, r2, s) {
le(r1.left, r2.left, "Left edges out" + s);
le(r2.right, r1.right, "Right edges out" + s);
le(r1.top, r2.top, "Top edges out" + s);
le(r2.bottom, r1.bottom, "Bottom edges out" + s);
}
function isRect(r1, r2) {
return r1.left == r2.left && r1.right == r2.right &&
r1.top == r2.top && r1.bottom == r2.bottom;
}
function isRectInList(r, list) {
for (var i = 0; i < list.length; ++i) {
if (isRect(r, list[i]))
return true;
}
return false;
}
function doesRectContain(r1, r2) {
return r1.left <= r2.left && r2.right <= r1.right &&
r1.top <= r2.top && r2.bottom <= r1.bottom;
}
function rectToString(r) {
return "(" + r.left + "," + r.top + "," + r.right + "," + r.bottom + ")";
}
function doesRectContainListElement(r, list) {
dump("Incoming rect: " + rectToString(r) + "\n");
for (var i = 0; i < list.length; ++i) {
dump("List rect " + i + ": " + rectToString(list[i]));
if (doesRectContain(r, list[i])) {
dump(" FOUND\n");
return true;
}
dump("\n");
}
dump("NOT FOUND\n");
return false;
}
function checkGotSubdoc(list, container) {
var r = container.getBoundingClientRect();
return doesRectContainListElement(r, list);
}
function runTest1() {
// test basic functionality
var iterations = 0;
var foundExactRect = false;
function listener(event) {
var r = event.boundingClientRect;
var bounds = document.getElementById('d').getBoundingClientRect();
checkContains(r, bounds, "");
if (isRectInList(bounds, event.clientRects)) {
foundExactRect = true;
}
window.removeEventListener("MozAfterPaint", listener, false);
++iterations;
if (iterations < 4) {
setTimeout(triggerPaint, 100);
} else {
ok(foundExactRect, "Found exact rect");
runNext();
}
}
function triggerPaint() {
window.addEventListener("MozAfterPaint", listener, false);
flash(document, 'd');
}
triggerPaint();
}
function runTest2(frameID, containerID) {
// test reporting of painting in subdocuments
var fired = 0;
var gotSubdocPrivileged = false;
var gotSubdocNonprivileged = false;
var iframe = document.getElementById(frameID);
var container = document.getElementById(containerID);
function listener(event) {
if (checkGotSubdoc(event.clientRects, container))
gotSubdocNonprivileged = true;
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
if (checkGotSubdoc(event.clientRects, container))
gotSubdocPrivileged = true;
if (++fired == 1)
setTimeout(check, 100);
}
function check() {
is(fired, 1, "Wrong event count (" + frameID + ")");
ok(gotSubdocPrivileged, "Didn't get subdoc invalidation while we were privileged (" + frameID + ")");
ok(!gotSubdocNonprivileged, "Got subdoc invalidation while we were not privileged (" + frameID + ")");
window.removeEventListener("MozAfterPaint", listener, false);
runNext();
}
function triggerPaint() {
window.addEventListener("MozAfterPaint", listener, false);
document.body.offsetTop;
flash(iframe.contentDocument, 'd');
// make sure an event fires; since we're not using a chrome event handler, even though we
// can get privileges we wouldn't get the event
flash(document, 'd');
}
triggerPaint();
}
function runTest3() {
// test reporting of painting of scrolled-out-of-view areas
var gotScrolledOutInMainDoc = false;
var gotScrolledOutInSubdoc = false;
var iframe = document.getElementById("iframe");
function listener(event) {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
if (checkGotSubdoc(event.clientRects, iframe))
gotScrolledOutInMainDoc = true;
}
function check() {
ok(!gotScrolledOutInMainDoc, "scrolled-out invalidation should not propagate to main doc");
window.removeEventListener("MozAfterPaint", listener, false);
iframe.contentWindow.removeEventListener("MozAfterPaint", IFRAMEListener, false);
runNext();
}
function IFRAMEListener(event) {
if (doesRectContainListElement(
iframe.contentDocument.getElementById("d2").getBoundingClientRect(), event.clientRects)) {
ok(true, "scrolled-out invalidation should notify in subdoc");
setTimeout(check, 0);
}
}
function triggerPaint() {
window.addEventListener("MozAfterPaint", listener, false);
iframe.contentWindow.addEventListener("MozAfterPaint", IFRAMEListener, false);
flash(iframe.contentDocument, 'd2');
}
triggerPaint();
}
var test = 0;
var tests = [runTest1,
function() { runTest2("iframe", "iframe") },
function() { runTest2("iframe2", "svg") },
runTest3];
function runNext() {
if (test < tests.length) {
++test;
tests[test - 1]();
} else {
SimpleTest.finish();
}
}
window.onload = runNext();
]]></script>
</pre>
</body>

View File

@ -117,18 +117,11 @@ public:
}
virtual void Paint(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx);
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap);
NS_DISPLAY_DECL_NAME("ButtonBorderBackground", TYPE_BUTTON_BORDER_BACKGROUND)
private:
nsButtonFrameRenderer* mBFR;
};
nsRect
nsDisplayButtonBorderBackground::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
*aSnap = false;
return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
}
class nsDisplayButtonForeground : public nsDisplayItem {
public:
nsDisplayButtonForeground(nsDisplayListBuilder* aBuilder,

View File

@ -350,7 +350,7 @@ nsComboboxControlFrame::SetFocus(bool aOn, bool aRepaint)
// This is needed on a temporary basis. It causes the focus
// rect to be drawn. This is much faster than ReResolvingStyle
// Bug 32920
InvalidateFrame();
Invalidate(nsRect(0,0,mRect.width,mRect.height));
}
void

View File

@ -584,7 +584,7 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, mContentFrame);
FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus);
InvalidateFrame();
Invalidate(aDesiredSize.VisualOverflow());
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
return NS_OK;

View File

@ -255,7 +255,15 @@ nsListControlFrame::InvalidateFocus()
nsIFrame* containerFrame = GetOptionsContainer();
if (containerFrame) {
containerFrame->InvalidateFrame();
// Invalidating from the containerFrame because that's where our focus
// is drawn.
// The origin of the scrollport is the origin of containerFrame.
float inflation = nsLayoutUtils::FontSizeInflationFor(this);
nsRect invalidateArea = containerFrame->GetVisualOverflowRect();
nsRect emptyFallbackArea(0, 0, GetScrollPortRect().width,
CalcFallbackRowHeight(inflation));
invalidateArea.UnionRect(invalidateArea, emptyFallbackArea);
containerFrame->Invalidate(invalidateArea);
}
}
@ -999,8 +1007,6 @@ nsListControlFrame::Init(nsIContent* aContent,
mLastDropdownBackstopColor = PresContext()->DefaultBackgroundColor();
AddStateBits(NS_FRAME_IN_POPUP);
return result;
}
@ -1699,6 +1705,18 @@ nsListControlFrame::GetType() const
return nsGkAtoms::listControlFrame;
}
void
nsListControlFrame::InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild,
PRUint32 aFlags)
{
if (!IsInDropDownMode()) {
nsHTMLScrollFrame::InvalidateInternal(aDamageRect, aX, aY, this, aFlags);
return;
}
InvalidateRoot(aDamageRect + nsPoint(aX, aY), aFlags);
}
#ifdef DEBUG
NS_IMETHODIMP
nsListControlFrame::GetFrameName(nsAString& aResult) const

View File

@ -91,6 +91,10 @@ public:
~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
}
virtual void InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild,
PRUint32 aFlags);
#ifdef DEBUG
NS_IMETHOD GetFrameName(nsAString& aResult) const;
#endif

View File

@ -210,7 +210,7 @@ nsMeterFrame::AttributeChanged(PRInt32 aNameSpaceID,
PresContext()->PresShell()->FrameNeedsReflow(barFrame,
nsIPresShell::eResize,
NS_FRAME_IS_DIRTY);
InvalidateFrame();
Invalidate(GetVisualOverflowRectRelativeToSelf());
}
return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,

View File

@ -225,7 +225,7 @@ nsProgressFrame::AttributeChanged(PRInt32 aNameSpaceID,
NS_ASSERTION(barFrame, "The progress frame should have a child with a frame!");
PresContext()->PresShell()->FrameNeedsReflow(barFrame, nsIPresShell::eResize,
NS_FRAME_IS_DIRTY);
InvalidateFrame();
Invalidate(GetVisualOverflowRectRelativeToSelf());
}
return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);

View File

@ -14,7 +14,7 @@ load 310556-1.xhtml
load 322780-1.xul
load 323381-1.html
load 323381-2.html
asserts(2) asserts-if(gtk2Widget,17-18) load 323386-1.html # Bug 575011
asserts(2) asserts-if(gtk2Widget,17) load 323386-1.html # Bug 575011
load 323389-1.html
load 323389-2.html
load 323493-1.html
@ -259,8 +259,8 @@ load 465651-1.html
load 467137-1.html
load 467213-1.html
load 467487-1.html
asserts(6-9) load 467493-1.html
asserts(4-8) load 467493-2.html
asserts(5-7) load 467493-1.html
asserts(4-6) load 467493-2.html
load 467875-1.xhtml
load 467914-1.html
load 468207-1.html
@ -322,7 +322,7 @@ load 536692-1.xhtml
load 541277-1.html
load 541277-2.html
asserts(3) load 541714-1.html
asserts(3-8) load 541714-2.html
asserts(3-7) load 541714-2.html
load 542136-1.html
load 545571-1.html
load 547338.xul

View File

@ -456,6 +456,23 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat
nsContainerFrame::PositionChildViews(aKidFrame);
}
if (oldRect.TopLeft() != rect.TopLeft() ||
(aDelegatingFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
// The frame moved
aKidFrame->GetParent()->Invalidate(oldOverflowRect);
aKidFrame->InvalidateFrameSubtree();
} else if (oldRect.Size() != rect.Size()) {
// Invalidate the area where the frame changed size.
nscoord innerWidth = NS_MIN(oldRect.width, rect.width);
nscoord innerHeight = NS_MIN(oldRect.height, rect.height);
nscoord outerWidth = NS_MAX(oldRect.width, rect.width);
nscoord outerHeight = NS_MAX(oldRect.height, rect.height);
aKidFrame->GetParent()->Invalidate(
nsRect(rect.x + innerWidth, rect.y, outerWidth - innerWidth, outerHeight));
// Invalidate the horizontal strip
aKidFrame->GetParent()->Invalidate(
nsRect(rect.x, rect.y + innerHeight, outerWidth, outerHeight - innerHeight));
}
aKidFrame->DidReflow(aPresContext, &kidReflowState, NS_FRAME_REFLOW_FINISHED);
#ifdef DEBUG

View File

@ -487,6 +487,32 @@ nsBlockFrame::GetType() const
return nsGkAtoms::blockFrame;
}
void
nsBlockFrame::InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild,
PRUint32 aFlags)
{
// Optimize by suppressing invalidation of areas that are clipped out
// with CSS 'clip'. Don't suppress invalidation of *this* frame directly,
// because when 'clip' shrinks we need to invalidate this frame and
// be able to invalidate areas outside the 'clip'.
if (aForChild) {
const nsStyleDisplay* disp = GetStyleDisplay();
nsRect clipRect;
if (GetClipPropClipRect(disp, &clipRect, GetSize())) {
// Restrict the invalidated area to abs-pos clip rect
// abs-pos clipping clips everything in the frame
nsRect r;
if (r.IntersectRect(aDamageRect, clipRect - nsPoint(aX, aY))) {
nsBlockFrameSuper::InvalidateInternal(r, aX, aY, this, aFlags);
}
return;
}
}
nsBlockFrameSuper::InvalidateInternal(aDamageRect, aX, aY, this, aFlags);
}
nscoord
nsBlockFrame::GetBaseline() const
{
@ -1187,6 +1213,9 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
}
}
// Determine if we need to repaint our border, background or outline
CheckInvalidateSizeChange(aMetrics);
FinishAndStoreOverflow(&aMetrics);
// Clear the float manager pointer in the block reflow state so we
@ -2446,6 +2475,18 @@ nsBlockFrame::DeleteLine(nsBlockReflowState& aState,
}
}
static void
InvalidateThebesLayersInLineBox(nsIFrame* aBlock, nsLineBox* aLine)
{
if (aBlock->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT) {
PRInt32 childCount = aLine->GetChildCount();
for (nsIFrame* f = aLine->mFirstChild; childCount;
--childCount, f = f->GetNextSibling()) {
FrameLayerBuilder::InvalidateThebesLayersInSubtree(f);
}
}
}
/**
* Reflow a line. The line will either contain a single block frame
* or contain 1 or more inline frames. aKeepReflowGoing indicates
@ -2468,10 +2509,78 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
// Now that we know what kind of line we have, reflow it
if (aLine->IsBlock()) {
nsRect oldBounds = aLine->mFirstChild->GetRect();
nsRect oldVisOverflow(aLine->GetVisualOverflowArea());
rv = ReflowBlockFrame(aState, aLine, aKeepReflowGoing);
} else {
nsRect newBounds = aLine->mFirstChild->GetRect();
// We expect blocks to damage any area inside their bounds that is
// dirty; however, if the frame changes size or position then we
// need to do some repainting.
// XXX roc --- the above statement is ambiguous about whether 'bounds'
// means the frame's bounds or overflowArea, and in fact this is a source
// of much confusion and bugs. Thus the following hack considers *both*
// overflowArea and bounds. This should be considered a temporary hack
// until we decide how it's really supposed to work.
// Note that we have a similar hack in nsTableFrame::InvalidateFrame.
nsRect visOverflow(aLine->GetVisualOverflowArea());
if (oldVisOverflow.TopLeft() != visOverflow.TopLeft() ||
oldBounds.TopLeft() != newBounds.TopLeft()) {
// The block has moved, and so to be safe we need to repaint
// XXX We need to improve on this...
nsRect dirtyRect;
dirtyRect.UnionRect(oldVisOverflow, visOverflow);
#ifdef NOISY_BLOCK_INVALIDATE
printf("%p invalidate 6 (%d, %d, %d, %d)\n",
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
#endif
Invalidate(dirtyRect);
FrameLayerBuilder::InvalidateThebesLayersInSubtree(aLine->mFirstChild);
} else {
nsRect combinedAreaHStrip, combinedAreaVStrip;
nsRect boundsHStrip, boundsVStrip;
nsLayoutUtils::GetRectDifferenceStrips(oldBounds, newBounds,
&boundsHStrip, &boundsVStrip);
nsLayoutUtils::GetRectDifferenceStrips(oldVisOverflow, visOverflow,
&combinedAreaHStrip,
&combinedAreaVStrip);
#ifdef NOISY_BLOCK_INVALIDATE
printf("%p invalidate boundsVStrip (%d, %d, %d, %d)\n",
this, boundsVStrip.x, boundsVStrip.y, boundsVStrip.width, boundsVStrip.height);
printf("%p invalidate boundsHStrip (%d, %d, %d, %d)\n",
this, boundsHStrip.x, boundsHStrip.y, boundsHStrip.width, boundsHStrip.height);
printf("%p invalidate combinedAreaVStrip (%d, %d, %d, %d)\n",
this, combinedAreaVStrip.x, combinedAreaVStrip.y, combinedAreaVStrip.width, combinedAreaVStrip.height);
printf("%p invalidate combinedAreaHStrip (%d, %d, %d, %d)\n",
this, combinedAreaHStrip.x, combinedAreaHStrip.y, combinedAreaHStrip.width, combinedAreaHStrip.height);
#endif
// The first thing Invalidate does is check if the rect is empty, so
// don't bother doing that here.
Invalidate(boundsVStrip);
Invalidate(boundsHStrip);
Invalidate(combinedAreaVStrip);
Invalidate(combinedAreaHStrip);
}
}
else {
nsRect oldVisOverflow(aLine->GetVisualOverflowArea());
aLine->SetLineWrapped(false);
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
// We don't really know what changed in the line, so use the union
// of the old and new combined areas
nsRect dirtyRect;
dirtyRect.UnionRect(oldVisOverflow, aLine->GetVisualOverflowArea());
#ifdef NOISY_BLOCK_INVALIDATE
printf("%p invalidate (%d, %d, %d, %d)\n",
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
if (aLine->IsForceInvalidate())
printf(" dirty line is %p\n", static_cast<void*>(aLine.get()));
#endif
Invalidate(dirtyRect);
InvalidateThebesLayersInLineBox(this, aLine);
}
return rv;
@ -2575,6 +2684,9 @@ nsBlockFrame::PullFrameFrom(nsBlockReflowState& aState,
} else {
// Free up the fromLine now that it's empty
// Its bounds might need to be redrawn, though.
// XXX WHY do we invalidate the bounds AND the combined area? doesn't
// the combined area always enclose the bounds?
Invalidate(fromLine->mBounds);
FrameLines* overflowLines =
aFromOverflowLine ? aFromContainer->RemoveOverflowLines() : nsnull;
nsLineList* fromLineList =
@ -2582,6 +2694,7 @@ nsBlockFrame::PullFrameFrom(nsBlockReflowState& aState,
if (aFromLine.next() != fromLineList->end())
aFromLine.next()->MarkPreviousMarginDirty();
Invalidate(fromLine->GetVisualOverflowArea());
fromLineList->erase(aFromLine);
// aFromLine is now invalid
aFromContainer->FreeLineBox(fromLine);
@ -2621,8 +2734,11 @@ nsBlockFrame::SlideLine(nsBlockReflowState& aState,
{
NS_PRECONDITION(aDY != 0, "why slide a line nowhere?");
Invalidate(aLine->GetVisualOverflowArea());
// Adjust line state
aLine->SlideBy(aDY);
Invalidate(aLine->GetVisualOverflowArea());
InvalidateThebesLayersInLineBox(this, aLine);
// Adjust the frames in the line
nsIFrame* kid = aLine->mFirstChild;
@ -2920,6 +3036,9 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
// its view as needed.
nsPoint originalPosition = frame->GetPosition();
while (true) {
// Save the frame's current position. We might need it later.
nscoord passOriginalY = frame->GetRect().y;
clearance = 0;
nscoord topMargin = 0;
bool mayNeedRetry = false;
@ -3086,6 +3205,14 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
clearance, aState.IsAdjacentWithTop(),
aLine.get(), blockHtmlRS, frameReflowStatus, aState);
// If this was a second-pass reflow and the block's vertical position
// changed, invalidates from the first pass might have happened in the
// wrong places. Invalidate the entire overflow rect at the new position.
if (!mayNeedRetry && clearanceFrame &&
frame->GetRect().y != passOriginalY) {
Invalidate(frame->GetVisualOverflowRect() + frame->GetPosition());
}
NS_ENSURE_SUCCESS(rv, rv);
if (mayNeedRetry && clearanceFrame) {
@ -5420,6 +5547,7 @@ nsBlockFrame::DoRemoveFrame(nsIFrame* aDeletedFrame, PRUint32 aFlags)
this, visOverflow.x, visOverflow.y,
visOverflow.width, visOverflow.height);
#endif
Invalidate(visOverflow);
} else {
// XXX update searchingOverflowList directly, remove only when empty
FrameLines* overflowLines = RemoveOverflowLines();
@ -5878,8 +6006,24 @@ nsBlockFrame::ReflowPushedFloats(nsBlockReflowState& aState,
}
if (NS_SUBTREE_DIRTY(f) || aState.mReflowState.ShouldReflowAllKids()) {
// Cache old bounds
nsRect oldRect = f->GetRect();
nsRect oldOverflow = f->GetVisualOverflowRect();
// Reflow
aState.FlowAndPlaceFloat(f);
// Invalidate if there was a position or size change
nsRect rect = f->GetRect();
if (!rect.IsEqualInterior(oldRect)) {
nsRect dirtyRect = oldOverflow;
dirtyRect.MoveBy(oldRect.x, oldRect.y);
Invalidate(dirtyRect);
dirtyRect = f->GetVisualOverflowRect();
dirtyRect.MoveBy(rect.x, rect.y);
Invalidate(dirtyRect);
}
}
else {
// Just reload the float region into the space manager

View File

@ -158,6 +158,9 @@ public:
NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists);
virtual void InvalidateInternal(const nsRect& aDamageRect,
nscoord aX, nscoord aY, nsIFrame* aForChild,
PRUint32 aFlags);
virtual nsIAtom* GetType() const;
virtual bool IsFrameOfType(PRUint32 aFlags) const
{

View File

@ -790,6 +790,7 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat)
aFloat->SetPosition(origin);
nsContainerFrame::PositionFrameView(aFloat);
nsContainerFrame::PositionChildViews(aFloat);
FrameLayerBuilder::InvalidateThebesLayersInSubtree(aFloat);
}
// Update the float combined area state

View File

@ -1481,7 +1481,7 @@ NS_IMETHODIMP nsBulletFrame::OnDataAvailable(imgIRequest *aRequest,
// The image has changed.
// Invalidate the entire content area. Maybe it's not optimal but it's simple and
// always correct, and I'll be a stunned mullet if it ever matters for performance
InvalidateFrame();
Invalidate(nsRect(0, 0, mRect.width, mRect.height));
return NS_OK;
}
@ -1523,7 +1523,7 @@ NS_IMETHODIMP nsBulletFrame::FrameChanged(imgIRequest *aRequest,
{
// Invalidate the entire content area. Maybe it's not optimal but it's simple and
// always correct.
InvalidateFrame();
Invalidate(nsRect(0, 0, mRect.width, mRect.height));
return NS_OK;
}

View File

@ -156,6 +156,12 @@ nsCanvasFrame::RemoveFrame(ChildListID aListID,
if (aOldFrame != mFrames.FirstChild())
return NS_ERROR_FAILURE;
// It's our one and only child frame
// Damage the area occupied by the deleted frame
// The child of the canvas probably can't have an outline, but why bother
// thinking about that?
Invalidate(aOldFrame->GetVisualOverflowRect() + aOldFrame->GetPosition());
// Remove the frame and destroy it
mFrames.DestroyFrame(aOldFrame);
@ -454,7 +460,15 @@ nsCanvasFrame::Reflow(nsPresContext* aPresContext,
// could also include overflow to our top and left (out of the viewport)
// which doesn't need to be painted.
nsIFrame* viewport = PresContext()->GetPresShell()->GetRootFrame();
viewport->InvalidateFrame();
viewport->Invalidate(nsRect(nsPoint(0, 0), viewport->GetSize()));
} else {
nsRect newKidRect = kidFrame->GetRect();
if (newKidRect.TopLeft() == oldKidRect.TopLeft()) {
InvalidateRectDifference(oldKidRect, kidFrame->GetRect());
} else {
Invalidate(oldKidRect);
Invalidate(newKidRect);
}
}
// Return our desired size. Normally it's what we're told, but
@ -498,7 +512,7 @@ nsCanvasFrame::Reflow(nsPresContext* aPresContext,
const nsStyleBackground::Layer& layer = bg->mLayers[i];
if (layer.mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED &&
layer.RenderingMightDependOnFrameSize()) {
InvalidateFrame();
Invalidate(nsRect(nsPoint(0, 0), GetSize()));
break;
}
}

View File

@ -115,22 +115,6 @@ protected:
bool mAddedScrollPositionListener;
};
class nsDisplayCanvasBackgroundGeometry : public nsDisplayItemGeometry
{
public:
virtual void MoveBy(const nsPoint& aOffset)
{
mBounds.MoveBy(aOffset);
mChildBorder.MoveBy(aOffset);
mPaddingRect.MoveBy(aOffset);
mContentRect.MoveBy(aOffset);
}
nsRect mChildBorder;
nsRect mPaddingRect;
nsRect mContentRect;
};
/**
* Override nsDisplayBackground methods so that we pass aBGClipRect to
* PaintBackground, covering the whole overflow area.
@ -184,46 +168,7 @@ public:
// We need to override so we don't consider border-radius.
aOutFrames->AppendElement(mFrame);
}
virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder)
{
nsDisplayCanvasBackgroundGeometry* geometry = new nsDisplayCanvasBackgroundGeometry;
nsIFrame *child = mFrame->GetFirstPrincipalChild();
bool snap;
geometry->mBounds = GetBounds(aBuilder, &snap);
if (child) {
geometry->mChildBorder = child->GetRect();
}
geometry->mPaddingRect = GetPaddingRect();
geometry->mContentRect = GetContentRect();
return geometry;
}
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion)
{
const nsDisplayCanvasBackgroundGeometry* geometry = static_cast<const nsDisplayCanvasBackgroundGeometry*>(aGeometry);
if (ShouldFixToViewport(aBuilder)) {
// This is incorrect, We definitely need to check more things here.
return;
}
nsIFrame *child = mFrame->GetFirstPrincipalChild();
bool snap;
if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) ||
(child && !geometry->mChildBorder.IsEqualInterior(child->GetRect())) ||
!geometry->mPaddingRect.IsEqualInterior(GetPaddingRect()) ||
!geometry->mContentRect.IsEqualInterior(GetContentRect())) {
if (!RenderingMightDependOnFrameSize() && geometry->mBounds.TopLeft() == GetBounds(aBuilder, &snap).TopLeft()) {
aInvalidRegion->Xor(GetBounds(aBuilder, &snap), geometry->mBounds);
} else {
aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds);
}
}
}
virtual void Paint(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx);

View File

@ -441,7 +441,13 @@ static void MoveChildTo(nsIFrame* aParent, nsIFrame* aChild, nsPoint aOrigin) {
return;
}
nsRect r = aChild->GetVisualOverflowRect();
r += aChild->GetPosition();
aParent->Invalidate(r);
r -= aChild->GetPosition();
aChild->SetPosition(aOrigin);
r += aOrigin;
aParent->Invalidate(r);
PlaceFrameView(aChild);
}
@ -1059,6 +1065,8 @@ nsColumnSetFrame::Reflow(nsPresContext* aPresContext,
aStatus = NS_FRAME_COMPLETE;
}
CheckInvalidateSizeChange(aDesiredSize);
// XXXjwir3: This call should be replaced with FinishWithAbsoluteFrames
// when bug 724978 is fixed and nsColumnSetFrame is a full absolute
// container.

View File

@ -890,6 +890,11 @@ nsContainerFrame::ReflowChild(nsIFrame* aKidFrame,
aKidFrame->WillReflow(aPresContext);
if (NS_FRAME_NO_MOVE_FRAME != (aFlags & NS_FRAME_NO_MOVE_FRAME)) {
if ((aFlags & NS_FRAME_INVALIDATE_ON_MOVE) &&
!(aKidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
aKidFrame->GetPosition() != nsPoint(aX, aY)) {
aKidFrame->InvalidateFrameSubtree();
}
aKidFrame->SetPosition(nsPoint(aX, aY));
}
@ -998,6 +1003,13 @@ nsContainerFrame::FinishReflowChild(nsIFrame* aKidFrame,
// correctly positioned
PositionChildViews(aKidFrame);
}
// We also need to redraw everything associated with the frame
// because if the frame's Reflow issued any invalidates, then they
// will be at the wrong offset ... note that this includes
// invalidates issued against the frame's children, so we need to
// invalidate the overflow area too.
aKidFrame->Invalidate(aDesiredSize.VisualOverflow());
}
return aKidFrame->DidReflow(aPresContext, aReflowState, NS_FRAME_REFLOW_FINISHED);
@ -1077,6 +1089,10 @@ nsContainerFrame::ReflowOverflowContainerChildren(nsPresContext* aPres
frame, availSpace);
nsReflowStatus frameStatus = NS_FRAME_COMPLETE;
// Cache old bounds
nsRect oldRect = frame->GetRect();
nsRect oldOverflow = frame->GetVisualOverflowRect();
// Reflow
rv = ReflowChild(frame, aPresContext, desiredSize, frameState,
prevRect.x, 0, aFlags, frameStatus, &tracker);
@ -1087,6 +1103,18 @@ nsContainerFrame::ReflowOverflowContainerChildren(nsPresContext* aPres
prevRect.x, 0, aFlags);
NS_ENSURE_SUCCESS(rv, rv);
// Invalidate if there was a position or size change
nsRect rect = frame->GetRect();
if (!rect.IsEqualInterior(oldRect)) {
nsRect dirtyRect = oldOverflow;
dirtyRect.MoveBy(oldRect.x, oldRect.y);
Invalidate(dirtyRect);
dirtyRect = frame->GetVisualOverflowRect();
dirtyRect.MoveBy(rect.x, rect.y);
Invalidate(dirtyRect);
}
// Handle continuations
if (!NS_FRAME_IS_FULLY_COMPLETE(frameStatus)) {
if (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
@ -1301,6 +1329,8 @@ nsContainerFrame::DeleteNextInFlowChild(nsPresContext* aPresContext,
}
}
aNextInFlow->InvalidateFrameSubtree();
// Take the next-in-flow out of the parent's child list
#ifdef DEBUG
nsresult rv =

View File

@ -86,7 +86,6 @@
#include "nsChangeHint.h"
#include "nsDeckFrame.h"
#include "nsTableFrame.h"
#include "nsSubDocumentFrame.h"
#include "gfxContext.h"
#include "nsRenderingContext.h"
@ -491,8 +490,7 @@ nsFrame::Init(nsIContent* aContent,
// Make bits that are currently off (see constructor) the same:
mState |= state & (NS_FRAME_INDEPENDENT_SELECTION |
NS_FRAME_GENERATED_CONTENT |
NS_FRAME_IN_POPUP);
NS_FRAME_GENERATED_CONTENT);
}
const nsStyleDisplay *disp = GetStyleDisplay();
if (disp->HasTransform()) {
@ -1209,23 +1207,6 @@ nsFrame::GetChildLists(nsTArray<ChildList>* aLists) const
}
}
void
nsIFrame::GetCrossDocChildLists(nsTArray<ChildList>* aLists)
{
nsSubDocumentFrame* subdocumentFrame = do_QueryFrame(this);
if (subdocumentFrame) {
// Descend into the subdocument
nsIFrame* root = subdocumentFrame->GetSubdocumentRootFrame();
if (root) {
aLists->AppendElement(nsIFrame::ChildList(
nsFrameList(root, nsLayoutUtils::GetLastSibling(root)),
nsIFrame::kPrincipalList));
}
}
GetChildLists(aLists);
}
static nsIFrame*
GetActiveSelectionFrame(nsPresContext* aPresContext, nsIFrame* aFrame)
{
@ -4422,6 +4403,46 @@ nsIFrame::IsLeaf() const
return true;
}
Layer*
nsIFrame::InvalidateLayer(const nsRect& aDamageRect, PRUint32 aDisplayItemKey)
{
NS_ASSERTION(aDisplayItemKey > 0, "Need a key");
Layer* layer = FrameLayerBuilder::GetDedicatedLayer(this, aDisplayItemKey);
if (!layer) {
Invalidate(aDamageRect);
return nsnull;
}
PRUint32 flags = INVALIDATE_NO_THEBES_LAYERS;
if (aDisplayItemKey == nsDisplayItem::TYPE_VIDEO ||
aDisplayItemKey == nsDisplayItem::TYPE_PLUGIN ||
aDisplayItemKey == nsDisplayItem::TYPE_CANVAS) {
flags |= INVALIDATE_NO_UPDATE_LAYER_TREE;
}
InvalidateWithFlags(aDamageRect, flags);
return layer;
}
void
nsIFrame::InvalidateTransformLayer()
{
NS_ASSERTION(mParent, "How can a viewport frame have a transform?");
bool hasLayer =
FrameLayerBuilder::GetDedicatedLayer(this, nsDisplayItem::TYPE_TRANSFORM) != nsnull;
// Invalidate post-transform area in the parent. We have to invalidate
// in the parent because our transform style may have changed from what was
// used to paint this frame.
// It's OK to bypass the SVG effects processing and other processing
// performed if we called this->InvalidateWithFlags, because those effects
// are performed before applying transforms.
mParent->InvalidateInternal(GetVisualOverflowRect() + GetPosition(),
0, 0, this,
hasLayer ? INVALIDATE_NO_THEBES_LAYERS : 0);
}
class LayerActivity {
public:
LayerActivity(nsIFrame* aFrame) : mFrame(aFrame), mChangeHint(nsChangeHint(0)) {}
@ -4518,6 +4539,135 @@ nsFrame::ShutdownLayerActivityTimer()
gLayerActivityTracker = nsnull;
}
void
nsIFrame::InvalidateWithFlags(const nsRect& aDamageRect, PRUint32 aFlags)
{
if (aDamageRect.IsEmpty()) {
return;
}
// Don't allow invalidates to do anything when
// painting is suppressed.
nsIPresShell *shell = PresContext()->GetPresShell();
if (shell) {
if (shell->IsPaintingSuppressed())
return;
}
InvalidateInternal(aDamageRect, 0, 0, nsnull, aFlags);
}
/**
* Helper function that funnels an InvalidateInternal request up to the
* parent. This function is used so that if MOZ_SVG is not defined, we still
* have unified control paths in the InvalidateInternal chain.
*
* @param aDamageRect The rect to invalidate.
* @param aX The x offset from the origin of this frame to the rectangle.
* @param aY The y offset from the origin of this frame to the rectangle.
* @param aImmediate Whether to redraw immediately.
* @return None, though this funnels the request up to the parent frame.
*/
void
nsIFrame::InvalidateInternalAfterResize(const nsRect& aDamageRect, nscoord aX,
nscoord aY, PRUint32 aFlags)
{
if (aDamageRect.IsEmpty()) {
return;
}
/* If we're a transformed frame, then we need to apply our transform to the
* damage rectangle so that the redraw correctly redraws the transformed
* region. We're moved over aX and aY from our origin, but since this aX
* and aY is contained within our border, we need to scoot back by -aX and
* -aY to get back to the origin of the transform.
*
* There's one more problem, though, and that's that we don't know what
* coordinate space this rectangle is in. Sometimes it's in the local
* coordinate space for the frame, and sometimes its in the transformed
* coordinate space. If we get it wrong, we'll display incorrectly. Until I
* find a better fix for this problem, we'll invalidate the union of the two
* rectangles (original rectangle and transformed rectangle). At least one of
* these will be correct.
*
* When we are preserving-3d, we can have arbitrary hierarchies of preserved 3d
* children. The computed transform on these children is relative to the root
* transform object in the hierarchy, not necessarily their direct ancestor.
* In this case we transform by the child's transform, and mark the rectangle
* as being transformed until it is passed up to the root of the hierarchy.
*
* See bug #452496 for more details.
*/
// Check the transformed flags and remove it
bool rectIsTransformed = (aFlags & INVALIDATE_ALREADY_TRANSFORMED);
if (!Preserves3D()) {
// We only want to remove the flag if we aren't preserving 3d. Otherwise
// the rect will already have been transformed into the root preserve-3d
// frame coordinate space, and we should continue passing it up without
// further transforms.
aFlags &= ~INVALIDATE_ALREADY_TRANSFORMED;
}
if ((mState & NS_FRAME_HAS_CONTAINER_LAYER) &&
!(aFlags & INVALIDATE_NO_THEBES_LAYERS)) {
// XXX for now I'm going to assume this is in the local coordinate space
// This only matters for frames with transforms and retained layers,
// which can't happen right now since transforms trigger fallback
// rendering and the display items that trigger layers are nested inside
// the nsDisplayTransform
// XXX need to set INVALIDATE_NO_THEBES_LAYERS for certain kinds of
// invalidation, e.g. video update, 'opacity' change
FrameLayerBuilder::InvalidateThebesLayerContents(this,
aDamageRect + nsPoint(aX, aY));
// Don't need to invalidate any more Thebes layers
aFlags |= INVALIDATE_NO_THEBES_LAYERS;
if (aFlags & INVALIDATE_ONLY_THEBES_LAYERS) {
return;
}
}
if (IsTransformed() && !rectIsTransformed) {
nsRect newDamageRect = nsDisplayTransform::TransformRectOut
(aDamageRect, this, nsPoint(-aX, -aY));
if (!(GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
newDamageRect.UnionRect(newDamageRect, aDamageRect);
}
// If we are preserving 3d, then our computed transform includes that of any
// ancestor frames that also preserve 3d. Mark the rectangle as already being
// transformed into the parent's coordinate space.
if (Preserves3D()) {
aFlags |= INVALIDATE_ALREADY_TRANSFORMED;
}
GetParent()->
InvalidateInternal(newDamageRect, aX + mRect.x, aY + mRect.y, this,
aFlags);
}
else
GetParent()->
InvalidateInternal(aDamageRect, aX + mRect.x, aY + mRect.y, this, aFlags);
}
void
nsIFrame::InvalidateInternal(const nsRect& aDamageRect, nscoord aX, nscoord aY,
nsIFrame* aForChild, PRUint32 aFlags)
{
nsSVGEffects::InvalidateDirectRenderingObservers(this);
if (nsSVGIntegrationUtils::UsingEffectsForFrame(this)) {
nsRect r = nsSVGIntegrationUtils::GetInvalidAreaForChangedSource(this,
aDamageRect + nsPoint(aX, aY));
/* Rectangle is now in our own local space, so aX and aY are effectively
* zero. Thus we'll pretend that the entire time this was in our own
* local coordinate space and do any remaining processing.
*/
InvalidateInternalAfterResize(r, 0, 0, aFlags);
return;
}
InvalidateInternalAfterResize(aDamageRect, aX, aY, aFlags);
}
gfx3DMatrix
nsIFrame::GetTransformMatrix(nsIFrame* aStopAtAncestor,
nsIFrame** aOutAncestor)
@ -4586,112 +4736,63 @@ nsIFrame::GetTransformMatrix(nsIFrame* aStopAtAncestor,
}
void
nsIFrame::InvalidateFrameSubtree(PRUint32 aFlags)
nsIFrame::InvalidateRectDifference(const nsRect& aR1, const nsRect& aR2)
{
InvalidateFrame(aFlags);
if (HasAnyStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT)) {
return;
}
AddStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT);
nsAutoTArray<nsIFrame::ChildList,4> childListArray;
GetCrossDocChildLists(&childListArray);
nsIFrame::ChildListArrayIterator lists(childListArray);
for (; !lists.IsDone(); lists.Next()) {
nsFrameList::Enumerator childFrames(lists.CurrentList());
for (; !childFrames.AtEnd(); childFrames.Next()) {
childFrames.get()->
InvalidateFrameSubtree(aFlags | INVALIDATE_DONT_SCHEDULE_PAINT);
}
}
nsRect sizeHStrip, sizeVStrip;
nsLayoutUtils::GetRectDifferenceStrips(aR1, aR2, &sizeHStrip, &sizeVStrip);
Invalidate(sizeVStrip);
Invalidate(sizeHStrip);
}
void
nsIFrame::ClearInvalidationStateBits()
nsIFrame::InvalidateFrameSubtree()
{
if (HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) {
nsAutoTArray<nsIFrame::ChildList,4> childListArray;
GetCrossDocChildLists(&childListArray);
nsIFrame::ChildListArrayIterator lists(childListArray);
for (; !lists.IsDone(); lists.Next()) {
nsFrameList::Enumerator childFrames(lists.CurrentList());
for (; !childFrames.AtEnd(); childFrames.Next()) {
childFrames.get()->ClearInvalidationStateBits();
}
}
}
RemoveStateBits(NS_FRAME_NEEDS_PAINT |
NS_FRAME_DESCENDANT_NEEDS_PAINT |
NS_FRAME_ALL_DESCENDANTS_NEED_PAINT);
Invalidate(GetVisualOverflowRectRelativeToSelf());
FrameLayerBuilder::InvalidateThebesLayersInSubtree(this);
}
void
nsIFrame::InvalidateFrame(PRUint32 aFlags)
nsIFrame::InvalidateOverflowRect()
{
AddStateBits(NS_FRAME_NEEDS_PAINT);
nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(this);
while (parent && !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) {
parent->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
}
if (!(aFlags & INVALIDATE_DONT_SCHEDULE_PAINT)) {
SchedulePaint();
}
}
bool
nsIFrame::IsInvalid()
{
return HasAnyStateBits(NS_FRAME_NEEDS_PAINT);
}
void
nsIFrame::SchedulePaint(PRUint32 aFlags)
{
nsPresContext *pres = PresContext()->GetRootPresContext();
if (HasAnyStateBits(NS_FRAME_IN_POPUP) || !pres) {
nsIFrame *displayRoot = nsLayoutUtils::GetDisplayRootFrame(this);
NS_ASSERTION(displayRoot, "Need a display root to schedule a paint!");
if (!displayRoot) {
return;
}
pres = displayRoot->PresContext();
}
pres->PresShell()->ScheduleViewManagerFlush(aFlags);
}
Layer*
nsIFrame::InvalidateLayer(PRUint32 aDisplayItemKey, const nsIntRect* aDamageRect)
{
NS_ASSERTION(aDisplayItemKey > 0, "Need a key");
Layer* layer = FrameLayerBuilder::GetDedicatedLayer(this, aDisplayItemKey);
if (aDamageRect && aDamageRect->IsEmpty()) {
return layer;
}
if (!layer) {
InvalidateFrame();
return nsnull;
}
if (aDamageRect) {
layer->AddInvalidRect(*aDamageRect);
} else {
layer->SetInvalidRectToVisibleRegion();
}
SchedulePaint(PAINT_COMPOSITE_ONLY);
return layer;
Invalidate(GetVisualOverflowRectRelativeToSelf());
}
NS_DECLARE_FRAME_PROPERTY(DeferInvalidatesProperty, nsIFrame::DestroyRegion)
void
nsIFrame::InvalidateRoot(const nsRect& aDamageRect, PRUint32 aFlags)
{
NS_ASSERTION(nsLayoutUtils::GetDisplayRootFrame(this) == this,
"Can only call this on display roots");
if ((mState & NS_FRAME_HAS_CONTAINER_LAYER) &&
!(aFlags & INVALIDATE_NO_THEBES_LAYERS)) {
FrameLayerBuilder::InvalidateThebesLayerContents(this, aDamageRect);
if (aFlags & INVALIDATE_ONLY_THEBES_LAYERS) {
return;
}
}
nsRect rect = aDamageRect;
nsRegion* excludeRegion = static_cast<nsRegion*>
(Properties().Get(DeferInvalidatesProperty()));
if (excludeRegion && (aFlags & INVALIDATE_EXCLUDE_CURRENT_PAINT)) {
nsRegion r;
r.Sub(rect, *excludeRegion);
if (r.IsEmpty())
return;
rect = r.GetBounds();
}
if (!(aFlags & INVALIDATE_NO_UPDATE_LAYER_TREE)) {
AddStateBits(NS_FRAME_UPDATE_LAYER_TREE);
}
nsIView* view = GetView();
NS_ASSERTION(view, "This can only be called on frames with views");
view->GetViewManager()->InvalidateViewNoSuppression(view, rect);
}
void
nsIFrame::BeginDeferringInvalidatesForDisplayRoot(const nsRegion& aExcludeRegion)
{
@ -4930,6 +5031,107 @@ nsFrame::UpdateOverflow()
return false;
}
void
nsFrame::CheckInvalidateSizeChange(nsHTMLReflowMetrics& aNewDesiredSize)
{
nsIFrame::CheckInvalidateSizeChange(mRect, GetVisualOverflowRect(),
nsSize(aNewDesiredSize.width, aNewDesiredSize.height));
}
static void
InvalidateRectForFrameSizeChange(nsIFrame* aFrame, const nsRect& aRect)
{
nsStyleContext *bgSC;
if (!nsCSSRendering::FindBackground(aFrame->PresContext(), aFrame, &bgSC)) {
nsIFrame* rootFrame =
aFrame->PresContext()->PresShell()->FrameManager()->GetRootFrame();
rootFrame->Invalidate(nsRect(nsPoint(0, 0), rootFrame->GetSize()));
}
aFrame->Invalidate(aRect);
}
void
nsIFrame::CheckInvalidateSizeChange(const nsRect& aOldRect,
const nsRect& aOldVisualOverflowRect,
const nsSize& aNewDesiredSize)
{
if (aNewDesiredSize == aOldRect.Size())
return;
// Below, we invalidate the old frame area (or, in the case of
// outline, combined area) if the outline, border or background
// settings indicate that something other than the difference
// between the old and new areas needs to be painted. We are
// assuming that the difference between the old and new areas will
// be invalidated by some other means. That also means invalidating
// the old frame area is the same as invalidating the new frame area
// (since in either case the UNION of old and new areas will be
// invalidated)
// We use InvalidateRectForFrameSizeChange throughout this method, even
// though root-invalidation is technically only needed in the case where
// layer.RenderingMightDependOnFrameSize(). This allows us to simplify the
// code somewhat and return immediately after invalidation in the earlier
// cases.
// Invalidate the entire old frame+outline if the frame has an outline
bool anyOutlineOrEffects;
nsRect r = ComputeOutlineAndEffectsRect(this, &anyOutlineOrEffects,
aOldVisualOverflowRect,
aNewDesiredSize,
false);
if (anyOutlineOrEffects) {
r.UnionRect(aOldVisualOverflowRect, r);
InvalidateRectForFrameSizeChange(this, r);
return;
}
// Invalidate the old frame border box if the frame has borders. Those
// borders may be moving.
const nsStyleBorder* border = GetStyleBorder();
NS_FOR_CSS_SIDES(side) {
if (border->GetComputedBorderWidth(side) != 0) {
if ((side == NS_SIDE_LEFT || side == NS_SIDE_TOP) &&
!nsLayoutUtils::HasNonZeroCornerOnSide(border->mBorderRadius, side) &&
!border->GetBorderImage() &&
border->GetBorderStyle(side) == NS_STYLE_BORDER_STYLE_SOLID) {
// We also need to be sure that the bottom-left or top-right
// corner is simple. For example, if the bottom or right border
// has a different color, we would need to invalidate the corner
// area. But that's OK because if there is a right or bottom border,
// we'll invalidate the entire border-box here anyway.
continue;
}
InvalidateRectForFrameSizeChange(this, nsRect(0, 0, aOldRect.width, aOldRect.height));
return;
}
}
const nsStyleBackground *bg = GetStyleBackground();
if (!bg->IsTransparent()) {
// Invalidate the old frame background if the frame has a background
// whose position depends on the size of the frame
NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) {
const nsStyleBackground::Layer &layer = bg->mLayers[i];
if (layer.RenderingMightDependOnFrameSize()) {
InvalidateRectForFrameSizeChange(this, nsRect(0, 0, aOldRect.width, aOldRect.height));
return;
}
}
// Invalidate the old frame background if the frame has a background
// that is being clipped by border-radius, since the old or new area
// clipped off by the radius is not necessarily in the area that has
// already been invalidated (even if only the top-left corner has a
// border radius).
if (nsLayoutUtils::HasNonZeroCorner(border->mBorderRadius)) {
InvalidateRectForFrameSizeChange(this, nsRect(0, 0, aOldRect.width, aOldRect.height));
return;
}
}
}
// Define the MAX_FRAME_DEPTH to be the ContentSink's MAX_REFLOW_DEPTH plus
// 4 for the frames above the document's frames:
// the Viewport, GFXScroll, ScrollPort, and Canvas
@ -6665,7 +6867,7 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
// If there is no outline or other effects now, then we don't have
// to do anything here since removing those styles can't require
// repainting of areas that weren't in the old overflow area.
InvalidateFrame();
Invalidate(aOverflowAreas.VisualOverflow());
} else if (hasClipPropClip || didHaveClipPropClip) {
// If we are (or were) clipped by the 'clip' property, and our
// overflow area changes, it might be because the clipping changed.
@ -6673,9 +6875,31 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
// repaint the old overflow area, so if the overflow area has
// changed (in particular, if it grows), we have to repaint the
// new area here.
InvalidateFrame();
Invalidate(aOverflowAreas.VisualOverflow());
}
}
// XXXSDL For SVG the invalidation happens in UpdateBounds for now, so we
// don't currently invalidate SVG here:
if (anyOverflowChanged && hasTransform &&
!(GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
// When there's a transform, changes to that style might require
// repainting of the old and new overflow areas in the widget.
// Repainting of the frame itself will not be required if there's
// a retained layer, so we can call InvalidateLayer here
// which will avoid repainting ThebesLayers if possible.
// nsCSSFrameConstructor::DoApplyRenderingChangeToTree repaints
// the old overflow area in the widget in response to
// nsChangeHint_UpdateTransformLayer. But since the new overflow
// area is not known at that time, we have to handle it here.
// If the overflow area hasn't changed, then it doesn't matter that
// we didn't reach here since repainting the old overflow area was enough.
// If there is no transform now, then the container layer for
// the transform will go away and the frame contents will change
// ThebesLayers, forcing it to be invalidated, so it doesn't matter
// that we didn't reach here.
InvalidateLayer(aOverflowAreas.VisualOverflow(),
nsDisplayItem::TYPE_TRANSFORM);
}
return anyOverflowChanged;
}
@ -7152,8 +7376,11 @@ nsFrame::RefreshSizeCache(nsBoxLayoutState& aState)
if (!DoesNeedRecalc(metrics->mBlockPrefSize))
return NS_OK;
// get the old rect.
nsRect oldRect = GetRect();
// the rect we plan to size to.
nsRect rect = GetRect();
nsRect rect(oldRect);
nsMargin bp(0,0,0,0);
GetBorderAndPadding(bp);
@ -7175,6 +7402,15 @@ nsFrame::RefreshSizeCache(nsBoxLayoutState& aState)
rect.x, rect.y,
metrics->mBlockPrefSize.width, NS_UNCONSTRAINEDSIZE);
nsRect newRect = GetRect();
// make sure we draw any size change
if (oldRect.width != newRect.width || oldRect.height != newRect.height) {
newRect.x = 0;
newRect.y = 0;
Redraw(aState, &newRect);
}
metrics->mBlockMinSize.height = 0;
// ok we need the max ascent of the items on the line. So to do this
// ask the block for its line iterator. Get the max ascent.
@ -7688,55 +7924,6 @@ nsFrame::BoxMetrics() const
return metrics;
}
/**
* Adds the NS_FRAME_IN_POPUP state bit to the current frame,
* and all descendant frames (including cross-doc ones).
*/
static void
AddInPopupStateBitToDescendants(nsIFrame* aFrame)
{
aFrame->AddStateBits(NS_FRAME_IN_POPUP);
nsAutoTArray<nsIFrame::ChildList,4> childListArray;
aFrame->GetCrossDocChildLists(&childListArray);
nsIFrame::ChildListArrayIterator lists(childListArray);
for (; !lists.IsDone(); lists.Next()) {
nsFrameList::Enumerator childFrames(lists.CurrentList());
for (; !childFrames.AtEnd(); childFrames.Next()) {
AddInPopupStateBitToDescendants(childFrames.get());
}
}
}
/**
* Removes the NS_FRAME_IN_POPUP state bit from the current
* frames and all descendant frames (including cross-doc ones),
* unless the frame is a popup itself.
*/
static void
RemoveInPopupStateBitFromDescendants(nsIFrame* aFrame)
{
if (!aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP) ||
aFrame->GetType() == nsGkAtoms::listControlFrame ||
aFrame->GetType() == nsGkAtoms::menuPopupFrame) {
return;
}
aFrame->RemoveStateBits(NS_FRAME_IN_POPUP);
nsAutoTArray<nsIFrame::ChildList,4> childListArray;
aFrame->GetCrossDocChildLists(&childListArray);
nsIFrame::ChildListArrayIterator lists(childListArray);
for (; !lists.IsDone(); lists.Next()) {
nsFrameList::Enumerator childFrames(lists.CurrentList());
for (; !childFrames.AtEnd(); childFrames.Next()) {
RemoveInPopupStateBitFromDescendants(childFrames.get());
}
}
}
void
nsFrame::SetParent(nsIFrame* aParent)
{
@ -7755,26 +7942,13 @@ nsFrame::SetParent(nsIFrame* aParent)
f->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
}
}
if (HasInvalidFrameInSubtree()) {
for (nsIFrame* f = aParent;
f && !f->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
f->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
}
}
if (aParent->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
AddInPopupStateBitToDescendants(this);
} else {
RemoveInPopupStateBitFromDescendants(this);
}
// If our new parent only has invalid children, then we just invalidate
// ourselves too. This is probably faster than clearing the flag all
// the way up the frame tree.
if (aParent->HasAnyStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT)) {
InvalidateFrame(INVALIDATE_DONT_SCHEDULE_PAINT);
if (GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT) {
for (nsIFrame* f = aParent;
f && !(f->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT);
f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
f->AddStateBits(NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT);
}
}
}

View File

@ -363,6 +363,16 @@ public:
//--------------------------------------------------
// Additional methods
/**
* Helper method to invalidate portions of a standard container frame if the
* desired size indicates that the size has changed (specifically border,
* background and outline).
* We assume that the difference between the old frame area and the new
* frame area is invalidated by some other means.
* @param aDesiredSize the new size of the frame
*/
void CheckInvalidateSizeChange(nsHTMLReflowMetrics& aNewDesiredSize);
// Helper function that tests if the frame tree is too deep; if it is
// it marks the frame as "unflowable", zeroes out the metrics, sets
// the reflow status, and returns true. Otherwise, the frame is

Some files were not shown because too many files have changed in this diff Show More