diff options
author | Rogan Creswick <creswick@galois.com> | 2012-03-31 08:08:11 -0700 |
---|---|---|
committer | Rogan Creswick <creswick@galois.com> | 2012-03-31 08:08:11 -0700 |
commit | ec532e93339a942a395829ec87f427852cd72e00 (patch) | |
tree | f6ad13ca7f90f26fda9bc23e428ee367f153e3d2 /tools/addon-sdk-1.4/packages/api-utils/lib/content/worker.js | |
parent | 780bf48de85215f5b0b6fde0df40599ac6f9c037 (diff) |
removed older addon-sdks from tools
Diffstat (limited to 'tools/addon-sdk-1.4/packages/api-utils/lib/content/worker.js')
-rw-r--r-- | tools/addon-sdk-1.4/packages/api-utils/lib/content/worker.js | 662 |
1 files changed, 0 insertions, 662 deletions
diff --git a/tools/addon-sdk-1.4/packages/api-utils/lib/content/worker.js b/tools/addon-sdk-1.4/packages/api-utils/lib/content/worker.js deleted file mode 100644 index 6ded506..0000000 --- a/tools/addon-sdk-1.4/packages/api-utils/lib/content/worker.js +++ /dev/null @@ -1,662 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et: */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Jetpack. - * - * The Initial Developer of the Original Code is - * the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Irakli Gozalishvili <gozala@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ -"use strict"; - -const { Trait } = require('../traits'); -const { EventEmitter, EventEmitterTrait } = require('../events'); -const { Ci, Cu, Cc } = require('chrome'); -const timer = require('../timer'); -const { toFilename } = require('../url'); -const file = require('../file'); -const unload = require('../unload'); -const observers = require('../observer-service'); -const { Cortex } = require('../cortex'); -const { Enqueued } = require('../utils/function'); -const self = require("self"); -const scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"]. - getService(Ci.mozIJSSubScriptLoader); - -const CONTENT_PROXY_URL = self.data.url("content-proxy.js"); - -const JS_VERSION = '1.8'; - -const ERR_DESTROYED = - "The page has been destroyed and can no longer be used."; - -/** - * This key is not exported and should only be used for proxy tests. - * The following `PRIVATE_KEY` is used in addon module scope in order to tell - * Worker API to expose `UNWRAP_ACCESS_KEY` in content script. - * This key allows test-content-proxy.js to unwrap proxy with valueOf: - * let xpcWrapper = proxyWrapper.valueOf(UNWRAP_ACCESS_KEY); - */ -const PRIVATE_KEY = {}; - -function ensureArgumentsAreJSON(array, window) { - // JSON.stringify is buggy with cross-sandbox values, - // it may return "{}" on functions. Use a replacer to match them correctly. - function replacer(k, v) { - return typeof v === "function" ? undefined : v; - } - // If a window is given, we use its `JSON.parse` object in order to - // create JS objects for its compartments (See bug 714891) - let parse = JSON.parse; - if (window) { - // As we can't directly rely on `window.wrappedJSObject.JSON`, we create - // a temporary sandbox in order to get access to a safe `JSON` object: - parse = Cu.Sandbox(window).JSON.parse; - } - return parse(JSON.stringify(array, replacer)); -} - -/** - * Extended `EventEmitter` allowing us to emit events asynchronously. - */ -const AsyncEventEmitter = EventEmitter.compose({ - /** - * Emits event in the next turn of event loop. - */ - _asyncEmit: function _asyncEmit() { - timer.setTimeout(function emitter(emit, scope, params) { - emit.apply(scope, params); - }, 0, this._emit, this, arguments) - } -}); - -/** - * Local trait providing implementation of the workers global scope. - * Used to configure global object in the sandbox. - * @see http://www.w3.org/TR/workers/#workerglobalscope - */ -const WorkerGlobalScope = AsyncEventEmitter.compose({ - on: Trait.required, - _removeAllListeners: Trait.required, - - // wrapped functions from `'timer'` module. - // Wrapper adds `try catch` blocks to the callbacks in order to - // emit `error` event on a symbiont if exception is thrown in - // the Worker global scope. - // @see http://www.w3.org/TR/workers/#workerutils - - // List of all living timeouts/intervals - _timers: null, - - setTimeout: function setTimeout(callback, delay) { - let params = Array.slice(arguments, 2); - let id = timer.setTimeout(function(self) { - try { - delete self._timers[id]; - callback.apply(null, params); - } catch(e) { - self._addonWorker._asyncEmit('error', e); - } - }, delay, this); - this._timers[id] = true; - return id; - }, - clearTimeout: function clearTimeout(id){ - delete this._timers[id]; - return timer.clearTimeout(id); - }, - - setInterval: function setInterval(callback, delay) { - let params = Array.slice(arguments, 2); - let id = timer.setInterval(function(self) { - try { - callback.apply(null, params); - } catch(e) { - self._addonWorker._asyncEmit('error', e); - } - }, delay, this); - this._timers[id] = true; - return id; - }, - clearInterval: function clearInterval(id) { - delete this._timers[id]; - return timer.clearInterval(id); - }, - - /** - * `onMessage` function defined in the global scope of the worker context. - */ - get _onMessage() this.__onMessage, - set _onMessage(value) { - let listener = this.__onMessage; - if (listener && value !== listener) { - this.removeListener('message', listener); - this.__onMessage = undefined; - } - if (value) - this.on('message', this.__onMessage = value); - }, - __onMessage: undefined, - - /** - * Function for sending data to the addon side. - * Validates that data is a `JSON` or primitive value and emits - * 'message' event on the worker in the next turn of the event loop. - * _Later this will be sending data across process boundaries._ - * @param {JSON|String|Number|Boolean} data - */ - postMessage: function postMessage(data) { - if (!this._addonWorker) - throw new Error(ERR_DESTROYED); - this._addonWorker._asyncEmit('message', ensureArgumentsAreJSON(data)); - }, - - /** - * EventEmitter, that behaves (calls listeners) asynchronously. - * A way to send customized messages to / from the worker. - * Events from in the worker can be observed / emitted via self.on / self.emit - */ - get port() this._port._public, - - /** - * Same object than this.port but private API. - * Allow access to _asyncEmit, in order to send event to port. - */ - _port: null, - - /** - * Alias to the global scope in the context of worker. Similar to - * `window` concept. - */ - get self() this._public, - - /** - * Configures sandbox and loads content scripts into it. - * @param {Worker} worker - * content worker - */ - constructor: function WorkerGlobalScope(worker) { - this._addonWorker = worker; - - // Hack in order to allow addon worker to access _asyncEmit - // as this is the private object of WorkerGlobalScope - worker._contentWorker = this; - - // create an event emitter that receive and send events from/to the addon - let contentWorker = this; - this._port = EventEmitterTrait.create({ - emit: function () { - let addonWorker = contentWorker._addonWorker; - if (!addonWorker) - throw new Error(ERR_DESTROYED); - addonWorker._onContentScriptEvent.apply(addonWorker, arguments); - } - }); - // create emit that executes in next turn of event loop. - this._port._asyncEmit = Enqueued(this._port._emit); - // expose wrapped port, that exposes only public properties. - this._port._public = Cortex(this._port); - - // We receive an unwrapped window, with raw js access - let window = worker._window; - - let proto = window; - let proxySandbox = null; - // Build content proxies only if the document has a non-system principal - if (window.wrappedJSObject) { - // Instantiate the proxy code in another Sandbox in order to prevent - // content script from polluting globals used by proxy code - proxySandbox = Cu.Sandbox(window, { - wantXrays: true - }); - proxySandbox.console = console; - // Execute the proxy code - scriptLoader.loadSubScript(CONTENT_PROXY_URL, proxySandbox); - // Get a reference of the window's proxy - proto = proxySandbox.create(window); - } - - // Create the sandbox and bind it to window in order for content scripts to - // have access to all standard globals (window, document, ...) - let sandbox = this._sandbox = new Cu.Sandbox(window, { - sandboxPrototype: proto, - wantXrays: true - }); - Object.defineProperties(sandbox, { - // We need "this === window === top" to be true in toplevel scope: - window: { get: function() sandbox }, - top: { get: function() sandbox }, - // Use the Greasemonkey naming convention to provide access to the - // unwrapped window object so the content script can access document - // JavaScript values. - // NOTE: this functionality is experimental and may change or go away - // at any time! - unsafeWindow: { get: function () window.wrappedJSObject } - }); - - // Internal feature that is only used by SDK tests: - // Expose unlock key to content script context. - // See `PRIVATE_KEY` definition for more information. - if (proxySandbox && worker._expose_key) - sandbox.UNWRAP_ACCESS_KEY = proxySandbox.UNWRAP_ACCESS_KEY; - // Initialize timer lists - this._timers = {}; - - let publicAPI = this._public; - - // List of content script globals: - let keys = ['setTimeout', 'clearTimeout', 'setInterval', 'clearInterval', - 'self']; - for each (let key in keys) { - Object.defineProperty( - sandbox, key, Object.getOwnPropertyDescriptor(publicAPI, key) - ); - } - let self = this; - Object.defineProperties(sandbox, { - onMessage: { - get: function() self._onMessage, - set: function(value) { - console.warn("The global `onMessage` function in content scripts " + - "is deprecated in favor of the `self.on()` function. " + - "Replace `onMessage = function (data){}` definitions " + - "with calls to `self.on('message', function (data){})`. " + - "For more info on `self.on`, see " + - "<https://addons.mozilla.org/en-US/developers/docs/sdk/latest/dev-guide/addon-development/web-content.html>."); - self._onMessage = value; - }, - configurable: true - }, - console: { value: console, configurable: true }, - - // Deprecated use of on/postMessage from globals - on: { - value: function () { - console.warn("The global `on()` function in content scripts is " + - "deprecated in favor of the `self.on()` function, " + - "which works the same. Replace calls to `on()` with " + - "calls to `self.on()`" + - "For more info on `self.on`, see " + - "<https://addons.mozilla.org/en-US/developers/docs/sdk/latest/dev-guide/addon-development/web-content.html>."); - publicAPI.on.apply(publicAPI, arguments); - }, - configurable: true - }, - postMessage: { - value: function () { - console.warn("The global `postMessage()` function in content " + - "scripts is deprecated in favor of the " + - "`self.postMessage()` function, which works the same. " + - "Replace calls to `postMessage()` with calls to " + - "`self.postMessage()`." + - "For more info on `self.on`, see " + - "<https://addons.mozilla.org/en-US/developers/docs/sdk/latest/dev-guide/addon-development/web-content.html>."); - publicAPI.postMessage.apply(publicAPI, arguments); - }, - configurable: true - } - }); - - // Temporary fix for test-widget, that pass self.postMessage to proxy code - // that first try to access to `___proxy` and then call it through `apply`. - // We need to move function given to content script to a sandbox - // with same principal than the content script. - // In the meantime, we need to allow such access explicitly - // by using `__exposedProps__` property, documented here: - // https://developer.mozilla.org/en/XPConnect_wrappers - sandbox.self.postMessage.__exposedProps__ = { - ___proxy: 'rw', - apply: 'rw' - } - - // Inject `addon` global into target document if document is trusted, - // `addon` in document is equivalent to `self` in content script. - if (worker._injectInDocument) { - let win = window.wrappedJSObject ? window.wrappedJSObject : window; - Object.defineProperty(win, "addon", { - get: function () publicAPI - } - ); - } - - // The order of `contentScriptFile` and `contentScript` evaluation is - // intentional, so programs can load libraries like jQuery from script URLs - // and use them in scripts. - let contentScriptFile = ('contentScriptFile' in worker) ? worker.contentScriptFile - : null, - contentScript = ('contentScript' in worker) ? worker.contentScript : null; - - if (contentScriptFile) { - if (Array.isArray(contentScriptFile)) - this._importScripts.apply(this, contentScriptFile); - else - this._importScripts(contentScriptFile); - } - if (contentScript) { - this._evaluate( - Array.isArray(contentScript) ? contentScript.join(';\n') : contentScript - ); - } - }, - _destructor: function _destructor() { - this._removeAllListeners(); - // Unregister all setTimeout/setInterval - // We can use `clearTimeout` for both setTimeout/setInterval - // as internal implementation of timer module use same method for both. - for (let id in this._timers) - timer.clearTimeout(id); - this._sandbox = null; - this._addonWorker = null; - this.__onMessage = undefined; - }, - - /** - * JavaScript sandbox where all the content scripts are evaluated. - * {Sandbox} - */ - _sandbox: null, - - /** - * Reference to the addon side of the worker. - * @type {Worker} - */ - _addonWorker: null, - - /** - * Evaluates code in the sandbox. - * @param {String} code - * JavaScript source to evaluate. - * @param {String} [filename='javascript:' + code] - * Name of the file - */ - _evaluate: function(code, filename) { - filename = filename || 'javascript:' + code; - try { - Cu.evalInSandbox(code, this._sandbox, JS_VERSION, filename, 1); - } - catch(e) { - this._addonWorker._asyncEmit('error', e); - } - }, - /** - * Imports scripts to the sandbox by reading files under urls and - * evaluating its source. If exception occurs during evaluation - * `"error"` event is emitted on the worker. - * This is actually an analog to the `importScript` method in web - * workers but in our case it's not exposed even though content - * scripts may be able to do it synchronously since IO operation - * takes place in the UI process. - */ - _importScripts: function _importScripts(url) { - let urls = Array.slice(arguments, 0); - for each (let contentScriptFile in urls) { - try { - let filename = toFilename(contentScriptFile); - this._evaluate(file.read(filename), filename); - } - catch(e) { - this._addonWorker._asyncEmit('error', e) - } - } - } -}); - -/** - * Message-passing facility for communication between code running - * in the content and add-on process. - * @see https://jetpack.mozillalabs.com/sdk/latest/docs/#module/api-utils/content/worker - */ -const Worker = AsyncEventEmitter.compose({ - on: Trait.required, - _asyncEmit: Trait.required, - _removeAllListeners: Trait.required, - - /** - * Sends a message to the worker's global scope. Method takes single - * argument, which represents data to be sent to the worker. The data may - * be any primitive type value or `JSON`. Call of this method asynchronously - * emits `message` event with data value in the global scope of this - * symbiont. - * - * `message` event listeners can be set either by calling - * `self.on` with a first argument string `"message"` or by - * implementing `onMessage` function in the global scope of this worker. - * @param {Number|String|JSON} data - */ - postMessage: function postMessage(data) { - if (!this._contentWorker) - throw new Error(ERR_DESTROYED); - this._contentWorker._asyncEmit('message', - ensureArgumentsAreJSON(data, this._window)); - }, - - /** - * EventEmitter, that behaves (calls listeners) asynchronously. - * A way to send customized messages to / from the worker. - * Events from in the worker can be observed / emitted via - * worker.on / worker.emit. - */ - get port() { - // We generate dynamically this attribute as it needs to be accessible - // before Worker.constructor gets called. (For ex: Panel) - - // create an event emitter that receive and send events from/to the worker - let self = this; - this._port = EventEmitterTrait.create({ - emit: function () self._emitEventToContent(arguments) - }); - // create emit that executes in next turn of event loop. - this._port._asyncEmit = Enqueued(this._port._emit); - // expose wrapped port, that exposes only public properties: - // We need to destroy this getter in order to be able to set the - // final value. We need to update only public port attribute as we never - // try to access port attribute from private API. - delete this._public.port; - this._public.port = Cortex(this._port); - // Replicate public port to the private object - delete this.port; - this.port = this._public.port; - - return this._port; - }, - - /** - * Same object than this.port but private API. - * Allow access to _asyncEmit, in order to send event to port. - */ - _port: null, - - /** - * Emit a custom event to the content script, - * i.e. emit this event on `self.port` - */ - _emitEventToContent: function _emitEventToContent(args) { - // We need to save events that are emitted before the worker is - // initialized - if (!this._inited) { - this._earlyEvents.push(args); - return; - } - - // We throw exception when the worker has been destroyed - if (!this._contentWorker) { - throw new Error(ERR_DESTROYED); - } - - let scope = this._contentWorker._port; - // Ensure that we pass only JSON values - let array = Array.prototype.slice.call(args); - scope._asyncEmit.apply(scope, ensureArgumentsAreJSON(array, this._window)); - }, - - // Is worker connected to the content worker (i.e. WorkerGlobalScope) ? - _inited: false, - - // List of custom events fired before worker is initialized - get _earlyEvents() { - delete this._earlyEvents; - this._earlyEvents = []; - return this._earlyEvents; - }, - - constructor: function Worker(options) { - options = options || {}; - - if ('window' in options) - this._window = options.window; - if ('contentScriptFile' in options) - this.contentScriptFile = options.contentScriptFile; - if ('contentScript' in options) - this.contentScript = options.contentScript; - if ('onError' in options) - this.on('error', options.onError); - if ('onMessage' in options) - this.on('message', options.onMessage); - if ('onDetach' in options) - this.on('detach', options.onDetach); - - // Internal feature that is only used by SDK unit tests. - // See `PRIVATE_KEY` definition for more information. - if ('exposeUnlockKey' in options && options.exposeUnlockKey === PRIVATE_KEY) - this._expose_key = true; - - // Track document unload to destroy this worker. - // We can't watch for unload event on page's window object as it - // prevents bfcache from working: - // https://developer.mozilla.org/En/Working_with_BFCache - this._windowID = this._window. - QueryInterface(Ci.nsIInterfaceRequestor). - getInterface(Ci.nsIDOMWindowUtils). - currentInnerWindowID; - observers.add("inner-window-destroyed", - this._documentUnload = this._documentUnload.bind(this)); - - unload.ensure(this._public, "destroy"); - - // Ensure that worker._port is initialized for contentWorker to be able - // to send use event during WorkerGlobalScope(this) - this.port; - - // will set this._contentWorker pointing to the private API: - WorkerGlobalScope(this); - - // Mainly enable worker.port.emit to send event to the content worker - this._inited = true; - - // Flush all events that have been fired before the worker is initialized. - this._earlyEvents.forEach((function (args) this._emitEventToContent(args)). - bind(this)); - }, - - _documentUnload: function _documentUnload(subject, topic, data) { - let innerWinID = subject.QueryInterface(Ci.nsISupportsPRUint64).data; - if (innerWinID != this._windowID) return false; - this._workerCleanup(); - return true; - }, - - get url() { - // this._window will be null after detach - return this._window ? this._window.document.location.href : null; - }, - - get tab() { - if (this._window) { - let tab = require("../tabs/tab"); - // this._window will be null after detach - return tab.getTabForWindow(this._window); - } - return null; - }, - - /** - * Tells content worker to unload itself and - * removes all the references from itself. - */ - destroy: function destroy() { - this._workerCleanup(); - this._removeAllListeners('message'); - this._removeAllListeners('error'); - this._removeAllListeners('detach'); - }, - - /** - * Remove all internal references to the attached document - * Tells _port to unload itself and removes all the references from itself. - */ - _workerCleanup: function _workerCleanup() { - // maybe unloaded before content side is created - // As Symbiont call worker.constructor on document load - if (this._contentWorker) - this._contentWorker._destructor(); - this._contentWorker = null; - this._window = null; - // This method may be called multiple times, - // avoid dispatching `detach` event more than once - if (this._windowID) { - this._windowID = null; - observers.remove("inner-window-destroyed", this._documentUnload); - this._earlyEvents.slice(0, this._earlyEvents.length); - this._emit("detach"); - } - }, - - /** - * Receive an event from the content script that need to be sent to - * worker.port. Provide a way for composed object to catch all events. - */ - _onContentScriptEvent: function _onContentScriptEvent() { - // Ensure that we pass only JSON values - let array = Array.prototype.slice.call(arguments); - this._port._asyncEmit.apply(this._port, ensureArgumentsAreJSON(array)); - }, - - /** - * Reference to the content side of the worker. - * @type {WorkerGlobalScope} - */ - _contentWorker: null, - - /** - * Reference to the window that is accessible from - * the content scripts. - * @type {Object} - */ - _window: null, - - /** - * Flag to enable `addon` object injection in document. (bug 612726) - * @type {Boolean} - */ - _injectInDocument: false -}); -exports.Worker = Worker; |