forked from mirrors/gecko-dev
		
	 f99ee35b82
			
		
	
	
		f99ee35b82
		
	
	
	
	
		
			
			Creating non-shared scopes for frame scripts is fairly expensive. After these changes it's even more expensive. However, many frame scripts have no use for the shared scopes at all. Run-once scripts which execute in closures, for instance, make no use of them. And after bug 1472491, neither do most of our default frame scripts. MozReview-Commit-ID: 9PK7bYdQ0yh --HG-- extra : rebase_source : db2516d2f00a75e233e1957649f2b62a9299b7cd
		
			
				
	
	
		
			232 lines
		
	
	
	
		
			7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			232 lines
		
	
	
	
		
			7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 | |
| /* 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/. */
 | |
| /* globals  APP_STARTUP, ADDON_INSTALL */
 | |
| "use strict";
 | |
| 
 | |
| ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 | |
| XPCOMUtils.defineLazyModuleGetters(this, {
 | |
|   OnboardingTourType: "resource://onboarding/modules/OnboardingTourType.jsm",
 | |
|   OnboardingTelemetry: "resource://onboarding/modules/OnboardingTelemetry.jsm",
 | |
|   Services: "resource://gre/modules/Services.jsm",
 | |
|   UIState: "resource://services-sync/UIState.jsm",
 | |
| });
 | |
| 
 | |
| XPCOMUtils.defineLazyServiceGetter(this, "resProto",
 | |
|                                    "@mozilla.org/network/protocol;1?name=resource",
 | |
|                                    "nsISubstitutingProtocolHandler");
 | |
| 
 | |
| const RESOURCE_HOST = "onboarding";
 | |
| 
 | |
| const {PREF_STRING, PREF_BOOL, PREF_INT} = Ci.nsIPrefBranch;
 | |
| 
 | |
| const BROWSER_READY_NOTIFICATION = "browser-delayed-startup-finished";
 | |
| const BROWSER_SESSION_STORE_NOTIFICATION = "sessionstore-windows-restored";
 | |
| const PREF_WHITELIST = [
 | |
|   ["browser.onboarding.enabled", PREF_BOOL],
 | |
|   ["browser.onboarding.state", PREF_STRING],
 | |
|   ["browser.onboarding.notification.finished", PREF_BOOL],
 | |
|   ["browser.onboarding.notification.prompt-count", PREF_INT],
 | |
|   ["browser.onboarding.notification.last-time-of-changing-tour-sec", PREF_INT],
 | |
|   ["browser.onboarding.notification.tour-ids-queue", PREF_STRING],
 | |
| ];
 | |
| 
 | |
| [
 | |
|   "onboarding-tour-addons",
 | |
|   "onboarding-tour-customize",
 | |
|   "onboarding-tour-default-browser",
 | |
|   "onboarding-tour-library",
 | |
|   "onboarding-tour-performance",
 | |
|   "onboarding-tour-private-browsing",
 | |
|   "onboarding-tour-screenshots",
 | |
|   "onboarding-tour-singlesearch",
 | |
|   "onboarding-tour-sync",
 | |
| ].forEach(tourId => PREF_WHITELIST.push([`browser.onboarding.tour.${tourId}.completed`, PREF_BOOL]));
 | |
| 
 | |
| let waitingForBrowserReady = true;
 | |
| let startupData;
 | |
| 
 | |
| /**
 | |
|  * Set pref. Why no `getPrefs` function is due to the privilege level.
 | |
|  * We cannot set prefs inside a framescript but can read.
 | |
|  * For simplicity and efficiency, we still read prefs inside the framescript.
 | |
|  *
 | |
|  * @param {Array} prefs the array of prefs to set.
 | |
|  *   The array element carries info to set pref, should contain
 | |
|  *   - {String} name the pref name, such as `browser.onboarding.state`
 | |
|  *   - {*} value the value to set
 | |
|  **/
 | |
