diff options
Diffstat (limited to 'application/basilisk/base/content/browser-fullZoom.js')
-rw-r--r-- | application/basilisk/base/content/browser-fullZoom.js | 526 |
1 files changed, 0 insertions, 526 deletions
diff --git a/application/basilisk/base/content/browser-fullZoom.js b/application/basilisk/base/content/browser-fullZoom.js deleted file mode 100644 index 890cd8440..000000000 --- a/application/basilisk/base/content/browser-fullZoom.js +++ /dev/null @@ -1,526 +0,0 @@ -/* 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/. */ - -/** - * Controls the "full zoom" setting and its site-specific preferences. - */ -var FullZoom = { - // Identifies the setting in the content prefs database. - name: "browser.content.full-zoom", - - // browser.zoom.siteSpecific preference cache - _siteSpecificPref: undefined, - - // browser.zoom.updateBackgroundTabs preference cache - updateBackgroundTabs: undefined, - - // This maps the browser to monotonically increasing integer - // tokens. _browserTokenMap[browser] is increased each time the zoom is - // changed in the browser. See _getBrowserToken and _ignorePendingZoomAccesses. - _browserTokenMap: new WeakMap(), - - // Stores initial locations if we receive onLocationChange - // events before we're initialized. - _initialLocations: new WeakMap(), - - get siteSpecific() { - return this._siteSpecificPref; - }, - - // nsISupports - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMEventListener, - Ci.nsIObserver, - Ci.nsIContentPrefObserver, - Ci.nsISupportsWeakReference, - Ci.nsISupports]), - - // Initialization & Destruction - - init: function FullZoom_init() { - gBrowser.addEventListener("ZoomChangeUsingMouseWheel", this); - - // Register ourselves with the service so we know when our pref changes. - 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"); - this.updateBackgroundTabs = - gPrefService.getBoolPref("browser.zoom.updateBackgroundTabs"); - // Listen for changes to the browser.zoom branch so we can enable/disable - // updating background tabs and per-site saving and restoring of zoom levels. - gPrefService.addObserver("browser.zoom.", this, true); - - // If we received onLocationChange events for any of the current browsers - // before we were initialized we want to replay those upon initialization. - for (let browser of gBrowser.browsers) { - if (this._initialLocations.has(browser)) { - this.onLocationChange(...this._initialLocations.get(browser), browser); - } - } - - // This should be nulled after initialization. - this._initialLocations = null; - }, - - destroy: function FullZoom_destroy() { - gPrefService.removeObserver("browser.zoom.", this); - this._cps2.removeObserverForName(this.name, this); - gBrowser.removeEventListener("ZoomChangeUsingMouseWheel", this); - }, - - - // Event Handlers - - // nsIDOMEventListener - - handleEvent: function FullZoom_handleEvent(event) { - switch (event.type) { - case "ZoomChangeUsingMouseWheel": - let browser = this._getTargetedBrowser(event); - this._ignorePendingZoomAccesses(browser); - this._applyZoomToPref(browser); - break; - } - }, - - // nsIObserver - - observe: function (aSubject, aTopic, aData) { - switch (aTopic) { - case "nsPref:changed": - switch (aData) { - case "browser.zoom.siteSpecific": - this._siteSpecificPref = - gPrefService.getBoolPref("browser.zoom.siteSpecific"); - break; - case "browser.zoom.updateBackgroundTabs": - this.updateBackgroundTabs = - gPrefService.getBoolPref("browser.zoom.updateBackgroundTabs"); - break; - } - break; - } - }, - - // nsIContentPrefObserver - - onContentPrefSet: function FullZoom_onContentPrefSet(aGroup, aName, aValue, aIsPrivate) { - this._onContentPrefChanged(aGroup, aValue, aIsPrivate); - }, - - onContentPrefRemoved: function FullZoom_onContentPrefRemoved(aGroup, aName, aIsPrivate) { - this._onContentPrefChanged(aGroup, undefined, aIsPrivate); - }, - - /** - * 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, aIsPrivate) { - if (this._isNextContentPrefChangeInternal) { - // Ignore changes that FullZoom itself makes. This works because the - // content pref service calls callbacks before notifying observers, and it - // does both in the same turn of the event loop. - delete this._isNextContentPrefChangeInternal; - return; - } - - let browser = gBrowser.selectedBrowser; - if (!browser.currentURI) - return; - - let ctxt = this._loadContextFromBrowser(browser); - let domain = this._cps2.extractDomain(browser.currentURI.spec); - if (aGroup) { - if (aGroup == domain && ctxt.usePrivateBrowsing == aIsPrivate) - this._applyPrefToZoom(aValue, browser); - 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 token = this._getBrowserToken(browser); - this._cps2.getByDomainAndName(browser.currentURI.spec, this.name, ctxt, { - handleResult: function () { hasPref = true; }, - handleCompletion: function () { - if (!hasPref && token.isCurrent) - this._applyPrefToZoom(undefined, browser); - }.bind(this) - }); - }, - - // location change observer - - /** - * Called when the location of a tab changes. - * When that happens, we need to update the current zoom level if appropriate. - * - * @param aURI - * A URI object representing the new location. - * @param aIsTabSwitch - * Whether this location change has happened because of a tab switch. - * @param aBrowser - * (optional) browser object displaying the document - */ - onLocationChange: function FullZoom_onLocationChange(aURI, aIsTabSwitch, aBrowser) { - let browser = aBrowser || gBrowser.selectedBrowser; - - // If we haven't been initialized yet but receive an onLocationChange - // notification then let's store and replay it upon initialization. - if (this._initialLocations) { - this._initialLocations.set(browser, [aURI, aIsTabSwitch]); - return; - } - - // Ignore all pending async zoom accesses in the browser. Pending accesses - // that started before the location change will be prevented from applying - // to the new location. - this._ignorePendingZoomAccesses(browser); - - if (!aURI || (aIsTabSwitch && !this.siteSpecific)) { - this._notifyOnLocationChange(browser); - return; - } - - // Avoid the cps roundtrip and apply the default/global pref. - if (aURI.spec == "about:blank") { - this._applyPrefToZoom(undefined, browser, - this._notifyOnLocationChange.bind(this, browser)); - return; - } - - // Media documents should always start at 1, and are not affected by prefs. - if (!aIsTabSwitch && browser.isSyntheticDocument) { - ZoomManager.setZoomForBrowser(browser, 1); - // _ignorePendingZoomAccesses already called above, so no need here. - this._notifyOnLocationChange(browser); - return; - } - - // See if the zoom pref is cached. - let ctxt = this._loadContextFromBrowser(browser); - let pref = this._cps2.getCachedByDomainAndName(aURI.spec, this.name, ctxt); - if (pref) { - this._applyPrefToZoom(pref.value, browser, - this._notifyOnLocationChange.bind(this, browser)); - return; - } - - // It's not cached, so we have to asynchronously fetch it. - let value = undefined; - let token = this._getBrowserToken(browser); - this._cps2.getByDomainAndName(aURI.spec, this.name, ctxt, { - handleResult: function (resultPref) { value = resultPref.value; }, - handleCompletion: function () { - if (!token.isCurrent) { - this._notifyOnLocationChange(browser); - return; - } - this._applyPrefToZoom(value, browser, - this._notifyOnLocationChange.bind(this, browser)); - }.bind(this) - }); - }, - - // update state of zoom type menu item - - updateMenu: function FullZoom_updateMenu() { - var menuItem = document.getElementById("toggle_zoom"); - - menuItem.setAttribute("checked", !ZoomManager.useFullZoom); - }, - - // Setting & Pref Manipulation - - /** - * Reduces the zoom level of the page in the current browser. - */ - reduce: function FullZoom_reduce() { - ZoomManager.reduce(); - let browser = gBrowser.selectedBrowser; - this._ignorePendingZoomAccesses(browser); - this._applyZoomToPref(browser); - }, - - /** - * Enlarges the zoom level of the page in the current browser. - */ - enlarge: function FullZoom_enlarge() { - ZoomManager.enlarge(); - let browser = gBrowser.selectedBrowser; - this._ignorePendingZoomAccesses(browser); - this._applyZoomToPref(browser); - }, - - /** - * Sets the zoom level for the given browser to the given floating - * point value, where 1 is the default zoom level. - */ - setZoom: function (value, browser = gBrowser.selectedBrowser) { - ZoomManager.setZoomForBrowser(browser, value); - this._ignorePendingZoomAccesses(browser); - this._applyZoomToPref(browser); - }, - - /** - * Sets the zoom level of the page in the given browser to the global zoom - * level. - * - * @return A promise which resolves when the zoom reset has been applied. - */ - reset: function FullZoom_reset(browser = gBrowser.selectedBrowser) { - let token = this._getBrowserToken(browser); - let result = this._getGlobalValue(browser).then(value => { - if (token.isCurrent) { - ZoomManager.setZoomForBrowser(browser, value === undefined ? 1 : value); - this._ignorePendingZoomAccesses(browser); - Services.obs.notifyObservers(browser, "browser-fullZoom:zoomReset", ""); - } - }); - this._removePref(browser); - return result; - }, - - /** - * Set the zoom level for a given browser. - * - * Per nsPresContext::setFullZoom, we can set the zoom to its current value - * without significant impact on performance, as the setting is only applied - * if it differs from the current setting. In fact getting the zoom and then - * checking ourselves if it differs costs more. - * - * And perhaps we should always set the zoom even if it was more expensive, - * since nsDocumentViewer::SetTextZoom claims that child documents can have - * a different text zoom (although it would be unusual), and it implies that - * those child text zooms should get updated when the parent zoom gets set, - * and perhaps the same is true for full zoom - * (although nsDocumentViewer::SetFullZoom doesn't mention it). - * - * 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. - * - * @param aValue The zoom level value. - * @param aBrowser The zoom is set in this browser. Required. - * @param aCallback If given, it's asynchronously called when complete. - */ - _applyPrefToZoom: function FullZoom__applyPrefToZoom(aValue, aBrowser, aCallback) { - if (!this.siteSpecific || gInPrintPreviewMode) { - this._executeSoon(aCallback); - return; - } - - // The browser is sometimes half-destroyed because this method is called - // by content pref service callbacks, which themselves can be called at any - // time, even after browsers are closed. - if (!aBrowser.parentNode || aBrowser.isSyntheticDocument) { - this._executeSoon(aCallback); - return; - } - - if (aValue !== undefined) { - ZoomManager.setZoomForBrowser(aBrowser, this._ensureValid(aValue)); - this._ignorePendingZoomAccesses(aBrowser); - this._executeSoon(aCallback); - return; - } - - let token = this._getBrowserToken(aBrowser); - this._getGlobalValue(aBrowser).then(value => { - if (token.isCurrent) { - ZoomManager.setZoomForBrowser(aBrowser, value === undefined ? 1 : value); - this._ignorePendingZoomAccesses(aBrowser); - } - this._executeSoon(aCallback); - }); - }, - - /** - * Saves the zoom level of the page in the given browser to the content - * prefs store. - * - * @param browser The zoom of this browser will be saved. Required. - */ - _applyZoomToPref: function FullZoom__applyZoomToPref(browser) { - Services.obs.notifyObservers(browser, "browser-fullZoom:zoomChange", ""); - if (!this.siteSpecific || - gInPrintPreviewMode || - browser.isSyntheticDocument) - return; - - this._cps2.set(browser.currentURI.spec, this.name, - ZoomManager.getZoomForBrowser(browser), - this._loadContextFromBrowser(browser), { - handleCompletion: function () { - this._isNextContentPrefChangeInternal = true; - }.bind(this), - }); - }, - - /** - * Removes from the content prefs store the zoom level of the given browser. - * - * @param browser The zoom of this browser will be removed. Required. - */ - _removePref: function FullZoom__removePref(browser) { - Services.obs.notifyObservers(browser, "browser-fullZoom:zoomReset", ""); - if (browser.isSyntheticDocument) - return; - let ctxt = this._loadContextFromBrowser(browser); - this._cps2.removeByDomainAndName(browser.currentURI.spec, this.name, ctxt, { - handleCompletion: function () { - this._isNextContentPrefChangeInternal = true; - }.bind(this), - }); - }, - - // Utilities - - /** - * Returns the zoom change token of the given browser. Asynchronous - * operations that access the given browser's zoom should use this method to - * capture the token before starting and use token.isCurrent to determine if - * it's safe to access the zoom when done. If token.isCurrent is false, then - * after the async operation started, either the browser's zoom was changed or - * the browser was destroyed, and depending on what the operation is doing, it - * may no longer be safe to set and get its zoom. - * - * @param browser The token of this browser will be returned. - * @return An object with an "isCurrent" getter. - */ - _getBrowserToken: function FullZoom__getBrowserToken(browser) { - let map = this._browserTokenMap; - if (!map.has(browser)) - map.set(browser, 0); - return { - token: map.get(browser), - get isCurrent() { - // At this point, the browser may have been destructed and unbound but - // its outer ID not removed from the map because outer-window-destroyed - // hasn't been received yet. In that case, the browser is unusable, it - // has no properties, so return false. Check for this case by getting a - // property, say, docShell. - return map.get(browser) === this.token && browser.parentNode; - }, - }; - }, - - /** - * Returns the browser that the supplied zoom event is associated with. - * @param event The ZoomChangeUsingMouseWheel event. - * @return The associated browser element, if one exists, otherwise null. - */ - _getTargetedBrowser: function FullZoom__getTargetedBrowser(event) { - let target = event.originalTarget; - - // With remote content browsers, the event's target is the browser - // we're looking for. - const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; - if (target instanceof window.XULElement && - target.localName == "browser" && - target.namespaceURI == XUL_NS) - return target; - - // With in-process content browsers, the event's target is the content - // document. - if (target.nodeType == Node.DOCUMENT_NODE) - return gBrowser.getBrowserForDocument(target); - - throw new Error("Unexpected ZoomChangeUsingMouseWheel event source"); - }, - - /** - * Increments the zoom change token for the given browser so that pending - * async operations know that it may be unsafe to access they zoom when they - * finish. - * - * @param browser Pending accesses in this browser will be ignored. - */ - _ignorePendingZoomAccesses: function FullZoom__ignorePendingZoomAccesses(browser) { - let map = this._browserTokenMap; - map.set(browser, (map.get(browser) || 0) + 1); - }, - - _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; - - if (aValue < ZoomManager.MIN) - return ZoomManager.MIN; - - if (aValue > ZoomManager.MAX) - return ZoomManager.MAX; - - return aValue; - }, - - /** - * Gets the global browser.content.full-zoom content preference. - * - * @param browser The browser pertaining to the zoom. - * @returns Promise<prefValue> - * Resolves to the preference value when done. - */ - _getGlobalValue: function FullZoom__getGlobalValue(browser) { - // * !("_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. - return new Promise(resolve => { - if ("_globalValue" in this) { - resolve(this._globalValue); - return; - } - let value = undefined; - this._cps2.getGlobal(this.name, this._loadContextFromBrowser(browser), { - handleResult: function (pref) { value = pref.value; }, - handleCompletion: (reason) => { - this._globalValue = this._ensureValid(value); - resolve(this._globalValue); - } - }); - }); - }, - - /** - * Gets the load context from the given Browser. - * - * @param Browser The Browser whose load context will be returned. - * @return The nsILoadContext of the given Browser. - */ - _loadContextFromBrowser: function FullZoom__loadContextFromBrowser(browser) { - return browser.loadContext; - }, - - /** - * Asynchronously broadcasts "browser-fullZoom:location-change" so that - * listeners can 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(browser) { - this._executeSoon(function () { - Services.obs.notifyObservers(browser, "browser-fullZoom:location-change", ""); - }); - }, - - _executeSoon: function FullZoom__executeSoon(callback) { - if (!callback) - return; - Services.tm.mainThread.dispatch(callback, Ci.nsIThread.DISPATCH_NORMAL); - }, -}; |