Bug 1545516 - Don't flush parent document layout for detached frames from EnsureSizeAndPositionUpToDate. r=dholbert,bzbarsky

And add a test for the same not happening already for normal flushes.

Differential Revision: https://phabricator.services.mozilla.com/D28192

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Emilio Cobos Álvarez 2019-04-20 14:41:55 +00:00
Родитель 52b651e168
Коммит 0750826c4b
3 изменённых файлов: 48 добавлений и 3 удалений

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

@ -7357,9 +7357,13 @@ void nsGlobalWindowOuter::EnsureSizeAndPositionUpToDate() {
// If we're a subframe, make sure our size is up to date. It's OK that this
// crosses the content/chrome boundary, since chrome can have pending reflows
// too.
nsGlobalWindowOuter* parent = nsGlobalWindowOuter::Cast(GetPrivateParent());
if (parent) {
parent->FlushPendingNotifications(FlushType::Layout);
//
// Make sure to go through the document chain rather than the window chain to
// not flush on detached iframes, see bug 1545516.
if (mDoc) {
if (RefPtr<Document> parent = mDoc->GetParentDocument()) {
parent->FlushPendingNotifications(FlushType::Layout);
}
}
}

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

@ -225,6 +225,7 @@ support-files = flexbox_layout_testcases.js
[test_flexbox_order_table.html]
[test_flexbox_reflow_counts.html]
skip-if = verify
[test_flushing_frame.html]
[test_font_face_cascade.html]
[test_font_face_parser.html]
[test_font_family_parsing.html]

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

@ -0,0 +1,40 @@
<!doctype html>
<meta charset="utf-8">
<title>
Test for bug 1545516: We don't flush layout unnecessarily on the parent
document when the frame is already disconnected.
</title>
<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<div id="content"></div>
<script>
SimpleTest.waitForExplicitFinish();
const iframe = document.createElement("iframe");
const content = document.querySelector("#content");
const parentUtils = SpecialPowers.getDOMWindowUtils(window);
iframe.onload = function() {
const win = iframe.contentWindow;
iframe.offsetTop; // flush layout
content.style.display = "inline"; // Dirty style with something that will reframe.
const previousConstructCount = parentUtils.framesConstructed;
let pagehideRan = false;
win.addEventListener("pagehide", function() {
pagehideRan = true;
win.foo = win.innerWidth;
is(parentUtils.framesConstructed, previousConstructCount, "innerWidth shouldn't have flushed parent document layout")
win.bar = win.document.documentElement.offsetHeight;
is(parentUtils.framesConstructed, previousConstructCount, "offsetHeight shouldn't have flushed parent document layout")
win.baz = win.getComputedStyle(win.document.documentElement).color;
is(parentUtils.framesConstructed, previousConstructCount, "getComputedStyle shouldn't have flushed parent document layout")
});
iframe.remove(); // Remove the iframe
is(pagehideRan, true, "pagehide handler should've ran");
is(parentUtils.framesConstructed, previousConstructCount, "Nothing should've flushed the parent document layout yet");
content.offsetTop;
isnot(parentUtils.framesConstructed, previousConstructCount, "We should've flushed layout now");
SimpleTest.finish();
};
document.body.appendChild(iframe);
</script>