forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			336 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			336 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /*
 | |
| #ifdef 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/.
 | |
| #endif
 | |
|  */
 | |
| 
 | |
| // One of the possible values for the mousewheel.* preferences.
 | |
| // 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.
 | |
|  */
 | |
| 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,
 | |
| 
 | |
|   // browser.zoom.updateBackgroundTabs preference cache
 | |
|   updateBackgroundTabs: undefined,
 | |
| 
 | |
|   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() {
 | |
|     // Listen for scrollwheel events so we can save scrollwheel-based changes.
 | |
|     window.addEventListener("DOMMouseScroll", this, false);
 | |
| 
 | |
|     // Register ourselves with the service so we know when our pref changes.
 | |
|     getContentPrefs().addObserver(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);
 | |
|   },
 | |
| 
 | |
|   destroy: function FullZoom_destroy() {
 | |
|     gPrefService.removeObserver("browser.zoom.", this);
 | |
|     getContentPrefs().removeObserver(this.name, this);
 | |
|     window.removeEventListener("DOMMouseScroll", this, false);
 | |
|   },
 | |
| 
 | |
| 
 | |
|   //**************************************************************************//
 | |
|   // Event Handlers
 | |
| 
 | |
|   // nsIDOMEventListener
 | |
| 
 | |
|   handleEvent: function FullZoom_handleEvent(event) {
 | |
|     switch (event.type) {
 | |
|       case "DOMMouseScroll":
 | |
|         this._handleMouseScrolled(event);
 | |
|         break;
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   _handleMouseScrolled: function FullZoom__handleMouseScrolled(event) {
 | |
|     // Construct the "mousewheel action" pref key corresponding to this event.
 | |
|     // Based on nsEventStateManager::WheelPrefs::GetBasePrefName().
 | |
|     var pref = "mousewheel.";
 | |
| 
 | |
|     var pressedModifierCount = event.shiftKey + event.ctrlKey + event.altKey +
 | |
|                                  event.metaKey + event.getModifierState("OS");
 | |
|     if (pressedModifierCount != 1) {
 | |
|       pref += "default.";
 | |
|     } else if (event.shiftKey) {
 | |
|       pref += "with_shift.";
 | |
|     } else if (event.ctrlKey) {
 | |
|       pref += "with_control.";
 | |
|     } else if (event.altKey) {
 | |
|       pref += "with_alt.";
 | |
|     } else if (event.metaKey) {
 | |
|       pref += "with_meta.";
 | |
|     } else {
 | |
|       pref += "with_win.";
 | |
|     }
 | |
| 
 | |
|     pref += "action";
 | |
| 
 | |
|     // Don't do anything if this isn't a "zoom" scroll event.
 | |
|     var isZoomEvent = false;
 | |
|     try {
 | |
|       isZoomEvent = (gPrefService.getIntPref(pref) == MOUSE_SCROLL_ZOOM);
 | |
|     } catch (e) {}
 | |
|     if (!isZoomEvent)
 | |
|       return;
 | |
| 
 | |
|     // XXX Lazily cache all the possible action prefs so we don't have to get
 | |
|     // them anew from the pref service for every scroll event?  We'd have to
 | |
|     // make sure to observe them so we can update the cache when they change.
 | |
| 
 | |
|     // 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);
 | |
|   },
 | |
| 
 | |
|   // 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) {
 | |
|     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();
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   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;
 | |
| 
 | |
|       // 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();
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   // 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) {
 | |
|     if (!aURI || (aIsTabSwitch && !this.siteSpecific))
 | |
|       return;
 | |
| 
 | |
|     // Avoid the cps roundtrip and apply the default/global pref.
 | |
|     if (aURI.spec == "about:blank") {
 | |
|       this._applyPrefToSetting(undefined, aBrowser);
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     let browser = aBrowser || gBrowser.selectedBrowser;
 | |
| 
 | |
|     // Media documents should always start at 1, and are not affected by prefs.
 | |
|     if (!aIsTabSwitch && browser.contentDocument.mozSyntheticDocument) {
 | |
|       ZoomManager.setZoomForBrowser(browser, 1);
 | |
|       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);
 | |
|         }
 | |
|       });
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   // 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
 | |
| 
 | |
|   reduce: function FullZoom_reduce() {
 | |
|     ZoomManager.reduce();
 | |
|     this._applySettingToPref();
 | |
|   },
 | |
| 
 | |
|   enlarge: function FullZoom_enlarge() {
 | |
|     ZoomManager.enlarge();
 | |
|     this._applySettingToPref();
 | |
|   },
 | |
| 
 | |
|   reset: function FullZoom_reset() {
 | |
|     if (typeof this.globalValue != "undefined")
 | |
|       ZoomManager.zoom = this.globalValue;
 | |
|     else
 | |
|       ZoomManager.reset();
 | |
| 
 | |
|     this._removePref();
 | |
|   },
 | |
| 
 | |
|   /**
 | |
|    * Set the zoom level for the current tab.
 | |
|    *
 | |
|    * 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 DocumentViewerImpl::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 DocumentViewerImpl::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.
 | |
|    **/
 | |
|   _applyPrefToSetting: function FullZoom__applyPrefToSetting(aValue, aBrowser) {
 | |
|     if ((!this.siteSpecific) || gInPrintPreviewMode)
 | |
|       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)
 | |
|       return;
 | |
| 
 | |
|     var zoomLevel = ZoomManager.zoom;
 | |
|     getContentPrefs(gBrowser.contentDocument.defaultView).setPref(gBrowser.currentURI, this.name, zoomLevel);
 | |
|   },
 | |
| 
 | |
|   _removePref: function FullZoom__removePref() {
 | |
|     if (!(content.document.mozSyntheticDocument))
 | |
|       getContentPrefs(gBrowser.contentDocument.defaultView).removePref(gBrowser.currentURI, this.name);
 | |
|   },
 | |
| 
 | |
| 
 | |
|   //**************************************************************************//
 | |
|   // Utilities
 | |
| 
 | |
|   _ensureValid: function FullZoom__ensureValid(aValue) {
 | |
|     if (isNaN(aValue))
 | |
|       return 1;
 | |
| 
 | |
|     if (aValue < ZoomManager.MIN)
 | |
|       return ZoomManager.MIN;
 | |
| 
 | |
|     if (aValue > ZoomManager.MAX)
 | |
|       return ZoomManager.MAX;
 | |
| 
 | |
|     return aValue;
 | |
|   }
 | |
| };
 | 
