browser/base/content/test/general/browser_tabopen_reflows.js

branch
TOR_BUG_3246
changeset 6
8bccb770b82d
equal deleted inserted replaced
-1:000000000000 0:50b79cd9dfd3
1 /* Any copyright is dedicated to the Public Domain.
2 http://creativecommons.org/publicdomain/zero/1.0/ */
3
4 XPCOMUtils.defineLazyGetter(this, "docShell", () => {
5 return window.QueryInterface(Ci.nsIInterfaceRequestor)
6 .getInterface(Ci.nsIWebNavigation)
7 .QueryInterface(Ci.nsIDocShell);
8 });
9
10 const EXPECTED_REFLOWS = [
11 // tabbrowser.adjustTabstrip() call after tabopen animation has finished
12 "adjustTabstrip@chrome://browser/content/tabbrowser.xml|" +
13 "_handleNewTab@chrome://browser/content/tabbrowser.xml|" +
14 "onxbltransitionend@chrome://browser/content/tabbrowser.xml|",
15
16 // switching focus in updateCurrentBrowser() causes reflows
17 "updateCurrentBrowser@chrome://browser/content/tabbrowser.xml|" +
18 "onselect@chrome://browser/content/browser.xul|",
19
20 // switching focus in openLinkIn() causes reflows
21 "openLinkIn@chrome://browser/content/utilityOverlay.js|" +
22 "openUILinkIn@chrome://browser/content/utilityOverlay.js|" +
23 "BrowserOpenTab@chrome://browser/content/browser.js|",
24
25 // accessing element.scrollPosition in _fillTrailingGap() flushes layout
26 "get_scrollPosition@chrome://global/content/bindings/scrollbox.xml|" +
27 "_fillTrailingGap@chrome://browser/content/tabbrowser.xml|" +
28 "_handleNewTab@chrome://browser/content/tabbrowser.xml|" +
29 "onxbltransitionend@chrome://browser/content/tabbrowser.xml|",
30
31 // The TabView iframe causes reflows in the parent document.
32 "iQClass_height@chrome://browser/content/tabview.js|" +
33 "GroupItem_getContentBounds@chrome://browser/content/tabview.js|" +
34 "GroupItem_shouldStack@chrome://browser/content/tabview.js|" +
35 "GroupItem_arrange@chrome://browser/content/tabview.js|" +
36 "GroupItem_add@chrome://browser/content/tabview.js|" +
37 "GroupItems_newTab@chrome://browser/content/tabview.js|" +
38 "TabItem__reconnect@chrome://browser/content/tabview.js|" +
39 "TabItem@chrome://browser/content/tabview.js|" +
40 "TabItems_link@chrome://browser/content/tabview.js|" +
41 "TabItems_init/this._eventListeners.open@chrome://browser/content/tabview.js|",
42
43 // SessionStore.getWindowDimensions()
44 "ssi_getWindowDimension@resource:///modules/sessionstore/SessionStore.jsm|" +
45 "ssi_updateWindowFeatures/<@resource:///modules/sessionstore/SessionStore.jsm|" +
46 "ssi_updateWindowFeatures@resource:///modules/sessionstore/SessionStore.jsm|" +
47 "ssi_collectWindowData@resource:///modules/sessionstore/SessionStore.jsm|",
48
49 // tabPreviews.capture()
50 "tabPreviews_capture@chrome://browser/content/browser.js|" +
51 "tabPreviews_handleEvent/<@chrome://browser/content/browser.js|",
52
53 // tabPreviews.capture()
54 "tabPreviews_capture@chrome://browser/content/browser.js|" +
55 "@chrome://browser/content/browser.js|"
56 ];
57
58 const PREF_PRELOAD = "browser.newtab.preload";
59 const PREF_NEWTAB_DIRECTORYSOURCE = "browser.newtabpage.directorySource";
60
61 /*
62 * This test ensures that there are no unexpected
63 * uninterruptible reflows when opening new tabs.
64 */
65 function test() {
66 waitForExplicitFinish();
67
68 Services.prefs.setBoolPref(PREF_PRELOAD, false);
69 Services.prefs.setCharPref(PREF_NEWTAB_DIRECTORYSOURCE, "data:application/json,{}");
70 registerCleanupFunction(() => {
71 Services.prefs.clearUserPref(PREF_PRELOAD);
72 Services.prefs.clearUserPref(PREF_NEWTAB_DIRECTORYSOURCE);
73 });
74
75 // Add a reflow observer and open a new tab.
76 docShell.addWeakReflowObserver(observer);
77 BrowserOpenTab();
78
79 // Wait until the tabopen animation has finished.
80 waitForTransitionEnd(function () {
81 // Remove reflow observer and clean up.
82 docShell.removeWeakReflowObserver(observer);
83 gBrowser.removeCurrentTab();
84
85 finish();
86 });
87 }
88
89 let observer = {
90 reflow: function (start, end) {
91 // Gather information about the current code path.
92 let path = (new Error().stack).split("\n").slice(1).map(line => {
93 return line.replace(/:\d+:\d+$/, "");
94 }).join("|");
95 let pathWithLineNumbers = (new Error().stack).split("\n").slice(1).join("|");
96
97 // Stack trace is empty. Reflow was triggered by native code.
98 if (path === "") {
99 return;
100 }
101
102 // Check if this is an expected reflow.
103 for (let stack of EXPECTED_REFLOWS) {
104 if (path.startsWith(stack)) {
105 ok(true, "expected uninterruptible reflow '" + stack + "'");
106 return;
107 }
108 }
109
110 ok(false, "unexpected uninterruptible reflow '" + pathWithLineNumbers + "'");
111 },
112
113 reflowInterruptible: function (start, end) {
114 // We're not interested in interruptible reflows.
115 },
116
117 QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver,
118 Ci.nsISupportsWeakReference])
119 };
120
121 function waitForTransitionEnd(callback) {
122 let tab = gBrowser.selectedTab;
123 tab.addEventListener("transitionend", function onEnd(event) {
124 if (event.propertyName === "max-width") {
125 tab.removeEventListener("transitionend", onEnd);
126 executeSoon(callback);
127 }
128 });
129 }

mercurial