forked from mirrors/gecko-dev
		
	 7df117fdb9
			
		
	
	
		7df117fdb9
		
	
	
	
	
		
			
			--HG-- extra : commitid : LsM4DGXki7Q extra : rebase_source : 37969b5cbad6f656485554f336bccffc5a6e4994
		
			
				
	
	
		
			157 lines
		
	
	
	
		
			5.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			157 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();
 | |
|       }
 | |
|     });
 | |
|   });
 | |
| }
 |