mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-10-09 16:55:15 +00:00
158 lines
5.9 KiB
JavaScript
158 lines
5.9 KiB
JavaScript
|
/* 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();
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
}
|