| function setPrefs(prefs) {
 | |
|   prefs.forEach(pref => {
 | |
|     let prefObj = PREF_WHITELIST.find(([name, ]) => name == pref.name);
 | |
|     if (!prefObj) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     let [name, type] = prefObj;
 | |
| 
 | |
|     switch (type) {
 | |
|       case PREF_BOOL:
 | |
|         Services.prefs.setBoolPref(name, pref.value);
 | |
|         break;
 | |
|       case PREF_INT:
 | |
|         Services.prefs.setIntPref(name, pref.value);
 | |
|         break;
 | |
|       case PREF_STRING:
 | |
|         Services.prefs.setStringPref(name, pref.value);
 | |
|         break;
 | |
|       default:
 | |
|         throw new TypeError(`Unexpected type (${type}) for preference ${name}.`);
 | |
|     }
 | |
|   });
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * syncTourChecker listens to and maintains the login status inside, and can be
 | |
|  * queried at any time once initialized.
 | |
|  */
 | |
| let syncTourChecker = {
 | |
|   _registered: false,
 | |
|   _loggedIn: false,
 | |
| 
 | |
|   isLoggedIn() {
 | |
|     return this._loggedIn;
 | |
|   },
 | |
| 
 | |
|   observe(subject, topic) {
 | |
|     const state = UIState.get();
 | |
|     if (state.status == UIState.STATUS_NOT_CONFIGURED) {
 | |
|       this._loggedIn = false;
 | |
|     } else {
 | |
|       this.setComplete();
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   init() {
 | |
|     if (!Services.prefs.getBoolPref("identity.fxaccounts.enabled")) {
 | |
|       return;
 | |
|     }
 | |
|     // Check if we've already logged in at startup.
 | |
|     const state = UIState.get();
 | |
|     if (state.status != UIState.STATUS_NOT_CONFIGURED) {
 | |
|       this.setComplete();
 | |
|     }
 | |
|     this.register();
 | |
|   },
 | |
| 
 | |
|   register() {
 | |
|     if (this._registered) {
 | |
|       return;
 | |
|     }
 | |
|     Services.obs.addObserver(this, "sync-ui-state:update");
 | |
|     this._registered = true;
 | |
|   },
 | |
| 
 | |
|   setComplete() {
 | |
|     this._loggedIn = true;
 | |
|     Services.prefs.setBoolPref("browser.onboarding.tour.onboarding-tour-sync.completed", true);
 | |
|   },
 | |
| 
 | |
|   unregister() {
 | |
|     if (!this._registered) {
 | |
|       return;
 | |
|     }
 | |
|     Services.obs.removeObserver(this, "sync-ui-state:update");
 | |
|     this._registered = false;
 | |
|   },
 | |
| 
 | |
|   uninit() {
 | |
|     this.unregister();
 | |
|   },
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Listen and process events from content.
 | |
|  */
 | |
| function initContentMessageListener() {
 | |
|   Services.mm.addMessageListener("Onboarding:OnContentMessage", msg => {
 | |
|     switch (msg.data.action) {
 | |
|       case "set-prefs":
 | |
|         setPrefs(msg.data.params);
 | |
|         break;
 | |
|       case "get-login-status":
 | |
|         msg.target.messageManager.sendAsyncMessage("Onboarding:ResponseLoginStatus", {
 | |
|           isLoggedIn: syncTourChecker.isLoggedIn()
 | |
|         });
 | |
|         break;
 | |
|       case "ping-centre":
 | |
|         try {
 | |
|           OnboardingTelemetry.process(msg.data.params.data);
 | |
|         } catch (e) {
 | |
|           Cu.reportError(e);
 | |
|         }
 | |
|         break;
 | |
|     }
 | |
|   });
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * onBrowserReady - Continues startup of the add-on after browser is ready.
 | |
|  */
 | |
| function onBrowserReady() {
 | |
|   waitingForBrowserReady = false;
 | |
| 
 | |
|   OnboardingTourType.check();
 | |
|   OnboardingTelemetry.init(startupData);
 | |
|   Services.mm.loadFrameScript("resource://onboarding/onboarding.js", true, true);
 | |
|   initContentMessageListener();
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * observe - nsIObserver callback to handle various browser notifications.
 | |
|  */
 | |
| function observe(subject, topic, data) {
 | |
|   switch (topic) {
 | |
|     case BROWSER_READY_NOTIFICATION:
 | |
|       Services.obs.removeObserver(observe, BROWSER_READY_NOTIFICATION);
 | |
|       onBrowserReady();
 | |
|       break;
 | |
|     case BROWSER_SESSION_STORE_NOTIFICATION:
 | |
|       Services.obs.removeObserver(observe, BROWSER_SESSION_STORE_NOTIFICATION);
 | |
|       // Postpone Firefox account checking until "before handling user events"
 | |
|       // phase to meet performance criteria. The reason we don't postpone the
 | |
|       // whole onBrowserReady here is because in that way we will miss onload
 | |
|       // events for onboarding.js.
 | |
|       Services.tm.idleDispatchToMainThread(() => syncTourChecker.init());
 | |
|       break;
 | |
|   }
 | |
| }
 | |
| 
 | |
| function install(aData, aReason) {}
 | |
| 
 | |
| function uninstall(aData, aReason) {}
 | |
| 
 | |
| function startup(aData, aReason) {
 | |
|   resProto.setSubstitutionWithFlags(RESOURCE_HOST,
 | |
|                                     Services.io.newURI("chrome/content/", null, aData.resourceURI),
 | |
|                                     resProto.ALLOW_CONTENT_ACCESS);
 | |
| 
 | |
|   // Cache startup data which contains stuff like the version number, etc.
 | |
|   // so we can use it when we init the telemetry
 | |
|   startupData = aData;
 | |
|   // Only start Onboarding when the browser UI is ready
 | |
|   if (Services.startup.startingUp) {
 | |
|     Services.obs.addObserver(observe, BROWSER_READY_NOTIFICATION);
 | |
|     Services.obs.addObserver(observe, BROWSER_SESSION_STORE_NOTIFICATION);
 | |
|   } else {
 | |
|     onBrowserReady();
 | |
|     syncTourChecker.init();
 | |
|   }
 | |
| }
 | |
| 
 | |
| function shutdown(aData, aReason) {
 | |
|   resProto.setSubstitution(RESOURCE_HOST, null);
 | |
| 
 | |
|   startupData = null;
 | |
|   // Stop waiting for browser to be ready
 | |
|   if (waitingForBrowserReady) {
 | |
|     Services.obs.removeObserver(observe, BROWSER_READY_NOTIFICATION);
 | |
|   }
 | |
|   syncTourChecker.uninit();
 | |
| }
 |