diff --git a/browser/base/content/browser-fullZoom.js b/browser/base/content/browser-fullZoom.js index 574f384b935c..ebcaaa0e0911 100644 --- a/browser/base/content/browser-fullZoom.js +++ b/browser/base/content/browser-fullZoom.js @@ -10,15 +10,6 @@ // From nsEventStateManager.cpp. const MOUSE_SCROLL_ZOOM = 3; -Cu.import('resource://gre/modules/ContentPrefInstance.jsm'); - -function getContentPrefs(aWindow) { - let context = aWindow ? aWindow.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsILoadContext) : null; - return new ContentPrefInstance(context); -} - /** * Controls the "full zoom" setting and its site-specific preferences. */ @@ -26,17 +17,6 @@ var FullZoom = { // Identifies the setting in the content prefs database. name: "browser.content.full-zoom", - // The global value (if any) for the setting. Lazily loaded from the service - // when first requested, then updated by the pref change listener as it changes. - // If there is no global value, then this should be undefined. - get globalValue() { - var globalValue = getContentPrefs(gBrowser.contentDocument.defaultView).getPref(null, this.name); - if (typeof globalValue != "undefined") - globalValue = this._ensureValid(globalValue); - delete this.globalValue; - return this.globalValue = globalValue; - }, - // browser.zoom.siteSpecific preference cache _siteSpecificPref: undefined, @@ -64,7 +44,9 @@ var FullZoom = { window.addEventListener("DOMMouseScroll", this, false); // Register ourselves with the service so we know when our pref changes. - getContentPrefs().addObserver(this.name, this); + this._cps2 = Cc["@mozilla.org/content-pref/service;1"]. + getService(Ci.nsIContentPrefService2); + this._cps2.addObserverForName(this.name, this); this._siteSpecificPref = gPrefService.getBoolPref("browser.zoom.siteSpecific"); @@ -77,7 +59,7 @@ var FullZoom = { destroy: function FullZoom_destroy() { gPrefService.removeObserver("browser.zoom.", this); - getContentPrefs().removeObserver(this.name, this); + this._cps2.removeObserverForName(this.name, this); window.removeEventListener("DOMMouseScroll", this, false); }, @@ -133,7 +115,14 @@ var FullZoom = { // We have to call _applySettingToPref in a timeout because we handle // the event before the event state manager has a chance to apply the zoom // during nsEventStateManager::PostHandleEvent. - window.setTimeout(function (self) { self._applySettingToPref() }, 0, this); + // + // Since the zoom will have already been updated by the time + // _applySettingToPref is called, pass true to suppress updating the zoom + // again. Note that this is not an optimization: due to asynchronicity of + // the content preference service, the zoom may have been updated again by + // the time that onContentPrefSet is called as a result of this call to + // _applySettingToPref. + window.setTimeout(function (self) self._applySettingToPref(true), 0, this); }, // nsIObserver @@ -158,33 +147,53 @@ var FullZoom = { // nsIContentPrefObserver onContentPrefSet: function FullZoom_onContentPrefSet(aGroup, aName, aValue) { - let contentPrefs = getContentPrefs(gBrowser.contentDocument.defaultView); - if (aGroup == contentPrefs.grouper.group(gBrowser.currentURI)) - this._applyPrefToSetting(aValue); - else if (aGroup == null) { - this.globalValue = this._ensureValid(aValue); - - // If the current page doesn't have a site-specific preference, - // then its zoom should be set to the new global preference now that - // the global preference has changed. - if (!contentPrefs.hasPref(gBrowser.currentURI, this.name)) - this._applyPrefToSetting(); + if (this._ignoreNextOnContentPrefSet) { + delete this._ignoreNextOnContentPrefSet; + return; } + this._onContentPrefChanged(aGroup, aValue); }, onContentPrefRemoved: function FullZoom_onContentPrefRemoved(aGroup, aName) { - let contentPrefs = getContentPrefs(gBrowser.contentDocument.defaultView); - if (aGroup == contentPrefs.grouper.group(gBrowser.currentURI)) - this._applyPrefToSetting(); - else if (aGroup == null) { - this.globalValue = undefined; + this._onContentPrefChanged(aGroup, undefined); + }, - // If the current page doesn't have a site-specific preference, - // then its zoom should be set to the default preference now that - // the global preference has changed. - if (!contentPrefs.hasPref(gBrowser.currentURI, this.name)) - this._applyPrefToSetting(); + /** + * Appropriately updates the zoom level after a content preference has + * changed. + * + * @param aGroup The group of the changed preference. + * @param aValue The new value of the changed preference. Pass undefined to + * indicate the preference's removal. + */ + _onContentPrefChanged: function FullZoom__onContentPrefChanged(aGroup, aValue) { + if (!gBrowser.currentURI) + return; + + let domain = this._cps2.extractDomain(gBrowser.currentURI.spec); + if (aGroup) { + if (aGroup == domain) + this._applyPrefToSetting(aValue); + return; } + + this._globalValue = aValue === undefined ? aValue : + this._ensureValid(aValue); + + // If the current page doesn't have a site-specific preference, then its + // zoom should be set to the new global preference now that the global + // preference has changed. + let hasPref = false; + let ctxt = this._loadContextFromWindow(gBrowser.contentWindow); + this._cps2.getByDomainAndName(gBrowser.currentURI.spec, this.name, ctxt, { + handleResult: function () hasPref = true, + handleCompletion: function () { + if (!hasPref && + gBrowser.currentURI && + this._cps2.extractDomain(gBrowser.currentURI.spec) == domain) + this._applyPrefToSetting(); + }.bind(this) + }); }, // location change observer @@ -201,12 +210,16 @@ var FullZoom = { * (optional) browser object displaying the document */ onLocationChange: function FullZoom_onLocationChange(aURI, aIsTabSwitch, aBrowser) { - if (!aURI || (aIsTabSwitch && !this.siteSpecific)) + if (!aURI || (aIsTabSwitch && !this.siteSpecific)) { + this._notifyOnLocationChange(); return; + } // Avoid the cps roundtrip and apply the default/global pref. if (aURI.spec == "about:blank") { - this._applyPrefToSetting(undefined, aBrowser); + this._applyPrefToSetting(undefined, aBrowser, function () { + this._notifyOnLocationChange(); + }.bind(this)); return; } @@ -215,24 +228,32 @@ var FullZoom = { // Media documents should always start at 1, and are not affected by prefs. if (!aIsTabSwitch && browser.contentDocument.mozSyntheticDocument) { ZoomManager.setZoomForBrowser(browser, 1); + this._notifyOnLocationChange(); return; } - let contentPrefs = getContentPrefs(gBrowser.contentDocument.defaultView); - if (contentPrefs.hasCachedPref(aURI, this.name)) { - let zoomValue = contentPrefs.getPref(aURI, this.name); - this._applyPrefToSetting(zoomValue, browser); - } else { - var self = this; - contentPrefs.getPref(aURI, this.name, function (aResult) { - // Check that we're still where we expect to be in case this took a while. - // Null check currentURI, since the window may have been destroyed before - // we were called. - if (browser.currentURI && aURI.equals(browser.currentURI)) { - self._applyPrefToSetting(aResult, browser); - } - }); + let ctxt = this._loadContextFromWindow(browser.contentWindow); + let pref = this._cps2.getCachedByDomainAndName(aURI.spec, this.name, ctxt); + if (pref) { + this._applyPrefToSetting(pref.value, browser, function () { + this._notifyOnLocationChange(); + }.bind(this)); + return; } + + let value = undefined; + this._cps2.getByDomainAndName(aURI.spec, this.name, ctxt, { + handleResult: function (resultPref) value = resultPref.value, + handleCompletion: function () { + if (browser.currentURI && + this._cps2.extractDomain(browser.currentURI.spec) == + this._cps2.extractDomain(aURI.spec)) { + this._applyPrefToSetting(value, browser, function () { + this._notifyOnLocationChange(); + }.bind(this)); + } + }.bind(this) + }); }, // update state of zoom type menu item @@ -246,23 +267,43 @@ var FullZoom = { //**************************************************************************// // Setting & Pref Manipulation - reduce: function FullZoom_reduce() { + /** + * Reduces the zoom level of the page in the current browser. + * + * @param callback Optional. If given, it's asynchronously called when the + * zoom update completes. + */ + reduce: function FullZoom_reduce(callback) { ZoomManager.reduce(); - this._applySettingToPref(); + this._applySettingToPref(false, callback); }, - enlarge: function FullZoom_enlarge() { + /** + * Enlarges the zoom level of the page in the current browser. + * + * @param callback Optional. If given, it's asynchronously called when the + * zoom update completes. + */ + enlarge: function FullZoom_enlarge(callback) { ZoomManager.enlarge(); - this._applySettingToPref(); + this._applySettingToPref(false, callback); }, - reset: function FullZoom_reset() { - if (typeof this.globalValue != "undefined") - ZoomManager.zoom = this.globalValue; - else - ZoomManager.reset(); - - this._removePref(); + /** + * Sets the zoom level of the page in the current browser to the global zoom + * level. + * + * @param callback Optional. If given, it's asynchronously called when the + * zoom update completes. + */ + reset: function FullZoom_reset(callback) { + this._getGlobalValue(gBrowser.contentWindow, function (value) { + if (value === undefined) + ZoomManager.reset(); + else + ZoomManager.zoom = value; + this._removePref(callback); + }); }, /** @@ -283,38 +324,91 @@ var FullZoom = { * So when we apply new zoom values to the browser, we simply set the zoom. * We don't check first to see if the new value is the same as the current * one. - **/ - _applyPrefToSetting: function FullZoom__applyPrefToSetting(aValue, aBrowser) { - if ((!this.siteSpecific) || gInPrintPreviewMode) + * + * @param aValue The zoom level value. + * @param aBrowser The browser containing the page whose zoom level is to be + * set. If falsey, the currently selected browser is used. + * @param aCallback Optional. If given, it's asynchronously called when + * complete. + */ + _applyPrefToSetting: function FullZoom__applyPrefToSetting(aValue, aBrowser, aCallback) { + if (!this.siteSpecific || gInPrintPreviewMode) { + this._executeSoon(aCallback); return; + } var browser = aBrowser || (gBrowser && gBrowser.selectedBrowser); - try { - if (browser.contentDocument.mozSyntheticDocument) - return; - - if (typeof aValue != "undefined") - ZoomManager.setZoomForBrowser(browser, this._ensureValid(aValue)); - else if (typeof this.globalValue != "undefined") - ZoomManager.setZoomForBrowser(browser, this.globalValue); - else - ZoomManager.setZoomForBrowser(browser, 1); - } - catch(ex) {} - }, - - _applySettingToPref: function FullZoom__applySettingToPref() { - if (!this.siteSpecific || gInPrintPreviewMode || - content.document.mozSyntheticDocument) + if (browser.contentDocument.mozSyntheticDocument) { + this._executeSoon(aCallback); return; + } - var zoomLevel = ZoomManager.zoom; - getContentPrefs(gBrowser.contentDocument.defaultView).setPref(gBrowser.currentURI, this.name, zoomLevel); + if (aValue !== undefined) { + ZoomManager.setZoomForBrowser(browser, this._ensureValid(aValue)); + this._executeSoon(aCallback); + return; + } + + this._getGlobalValue(browser.contentWindow, function (value) { + if (gBrowser.selectedBrowser == browser) + ZoomManager.setZoomForBrowser(browser, value === undefined ? 1 : value); + this._executeSoon(aCallback); + }); }, - _removePref: function FullZoom__removePref() { - if (!(content.document.mozSyntheticDocument)) - getContentPrefs(gBrowser.contentDocument.defaultView).removePref(gBrowser.currentURI, this.name); + /** + * Saves the zoom level of the page in the current browser to the content + * prefs store. + * + * @param suppressZoomChange Because this method sets a content preference, + * our onContentPrefSet method is called as a + * result, which updates the current zoom level. + * If suppressZoomChange is true, then the next + * call to onContentPrefSet will not update the + * zoom level. + * @param callback Optional. If given, it's asynchronously called + * when done. + */ + _applySettingToPref: function FullZoom__applySettingToPref(suppressZoomChange, callback) { + if (!this.siteSpecific || + gInPrintPreviewMode || + content.document.mozSyntheticDocument) { + this._executeSoon(callback); + return; + } + + this._cps2.set(gBrowser.currentURI.spec, this.name, ZoomManager.zoom, + this._loadContextFromWindow(gBrowser.contentWindow), { + handleCompletion: function () { + if (suppressZoomChange) + // The content preference service calls observers after callbacks, and + // it calls both in the same turn of the event loop. onContentPrefSet + // will therefore be called next, in the same turn of the event loop, + // and it will check this flag. + this._ignoreNextOnContentPrefSet = true; + if (callback) + callback(); + }.bind(this) + }); + }, + + /** + * Removes from the content prefs store the zoom level of the current browser. + * + * @param callback Optional. If given, it's asynchronously called when done. + */ + _removePref: function FullZoom__removePref(callback) { + if (content.document.mozSyntheticDocument) { + this._executeSoon(callback); + return; + } + let ctxt = this._loadContextFromWindow(gBrowser.contentWindow); + this._cps2.removeByDomainAndName(gBrowser.currentURI.spec, this.name, ctxt, { + handleCompletion: function () { + if (callback) + callback(); + } + }); }, @@ -322,6 +416,8 @@ var FullZoom = { // Utilities _ensureValid: function FullZoom__ensureValid(aValue) { + // Note that undefined is a valid value for aValue that indicates a known- + // not-to-exist value. if (isNaN(aValue)) return 1; @@ -332,5 +428,68 @@ var FullZoom = { return ZoomManager.MAX; return aValue; - } + }, + + /** + * Gets the global browser.content.full-zoom content preference. + * + * WARNING: callback may be called synchronously or asynchronously. The + * reason is that it's usually desirable to avoid turns of the event loop + * where possible, since they can lead to visible, jarring jumps in zoom + * level. It's not always possible to avoid them, though. As a convenience, + * then, this method takes a callback and returns nothing. + * + * @param window The content window pertaining to the zoom. + * @param callback Synchronously or asynchronously called when done. It's + * bound to this object (FullZoom) and passed the preference + * value. + */ + _getGlobalValue: function FullZoom__getGlobalValue(window, callback) { + // * !("_globalValue" in this) => global value not yet cached. + // * this._globalValue === undefined => global value known not to exist. + // * Otherwise, this._globalValue is a number, the global value. + if ("_globalValue" in this) { + callback.call(this, this._globalValue); + return; + } + let value = undefined; + this._cps2.getGlobal(this.name, this._loadContextFromWindow(window), { + handleResult: function (pref) value = pref.value, + handleCompletion: function () { + this._globalValue = this._ensureValid(value); + callback.call(this, this._globalValue); + }.bind(this) + }); + }, + + /** + * Gets the load context from the given window. + * + * @param window The window whose load context will be returned. + * @return The nsILoadContext of the given window. + */ + _loadContextFromWindow: function FullZoom__loadContextFromWindow(window) { + return window. + QueryInterface(Ci.nsIInterfaceRequestor). + getInterface(Ci.nsIWebNavigation). + QueryInterface(Ci.nsILoadContext); + }, + + /** + * Asynchronously broadcasts a "browser-fullZoom:locationChange" notification + * so that tests can select tabs, load pages, etc. and be notified when the + * zoom levels on those pages change. The notification is always asynchronous + * so that observers are guaranteed a consistent behavior. + */ + _notifyOnLocationChange: function FullZoom__notifyOnLocationChange() { + this._executeSoon(function () { + Services.obs.notifyObservers(null, "browser-fullZoom:locationChange", ""); + }); + }, + + _executeSoon: function FullZoom__executeSoon(callback) { + if (!callback) + return; + Services.tm.mainThread.dispatch(callback, Ci.nsIThread.DISPATCH_NORMAL); + }, }; diff --git a/browser/base/content/test/browser_bug386835.js b/browser/base/content/test/browser_bug386835.js index 46a69ec395c7..ea4ffbc94414 100644 --- a/browser/base/content/test/browser_bug386835.js +++ b/browser/base/content/test/browser_bug386835.js @@ -8,136 +8,82 @@ const FORWARD = 1; function test() { waitForExplicitFinish(); - gTab1 = gBrowser.addTab(gTestPage); - gTab2 = gBrowser.addTab(); - gTab3 = gBrowser.addTab(); - gBrowser.selectedTab = gTab1; + Task.spawn(function () { + gTab1 = gBrowser.addTab(gTestPage); + gTab2 = gBrowser.addTab(); + gTab3 = gBrowser.addTab(); - load(gTab1, gTestPage, function () { - load(gTab2, gTestPage, secondPageLoaded); - }); + yield FullZoomHelper.selectTabAndWaitForLocationChange(gTab1); + yield FullZoomHelper.load(gTab1, gTestPage); + yield FullZoomHelper.load(gTab2, gTestPage); + }).then(secondPageLoaded, FullZoomHelper.failAndContinue(finish)); } function secondPageLoaded() { - zoomTest(gTab1, 1, "Initial zoom of tab 1 should be 1"); - zoomTest(gTab2, 1, "Initial zoom of tab 2 should be 1"); - zoomTest(gTab3, 1, "Initial zoom of tab 3 should be 1"); + Task.spawn(function () { + FullZoomHelper.zoomTest(gTab1, 1, "Initial zoom of tab 1 should be 1"); + FullZoomHelper.zoomTest(gTab2, 1, "Initial zoom of tab 2 should be 1"); + FullZoomHelper.zoomTest(gTab3, 1, "Initial zoom of tab 3 should be 1"); - // Now have three tabs, two with the test page, one blank. Tab 1 is selected - // Zoom tab 1 - FullZoom.enlarge(); - gLevel = ZoomManager.getZoomForBrowser(gBrowser.getBrowserForTab(gTab1)); + // Now have three tabs, two with the test page, one blank. Tab 1 is selected + // Zoom tab 1 + yield FullZoomHelper.enlarge(); + gLevel = ZoomManager.getZoomForBrowser(gBrowser.getBrowserForTab(gTab1)); - ok(gLevel > 1, "New zoom for tab 1 should be greater than 1"); - zoomTest(gTab2, 1, "Zooming tab 1 should not affect tab 2"); - zoomTest(gTab3, 1, "Zooming tab 1 should not affect tab 3"); + ok(gLevel > 1, "New zoom for tab 1 should be greater than 1"); + FullZoomHelper.zoomTest(gTab2, 1, "Zooming tab 1 should not affect tab 2"); + FullZoomHelper.zoomTest(gTab3, 1, "Zooming tab 1 should not affect tab 3"); - load(gTab3, gTestPage, thirdPageLoaded); + yield FullZoomHelper.load(gTab3, gTestPage); + }).then(thirdPageLoaded, FullZoomHelper.failAndContinue(finish)); } function thirdPageLoaded() { - zoomTest(gTab1, gLevel, "Tab 1 should still be zoomed"); - zoomTest(gTab2, 1, "Tab 2 should still not be affected"); - zoomTest(gTab3, gLevel, "Tab 3 should have zoomed as it was loading in the background"); + Task.spawn(function () { + FullZoomHelper.zoomTest(gTab1, gLevel, "Tab 1 should still be zoomed"); + FullZoomHelper.zoomTest(gTab2, 1, "Tab 2 should still not be affected"); + FullZoomHelper.zoomTest(gTab3, gLevel, "Tab 3 should have zoomed as it was loading in the background"); - // Switching to tab 2 should update its zoom setting. - afterZoom(function() { - zoomTest(gTab1, gLevel, "Tab 1 should still be zoomed"); - zoomTest(gTab2, gLevel, "Tab 2 should be zoomed now"); - zoomTest(gTab3, gLevel, "Tab 3 should still be zoomed"); + // Switching to tab 2 should update its zoom setting. + yield FullZoomHelper.selectTabAndWaitForLocationChange(gTab2); + FullZoomHelper.zoomTest(gTab1, gLevel, "Tab 1 should still be zoomed"); + FullZoomHelper.zoomTest(gTab2, gLevel, "Tab 2 should be zoomed now"); + FullZoomHelper.zoomTest(gTab3, gLevel, "Tab 3 should still be zoomed"); - load(gTab1, gTestImage, imageLoaded); - }); - - gBrowser.selectedTab = gTab2; + yield FullZoomHelper.load(gTab1, gTestImage); + }).then(imageLoaded, FullZoomHelper.failAndContinue(finish)); } function imageLoaded() { - zoomTest(gTab1, 1, "Zoom should be 1 when image was loaded in the background"); - gBrowser.selectedTab = gTab1; - zoomTest(gTab1, 1, "Zoom should still be 1 when tab with image is selected"); - - executeSoon(imageZoomSwitch); + Task.spawn(function () { + FullZoomHelper.zoomTest(gTab1, 1, "Zoom should be 1 when image was loaded in the background"); + yield FullZoomHelper.selectTabAndWaitForLocationChange(gTab1); + FullZoomHelper.zoomTest(gTab1, 1, "Zoom should still be 1 when tab with image is selected"); + }).then(imageZoomSwitch, FullZoomHelper.failAndContinue(finish)); } function imageZoomSwitch() { - navigate(BACK, function () { - navigate(FORWARD, function () { - zoomTest(gTab1, 1, "Tab 1 should not be zoomed when an image loads"); + Task.spawn(function () { + yield FullZoomHelper.navigate(BACK); + yield FullZoomHelper.navigate(FORWARD); + FullZoomHelper.zoomTest(gTab1, 1, "Tab 1 should not be zoomed when an image loads"); - afterZoom(function() { - zoomTest(gTab1, 1, "Tab 1 should still not be zoomed when deselected"); - finishTest(); - }); - gBrowser.selectedTab = gTab2; - }); - }); + yield FullZoomHelper.selectTabAndWaitForLocationChange(gTab2); + FullZoomHelper.zoomTest(gTab1, 1, "Tab 1 should still not be zoomed when deselected"); + }).then(finishTest, FullZoomHelper.failAndContinue(finish)); } var finishTestStarted = false; function finishTest() { - ok(!finishTestStarted, "finishTest called more than once"); - finishTestStarted = true; - gBrowser.selectedTab = gTab1; - FullZoom.reset(); - gBrowser.removeTab(gTab1); - FullZoom.reset(); - gBrowser.removeTab(gTab2); - FullZoom.reset(); - gBrowser.removeTab(gTab3); - finish(); -} - -function zoomTest(tab, val, msg) { - is(ZoomManager.getZoomForBrowser(tab.linkedBrowser), val, msg); -} - -function load(tab, url, cb) { - let didLoad = false; - let didZoom = false; - tab.linkedBrowser.addEventListener("load", function (event) { - event.currentTarget.removeEventListener("load", arguments.callee, true); - didLoad = true; - if (didZoom) - executeSoon(cb); - }, true); - - afterZoom(function() { - didZoom = true; - if (didLoad) - executeSoon(cb); - }); - - tab.linkedBrowser.loadURI(url); -} - -function navigate(direction, cb) { - let didPs = false; - let didZoom = false; - gBrowser.addEventListener("pageshow", function (event) { - gBrowser.removeEventListener("pageshow", arguments.callee, true); - didPs = true; - if (didZoom) - executeSoon(cb); - }, true); - - afterZoom(function() { - didZoom = true; - if (didPs) - executeSoon(cb); - }); - - if (direction == BACK) - gBrowser.goBack(); - else if (direction == FORWARD) - gBrowser.goForward(); -} - -function afterZoom(cb) { - let oldSZFB = ZoomManager.setZoomForBrowser; - ZoomManager.setZoomForBrowser = function(browser, value) { - oldSZFB.call(ZoomManager, browser, value); - ZoomManager.setZoomForBrowser = oldSZFB; - executeSoon(cb); - }; + Task.spawn(function () { + ok(!finishTestStarted, "finishTest called more than once"); + finishTestStarted = true; + yield FullZoomHelper.selectTabAndWaitForLocationChange(gTab1); + yield FullZoomHelper.reset(); + gBrowser.removeTab(gTab1); + yield FullZoomHelper.reset(); + gBrowser.removeTab(gTab2); + yield FullZoomHelper.reset(); + gBrowser.removeTab(gTab3); + }).then(finish, FullZoomHelper.failAndContinue(finish)); } diff --git a/browser/base/content/test/browser_bug416661.js b/browser/base/content/test/browser_bug416661.js index f459284eeeba..af0fe24fedcd 100644 --- a/browser/base/content/test/browser_bug416661.js +++ b/browser/base/content/test/browser_bug416661.js @@ -1,62 +1,42 @@ var tabElm, zoomLevel; function start_test_prefNotSet() { - is(ZoomManager.zoom, 1, "initial zoom level should be 1"); - FullZoom.enlarge(); + Task.spawn(function () { + is(ZoomManager.zoom, 1, "initial zoom level should be 1"); + yield FullZoomHelper.enlarge(); - //capture the zoom level to test later - zoomLevel = ZoomManager.zoom; - isnot(zoomLevel, 1, "zoom level should have changed"); + //capture the zoom level to test later + zoomLevel = ZoomManager.zoom; + isnot(zoomLevel, 1, "zoom level should have changed"); - afterZoomAndLoad(continue_test_prefNotSet); - content.location = - "http://mochi.test:8888/browser/browser/base/content/test/moz.png"; + yield FullZoomHelper.load(gBrowser.selectedTab, "http://mochi.test:8888/browser/browser/base/content/test/moz.png"); + }).then(continue_test_prefNotSet, FullZoomHelper.failAndContinue(finish)); } function continue_test_prefNotSet () { - is(ZoomManager.zoom, 1, "zoom level pref should not apply to an image"); - FullZoom.reset(); + Task.spawn(function () { + is(ZoomManager.zoom, 1, "zoom level pref should not apply to an image"); + yield FullZoomHelper.reset(); - afterZoomAndLoad(end_test_prefNotSet); - content.location = - "http://mochi.test:8888/browser/browser/base/content/test/zoom_test.html"; + yield FullZoomHelper.load(gBrowser.selectedTab, "http://mochi.test:8888/browser/browser/base/content/test/zoom_test.html"); + }).then(end_test_prefNotSet, FullZoomHelper.failAndContinue(finish)); } function end_test_prefNotSet() { - is(ZoomManager.zoom, zoomLevel, "the zoom level should have persisted"); + Task.spawn(function () { + is(ZoomManager.zoom, zoomLevel, "the zoom level should have persisted"); - // Reset the zoom so that other tests have a fresh zoom level - FullZoom.reset(); - gBrowser.removeCurrentTab(); - finish(); + // Reset the zoom so that other tests have a fresh zoom level + yield FullZoomHelper.reset(); + gBrowser.removeCurrentTab(); + }).then(finish, FullZoomHelper.failAndContinue(finish)); } - function test() { waitForExplicitFinish(); - tabElm = gBrowser.addTab(); - gBrowser.selectedTab = tabElm; - - afterZoomAndLoad(start_test_prefNotSet); - content.location = - "http://mochi.test:8888/browser/browser/base/content/test/zoom_test.html"; -} - -function afterZoomAndLoad(cb) { - let didLoad = false; - let didZoom = false; - tabElm.linkedBrowser.addEventListener("load", function() { - tabElm.linkedBrowser.removeEventListener("load", arguments.callee, true); - didLoad = true; - if (didZoom) - executeSoon(cb); - }, true); - let oldSZFB = ZoomManager.setZoomForBrowser; - ZoomManager.setZoomForBrowser = function(browser, value) { - oldSZFB.call(ZoomManager, browser, value); - ZoomManager.setZoomForBrowser = oldSZFB; - didZoom = true; - if (didLoad) - executeSoon(cb); - }; + Task.spawn(function () { + tabElm = gBrowser.addTab(); + yield FullZoomHelper.selectTabAndWaitForLocationChange(tabElm); + yield FullZoomHelper.load(tabElm, "http://mochi.test:8888/browser/browser/base/content/test/zoom_test.html"); + }).then(start_test_prefNotSet, FullZoomHelper.failAndContinue(finish)); } diff --git a/browser/base/content/test/browser_bug419612.js b/browser/base/content/test/browser_bug419612.js index 2ff094873dc8..76194c9f9bc9 100644 --- a/browser/base/content/test/browser_bug419612.js +++ b/browser/base/content/test/browser_bug419612.js @@ -1,49 +1,32 @@ function test() { waitForExplicitFinish(); - let testPage = "http://example.org/browser/browser/base/content/test/dummy_page.html"; - let tab1 = gBrowser.selectedTab = gBrowser.addTab(); - tab1.linkedBrowser.addEventListener("load", (function(event) { - event.currentTarget.removeEventListener("load", arguments.callee, true); + Task.spawn(function () { + let testPage = "http://example.org/browser/browser/base/content/test/dummy_page.html"; + let tab1 = gBrowser.addTab(); + yield FullZoomHelper.selectTabAndWaitForLocationChange(tab1); + yield FullZoomHelper.load(tab1, testPage); let tab2 = gBrowser.addTab(); - tab2.linkedBrowser.addEventListener("load", (function(event) { - event.currentTarget.removeEventListener("load", arguments.callee, true); + yield FullZoomHelper.load(tab2, testPage); - FullZoom.enlarge(); - let tab1Zoom = ZoomManager.getZoomForBrowser(tab1.linkedBrowser); + yield FullZoomHelper.enlarge(); + let tab1Zoom = ZoomManager.getZoomForBrowser(tab1.linkedBrowser); - afterZoom(function() { - let tab2Zoom = ZoomManager.getZoomForBrowser(tab2.linkedBrowser); - is(tab2Zoom, tab1Zoom, "Zoom should affect background tabs"); + yield FullZoomHelper.selectTabAndWaitForLocationChange(tab2); + let tab2Zoom = ZoomManager.getZoomForBrowser(tab2.linkedBrowser); + is(tab2Zoom, tab1Zoom, "Zoom should affect background tabs"); - gPrefService.setBoolPref("browser.zoom.updateBackgroundTabs", false); - FullZoom.reset(); - gBrowser.selectedTab = tab1; - tab1Zoom = ZoomManager.getZoomForBrowser(tab1.linkedBrowser); - tab2Zoom = ZoomManager.getZoomForBrowser(tab2.linkedBrowser); - isnot(tab1Zoom, tab2Zoom, "Zoom should not affect background tabs"); + gPrefService.setBoolPref("browser.zoom.updateBackgroundTabs", false); + yield FullZoomHelper.reset(); + gBrowser.selectedTab = tab1; + tab1Zoom = ZoomManager.getZoomForBrowser(tab1.linkedBrowser); + tab2Zoom = ZoomManager.getZoomForBrowser(tab2.linkedBrowser); + isnot(tab1Zoom, tab2Zoom, "Zoom should not affect background tabs"); - if (gPrefService.prefHasUserValue("browser.zoom.updateBackgroundTabs")) - gPrefService.clearUserPref("browser.zoom.updateBackgroundTabs"); - gBrowser.removeTab(tab1); - gBrowser.removeTab(tab2); - finish(); - }); - gBrowser.selectedTab = tab2; - }), true); - tab2.linkedBrowser.loadURI(testPage); - }), true); - content.location = testPage; -} - -function afterZoom(cb) { - let oldAPTS = FullZoom._applyPrefToSetting; - FullZoom._applyPrefToSetting = function(value, browser) { - if (!value) - value = undefined; - oldAPTS.call(FullZoom, value, browser); - FullZoom._applyPrefToSetting = oldAPTS; - executeSoon(cb); - }; + if (gPrefService.prefHasUserValue("browser.zoom.updateBackgroundTabs")) + gPrefService.clearUserPref("browser.zoom.updateBackgroundTabs"); + gBrowser.removeTab(tab1); + gBrowser.removeTab(tab2); + }).then(finish, FullZoomHelper.failAndContinue(finish)); } diff --git a/browser/base/content/test/browser_bug441778.js b/browser/base/content/test/browser_bug441778.js index 7fa37c65e70e..dd51d70e65ba 100644 --- a/browser/base/content/test/browser_bug441778.js +++ b/browser/base/content/test/browser_bug441778.js @@ -13,19 +13,22 @@ function test() { const TEST_PAGE_URL = 'data:text/html,'; const TEST_IFRAME_URL = "http://test2.example.org/"; - // Prepare the test tab - gBrowser.selectedTab = gBrowser.addTab(); - let testBrowser = gBrowser.selectedBrowser; + Task.spawn(function () { + // Prepare the test tab + let tab = gBrowser.addTab(); + yield FullZoomHelper.selectTabAndWaitForLocationChange(tab); - testBrowser.addEventListener("load", function () { - testBrowser.removeEventListener("load", arguments.callee, true); + let testBrowser = tab.linkedBrowser; + + yield FullZoomHelper.load(tab, TEST_PAGE_URL); // Change the zoom level and then save it so we can compare it to the level // after loading the sub-document. - FullZoom.enlarge(); + yield FullZoomHelper.enlarge(); var zoomLevel = ZoomManager.zoom; // Start the sub-document load. + let deferred = Promise.defer(); executeSoon(function () { testBrowser.addEventListener("load", function (e) { testBrowser.removeEventListener("load", arguments.callee, true); @@ -34,11 +37,10 @@ function test() { is(ZoomManager.zoom, zoomLevel, "zoom is retained after sub-document load"); gBrowser.removeCurrentTab(); - finish(); + deferred.resolve(); }, true); content.document.querySelector("iframe").src = TEST_IFRAME_URL; }); - }, true); - - content.location = TEST_PAGE_URL; + yield deferred.promise; + }).then(finish, FullZoomHelper.failAndContinue(finish)); } diff --git a/browser/base/content/test/browser_bug555224.js b/browser/base/content/test/browser_bug555224.js index fa38a471d32a..cff1ee12b6b4 100644 --- a/browser/base/content/test/browser_bug555224.js +++ b/browser/base/content/test/browser_bug555224.js @@ -4,59 +4,36 @@ const TEST_PAGE = "/browser/browser/base/content/test/dummy_page.html"; var gTestTab, gBgTab, gTestZoom; -function afterZoomAndLoad(aCallback, aTab) { - let didLoad = false; - let didZoom = false; - aTab.linkedBrowser.addEventListener("load", function() { - aTab.linkedBrowser.removeEventListener("load", arguments.callee, true); - didLoad = true; - if (didZoom) - executeSoon(aCallback); - }, true); - let oldAPTS = FullZoom._applyPrefToSetting; - FullZoom._applyPrefToSetting = function(value, browser) { - if (!value) - value = undefined; - oldAPTS.call(FullZoom, value, browser); - // Don't reset _applyPrefToSetting until we've seen the about:blank load(s) - if (browser && browser.currentURI.spec.startsWith("http:")) { - FullZoom._applyPrefToSetting = oldAPTS; - didZoom = true; - } - if (didLoad && didZoom) - executeSoon(aCallback); - }; -} - function testBackgroundLoad() { - is(ZoomManager.zoom, gTestZoom, "opening a background tab should not change foreground zoom"); + Task.spawn(function () { + is(ZoomManager.zoom, gTestZoom, "opening a background tab should not change foreground zoom"); - gBrowser.removeTab(gBgTab); + gBrowser.removeTab(gBgTab); - FullZoom.reset(); - gBrowser.removeTab(gTestTab); - - finish(); + yield FullZoomHelper.reset(); + gBrowser.removeTab(gTestTab); + }).then(finish, FullZoomHelper.failAndContinue(finish)); } function testInitialZoom() { - is(ZoomManager.zoom, 1, "initial zoom level should be 1"); - FullZoom.enlarge(); + Task.spawn(function () { + is(ZoomManager.zoom, 1, "initial zoom level should be 1"); + yield FullZoomHelper.enlarge(); - gTestZoom = ZoomManager.zoom; - isnot(gTestZoom, 1, "zoom level should have changed"); + gTestZoom = ZoomManager.zoom; + isnot(gTestZoom, 1, "zoom level should have changed"); - afterZoomAndLoad(testBackgroundLoad, - gBgTab = gBrowser.loadOneTab("http://mochi.test:8888" + TEST_PAGE, - {inBackground: true})); + gBgTab = gBrowser.addTab(); + yield FullZoomHelper.load(gBgTab, "http://mochi.test:8888" + TEST_PAGE); + }).then(testBackgroundLoad, FullZoomHelper.failAndContinue(finish)); } function test() { waitForExplicitFinish(); - gTestTab = gBrowser.addTab(); - gBrowser.selectedTab = gTestTab; - - afterZoomAndLoad(testInitialZoom, gTestTab); - content.location = "http://example.org" + TEST_PAGE; + Task.spawn(function () { + gTestTab = gBrowser.addTab(); + yield FullZoomHelper.selectTabAndWaitForLocationChange(gTestTab); + yield FullZoomHelper.load(gTestTab, "http://example.org" + TEST_PAGE); + }).then(testInitialZoom, FullZoomHelper.failAndContinue(finish)); } diff --git a/browser/base/content/test/browser_bug559991.js b/browser/base/content/test/browser_bug559991.js index 19d6127a0e8a..3bebc16e4f59 100644 --- a/browser/base/content/test/browser_bug559991.js +++ b/browser/base/content/test/browser_bug559991.js @@ -1,3 +1,5 @@ +var tab; + function test() { // ---------- @@ -5,53 +7,34 @@ function test() { waitForExplicitFinish(); - let oldOLC = FullZoom.onLocationChange; - FullZoom.onLocationChange = function(aURI, aIsTabSwitch, aBrowser) { - // Ignore calls that are not about tab switching on this test - if (aIsTabSwitch) - oldOLC.call(FullZoom, aURI, aIsTabSwitch, aBrowser); - }; - gPrefService.setBoolPref("browser.zoom.updateBackgroundTabs", true); gPrefService.setBoolPref("browser.zoom.siteSpecific", true); - let oldAPTS = FullZoom._applyPrefToSetting; let uri = "http://example.org/browser/browser/base/content/test/dummy_page.html"; - let tab = gBrowser.addTab(); - tab.linkedBrowser.addEventListener("load", function(event) { - tab.linkedBrowser.removeEventListener("load", arguments.callee, true); + Task.spawn(function () { + tab = gBrowser.addTab(); + yield FullZoomHelper.load(tab, uri); // ------------------------------------------------------------------- // Test - Trigger a tab switch that should update the zoom level - FullZoom._applyPrefToSetting = function() { - ok(true, "applyPrefToSetting was called"); - endTest(); - } - gBrowser.selectedTab = tab; - - }, true); - tab.linkedBrowser.loadURI(uri); - - // ------------- - // Test clean-up - function endTest() { - FullZoom._applyPrefToSetting = oldAPTS; - FullZoom.onLocationChange = oldOLC; - gBrowser.removeTab(tab); - - oldAPTS = null; - oldOLC = null; - tab = null; - - if (gPrefService.prefHasUserValue("browser.zoom.updateBackgroundTabs")) - gPrefService.clearUserPref("browser.zoom.updateBackgroundTabs"); - - if (gPrefService.prefHasUserValue("browser.zoom.siteSpecific")) - gPrefService.clearUserPref("browser.zoom.siteSpecific"); - - finish(); - } - + yield FullZoomHelper.selectTabAndWaitForLocationChange(tab); + ok(true, "applyPrefToSetting was called"); + }).then(endTest, FullZoomHelper.failAndContinue(endTest)); } +// ------------- +// Test clean-up +function endTest() { + gBrowser.removeTab(tab); + + tab = null; + + if (gPrefService.prefHasUserValue("browser.zoom.updateBackgroundTabs")) + gPrefService.clearUserPref("browser.zoom.updateBackgroundTabs"); + + if (gPrefService.prefHasUserValue("browser.zoom.siteSpecific")) + gPrefService.clearUserPref("browser.zoom.siteSpecific"); + + finish(); +} diff --git a/browser/base/content/test/browser_bug575830.js b/browser/base/content/test/browser_bug575830.js index 9f08d6779f8b..aed13eea5522 100644 --- a/browser/base/content/test/browser_bug575830.js +++ b/browser/base/content/test/browser_bug575830.js @@ -13,25 +13,22 @@ function test() { gBrowser.removeTab(tab2); }); - tab1 = gBrowser.addTab(TEST_IMAGE); - tab2 = gBrowser.addTab(); - gBrowser.selectedTab = tab1; + Task.spawn(function () { + tab1 = gBrowser.addTab(); + tab2 = gBrowser.addTab(); + yield FullZoomHelper.selectTabAndWaitForLocationChange(tab1); + yield FullZoomHelper.load(tab1, TEST_IMAGE); - tab1.linkedBrowser.addEventListener("load", function onload() { - tab1.linkedBrowser.removeEventListener("load", onload, true); is(ZoomManager.zoom, 1, "initial zoom level for first should be 1"); - FullZoom.enlarge(); + yield FullZoomHelper.enlarge(); let zoom = ZoomManager.zoom; isnot(zoom, 1, "zoom level should have changed"); - gBrowser.selectedTab = tab2; + yield FullZoomHelper.selectTabAndWaitForLocationChange(tab2); is(ZoomManager.zoom, 1, "initial zoom level for second tab should be 1"); - gBrowser.selectedTab = tab1; + yield FullZoomHelper.selectTabAndWaitForLocationChange(tab1); is(ZoomManager.zoom, zoom, "zoom level for first tab should not have changed"); - - finish(); - }, true); + }).then(finish, FullZoomHelper.failAndContinue(finish)); } - diff --git a/browser/base/content/test/browser_bug719271.js b/browser/base/content/test/browser_bug719271.js index 6db54554f50d..53aca641e457 100644 --- a/browser/base/content/test/browser_bug719271.js +++ b/browser/base/content/test/browser_bug719271.js @@ -11,131 +11,71 @@ var gTab1, gTab2, gLevel1, gLevel2; function test() { waitForExplicitFinish(); - gTab1 = gBrowser.addTab(); - gTab2 = gBrowser.addTab(); - gBrowser.selectedTab = gTab1; + Task.spawn(function () { + gTab1 = gBrowser.addTab(); + gTab2 = gBrowser.addTab(); - load(gTab1, TEST_PAGE, function() { - load(gTab2, TEST_VIDEO, zoomTab1); - }); + yield FullZoomHelper.selectTabAndWaitForLocationChange(gTab1); + yield FullZoomHelper.load(gTab1, TEST_PAGE); + yield FullZoomHelper.load(gTab2, TEST_VIDEO); + }).then(zoomTab1, FullZoomHelper.failAndContinue(finish)); } function zoomTab1() { - is(gBrowser.selectedTab, gTab1, "Tab 1 is selected"); - zoomTest(gTab1, 1, "Initial zoom of tab 1 should be 1"); - zoomTest(gTab2, 1, "Initial zoom of tab 2 should be 1"); + Task.spawn(function () { + is(gBrowser.selectedTab, gTab1, "Tab 1 is selected"); + FullZoomHelper.zoomTest(gTab1, 1, "Initial zoom of tab 1 should be 1"); + FullZoomHelper.zoomTest(gTab2, 1, "Initial zoom of tab 2 should be 1"); - FullZoom.enlarge(); - gLevel1 = ZoomManager.getZoomForBrowser(gBrowser.getBrowserForTab(gTab1)); + yield FullZoomHelper.enlarge(); + gLevel1 = ZoomManager.getZoomForBrowser(gBrowser.getBrowserForTab(gTab1)); - ok(gLevel1 > 1, "New zoom for tab 1 should be greater than 1"); - zoomTest(gTab2, 1, "Zooming tab 1 should not affect tab 2"); + ok(gLevel1 > 1, "New zoom for tab 1 should be greater than 1"); + FullZoomHelper.zoomTest(gTab2, 1, "Zooming tab 1 should not affect tab 2"); - gBrowser.selectedTab = gTab2; - zoomTest(gTab2, 1, "Tab 2 is still unzoomed after it is selected"); - zoomTest(gTab1, gLevel1, "Tab 1 is still zoomed"); - - zoomTab2(); + yield FullZoomHelper.selectTabAndWaitForLocationChange(gTab2); + FullZoomHelper.zoomTest(gTab2, 1, "Tab 2 is still unzoomed after it is selected"); + FullZoomHelper.zoomTest(gTab1, gLevel1, "Tab 1 is still zoomed"); + }).then(zoomTab2, FullZoomHelper.failAndContinue(finish)); } function zoomTab2() { - is(gBrowser.selectedTab, gTab2, "Tab 2 is selected"); + Task.spawn(function () { + is(gBrowser.selectedTab, gTab2, "Tab 2 is selected"); - FullZoom.reduce(); - let gLevel2 = ZoomManager.getZoomForBrowser(gBrowser.getBrowserForTab(gTab2)); + yield FullZoomHelper.reduce(); + let gLevel2 = ZoomManager.getZoomForBrowser(gBrowser.getBrowserForTab(gTab2)); - ok(gLevel2 < 1, "New zoom for tab 2 should be less than 1"); - zoomTest(gTab1, gLevel1, "Zooming tab 2 should not affect tab 1"); + ok(gLevel2 < 1, "New zoom for tab 2 should be less than 1"); + FullZoomHelper.zoomTest(gTab1, gLevel1, "Zooming tab 2 should not affect tab 1"); - afterZoom(function() { - zoomTest(gTab1, gLevel1, "Tab 1 should have the same zoom after it's selected"); - - testNavigation(); - }); - gBrowser.selectedTab = gTab1; + yield FullZoomHelper.selectTabAndWaitForLocationChange(gTab1); + FullZoomHelper.zoomTest(gTab1, gLevel1, "Tab 1 should have the same zoom after it's selected"); + }).then(testNavigation, FullZoomHelper.failAndContinue(finish)); } function testNavigation() { - load(gTab1, TEST_VIDEO, function() { - zoomTest(gTab1, 1, "Zoom should be 1 when a video was loaded"); - navigate(BACK, function() { - zoomTest(gTab1, gLevel1, "Zoom should be restored when a page is loaded"); - navigate(FORWARD, function() { - zoomTest(gTab1, 1, "Zoom should be 1 again when navigating back to a video"); - finishTest(); - }); - }); - }); + Task.spawn(function () { + yield FullZoomHelper.load(gTab1, TEST_VIDEO); + FullZoomHelper.zoomTest(gTab1, 1, "Zoom should be 1 when a video was loaded"); + yield FullZoomHelper.navigate(FullZoomHelper.BACK); + FullZoomHelper.zoomTest(gTab1, gLevel1, "Zoom should be restored when a page is loaded"); + yield FullZoomHelper.navigate(FullZoomHelper.FORWARD); + FullZoomHelper.zoomTest(gTab1, 1, "Zoom should be 1 again when navigating back to a video"); + }).then(finishTest, FullZoomHelper.failAndContinue(finish)); } var finishTestStarted = false; function finishTest() { - ok(!finishTestStarted, "finishTest called more than once"); - finishTestStarted = true; + Task.spawn(function () { + ok(!finishTestStarted, "finishTest called more than once"); + finishTestStarted = true; - gBrowser.selectedTab = gTab1; - FullZoom.reset(); - gBrowser.removeTab(gTab1); - - gBrowser.selectedTab = gTab2; - FullZoom.reset(); - gBrowser.removeTab(gTab2); - - finish(); -} - -function zoomTest(tab, val, msg) { - is(ZoomManager.getZoomForBrowser(tab.linkedBrowser), val, msg); -} - -function load(tab, url, cb) { - let didLoad = false; - let didZoom = false; - tab.linkedBrowser.addEventListener("load", function onload(event) { - event.currentTarget.removeEventListener("load", onload, true); - didLoad = true; - if (didZoom) - executeSoon(cb); - }, true); - - afterZoom(function() { - didZoom = true; - if (didLoad) - executeSoon(cb); - }); - - tab.linkedBrowser.loadURI(url); -} - -const BACK = 0; -const FORWARD = 1; -function navigate(direction, cb) { - let didPs = false; - let didZoom = false; - gBrowser.addEventListener("pageshow", function onpageshow(event) { - gBrowser.removeEventListener("pageshow", onpageshow, true); - didPs = true; - if (didZoom) - executeSoon(cb); - }, true); - - afterZoom(function() { - didZoom = true; - if (didPs) - executeSoon(cb); - }); - - if (direction == BACK) - gBrowser.goBack(); - else if (direction == FORWARD) - gBrowser.goForward(); -} - -function afterZoom(cb) { - let oldSZFB = ZoomManager.setZoomForBrowser; - ZoomManager.setZoomForBrowser = function(browser, value) { - oldSZFB.call(ZoomManager, browser, value); - ZoomManager.setZoomForBrowser = oldSZFB; - executeSoon(cb); - }; + yield FullZoomHelper.selectTabAndWaitForLocationChange(gTab1); + yield FullZoomHelper.reset(); + gBrowser.removeTab(gTab1); + yield FullZoomHelper.selectTabAndWaitForLocationChange(gTab2); + yield FullZoomHelper.reset(); + gBrowser.removeTab(gTab2); + }).then(finish, FullZoomHelper.failAndContinue(finish)); } diff --git a/browser/base/content/test/head.js b/browser/base/content/test/head.js index 8570e1613e12..43107dbd71be 100644 --- a/browser/base/content/test/head.js +++ b/browser/base/content/test/head.js @@ -261,3 +261,107 @@ function promiseHistoryClearedState(aURIs, aShouldBeCleared) { return deferred.promise; } + +let FullZoomHelper = { + + selectTabAndWaitForLocationChange: function selectTabAndWaitForLocationChange(tab) { + let deferred = Promise.defer(); + if (tab && gBrowser.selectedTab == tab) { + deferred.resolve(); + return deferred.promise; + } + if (tab) + gBrowser.selectedTab = tab; + Services.obs.addObserver(function obs() { + Services.obs.removeObserver(obs, "browser-fullZoom:locationChange"); + deferred.resolve(); + }, "browser-fullZoom:locationChange", false); + return deferred.promise; + }, + + load: function load(tab, url) { + let deferred = Promise.defer(); + let didLoad = false; + let didZoom = false; + + tab.linkedBrowser.addEventListener("load", function (event) { + event.currentTarget.removeEventListener("load", arguments.callee, true); + didLoad = true; + if (didZoom) + deferred.resolve(); + }, true); + + // Don't select background tabs. That way tests can use this method on + // background tabs without having them automatically be selected. Just wait + // for the zoom to change on the current tab if it's `tab`. + if (tab == gBrowser.selectedTab) { + this.selectTabAndWaitForLocationChange(null).then(function () { + didZoom = true; + if (didLoad) + deferred.resolve(); + }); + } + else + didZoom = true; + + tab.linkedBrowser.loadURI(url); + + return deferred.promise; + }, + + zoomTest: function zoomTest(tab, val, msg) { + is(ZoomManager.getZoomForBrowser(tab.linkedBrowser), val, msg); + }, + + enlarge: function enlarge() { + let deferred = Promise.defer(); + FullZoom.enlarge(function () deferred.resolve()); + return deferred.promise; + }, + + reduce: function reduce() { + let deferred = Promise.defer(); + FullZoom.reduce(function () deferred.resolve()); + return deferred.promise; + }, + + reset: function reset() { + let deferred = Promise.defer(); + FullZoom.reset(function () deferred.resolve()); + return deferred.promise; + }, + + BACK: 0, + FORWARD: 1, + navigate: function navigate(direction) { + let deferred = Promise.defer(); + let didPs = false; + let didZoom = false; + + gBrowser.addEventListener("pageshow", function (event) { + gBrowser.removeEventListener("pageshow", arguments.callee, true); + didPs = true; + if (didZoom) + deferred.resolve(); + }, true); + + if (direction == this.BACK) + gBrowser.goBack(); + else if (direction == this.FORWARD) + gBrowser.goForward(); + + this.selectTabAndWaitForLocationChange(null).then(function () { + didZoom = true; + if (didPs) + deferred.resolve(); + }); + return deferred.promise; + }, + + failAndContinue: function failAndContinue(func) { + return function (err) { + ok(false, err); + func(); + }; + }, +}; diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_zoom.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_zoom.js index cf4df0301ab6..827b915629d4 100644 --- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_zoom.js +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_zoom.js @@ -25,27 +25,29 @@ function test() { let mozillaZoom = aWindow.ZoomManager.zoom; // change the zoom on the mozilla page - aWindow.FullZoom.enlarge(); - // make sure the zoom level has been changed - isnot(aWindow.ZoomManager.zoom, mozillaZoom, "Zoom level can be changed"); - mozillaZoom = aWindow.ZoomManager.zoom; + aWindow.FullZoom.enlarge(function () { + // make sure the zoom level has been changed + isnot(aWindow.ZoomManager.zoom, mozillaZoom, "Zoom level can be changed"); + mozillaZoom = aWindow.ZoomManager.zoom; - // switch to about: tab - aWindow.gBrowser.selectedTab = tabAbout; + // switch to about: tab + aWindow.gBrowser.selectedTab = tabAbout; - // switch back to mozilla tab - aWindow.gBrowser.selectedTab = tabMozilla; + // switch back to mozilla tab + aWindow.gBrowser.selectedTab = tabMozilla; - // make sure the zoom level has not changed - is(aWindow.ZoomManager.zoom, mozillaZoom, - "Entering private browsing should not reset the zoom on a tab"); + // make sure the zoom level has not changed + is(aWindow.ZoomManager.zoom, mozillaZoom, + "Entering private browsing should not reset the zoom on a tab"); - // cleanup - aWindow.FullZoom.reset(); - aWindow.gBrowser.removeTab(tabMozilla); - aWindow.gBrowser.removeTab(tabAbout); - aWindow.close(); - aCallback(); + // cleanup + aWindow.FullZoom.reset(function () { + aWindow.gBrowser.removeTab(tabMozilla); + aWindow.gBrowser.removeTab(tabAbout); + aWindow.close(); + aCallback(); + }); + }); }, true); mozillaBrowser.contentWindow.location = "about:mozilla"; }, true); diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_zoomrestore.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_zoomrestore.js index 46a5ba76624d..9bac502a35a7 100644 --- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_zoomrestore.js +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_zoomrestore.js @@ -16,12 +16,14 @@ function test() { aWindow.gBrowser.selectedBrowser.removeEventListener("load", onLoad, true); if (aIsZoomedWindow) { // change the zoom on the blank page - aWindow.FullZoom.enlarge(); - isnot(aWindow.ZoomManager.zoom, 1, "Zoom level for about:blank should be changed"); - } else { - // make sure the zoom level is set to 1 - is(aWindow.ZoomManager.zoom, 1, "Zoom level for about:privatebrowsing should be reset"); + aWindow.FullZoom.enlarge(function () { + isnot(aWindow.ZoomManager.zoom, 1, "Zoom level for about:blank should be changed"); + aCallback(); + }); + return; } + // make sure the zoom level is set to 1 + is(aWindow.ZoomManager.zoom, 1, "Zoom level for about:privatebrowsing should be reset"); aCallback(); }, true); @@ -31,10 +33,18 @@ function test() { function finishTest() { // cleanup + let numWindows = windowsToReset.length; + if (!numWindows) { + finish(); + return; + } windowsToReset.forEach(function(win) { - win.FullZoom.reset(); + win.FullZoom.reset(function onReset() { + numWindows--; + if (!numWindows) + finish(); + }); }); - finish(); } function testOnWindow(options, callback) { diff --git a/dom/interfaces/base/nsIContentPrefService2.idl b/dom/interfaces/base/nsIContentPrefService2.idl index 4ff2434e4af7..22f8cd1714fc 100644 --- a/dom/interfaces/base/nsIContentPrefService2.idl +++ b/dom/interfaces/base/nsIContentPrefService2.idl @@ -59,11 +59,15 @@ interface nsIContentPref; * * Callbacks * - * The methods of callback objects are always called asynchronously. See - * nsIContentPrefCallback2 below for more information about callbacks. + * The methods of callback objects are always called asynchronously. + * + * Observers are called after callbacks are called, but they are called in the + * same turn of the event loop as callbacks. + * + * See nsIContentPrefCallback2 below for more information about callbacks. */ -[scriptable, uuid(51e1d34a-5e9d-4b77-b14c-0f8346e264ca)] +[scriptable, uuid(133608c7-f812-41ca-bc1c-62a4eb95e52a)] interface nsIContentPrefService2 : nsISupports { /** @@ -318,6 +322,17 @@ interface nsIContentPrefService2 : nsISupports */ void removeObserverForName(in AString name, in nsIContentPrefObserver observer); + + /** + * Extracts and returns the domain from the given string representation of a + * URI. This is how the API extracts domains from URIs passed to it. + * + * @param str The string representation of a URI, like + * "http://example.com/foo/bar". + * @return If the given string is a valid URI, the domain of that URI is + * returned. Otherwise, the string itself is returned. + */ + AString extractDomain(in AString str); }; /** @@ -336,7 +351,7 @@ interface nsIContentPrefCallback2 : nsISupports /** * Called when an error occurs. This may be called multiple times before - * onComplete is called. + * handleCompletion is called. * * @param error A number in Components.results describing the error. */ diff --git a/toolkit/components/contentprefs/ContentPrefService2.jsm b/toolkit/components/contentprefs/ContentPrefService2.jsm index 6b4085e03dca..9722fe4e5679 100644 --- a/toolkit/components/contentprefs/ContentPrefService2.jsm +++ b/toolkit/components/contentprefs/ContentPrefService2.jsm @@ -195,8 +195,8 @@ ContentPrefService2.prototype = { if (context && context.usePrivateBrowsing) { this._pbStore.set(group, name, value); this._schedule(function () { - this._cps._broadcastPrefSet(group, name, value); cbHandleCompletion(callback, Ci.nsIContentPrefCallback2.COMPLETE_OK); + this._cps._broadcastPrefSet(group, name, value); }); return; } @@ -258,11 +258,11 @@ ContentPrefService2.prototype = { this._execStmts(stmts, { onDone: function onDone(reason, ok) { - if (ok) { + if (ok) this._cache.setWithCast(group, name, value); - this._cps._broadcastPrefSet(group, name, value); - } cbHandleCompletion(callback, reason); + if (ok) + this._cps._broadcastPrefSet(group, name, value); }, onError: function onError(nsresult) { cbHandleError(callback, nsresult); @@ -342,11 +342,13 @@ ContentPrefService2.prototype = { this._pbStore.remove(sgroup, name); } } + } + cbHandleCompletion(callback, reason); + if (ok) { for (let [sgroup, , ] in prefs) { this._cps._broadcastPrefRemoved(sgroup, name); } } - cbHandleCompletion(callback, reason); }, onError: function onError(nsresult) { cbHandleError(callback, nsresult); @@ -421,18 +423,18 @@ ContentPrefService2.prototype = { this._cache.set(grp, name, undefined); }, onDone: function onDone(reason, ok) { - if (ok) { - if (context && context.usePrivateBrowsing) { - for (let [sgroup, sname, ] in this._pbStore) { - prefs.set(sgroup, sname); - this._pbStore.remove(sgroup, sname); - } + if (ok && context && context.usePrivateBrowsing) { + for (let [sgroup, sname, ] in this._pbStore) { + prefs.set(sgroup, sname); + this._pbStore.remove(sgroup, sname); } + } + cbHandleCompletion(callback, reason); + if (ok) { for (let [sgroup, sname, ] in prefs) { this._cps._broadcastPrefRemoved(sgroup, sname); } } - cbHandleCompletion(callback, reason); }, onError: function onError(nsresult) { cbHandleError(callback, nsresult); @@ -473,18 +475,18 @@ ContentPrefService2.prototype = { this._cache.set(grp, name, undefined); }, onDone: function onDone(reason, ok) { - if (ok) { - if (context && context.usePrivateBrowsing) { - for (let [sgroup, sname, ] in this._pbStore) { - prefs.set(sgroup, sname); - } - this._pbStore.removeGrouped(); + if (ok && context && context.usePrivateBrowsing) { + for (let [sgroup, sname, ] in this._pbStore) { + prefs.set(sgroup, sname); } + this._pbStore.removeGrouped(); + } + cbHandleCompletion(callback, reason); + if (ok) { for (let [sgroup, sname, ] in prefs) { this._cps._broadcastPrefRemoved(sgroup, sname); } } - cbHandleCompletion(callback, reason); }, onError: function onError(nsresult) { cbHandleError(callback, nsresult); @@ -544,20 +546,20 @@ ContentPrefService2.prototype = { this._cache.set(grp, name, undefined); }, onDone: function onDone(reason, ok) { - if (ok) { - if (context && context.usePrivateBrowsing) { - for (let [sgroup, sname, ] in this._pbStore) { - if (sname === name) { - prefs.set(sgroup, name); - this._pbStore.remove(sgroup, name); - } + if (ok && context && context.usePrivateBrowsing) { + for (let [sgroup, sname, ] in this._pbStore) { + if (sname === name) { + prefs.set(sgroup, name); + this._pbStore.remove(sgroup, name); } } + } + cbHandleCompletion(callback, reason); + if (ok) { for (let [sgroup, , ] in prefs) { this._cps._broadcastPrefRemoved(sgroup, name); } } - cbHandleCompletion(callback, reason); }, onError: function onError(nsresult) { cbHandleError(callback, nsresult); @@ -682,6 +684,10 @@ ContentPrefService2.prototype = { this._cps.removeObserver(name, observer); }, + extractDomain: function CPS2_extractDomain(str) { + return this._parseGroup(str); + }, + /** * Tests use this as a backchannel by calling it directly. * diff --git a/toolkit/components/contentprefs/tests/unit_cps2/head.js b/toolkit/components/contentprefs/tests/unit_cps2/head.js index ac0c45a2c86b..03e4bd4cf820 100644 --- a/toolkit/components/contentprefs/tests/unit_cps2/head.js +++ b/toolkit/components/contentprefs/tests/unit_cps2/head.js @@ -273,7 +273,7 @@ function dbOK(expectedRows) { stmt.finalize(); } -function on(event, names) { +function on(event, names, dontRemove) { let args = { reset: function () { for (let prop in this) { @@ -281,9 +281,6 @@ function on(event, names) { this[prop].splice(0, this[prop].length); } }, - destroy: function () { - names.forEach(function (n) cps.removeObserverForName(n, observers[n])); - }, }; let observers = {}; @@ -302,7 +299,15 @@ function on(event, names) { cps.addObserverForName(name, obs); }); - return args; + do_execute_soon(function () { + if (!dontRemove) + names.forEach(function (n) cps.removeObserverForName(n, observers[n])); + next(args); + }); +} + +function wait() { + do_execute_soon(next); } function observerArgsOK(actualArgs, expectedArgs) { diff --git a/toolkit/components/contentprefs/tests/unit_cps2/test_extractDomain.js b/toolkit/components/contentprefs/tests/unit_cps2/test_extractDomain.js new file mode 100644 index 000000000000..2ec3d6878b68 --- /dev/null +++ b/toolkit/components/contentprefs/tests/unit_cps2/test_extractDomain.js @@ -0,0 +1,20 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +function run_test() { + let tests = { + "http://example.com": "example.com", + "http://example.com/": "example.com", + "http://example.com/foo/bar/baz": "example.com", + "http://subdomain.example.com/foo/bar/baz": "subdomain.example.com", + "http://qix.quux.example.com/foo/bar/baz": "qix.quux.example.com", + "file:///home/foo/bar": "file:///home/foo/bar", + "not a url": "not a url", + }; + let cps = Cc["@mozilla.org/content-pref/service;1"]. + getService(Ci.nsIContentPrefService2); + for (let url in tests) { + do_check_eq(cps.extractDomain(url), tests[url]); + } +} diff --git a/toolkit/components/contentprefs/tests/unit_cps2/test_observers.js b/toolkit/components/contentprefs/tests/unit_cps2/test_observers.js index 421d0693068f..398d4b80edb3 100644 --- a/toolkit/components/contentprefs/tests/unit_cps2/test_observers.js +++ b/toolkit/components/contentprefs/tests/unit_cps2/test_observers.js @@ -9,43 +9,40 @@ function run_test() { let tests = [ function observerForName_set() { - let args = on("Set", ["foo", null, "bar"]); - yield set("a.com", "foo", 1); + let args = yield on("Set", ["foo", null, "bar"]); observerArgsOK(args.foo, [["a.com", "foo", 1]]); observerArgsOK(args.null, [["a.com", "foo", 1]]); observerArgsOK(args.bar, []); - args.reset(); yield setGlobal("foo", 2); + args = yield on("Set", ["foo", null, "bar"]); observerArgsOK(args.foo, [[null, "foo", 2]]); observerArgsOK(args.null, [[null, "foo", 2]]); observerArgsOK(args.bar, []); - args.reset(); }, function observerForName_remove() { yield set("a.com", "foo", 1); yield setGlobal("foo", 2); - let args = on("Removed", ["foo", null, "bar"]); yield cps.removeByDomainAndName("a.com", "bogus", null, makeCallback()); + let args = yield on("Removed", ["foo", null, "bar"]); observerArgsOK(args.foo, []); observerArgsOK(args.null, []); observerArgsOK(args.bar, []); - args.reset(); yield cps.removeByDomainAndName("a.com", "foo", null, makeCallback()); + args = yield on("Removed", ["foo", null, "bar"]); observerArgsOK(args.foo, [["a.com", "foo"]]); observerArgsOK(args.null, [["a.com", "foo"]]); observerArgsOK(args.bar, []); - args.reset(); yield cps.removeGlobal("foo", null, makeCallback()); + args = yield on("Removed", ["foo", null, "bar"]); observerArgsOK(args.foo, [[null, "foo"]]); observerArgsOK(args.null, [[null, "foo"]]); observerArgsOK(args.bar, []); - args.reset(); }, function observerForName_removeByDomain() { @@ -53,24 +50,23 @@ let tests = [ yield set("b.a.com", "bar", 2); yield setGlobal("foo", 3); - let args = on("Removed", ["foo", null, "bar"]); yield cps.removeByDomain("bogus", null, makeCallback()); + let args = yield on("Removed", ["foo", null, "bar"]); observerArgsOK(args.foo, []); observerArgsOK(args.null, []); observerArgsOK(args.bar, []); - args.reset(); yield cps.removeBySubdomain("a.com", null, makeCallback()); + args = yield on("Removed", ["foo", null, "bar"]); observerArgsOK(args.foo, [["a.com", "foo"]]); observerArgsOK(args.null, [["a.com", "foo"], ["b.a.com", "bar"]]); observerArgsOK(args.bar, [["b.a.com", "bar"]]); - args.reset(); yield cps.removeAllGlobals(null, makeCallback()); + args = yield on("Removed", ["foo", null, "bar"]); observerArgsOK(args.foo, [[null, "foo"]]); observerArgsOK(args.null, [[null, "foo"]]); observerArgsOK(args.bar, []); - args.reset(); }, function observerForName_removeAllDomains() { @@ -78,12 +74,11 @@ let tests = [ yield setGlobal("foo", 2); yield set("b.com", "bar", 3); - let args = on("Removed", ["foo", null, "bar"]); yield cps.removeAllDomains(null, makeCallback()); + let args = yield on("Removed", ["foo", null, "bar"]); observerArgsOK(args.foo, [["a.com", "foo"]]); observerArgsOK(args.null, [["a.com", "foo"], ["b.com", "bar"]]); observerArgsOK(args.bar, [["b.com", "bar"]]); - args.reset(); }, function observerForName_removeByName() { @@ -91,25 +86,25 @@ let tests = [ yield set("a.com", "bar", 2); yield setGlobal("foo", 3); - let args = on("Removed", ["foo", null, "bar"]); yield cps.removeByName("bogus", null, makeCallback()); + let args = yield on("Removed", ["foo", null, "bar"]); observerArgsOK(args.foo, []); observerArgsOK(args.null, []); observerArgsOK(args.bar, []); - args.reset(); yield cps.removeByName("foo", null, makeCallback()); + args = yield on("Removed", ["foo", null, "bar"]); observerArgsOK(args.foo, [["a.com", "foo"], [null, "foo"]]); observerArgsOK(args.null, [["a.com", "foo"], [null, "foo"]]); observerArgsOK(args.bar, []); - args.reset(); }, function removeObserverForName() { - let args = on("Set", ["foo", null, "bar"]); + let args = yield on("Set", ["foo", null, "bar"], true); cps.removeObserverForName("foo", args.foo.observer); yield set("a.com", "foo", 1); + yield wait(); observerArgsOK(args.foo, []); observerArgsOK(args.null, [["a.com", "foo", 1]]); observerArgsOK(args.bar, []); @@ -117,6 +112,7 @@ let tests = [ cps.removeObserverForName(null, args.null.observer); yield set("a.com", "foo", 2); + yield wait(); observerArgsOK(args.foo, []); observerArgsOK(args.null, []); observerArgsOK(args.bar, []); diff --git a/toolkit/components/contentprefs/tests/unit_cps2/xpcshell.ini b/toolkit/components/contentprefs/tests/unit_cps2/xpcshell.ini index 0fad2a9f2a94..cf1e1f5eb159 100644 --- a/toolkit/components/contentprefs/tests/unit_cps2/xpcshell.ini +++ b/toolkit/components/contentprefs/tests/unit_cps2/xpcshell.ini @@ -12,3 +12,4 @@ tail = [test_getCached.js] [test_getCachedSubdomains.js] [test_observers.js] +[test_extractDomain.js]