diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /browser/base/content/test/general/browser_tabopen_reflows.js | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'browser/base/content/test/general/browser_tabopen_reflows.js')
-rw-r--r-- | browser/base/content/test/general/browser_tabopen_reflows.js | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/browser/base/content/test/general/browser_tabopen_reflows.js b/browser/base/content/test/general/browser_tabopen_reflows.js new file mode 100644 index 000000000..8e04cf12e --- /dev/null +++ b/browser/base/content/test/general/browser_tabopen_reflows.js @@ -0,0 +1,157 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +XPCOMUtils.defineLazyGetter(this, "docShell", () => { + return window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShell); +}); + +const EXPECTED_REFLOWS = [ + // tabbrowser.adjustTabstrip() call after tabopen animation has finished + "adjustTabstrip@chrome://browser/content/tabbrowser.xml|" + + "_handleNewTab@chrome://browser/content/tabbrowser.xml|" + + "onxbltransitionend@chrome://browser/content/tabbrowser.xml|", + + // switching focus in updateCurrentBrowser() causes reflows + "_adjustFocusAfterTabSwitch@chrome://browser/content/tabbrowser.xml|" + + "updateCurrentBrowser@chrome://browser/content/tabbrowser.xml|" + + "onselect@chrome://browser/content/browser.xul|", + + // switching focus in openLinkIn() causes reflows + "openLinkIn@chrome://browser/content/utilityOverlay.js|" + + "openUILinkIn@chrome://browser/content/utilityOverlay.js|" + + "BrowserOpenTab@chrome://browser/content/browser.js|", + + // accessing element.scrollPosition in _fillTrailingGap() flushes layout + "get_scrollPosition@chrome://global/content/bindings/scrollbox.xml|" + + "_fillTrailingGap@chrome://browser/content/tabbrowser.xml|" + + "_handleNewTab@chrome://browser/content/tabbrowser.xml|" + + "onxbltransitionend@chrome://browser/content/tabbrowser.xml|", + + // SessionStore.getWindowDimensions() + "ssi_getWindowDimension@resource:///modules/sessionstore/SessionStore.jsm|" + + "ssi_updateWindowFeatures/<@resource:///modules/sessionstore/SessionStore.jsm|" + + "ssi_updateWindowFeatures@resource:///modules/sessionstore/SessionStore.jsm|" + + "ssi_collectWindowData@resource:///modules/sessionstore/SessionStore.jsm|", + + // selection change notification may cause querying the focused editor content + // by IME and that will cause reflow. + "select@chrome://global/content/bindings/textbox.xml|" + + "focusAndSelectUrlBar@chrome://browser/content/browser.js|" + + "openLinkIn@chrome://browser/content/utilityOverlay.js|" + + "openUILinkIn@chrome://browser/content/utilityOverlay.js|" + + "BrowserOpenTab@chrome://browser/content/browser.js|", + +]; + +const PREF_PRELOAD = "browser.newtab.preload"; +const PREF_NEWTAB_DIRECTORYSOURCE = "browser.newtabpage.directory.source"; + +/* + * This test ensures that there are no unexpected + * uninterruptible reflows when opening new tabs. + */ +add_task(function*() { + let DirectoryLinksProvider = Cu.import("resource:///modules/DirectoryLinksProvider.jsm", {}).DirectoryLinksProvider; + let NewTabUtils = Cu.import("resource://gre/modules/NewTabUtils.jsm", {}).NewTabUtils; + let Promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise; + + // resolves promise when directory links are downloaded and written to disk + function watchLinksChangeOnce() { + let deferred = Promise.defer(); + let observer = { + onManyLinksChanged: () => { + DirectoryLinksProvider.removeObserver(observer); + NewTabUtils.links.populateCache(() => { + NewTabUtils.allPages.update(); + deferred.resolve(); + }, true); + } + }; + observer.onDownloadFail = observer.onManyLinksChanged; + DirectoryLinksProvider.addObserver(observer); + return deferred.promise; + } + + let gOrigDirectorySource = Services.prefs.getCharPref(PREF_NEWTAB_DIRECTORYSOURCE); + registerCleanupFunction(() => { + Services.prefs.clearUserPref(PREF_PRELOAD); + Services.prefs.setCharPref(PREF_NEWTAB_DIRECTORYSOURCE, gOrigDirectorySource); + return watchLinksChangeOnce(); + }); + + Services.prefs.setBoolPref(PREF_PRELOAD, false); + // set directory source to dummy/empty links + Services.prefs.setCharPref(PREF_NEWTAB_DIRECTORYSOURCE, 'data:application/json,{"test":1}'); + + // run tests when directory source change completes + yield watchLinksChangeOnce(); + + // Perform a click in the top left of content to ensure the mouse isn't + // hovering over any of the tiles + let target = gBrowser.selectedBrowser; + let rect = target.getBoundingClientRect(); + let left = rect.left + 1; + let top = rect.top + 1; + + let utils = window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0); + utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0); + + // Add a reflow observer and open a new tab. + docShell.addWeakReflowObserver(observer); + BrowserOpenTab(); + + // Wait until the tabopen animation has finished. + yield waitForTransitionEnd(); + + // Remove reflow observer and clean up. + docShell.removeWeakReflowObserver(observer); + gBrowser.removeCurrentTab(); +}); + +var observer = { + reflow: function (start, end) { + // Gather information about the current code path. + let path = (new Error().stack).split("\n").slice(1).map(line => { + return line.replace(/:\d+:\d+$/, ""); + }).join("|"); + let pathWithLineNumbers = (new Error().stack).split("\n").slice(1).join("|"); + + // Stack trace is empty. Reflow was triggered by native code. + if (path === "") { + return; + } + + // Check if this is an expected reflow. + for (let stack of EXPECTED_REFLOWS) { + if (path.startsWith(stack)) { + ok(true, "expected uninterruptible reflow '" + stack + "'"); + return; + } + } + + ok(false, "unexpected uninterruptible reflow '" + pathWithLineNumbers + "'"); + }, + + reflowInterruptible: function (start, end) { + // We're not interested in interruptible reflows. + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver, + Ci.nsISupportsWeakReference]) +}; + +function waitForTransitionEnd() { + return new Promise(resolve => { + let tab = gBrowser.selectedTab; + tab.addEventListener("transitionend", function onEnd(event) { + if (event.propertyName === "max-width") { + tab.removeEventListener("transitionend", onEnd); + resolve(); + } + }); + }); +} |