browser/base/content/browser-fullZoom.js

Wed, 31 Dec 2014 06:55:46 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:46 +0100
changeset 1
ca08bd8f51b2
permissions
-rw-r--r--

Added tag TORBROWSER_REPLICA for changeset 6474c204b198

michael@0 1 /*
michael@0 2 #ifdef 0
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0 6 #endif
michael@0 7 */
michael@0 8
michael@0 9 /**
michael@0 10 * Controls the "full zoom" setting and its site-specific preferences.
michael@0 11 */
michael@0 12 var FullZoom = {
michael@0 13 // Identifies the setting in the content prefs database.
michael@0 14 name: "browser.content.full-zoom",
michael@0 15
michael@0 16 // browser.zoom.siteSpecific preference cache
michael@0 17 _siteSpecificPref: undefined,
michael@0 18
michael@0 19 // browser.zoom.updateBackgroundTabs preference cache
michael@0 20 updateBackgroundTabs: undefined,
michael@0 21
michael@0 22 // One of the possible values for the mousewheel.* preferences.
michael@0 23 // From EventStateManager.h.
michael@0 24 ACTION_ZOOM: 3,
michael@0 25
michael@0 26 // This maps the browser to monotonically increasing integer
michael@0 27 // tokens. _browserTokenMap[browser] is increased each time the zoom is
michael@0 28 // changed in the browser. See _getBrowserToken and _ignorePendingZoomAccesses.
michael@0 29 _browserTokenMap: new WeakMap(),
michael@0 30
michael@0 31 get siteSpecific() {
michael@0 32 return this._siteSpecificPref;
michael@0 33 },
michael@0 34
michael@0 35 //**************************************************************************//
michael@0 36 // nsISupports
michael@0 37
michael@0 38 QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMEventListener,
michael@0 39 Ci.nsIObserver,
michael@0 40 Ci.nsIContentPrefObserver,
michael@0 41 Ci.nsISupportsWeakReference,
michael@0 42 Ci.nsISupports]),
michael@0 43
michael@0 44 //**************************************************************************//
michael@0 45 // Initialization & Destruction
michael@0 46
michael@0 47 init: function FullZoom_init() {
michael@0 48 // Listen for scrollwheel events so we can save scrollwheel-based changes.
michael@0 49 window.addEventListener("DOMMouseScroll", this, false);
michael@0 50
michael@0 51 // Register ourselves with the service so we know when our pref changes.
michael@0 52 this._cps2 = Cc["@mozilla.org/content-pref/service;1"].
michael@0 53 getService(Ci.nsIContentPrefService2);
michael@0 54 this._cps2.addObserverForName(this.name, this);
michael@0 55
michael@0 56 this._siteSpecificPref =
michael@0 57 gPrefService.getBoolPref("browser.zoom.siteSpecific");
michael@0 58 this.updateBackgroundTabs =
michael@0 59 gPrefService.getBoolPref("browser.zoom.updateBackgroundTabs");
michael@0 60 // Listen for changes to the browser.zoom branch so we can enable/disable
michael@0 61 // updating background tabs and per-site saving and restoring of zoom levels.
michael@0 62 gPrefService.addObserver("browser.zoom.", this, true);
michael@0 63 },
michael@0 64
michael@0 65 destroy: function FullZoom_destroy() {
michael@0 66 gPrefService.removeObserver("browser.zoom.", this);
michael@0 67 this._cps2.removeObserverForName(this.name, this);
michael@0 68 window.removeEventListener("DOMMouseScroll", this, false);
michael@0 69 },
michael@0 70
michael@0 71
michael@0 72 //**************************************************************************//
michael@0 73 // Event Handlers
michael@0 74
michael@0 75 // nsIDOMEventListener
michael@0 76
michael@0 77 handleEvent: function FullZoom_handleEvent(event) {
michael@0 78 switch (event.type) {
michael@0 79 case "DOMMouseScroll":
michael@0 80 this._handleMouseScrolled(event);
michael@0 81 break;
michael@0 82 }
michael@0 83 },
michael@0 84
michael@0 85 _handleMouseScrolled: function FullZoom__handleMouseScrolled(event) {
michael@0 86 // Construct the "mousewheel action" pref key corresponding to this event.
michael@0 87 // Based on EventStateManager::WheelPrefs::GetBasePrefName().
michael@0 88 var pref = "mousewheel.";
michael@0 89
michael@0 90 var pressedModifierCount = event.shiftKey + event.ctrlKey + event.altKey +
michael@0 91 event.metaKey + event.getModifierState("OS");
michael@0 92 if (pressedModifierCount != 1) {
michael@0 93 pref += "default.";
michael@0 94 } else if (event.shiftKey) {
michael@0 95 pref += "with_shift.";
michael@0 96 } else if (event.ctrlKey) {
michael@0 97 pref += "with_control.";
michael@0 98 } else if (event.altKey) {
michael@0 99 pref += "with_alt.";
michael@0 100 } else if (event.metaKey) {
michael@0 101 pref += "with_meta.";
michael@0 102 } else {
michael@0 103 pref += "with_win.";
michael@0 104 }
michael@0 105
michael@0 106 pref += "action";
michael@0 107
michael@0 108 // Don't do anything if this isn't a "zoom" scroll event.
michael@0 109 var isZoomEvent = false;
michael@0 110 try {
michael@0 111 isZoomEvent = (gPrefService.getIntPref(pref) == this.ACTION_ZOOM);
michael@0 112 } catch (e) {}
michael@0 113 if (!isZoomEvent)
michael@0 114 return;
michael@0 115
michael@0 116 // XXX Lazily cache all the possible action prefs so we don't have to get
michael@0 117 // them anew from the pref service for every scroll event? We'd have to
michael@0 118 // make sure to observe them so we can update the cache when they change.
michael@0 119
michael@0 120 // We have to call _applyZoomToPref in a timeout because we handle the
michael@0 121 // event before the event state manager has a chance to apply the zoom
michael@0 122 // during EventStateManager::PostHandleEvent.
michael@0 123 let browser = gBrowser.selectedBrowser;
michael@0 124 let token = this._getBrowserToken(browser);
michael@0 125 window.setTimeout(function () {
michael@0 126 if (token.isCurrent)
michael@0 127 this._applyZoomToPref(browser);
michael@0 128 }.bind(this), 0);
michael@0 129 },
michael@0 130
michael@0 131 // nsIObserver
michael@0 132
michael@0 133 observe: function (aSubject, aTopic, aData) {
michael@0 134 switch (aTopic) {
michael@0 135 case "nsPref:changed":
michael@0 136 switch (aData) {
michael@0 137 case "browser.zoom.siteSpecific":
michael@0 138 this._siteSpecificPref =
michael@0 139 gPrefService.getBoolPref("browser.zoom.siteSpecific");
michael@0 140 break;
michael@0 141 case "browser.zoom.updateBackgroundTabs":
michael@0 142 this.updateBackgroundTabs =
michael@0 143 gPrefService.getBoolPref("browser.zoom.updateBackgroundTabs");
michael@0 144 break;
michael@0 145 }
michael@0 146 break;
michael@0 147 }
michael@0 148 },
michael@0 149
michael@0 150 // nsIContentPrefObserver
michael@0 151
michael@0 152 onContentPrefSet: function FullZoom_onContentPrefSet(aGroup, aName, aValue) {
michael@0 153 this._onContentPrefChanged(aGroup, aValue);
michael@0 154 },
michael@0 155
michael@0 156 onContentPrefRemoved: function FullZoom_onContentPrefRemoved(aGroup, aName) {
michael@0 157 this._onContentPrefChanged(aGroup, undefined);
michael@0 158 },
michael@0 159
michael@0 160 /**
michael@0 161 * Appropriately updates the zoom level after a content preference has
michael@0 162 * changed.
michael@0 163 *
michael@0 164 * @param aGroup The group of the changed preference.
michael@0 165 * @param aValue The new value of the changed preference. Pass undefined to
michael@0 166 * indicate the preference's removal.
michael@0 167 */
michael@0 168 _onContentPrefChanged: function FullZoom__onContentPrefChanged(aGroup, aValue) {
michael@0 169 if (this._isNextContentPrefChangeInternal) {
michael@0 170 // Ignore changes that FullZoom itself makes. This works because the
michael@0 171 // content pref service calls callbacks before notifying observers, and it
michael@0 172 // does both in the same turn of the event loop.
michael@0 173 delete this._isNextContentPrefChangeInternal;
michael@0 174 return;
michael@0 175 }
michael@0 176
michael@0 177 let browser = gBrowser.selectedBrowser;
michael@0 178 if (!browser.currentURI)
michael@0 179 return;
michael@0 180
michael@0 181 let domain = this._cps2.extractDomain(browser.currentURI.spec);
michael@0 182 if (aGroup) {
michael@0 183 if (aGroup == domain)
michael@0 184 this._applyPrefToZoom(aValue, browser);
michael@0 185 return;
michael@0 186 }
michael@0 187
michael@0 188 this._globalValue = aValue === undefined ? aValue :
michael@0 189 this._ensureValid(aValue);
michael@0 190
michael@0 191 // If the current page doesn't have a site-specific preference, then its
michael@0 192 // zoom should be set to the new global preference now that the global
michael@0 193 // preference has changed.
michael@0 194 let hasPref = false;
michael@0 195 let ctxt = this._loadContextFromBrowser(browser);
michael@0 196 let token = this._getBrowserToken(browser);
michael@0 197 this._cps2.getByDomainAndName(browser.currentURI.spec, this.name, ctxt, {
michael@0 198 handleResult: function () hasPref = true,
michael@0 199 handleCompletion: function () {
michael@0 200 if (!hasPref && token.isCurrent)
michael@0 201 this._applyPrefToZoom(undefined, browser);
michael@0 202 }.bind(this)
michael@0 203 });
michael@0 204 },
michael@0 205
michael@0 206 // location change observer
michael@0 207
michael@0 208 /**
michael@0 209 * Called when the location of a tab changes.
michael@0 210 * When that happens, we need to update the current zoom level if appropriate.
michael@0 211 *
michael@0 212 * @param aURI
michael@0 213 * A URI object representing the new location.
michael@0 214 * @param aIsTabSwitch
michael@0 215 * Whether this location change has happened because of a tab switch.
michael@0 216 * @param aBrowser
michael@0 217 * (optional) browser object displaying the document
michael@0 218 */
michael@0 219 onLocationChange: function FullZoom_onLocationChange(aURI, aIsTabSwitch, aBrowser) {
michael@0 220 // Ignore all pending async zoom accesses in the browser. Pending accesses
michael@0 221 // that started before the location change will be prevented from applying
michael@0 222 // to the new location.
michael@0 223 let browser = aBrowser || gBrowser.selectedBrowser;
michael@0 224 this._ignorePendingZoomAccesses(browser);
michael@0 225
michael@0 226 if (!aURI || (aIsTabSwitch && !this.siteSpecific)) {
michael@0 227 this._notifyOnLocationChange();
michael@0 228 return;
michael@0 229 }
michael@0 230
michael@0 231 // Avoid the cps roundtrip and apply the default/global pref.
michael@0 232 if (aURI.spec == "about:blank") {
michael@0 233 this._applyPrefToZoom(undefined, browser,
michael@0 234 this._notifyOnLocationChange.bind(this));
michael@0 235 return;
michael@0 236 }
michael@0 237
michael@0 238 // Media documents should always start at 1, and are not affected by prefs.
michael@0 239 if (!aIsTabSwitch && browser.isSyntheticDocument) {
michael@0 240 ZoomManager.setZoomForBrowser(browser, 1);
michael@0 241 // _ignorePendingZoomAccesses already called above, so no need here.
michael@0 242 this._notifyOnLocationChange();
michael@0 243 return;
michael@0 244 }
michael@0 245
michael@0 246 // See if the zoom pref is cached.
michael@0 247 let ctxt = this._loadContextFromBrowser(browser);
michael@0 248 let pref = this._cps2.getCachedByDomainAndName(aURI.spec, this.name, ctxt);
michael@0 249 if (pref) {
michael@0 250 this._applyPrefToZoom(pref.value, browser,
michael@0 251 this._notifyOnLocationChange.bind(this));
michael@0 252 return;
michael@0 253 }
michael@0 254
michael@0 255 // It's not cached, so we have to asynchronously fetch it.
michael@0 256 let value = undefined;
michael@0 257 let token = this._getBrowserToken(browser);
michael@0 258 this._cps2.getByDomainAndName(aURI.spec, this.name, ctxt, {
michael@0 259 handleResult: function (resultPref) value = resultPref.value,
michael@0 260 handleCompletion: function () {
michael@0 261 if (!token.isCurrent) {
michael@0 262 this._notifyOnLocationChange();
michael@0 263 return;
michael@0 264 }
michael@0 265 this._applyPrefToZoom(value, browser,
michael@0 266 this._notifyOnLocationChange.bind(this));
michael@0 267 }.bind(this)
michael@0 268 });
michael@0 269 },
michael@0 270
michael@0 271 // update state of zoom type menu item
michael@0 272
michael@0 273 updateMenu: function FullZoom_updateMenu() {
michael@0 274 var menuItem = document.getElementById("toggle_zoom");
michael@0 275
michael@0 276 menuItem.setAttribute("checked", !ZoomManager.useFullZoom);
michael@0 277 },
michael@0 278
michael@0 279 //**************************************************************************//
michael@0 280 // Setting & Pref Manipulation
michael@0 281
michael@0 282 /**
michael@0 283 * Reduces the zoom level of the page in the current browser.
michael@0 284 */
michael@0 285 reduce: function FullZoom_reduce() {
michael@0 286 ZoomManager.reduce();
michael@0 287 let browser = gBrowser.selectedBrowser;
michael@0 288 this._ignorePendingZoomAccesses(browser);
michael@0 289 this._applyZoomToPref(browser);
michael@0 290 },
michael@0 291
michael@0 292 /**
michael@0 293 * Enlarges the zoom level of the page in the current browser.
michael@0 294 */
michael@0 295 enlarge: function FullZoom_enlarge() {
michael@0 296 ZoomManager.enlarge();
michael@0 297 let browser = gBrowser.selectedBrowser;
michael@0 298 this._ignorePendingZoomAccesses(browser);
michael@0 299 this._applyZoomToPref(browser);
michael@0 300 },
michael@0 301
michael@0 302 /**
michael@0 303 * Sets the zoom level of the page in the current browser to the global zoom
michael@0 304 * level.
michael@0 305 */
michael@0 306 reset: function FullZoom_reset() {
michael@0 307 let browser = gBrowser.selectedBrowser;
michael@0 308 let token = this._getBrowserToken(browser);
michael@0 309 this._getGlobalValue(browser, function (value) {
michael@0 310 if (token.isCurrent) {
michael@0 311 ZoomManager.setZoomForBrowser(browser, value === undefined ? 1 : value);
michael@0 312 this._ignorePendingZoomAccesses(browser);
michael@0 313 this._executeSoon(function () {
michael@0 314 // _getGlobalValue may be either sync or async, so notify asyncly so
michael@0 315 // observers are guaranteed consistent behavior.
michael@0 316 Services.obs.notifyObservers(null, "browser-fullZoom:zoomReset", "");
michael@0 317 });
michael@0 318 }
michael@0 319 });
michael@0 320 this._removePref(browser);
michael@0 321 },
michael@0 322
michael@0 323 /**
michael@0 324 * Set the zoom level for a given browser.
michael@0 325 *
michael@0 326 * Per nsPresContext::setFullZoom, we can set the zoom to its current value
michael@0 327 * without significant impact on performance, as the setting is only applied
michael@0 328 * if it differs from the current setting. In fact getting the zoom and then
michael@0 329 * checking ourselves if it differs costs more.
michael@0 330 *
michael@0 331 * And perhaps we should always set the zoom even if it was more expensive,
michael@0 332 * since nsDocumentViewer::SetTextZoom claims that child documents can have
michael@0 333 * a different text zoom (although it would be unusual), and it implies that
michael@0 334 * those child text zooms should get updated when the parent zoom gets set,
michael@0 335 * and perhaps the same is true for full zoom
michael@0 336 * (although nsDocumentViewer::SetFullZoom doesn't mention it).
michael@0 337 *
michael@0 338 * So when we apply new zoom values to the browser, we simply set the zoom.
michael@0 339 * We don't check first to see if the new value is the same as the current
michael@0 340 * one.
michael@0 341 *
michael@0 342 * @param aValue The zoom level value.
michael@0 343 * @param aBrowser The zoom is set in this browser. Required.
michael@0 344 * @param aCallback If given, it's asynchronously called when complete.
michael@0 345 */
michael@0 346 _applyPrefToZoom: function FullZoom__applyPrefToZoom(aValue, aBrowser, aCallback) {
michael@0 347 if (!this.siteSpecific || gInPrintPreviewMode) {
michael@0 348 this._executeSoon(aCallback);
michael@0 349 return;
michael@0 350 }
michael@0 351
michael@0 352 // The browser is sometimes half-destroyed because this method is called
michael@0 353 // by content pref service callbacks, which themselves can be called at any
michael@0 354 // time, even after browsers are closed.
michael@0 355 if (!aBrowser.parentNode || aBrowser.isSyntheticDocument) {
michael@0 356 this._executeSoon(aCallback);
michael@0 357 return;
michael@0 358 }
michael@0 359
michael@0 360 if (aValue !== undefined) {
michael@0 361 ZoomManager.setZoomForBrowser(aBrowser, this._ensureValid(aValue));
michael@0 362 this._ignorePendingZoomAccesses(aBrowser);
michael@0 363 this._executeSoon(aCallback);
michael@0 364 return;
michael@0 365 }
michael@0 366
michael@0 367 let token = this._getBrowserToken(aBrowser);
michael@0 368 this._getGlobalValue(aBrowser, function (value) {
michael@0 369 if (token.isCurrent) {
michael@0 370 ZoomManager.setZoomForBrowser(aBrowser, value === undefined ? 1 : value);
michael@0 371 this._ignorePendingZoomAccesses(aBrowser);
michael@0 372 }
michael@0 373 this._executeSoon(aCallback);
michael@0 374 });
michael@0 375 },
michael@0 376
michael@0 377 /**
michael@0 378 * Saves the zoom level of the page in the given browser to the content
michael@0 379 * prefs store.
michael@0 380 *
michael@0 381 * @param browser The zoom of this browser will be saved. Required.
michael@0 382 */
michael@0 383 _applyZoomToPref: function FullZoom__applyZoomToPref(browser) {
michael@0 384 Services.obs.notifyObservers(null, "browser-fullZoom:zoomChange", "");
michael@0 385 if (!this.siteSpecific ||
michael@0 386 gInPrintPreviewMode ||
michael@0 387 browser.isSyntheticDocument)
michael@0 388 return;
michael@0 389
michael@0 390 this._cps2.set(browser.currentURI.spec, this.name,
michael@0 391 ZoomManager.getZoomForBrowser(browser),
michael@0 392 this._loadContextFromBrowser(browser), {
michael@0 393 handleCompletion: function () {
michael@0 394 this._isNextContentPrefChangeInternal = true;
michael@0 395 }.bind(this),
michael@0 396 });
michael@0 397 },
michael@0 398
michael@0 399 /**
michael@0 400 * Removes from the content prefs store the zoom level of the given browser.
michael@0 401 *
michael@0 402 * @param browser The zoom of this browser will be removed. Required.
michael@0 403 */
michael@0 404 _removePref: function FullZoom__removePref(browser) {
michael@0 405 Services.obs.notifyObservers(null, "browser-fullZoom:zoomReset", "");
michael@0 406 if (browser.isSyntheticDocument)
michael@0 407 return;
michael@0 408 let ctxt = this._loadContextFromBrowser(browser);
michael@0 409 this._cps2.removeByDomainAndName(browser.currentURI.spec, this.name, ctxt, {
michael@0 410 handleCompletion: function () {
michael@0 411 this._isNextContentPrefChangeInternal = true;
michael@0 412 }.bind(this),
michael@0 413 });
michael@0 414 },
michael@0 415
michael@0 416 //**************************************************************************//
michael@0 417 // Utilities
michael@0 418
michael@0 419 /**
michael@0 420 * Returns the zoom change token of the given browser. Asynchronous
michael@0 421 * operations that access the given browser's zoom should use this method to
michael@0 422 * capture the token before starting and use token.isCurrent to determine if
michael@0 423 * it's safe to access the zoom when done. If token.isCurrent is false, then
michael@0 424 * after the async operation started, either the browser's zoom was changed or
michael@0 425 * the browser was destroyed, and depending on what the operation is doing, it
michael@0 426 * may no longer be safe to set and get its zoom.
michael@0 427 *
michael@0 428 * @param browser The token of this browser will be returned.
michael@0 429 * @return An object with an "isCurrent" getter.
michael@0 430 */
michael@0 431 _getBrowserToken: function FullZoom__getBrowserToken(browser) {
michael@0 432 let map = this._browserTokenMap;
michael@0 433 if (!map.has(browser))
michael@0 434 map.set(browser, 0);
michael@0 435 return {
michael@0 436 token: map.get(browser),
michael@0 437 get isCurrent() {
michael@0 438 // At this point, the browser may have been destructed and unbound but
michael@0 439 // its outer ID not removed from the map because outer-window-destroyed
michael@0 440 // hasn't been received yet. In that case, the browser is unusable, it
michael@0 441 // has no properties, so return false. Check for this case by getting a
michael@0 442 // property, say, docShell.
michael@0 443 return map.get(browser) === this.token && browser.parentNode;
michael@0 444 },
michael@0 445 };
michael@0 446 },
michael@0 447
michael@0 448 /**
michael@0 449 * Increments the zoom change token for the given browser so that pending
michael@0 450 * async operations know that it may be unsafe to access they zoom when they
michael@0 451 * finish.
michael@0 452 *
michael@0 453 * @param browser Pending accesses in this browser will be ignored.
michael@0 454 */
michael@0 455 _ignorePendingZoomAccesses: function FullZoom__ignorePendingZoomAccesses(browser) {
michael@0 456 let map = this._browserTokenMap;
michael@0 457 map.set(browser, (map.get(browser) || 0) + 1);
michael@0 458 },
michael@0 459
michael@0 460 _ensureValid: function FullZoom__ensureValid(aValue) {
michael@0 461 // Note that undefined is a valid value for aValue that indicates a known-
michael@0 462 // not-to-exist value.
michael@0 463 if (isNaN(aValue))
michael@0 464 return 1;
michael@0 465
michael@0 466 if (aValue < ZoomManager.MIN)
michael@0 467 return ZoomManager.MIN;
michael@0 468
michael@0 469 if (aValue > ZoomManager.MAX)
michael@0 470 return ZoomManager.MAX;
michael@0 471
michael@0 472 return aValue;
michael@0 473 },
michael@0 474
michael@0 475 /**
michael@0 476 * Gets the global browser.content.full-zoom content preference.
michael@0 477 *
michael@0 478 * WARNING: callback may be called synchronously or asynchronously. The
michael@0 479 * reason is that it's usually desirable to avoid turns of the event loop
michael@0 480 * where possible, since they can lead to visible, jarring jumps in zoom
michael@0 481 * level. It's not always possible to avoid them, though. As a convenience,
michael@0 482 * then, this method takes a callback and returns nothing.
michael@0 483 *
michael@0 484 * @param browser The browser pertaining to the zoom.
michael@0 485 * @param callback Synchronously or asynchronously called when done. It's
michael@0 486 * bound to this object (FullZoom) and called as:
michael@0 487 * callback(prefValue)
michael@0 488 */
michael@0 489 _getGlobalValue: function FullZoom__getGlobalValue(browser, callback) {
michael@0 490 // * !("_globalValue" in this) => global value not yet cached.
michael@0 491 // * this._globalValue === undefined => global value known not to exist.
michael@0 492 // * Otherwise, this._globalValue is a number, the global value.
michael@0 493 if ("_globalValue" in this) {
michael@0 494 callback.call(this, this._globalValue, true);
michael@0 495 return;
michael@0 496 }
michael@0 497 let value = undefined;
michael@0 498 this._cps2.getGlobal(this.name, this._loadContextFromBrowser(browser), {
michael@0 499 handleResult: function (pref) value = pref.value,
michael@0 500 handleCompletion: function (reason) {
michael@0 501 this._globalValue = this._ensureValid(value);
michael@0 502 callback.call(this, this._globalValue);
michael@0 503 }.bind(this)
michael@0 504 });
michael@0 505 },
michael@0 506
michael@0 507 /**
michael@0 508 * Gets the load context from the given Browser.
michael@0 509 *
michael@0 510 * @param Browser The Browser whose load context will be returned.
michael@0 511 * @return The nsILoadContext of the given Browser.
michael@0 512 */
michael@0 513 _loadContextFromBrowser: function FullZoom__loadContextFromBrowser(browser) {
michael@0 514 return browser.loadContext;
michael@0 515 },
michael@0 516
michael@0 517 /**
michael@0 518 * Asynchronously broadcasts "browser-fullZoom:location-change" so that
michael@0 519 * listeners can be notified when the zoom levels on those pages change.
michael@0 520 * The notification is always asynchronous so that observers are guaranteed a
michael@0 521 * consistent behavior.
michael@0 522 */
michael@0 523 _notifyOnLocationChange: function FullZoom__notifyOnLocationChange() {
michael@0 524 this._executeSoon(function () {
michael@0 525 Services.obs.notifyObservers(null, "browser-fullZoom:location-change", "");
michael@0 526 });
michael@0 527 },
michael@0 528
michael@0 529 _executeSoon: function FullZoom__executeSoon(callback) {
michael@0 530 if (!callback)
michael@0 531 return;
michael@0 532 Services.tm.mainThread.dispatch(callback, Ci.nsIThread.DISPATCH_NORMAL);
michael@0 533 },
michael@0 534 };

mercurial