diff --git a/dom/base/nsGlobalWindowInner.cpp b/dom/base/nsGlobalWindowInner.cpp index 5b7a5c936e05..85c91cf6dcc3 100644 --- a/dom/base/nsGlobalWindowInner.cpp +++ b/dom/base/nsGlobalWindowInner.cpp @@ -6635,20 +6635,6 @@ void nsGlobalWindowInner::BeginWindowMove(Event& aMouseDownEvent, aError = widget->BeginMoveDrag(mouseEvent); } -static bool CheckSubframesNeedLayoutOrStyleFlush(Document* aDoc, void* aData) { - nsIPresShell* shell = aDoc->GetShell(); - if (shell) { - bool* needFlush = static_cast(aData); - - if (shell->NeedStyleFlush() || shell->NeedLayoutFlush()) { - *needFlush = true; - return false; - } - } - aDoc->EnumerateSubDocuments(CheckSubframesNeedLayoutOrStyleFlush, aData); - return true; -} - already_AddRefed nsGlobalWindowInner::PromiseDocumentFlushed( PromiseDocumentFlushedCallback& aCallback, ErrorResult& aError) { MOZ_RELEASE_ASSERT(IsChromeWindow()); @@ -6692,14 +6678,7 @@ already_AddRefed nsGlobalWindowInner::PromiseDocumentFlushed( UniquePtr flushResolver( new PromiseDocumentFlushedResolver(resultPromise, aCallback)); - // Check to see if any of the subdocuments need a style or - // layout flush too. - bool subframeNeedsFlush = false; - mDoc->EnumerateSubDocuments(CheckSubframesNeedLayoutOrStyleFlush, - &subframeNeedsFlush); - - if (!shell->NeedStyleFlush() && !shell->NeedLayoutFlush() && - !subframeNeedsFlush) { + if (!shell->NeedStyleFlush() && !shell->NeedLayoutFlush()) { flushResolver->Call(); return resultPromise.forget(); } @@ -6786,14 +6765,7 @@ void nsGlobalWindowInner::DidRefresh() { nsIPresShell* shell = mDoc->GetShell(); MOZ_ASSERT(shell); - // Check to see if any of the subdocuments need a style or - // layout flush too. - bool subframeNeedsFlush = false; - mDoc->EnumerateSubDocuments(CheckSubframesNeedLayoutOrStyleFlush, - &subframeNeedsFlush); - - if (shell->NeedStyleFlush() || shell->NeedLayoutFlush() || - subframeNeedsFlush) { + if (shell->NeedStyleFlush() || shell->NeedLayoutFlush()) { // By the time our observer fired, something has already invalidated // style or layout - or perhaps we're still in the middle of a flush that // was interrupted. In either case, we'll wait until the next refresh driver diff --git a/dom/base/test/browser_promiseDocumentFlushed.js b/dom/base/test/browser_promiseDocumentFlushed.js index ff57d747343e..c0678437b32b 100644 --- a/dom/base/test/browser_promiseDocumentFlushed.js +++ b/dom/base/test/browser_promiseDocumentFlushed.js @@ -22,14 +22,16 @@ function dirtyStyle() { gNavToolbox.style.color = "red"; } +const gWindowUtils = window.windowUtils; + /** * Asserts that no style or layout flushes are required by the * current window. */ -function assertNoFlushesRequired(win = window) { - Assert.ok(!win.windowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_STYLE), +function assertNoFlushesRequired() { + Assert.ok(!gWindowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_STYLE), "No style flushes are required."); - Assert.ok(!win.windowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_LAYOUT), + Assert.ok(!gWindowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_LAYOUT), "No layout flushes are required."); } @@ -37,55 +39,13 @@ function assertNoFlushesRequired(win = window) { * Asserts that the DOM has been dirtied, and so style and layout flushes * are required. */ -function assertFlushesRequired(win = window) { - Assert.ok(win.windowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_STYLE), +function assertFlushesRequired() { + Assert.ok(gWindowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_STYLE), "Style flush required."); - Assert.ok(win.windowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_LAYOUT), + Assert.ok(gWindowUtils.needsFlush(Ci.nsIDOMWindowUtils.FLUSH_LAYOUT), "Layout flush required."); } -/** - * Asserts that a window will not incur any layout flushes when - * running function fn. - * - * @param win (DOM window) - * The window that we expect to not see any layout flushes for. - * @param fn (function) - * The function to synchronously call while monitoring for - * layout flushes. - */ -function assertFunctionDoesNotFlushLayout(win, fn) { - let sawReflow = false; - - let observer = { - reflow(start, end) { - Assert.ok(false, "Saw a reflow when one was not expected"); - dump("Stack: " + new Error().stack + "\n"); - sawReflow = true; - }, - - reflowInterruptible(start, end) { - // Interruptible reflows are the reflows caused by the refresh - // driver ticking. These are fine. - }, - - QueryInterface: ChromeUtils.generateQI([Ci.nsIReflowObserver, - Ci.nsISupportsWeakReference]), - }; - - let docShell = win.docShell; - docShell.addWeakReflowObserver(observer); - - try { - fn(); - if (!sawReflow) { - Assert.ok(true, "Did not see any reflows."); - } - } finally { - docShell.removeWeakReflowObserver(observer); - } -} - /** * Removes style changes from dirtyTheDOM() from the browser window, * and resolves once the refresh driver ticks. @@ -283,55 +243,4 @@ add_task(async function test_execution_order() { Assert.equal(result[i], i, "Callbacks and Promises should have run in the expected order."); } - - await cleanTheDOM(); -}); - -/** - * Tests that if there's a subframe that needs a layout - * flush, that promiseDocumentFlushed will detect it, and - * wait until it doesn't before calling the callback. - */ -add_task(async function test_subframe_flushes() { - const DUMMY_PAGE = getRootDirectory(gTestPath); - const PAGE_NAME = "parent-document-flushed"; - const ABOUT_PAGE = `about:${PAGE_NAME}`; - - // For simplicity, we're forcing a non-remote browser here. This is so - // that we can easily load some subframes that could theoretically - // cause a flush to occur in the parent process. - await BrowserTestUtils.registerAboutPage(registerCleanupFunction, - PAGE_NAME, DUMMY_PAGE, 0); - await BrowserTestUtils.withNewTab({ - gBrowser, - url: ABOUT_PAGE, - }, async browser => { - Assert.ok(!browser.isRemoteBrowser, "Should have a non-remote browser."); - // We'll nest a frame within a frame to test that promiseDocumentFlushed - // isn't just checking the associated windows immediate children. - let outerContent = browser.contentWindow; - let outerDoc = browser.contentDocument; - let iframe = outerDoc.createElement("iframe"); - iframe.src = ABOUT_PAGE; - let loaded = BrowserTestUtils.waitForEvent(iframe, "load"); - outerDoc.body.appendChild(iframe); - await loaded; - - let innerContent = iframe.contentWindow; - let innerDoc = iframe.contentDocument; - let target = innerDoc.body; - Assert.ok(target); - - assertNoFlushesRequired(outerContent); - await window.promiseDocumentFlushed(() => {}); - - target.style.width = "5px"; - assertNoFlushesRequired(outerContent); - assertFlushesRequired(innerContent); - await window.promiseDocumentFlushed(() => { - assertFunctionDoesNotFlushLayout(innerContent, () => { - target.getBoundingClientRect(); - }); - }); - }); }); diff --git a/dom/webidl/Window.webidl b/dom/webidl/Window.webidl index 337f6ff4d950..5cb941d9072c 100644 --- a/dom/webidl/Window.webidl +++ b/dom/webidl/Window.webidl @@ -467,9 +467,8 @@ partial interface Window { /** * Calls the given function as soon as a style or layout flush for the - * top-level document (and all subframe descendants of it) are not - * necessary, and returns a Promise which resolves to the callback's - * return value after it executes. + * top-level document is not necessary, and returns a Promise which + * resolves to the callback's return value after it executes. * * In the event that the window goes away before a flush can occur, the * callback will still be called and the Promise resolved as the window