diff options
Diffstat (limited to 'tools/addon-sdk-1.12/lib/sdk/content')
-rw-r--r-- | tools/addon-sdk-1.12/lib/sdk/content/content-proxy.js | 870 | ||||
-rw-r--r-- | tools/addon-sdk-1.12/lib/sdk/content/content-worker.js | 308 | ||||
-rw-r--r-- | tools/addon-sdk-1.12/lib/sdk/content/content.js | 15 | ||||
-rw-r--r-- | tools/addon-sdk-1.12/lib/sdk/content/loader.js | 204 | ||||
-rw-r--r-- | tools/addon-sdk-1.12/lib/sdk/content/symbiont.js | 197 | ||||
-rw-r--r-- | tools/addon-sdk-1.12/lib/sdk/content/thumbnail.js | 46 | ||||
-rw-r--r-- | tools/addon-sdk-1.12/lib/sdk/content/worker.js | 582 |
7 files changed, 0 insertions, 2222 deletions
diff --git a/tools/addon-sdk-1.12/lib/sdk/content/content-proxy.js b/tools/addon-sdk-1.12/lib/sdk/content/content-proxy.js deleted file mode 100644 index 76df7f6..0000000 --- a/tools/addon-sdk-1.12/lib/sdk/content/content-proxy.js +++ /dev/null @@ -1,870 +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/. */ - -"use strict"; - -/* Trick the linker in order to avoid error on `Components.interfaces` usage. - We are tricking the linker with `require('./content-proxy.js')` from - worjer.js in order to ensure shipping this file! But then the linker think - that this file is going to be used as a CommonJS module where we forbid usage - of `Components`. -*/ -let Ci = Components['interfaces']; - -/** - * Access key that allows privileged code to unwrap proxy wrappers through - * valueOf: - * let xpcWrapper = proxyWrapper.valueOf(UNWRAP_ACCESS_KEY); - * This key should only be used by proxy unit test. - */ - const UNWRAP_ACCESS_KEY = {}; - - - /** - * Returns a closure that wraps arguments before calling the given function, - * which can be given to native functions that accept a function, such that when - * the closure is called, the given function is called with wrapped arguments. - * - * @param fun {Function} - * the function for which to create a closure wrapping its arguments - * @param obj {Object} - * target object from which `fun` comes from - * (optional, for debugging purpose) - * @param name {String} - * name of the attribute from which `fun` is binded on `obj` - * (optional, for debugging purpose) - * - * Example: - * function contentScriptListener(event) {} - * let wrapper = ContentScriptFunctionWrapper(contentScriptListener); - * xray.addEventListener("...", wrapper, false); - * -> Allow to `event` to be wrapped - */ -function ContentScriptFunctionWrapper(fun, obj, name) { - if ("___proxy" in fun && typeof fun.___proxy == "function") - return fun.___proxy; - - let wrappedFun = function () { - let args = []; - for (let i = 0, l = arguments.length; i < l; i++) - args.push(wrap(arguments[i])); - - //console.log("Called from native :"+obj+"."+name); - //console.log(">args "+arguments.length); - //console.log(fun); - - // Native code can execute this callback with `this` being the wrapped - // function. For example, window.mozRequestAnimationFrame. - if (this == wrappedFun) - return fun.apply(fun, args); - - return fun.apply(wrap(this), args); - }; - - Object.defineProperty(fun, "___proxy", {value : wrappedFun, - writable : false, - enumerable : false, - configurable : false}); - - return wrappedFun; -} - -/** - * Returns a closure that unwraps arguments before calling the `fun` function, - * which can be used to build a wrapper for a native function that accepts - * wrapped arguments, since native function only accept unwrapped arguments. - * - * @param fun {Function} - * the function to wrap - * @param originalObject {Object} - * target object from which `fun` comes from - * (optional, for debugging purpose) - * @param name {String} - * name of the attribute from which `fun` is binded on `originalObject` - * (optional, for debugging purpose) - * - * Example: - * wrapper.appendChild = NativeFunctionWrapper(xray.appendChild, xray); - * wrapper.appendChild(anotherWrapper); - * -> Allow to call xray.appendChild with unwrapped version of anotherWrapper - */ -function NativeFunctionWrapper(fun, originalObject, name) { - return function () { - let args = []; - let obj = this && typeof this.valueOf == "function" ? - this.valueOf(UNWRAP_ACCESS_KEY) : this; - - for (let i = 0, l = arguments.length; i < l; i++) - args.push( unwrap(arguments[i], obj, name) ); - - //if (name != "toString") - //console.log(">>calling native ["+(name?name:'#closure#')+"]: \n"+fun.apply+"\n"+obj+"\n("+args.join(', ')+")\nthis :"+obj+"from:"+originalObject+"\n"); - - // Need to use Function.prototype.apply.apply because XMLHttpRequest - // is a function (typeof return 'function') and fun.apply is null :/ - let unwrapResult = Function.prototype.apply.apply(fun, [obj, args]); - let result = wrap(unwrapResult, obj, name); - - //console.log("<< "+rr+" -> "+r); - - return result; - }; -} - -/* - * Unwrap a JS value that comes from the content script. - * Mainly converts proxy wrapper to XPCNativeWrapper. - */ -function unwrap(value, obj, name) { - //console.log("unwrap : "+value+" ("+name+")"); - if (!value) - return value; - let type = typeof value; - - // In case of proxy, unwrap them recursively - // (it should not be recursive, just in case of) - if (["object", "function"].indexOf(type) !== -1 && - "__isWrappedProxy" in value) { - while("__isWrappedProxy" in value) - value = value.valueOf(UNWRAP_ACCESS_KEY); - return value; - } - - // In case of functions we need to return a wrapper that converts native - // arguments applied to this function into proxies. - if (type == "function") - return ContentScriptFunctionWrapper(value, obj, name); - - // We must wrap objects coming from content script too, as they may have - // a function that will be called by a native method. - // For example: - // addEventListener(..., { handleEvent: function(event) {} }, ...); - if (type == "object") - return ContentScriptObjectWrapper(value); - - if (["string", "number", "boolean"].indexOf(type) !== -1) - return value; - //console.log("return non-wrapped to native : "+typeof value+" -- "+value); - return value; -} - -/** - * Returns an XrayWrapper proxy object that allow to wrap any of its function - * though `ContentScriptFunctionWrapper`. These proxies are given to - * XrayWrappers in order to automatically wrap values when they call a method - * of these proxies. So that they are only used internaly and content script, - * nor web page have ever access to them. As a conclusion, we can consider - * this code as being safe regarding web pages overload. - * - * - * @param obj {Object} - * object coming from content script context to wrap - * - * Example: - * let myListener = { handleEvent: function (event) {} }; - * node.addEventListener("click", myListener, false); - * `event` has to be wrapped, so handleEvent has to be wrapped using - * `ContentScriptFunctionWrapper` function. - * In order to do so, we build this new kind of proxies. - */ -function ContentScriptObjectWrapper(obj) { - if ("___proxy" in obj && typeof obj.___proxy == "object") - return obj.___proxy; - - function valueOf(key) { - if (key === UNWRAP_ACCESS_KEY) - return obj; - return this; - } - - let proxy = Proxy.create({ - // Fundamental traps - getPropertyDescriptor: function(name) { - return Object.getOwnPropertyDescriptor(obj, name); - }, - defineProperty: function(name, desc) { - return Object.defineProperty(obj, name, desc); - }, - getOwnPropertyNames: function () { - return Object.getOwnPropertyNames(obj); - }, - delete: function(name) { - return delete obj[name]; - }, - // derived traps - has: function(name) { - return name === "__isXrayWrapperProxy" || - name in obj; - }, - hasOwn: function(name) { - return Object.prototype.hasOwnProperty.call(obj, name); - }, - get: function(receiver, name) { - if (name == "valueOf") - return valueOf; - let value = obj[name]; - if (!value) - return value; - - return unwrap(value); - }, - set: function(receiver, name, val) { - obj[name] = val; - return true; - }, - enumerate: function() { - var result = []; - for each (let name in obj) { - result.push(name); - }; - return result; - }, - keys: function() { - return Object.keys(obj); - } - }); - - Object.defineProperty(obj, "___proxy", {value : proxy, - writable : false, - enumerable : false, - configurable : false}); - - return proxy; -} - -// List of all existing typed arrays. -// Can be found here: -// http://mxr.mozilla.org/mozilla-central/source/js/src/jsapi.cpp#1790 -const typedArraysCtor = [ - ArrayBuffer, - Int8Array, - Uint8Array, - Int16Array, - Uint16Array, - Int32Array, - Uint32Array, - Float32Array, - Float64Array, - Uint8ClampedArray -]; - -/* - * Wrap a JS value coming from the document by building a proxy wrapper. - */ -function wrap(value, obj, name, debug) { - if (!value) - return value; - let type = typeof value; - if (type == "object") { - // Bug 671016: Typed arrays don't need to be proxified. - // We avoid checking the whole constructor list on all objects - // by doing this check only on non-extensible objects: - if (!Object.isExtensible(value) && - typedArraysCtor.indexOf(value.constructor) !== -1) - return value; - - // Bug 715755: do not proxify COW wrappers - // These wrappers throw an exception when trying to access - // any attribute that is not in a white list - try { - ("nonExistantAttribute" in value); - } - catch(e) { - if (e.message.indexOf("Permission denied to access property") !== -1) - return value; - } - - // We may have a XrayWrapper proxy. - // For example: - // let myListener = { handleEvent: function () {} }; - // node.addEventListener("click", myListener, false); - // When native code want to call handleEvent, - // we go though ContentScriptFunctionWrapper that calls `wrap(this)` - // `this` is the XrayWrapper proxy of myListener. - // We return this object without building a CS proxy as it is already - // a value coming from the CS. - if ("__isXrayWrapperProxy" in value) - return value.valueOf(UNWRAP_ACCESS_KEY); - - // Unwrap object before wrapping it. - // It should not happen with CS proxy objects. - while("__isWrappedProxy" in value) { - value = value.valueOf(UNWRAP_ACCESS_KEY); - } - - if (XPCNativeWrapper.unwrap(value) !== value) - return getProxyForObject(value); - // In case of Event, HTMLCollection or NodeList or ??? - // XPCNativeWrapper.unwrap(value) === value - // but it's still a XrayWrapper so let's build a proxy - return getProxyForObject(value); - } - if (type == "function") { - if (XPCNativeWrapper.unwrap(value) !== value - || (typeof value.toString === "function" && - value.toString().match(/\[native code\]/))) { - return getProxyForFunction(value, NativeFunctionWrapper(value, obj, name)); - } - return value; - } - if (type == "string") - return value; - if (type == "number") - return value; - if (type == "boolean") - return value; - //console.log("return non-wrapped to wrapped : "+value); - return value; -} - -/* - * Wrap an object from the document to a proxy wrapper - */ -function getProxyForObject(obj) { - if (typeof obj != "object") { - let msg = "tried to proxify something other than an object: " + typeof obj; - console.warn(msg); - throw msg; - } - if ("__isWrappedProxy" in obj) { - return obj; - } - // Check if there is a proxy cached on this wrapper, - // but take care of prototype ___proxy attribute inheritance! - if (obj && obj.___proxy && obj.___proxy.valueOf(UNWRAP_ACCESS_KEY) === obj) { - return obj.___proxy; - } - - let proxy = Proxy.create(handlerMaker(obj)); - - Object.defineProperty(obj, "___proxy", {value : proxy, - writable : false, - enumerable : false, - configurable : false}); - return proxy; -} - -/* - * Wrap a function from the document to a proxy wrapper - */ -function getProxyForFunction(fun, callTrap) { - if (typeof fun != "function") { - let msg = "tried to proxify something other than a function: " + typeof fun; - console.warn(msg); - throw msg; - } - if ("__isWrappedProxy" in fun) - return obj; - if ("___proxy" in fun) - return fun.___proxy; - - let proxy = Proxy.createFunction(handlerMaker(fun), callTrap); - - Object.defineProperty(fun, "___proxy", {value : proxy, - writable : false, - enumerable : false, - configurable : false}); - - return proxy; -} - -/* - * Check if a DOM attribute name is an event name. - */ -function isEventName(id) { - if (id.indexOf("on") != 0 || id.length == 2) - return false; - // Taken from: - // http://mxr.mozilla.org/mozilla-central/source/dom/base/nsDOMClassInfo.cpp#7616 - switch (id[2]) { - case 'a' : - return (id == "onabort" || - id == "onafterscriptexecute" || - id == "onafterprint"); - case 'b' : - return (id == "onbeforeunload" || - id == "onbeforescriptexecute" || - id == "onblur" || - id == "onbeforeprint"); - case 'c' : - return (id == "onchange" || - id == "onclick" || - id == "oncontextmenu" || - id == "oncopy" || - id == "oncut" || - id == "oncanplay" || - id == "oncanplaythrough"); - case 'd' : - return (id == "ondblclick" || - id == "ondrag" || - id == "ondragend" || - id == "ondragenter" || - id == "ondragleave" || - id == "ondragover" || - id == "ondragstart" || - id == "ondrop" || - id == "ondurationchange"); - case 'e' : - return (id == "onerror" || - id == "onemptied" || - id == "onended"); - case 'f' : - return id == "onfocus"; - case 'h' : - return id == "onhashchange"; - case 'i' : - return (id == "oninput" || - id == "oninvalid"); - case 'k' : - return (id == "onkeydown" || - id == "onkeypress" || - id == "onkeyup"); - case 'l' : - return (id == "onload" || - id == "onloadeddata" || - id == "onloadedmetadata" || - id == "onloadstart"); - case 'm' : - return (id == "onmousemove" || - id == "onmouseout" || - id == "onmouseover" || - id == "onmouseup" || - id == "onmousedown" || - id == "onmessage"); - case 'p' : - return (id == "onpaint" || - id == "onpageshow" || - id == "onpagehide" || - id == "onpaste" || - id == "onpopstate" || - id == "onpause" || - id == "onplay" || - id == "onplaying" || - id == "onprogress"); - case 'r' : - return (id == "onreadystatechange" || - id == "onreset" || - id == "onresize" || - id == "onratechange"); - case 's' : - return (id == "onscroll" || - id == "onselect" || - id == "onsubmit" || - id == "onseeked" || - id == "onseeking" || - id == "onstalled" || - id == "onsuspend"); - case 't': - return id == "ontimeupdate" - /* - // TODO: Make it work for mobile version - || - (nsDOMTouchEvent::PrefEnabled() && - (id == "ontouchstart" || - id == "ontouchend" || - id == "ontouchmove" || - id == "ontouchenter" || - id == "ontouchleave" || - id == "ontouchcancel"))*/; - - case 'u' : - return id == "onunload"; - case 'v': - return id == "onvolumechange"; - case 'w': - return id == "onwaiting"; - } - - return false; -} - -// XrayWrappers miss some attributes. -// Here is a list of functions that return a value when it detects a miss: -const NODES_INDEXED_BY_NAME = ["IMG", "FORM", "APPLET", "EMBED", "OBJECT"]; -const xRayWrappersMissFixes = [ - - // Fix bug with XPCNativeWrapper on HTMLCollection - // We can only access array item once, then it's undefined :o - function (obj, name) { - let i = parseInt(name); - if (obj.toString().match(/HTMLCollection|NodeList/) && - i >= 0 && i < obj.length) { - return wrap(XPCNativeWrapper(obj.wrappedJSObject[name]), obj, name); - } - return null; - }, - - // Trap access to document["form name"] - // that may refer to an existing form node - // http://mxr.mozilla.org/mozilla-central/source/dom/base/nsDOMClassInfo.cpp#9285 - function (obj, name) { - if ("nodeType" in obj && obj.nodeType == 9) { - let node = obj.wrappedJSObject[name]; - // List of supported tag: - // http://mxr.mozilla.org/mozilla-central/source/content/html/content/src/nsGenericHTMLElement.cpp#1267 - if (node && NODES_INDEXED_BY_NAME.indexOf(node.tagName) != -1) - return wrap(XPCNativeWrapper(node)); - } - return null; - }, - - // Trap access to window["frame name"] and window.frames[i] - // that refer to an (i)frame internal window object - // http://mxr.mozilla.org/mozilla-central/source/dom/base/nsDOMClassInfo.cpp#6824 - function (obj, name) { - if (typeof obj == "object" && "document" in obj) { - // Ensure that we are on a window object - try { - obj.QueryInterface(Ci.nsIDOMWindow); - } - catch(e) { - return null; - } - - // Integer case: - let i = parseInt(name); - if (i >= 0 && i in obj) { - return wrap(XPCNativeWrapper(obj[i])); - } - - // String name case: - if (name in obj.wrappedJSObject) { - let win = obj.wrappedJSObject[name]; - let nodes = obj.document.getElementsByName(name); - for (let i = 0, l = nodes.length; i < l; i++) { - let node = nodes[i]; - if ("contentWindow" in node && node.contentWindow == win) - return wrap(node.contentWindow); - } - } - } - return null; - }, - - // Trap access to form["node name"] - // http://mxr.mozilla.org/mozilla-central/source/dom/base/nsDOMClassInfo.cpp#9477 - function (obj, name) { - if (typeof obj == "object" && "tagName" in obj && obj.tagName == "FORM") { - let match = obj.wrappedJSObject[name]; - let nodes = obj.ownerDocument.getElementsByName(name); - for (let i = 0, l = nodes.length; i < l; i++) { - let node = nodes[i]; - if (node == match) - return wrap(node); - } - } - return null; - } - -]; - -// XrayWrappers have some buggy methods. -// Here is the list of them with functions returning some replacement -// for a given object `obj`: -const xRayWrappersMethodsFixes = { - // postMessage method is checking the Javascript global - // and it expects it to be a window object. - // But in our case, the global object is our sandbox global object. - // See nsGlobalWindow::CallerInnerWindow(): - // http://mxr.mozilla.org/mozilla-central/source/dom/base/nsGlobalWindow.cpp#5893 - // nsCOMPtr<nsPIDOMWindow> win = do_QueryWrappedNative(wrapper); - // win is null - postMessage: function (obj) { - // Ensure that we are on a window object - try { - obj.QueryInterface(Ci.nsIDOMWindow); - } - catch(e) { - return null; - } - - // Create a wrapper that is going to call `postMessage` through `eval` - let f = function postMessage(message, targetOrigin) { - let jscode = "this.postMessage("; - if (typeof message != "string") - jscode += JSON.stringify(message); - else - jscode += "'" + message.toString().replace(/['\\]/g,"\\$&") + "'"; - - targetOrigin = targetOrigin.toString().replace(/['\\]/g,"\\$&"); - - jscode += ", '" + targetOrigin + "')"; - return this.wrappedJSObject.eval(jscode); - }; - return getProxyForFunction(f, NativeFunctionWrapper(f)); - }, - - // Fix mozMatchesSelector uses that is broken on XrayWrappers - // when we use document.documentElement.mozMatchesSelector.call(node, expr) - // It's only working if we call mozMatchesSelector on the node itself. - // SEE BUG 658909: mozMatchesSelector returns incorrect results with XrayWrappers - mozMatchesSelector: function (obj) { - // Ensure that we are on an object to expose this buggy method - try { - // Bug 707576 removed nsIDOMNSElement. - // Can be simplified as soon as Firefox 11 become the minversion - obj.QueryInterface("nsIDOMElement" in Ci ? Ci.nsIDOMElement : - Ci.nsIDOMNSElement); - } - catch(e) { - return null; - } - // We can't use `wrap` function as `f` is not a native function, - // so wrap it manually: - let f = function mozMatchesSelector(selectors) { - return this.mozMatchesSelector(selectors); - }; - - return getProxyForFunction(f, NativeFunctionWrapper(f)); - }, - - // Bug 679054: History API doesn't work with Proxy objects. We have to pass - // regular JS objects on `pushState` and `replaceState` methods. - // In addition, the first argument has to come from the same compartment. - pushState: function (obj) { - // Ensure that we are on an object that expose History API - try { - obj.QueryInterface(Ci.nsIDOMHistory); - } - catch(e) { - return null; - } - let f = function fix() { - // Call native method with JSON objects - // (need to convert `arguments` to an array via `slice`) - return this.pushState.apply(this, JSON.parse(JSON.stringify(Array.slice(arguments)))); - }; - - return getProxyForFunction(f, NativeFunctionWrapper(f)); - }, - replaceState: function (obj) { - // Ensure that we are on an object that expose History API - try { - obj.QueryInterface(Ci.nsIDOMHistory); - } - catch(e) { - return null; - } - let f = function fix() { - // Call native method with JSON objects - // (need to convert `arguments` to an array via `slice`) - return this.replaceState.apply(this, JSON.parse(JSON.stringify(Array.slice(arguments)))); - }; - - return getProxyForFunction(f, NativeFunctionWrapper(f)); - }, - - // Bug 769006: nsIDOMMutationObserver.observe fails with proxy as options - // attributes - observe: function observe(obj) { - // Ensure that we are on a DOMMutation object - try { - // nsIDOMMutationObserver starts with FF14 - if ("nsIDOMMutationObserver" in Ci) - obj.QueryInterface(Ci.nsIDOMMutationObserver); - else - return null; - } - catch(e) { - return null; - } - return function nsIDOMMutationObserverObserveFix(target, options) { - // Gets native/unwrapped this - let self = this && typeof this.valueOf == "function" ? - this.valueOf(UNWRAP_ACCESS_KEY) : this; - // Unwrap the xraywrapper target out of JS proxy - let targetXray = unwrap(target); - // But do not wrap `options` through ContentScriptObjectWrapper - let result = wrap(self.observe(targetXray, options)); - // Finally wrap result into JS proxies - return wrap(result); - }; - } -}; - -/* - * Generate handler for proxy wrapper - */ -function handlerMaker(obj) { - // Overloaded attributes dictionary - let overload = {}; - // Expando attributes dictionary (i.e. onclick, onfocus, on* ...) - let expando = {}; - // Cache of methods overloaded to fix XrayWrapper bug - let methodFixes = {}; - return { - // Fundamental traps - getPropertyDescriptor: function(name) { - return Object.getOwnPropertyDescriptor(obj, name); - }, - defineProperty: function(name, desc) { - return Object.defineProperty(obj, name, desc); - }, - getOwnPropertyNames: function () { - return Object.getOwnPropertyNames(obj); - }, - delete: function(name) { - delete expando[name]; - delete overload[name]; - return delete obj[name]; - }, - - // derived traps - has: function(name) { - if (name == "___proxy") return false; - if (isEventName(name)) { - // XrayWrappers throw exception when we try to access expando attributes - // even on "name in wrapper". So avoid doing it! - return name in expando; - } - return name in obj || name in overload || name == "__isWrappedProxy" || - undefined !== this.get(null, name); - }, - hasOwn: function(name) { - return Object.prototype.hasOwnProperty.call(obj, name); - }, - get: function(receiver, name) { - if (name == "___proxy") - return undefined; - - // Overload toString in order to avoid returning "[XrayWrapper [object HTMLElement]]" - // or "[object Function]" for function's Proxy - if (name == "toString") { - // Bug 714778: we should not pass obj.wrappedJSObject.toString - // in order to avoid sharing its proxy between two contents scripts. - // (not that `unwrappedObj` can be equal to `obj` when `obj` isn't - // an xraywrapper) - let unwrappedObj = XPCNativeWrapper.unwrap(obj); - return wrap(function () { - return unwrappedObj.toString.call( - this.valueOf(UNWRAP_ACCESS_KEY), arguments); - }, obj, name); - } - - // Offer a way to retrieve XrayWrapper from a proxified node through `valueOf` - if (name == "valueOf") - return function (key) { - if (key === UNWRAP_ACCESS_KEY) - return obj; - return this; - }; - - // Return overloaded value if there is one. - // It allows to overload native methods like addEventListener that - // are not saved, even on the wrapper itself. - // (And avoid some methods like toSource from being returned here! [__proto__ test]) - if (name in overload && - overload[name] != Object.getPrototypeOf(overload)[name] && - name != "__proto__") { - return overload[name]; - } - - // Catch exceptions thrown by XrayWrappers when we try to access on* - // attributes like onclick, onfocus, ... - if (isEventName(name)) { - //console.log("expando:"+obj+" - "+obj.nodeType); - return name in expando ? expando[name].original : undefined; - } - - // Overload some XrayWrappers method in order to fix its bugs - if (name in methodFixes && - methodFixes[name] != Object.getPrototypeOf(methodFixes)[name] && - name != "__proto__") - return methodFixes[name]; - if (Object.keys(xRayWrappersMethodsFixes).indexOf(name) !== -1) { - let fix = xRayWrappersMethodsFixes[name](obj); - if (fix) - return methodFixes[name] = fix; - } - - let o = obj[name]; - - // XrayWrapper miss some attributes, try to catch these and return a value - if (!o) { - for each(let atttributeFixer in xRayWrappersMissFixes) { - let fix = atttributeFixer(obj, name); - if (fix) - return fix; - } - } - - // Generic case - return wrap(o, obj, name); - - }, - - set: function(receiver, name, val) { - - if (isEventName(name)) { - //console.log("SET on* attribute : " + name + " / " + val + "/" + obj); - let shortName = name.replace(/^on/,""); - - // Unregister previously set listener - if (expando[name]) { - obj.removeEventListener(shortName, expando[name], true); - delete expando[name]; - } - - // Only accept functions - if (typeof val != "function") - return false; - - // Register a new listener - let original = val; - val = ContentScriptFunctionWrapper(val); - expando[name] = val; - val.original = original; - obj.addEventListener(name.replace(/^on/, ""), val, true); - return true; - } - - obj[name] = val; - - // Handle native method not overloaded on XrayWrappers: - // obj.addEventListener = val; -> obj.addEventlistener = native method - // And, XPCNativeWrapper bug where nested values appear to be wrapped: - // obj.customNestedAttribute = val -> obj.customNestedAttribute !== val - // obj.customNestedAttribute = "waive wrapper something" - // SEE BUG 658560: Fix identity problem with CrossOriginWrappers - // TODO: check that DOM can't be updated by the document itself and so overloaded value becomes wrong - // but I think such behavior is limited to primitive type - if ((typeof val == "function" || typeof val == "object") && name) { - overload[name] = val; - } - - return true; - }, - - enumerate: function() { - var result = []; - for each (let name in Object.keys(obj)) { - result.push(name); - }; - return result; - }, - - keys: function() { - return Object.keys(obj); - } - }; -}; - - -/* - * Wrap an object from the document to a proxy wrapper. - */ -function create(object) { - if ("wrappedJSObject" in object) - object = object.wrappedJSObject; - let xpcWrapper = XPCNativeWrapper(object); - // If we can't build an XPCNativeWrapper, it doesn't make sense to build - // a proxy. All proxy code is based on having such wrapper that store - // different JS attributes set. - // (we can't build XPCNativeWrapper when object is from the same - // principal/domain) - if (object === xpcWrapper) { - return object; - } - return getProxyForObject(xpcWrapper); -} diff --git a/tools/addon-sdk-1.12/lib/sdk/content/content-worker.js b/tools/addon-sdk-1.12/lib/sdk/content/content-worker.js deleted file mode 100644 index 8cf9c5c..0000000 --- a/tools/addon-sdk-1.12/lib/sdk/content/content-worker.js +++ /dev/null @@ -1,308 +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/. */ - -const ContentWorker = Object.freeze({ - // TODO: Bug 727854 Use same implementation than common JS modules, - // i.e. EventEmitter module - - /** - * Create an EventEmitter instance. - */ - createEventEmitter: function createEventEmitter(emit) { - let listeners = Object.create(null); - let eventEmitter = Object.freeze({ - emit: emit, - on: function on(name, callback) { - if (typeof callback !== "function") - return this; - if (!(name in listeners)) - listeners[name] = []; - listeners[name].push(callback); - return this; - }, - once: function once(name, callback) { - eventEmitter.on(name, function onceCallback() { - eventEmitter.removeListener(name, onceCallback); - callback.apply(callback, arguments); - }); - }, - removeListener: function removeListener(name, callback) { - if (!(name in listeners)) - return; - let index = listeners[name].indexOf(callback); - if (index == -1) - return; - listeners[name].splice(index, 1); - } - }); - function onEvent(name) { - if (!(name in listeners)) - return []; - let args = Array.slice(arguments, 1); - let results = []; - for each (let callback in listeners[name]) { - results.push(callback.apply(null, args)); - } - return results; - } - function hasListenerFor(name) { - if (!(name in listeners)) - return false; - return listeners[name].length > 0; - } - return { - eventEmitter: eventEmitter, - emit: onEvent, - hasListenerFor: hasListenerFor - }; - }, - - /** - * Create an EventEmitter instance to communicate with chrome module - * by passing only strings between compartments. - * This function expects `emitToChrome` function, that allows to send - * events to the chrome module. It returns the EventEmitter as `pipe` - * attribute, and, `onChromeEvent` a function that allows chrome module - * to send event into the EventEmitter. - * - * pipe.emit --> emitToChrome - * onChromeEvent --> callback registered through pipe.on - */ - createPipe: function createPipe(emitToChrome) { - function onEvent() { - // Convert to real array - let args = Array.slice(arguments); - // 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; - } - let str = JSON.stringify(args, replacer); - emitToChrome(str); - } - - let { eventEmitter, emit, hasListenerFor } = - ContentWorker.createEventEmitter(onEvent); - - return { - pipe: eventEmitter, - onChromeEvent: function onChromeEvent(array) { - // We either receive a stringified array, or a real array. - // We still allow to pass an array of objects, in WorkerSandbox.emitSync - // in order to allow sending DOM node reference between content script - // and modules (only used for context-menu API) - let args = typeof array == "string" ? JSON.parse(array) : array; - return emit.apply(null, args); - }, - hasListenerFor: hasListenerFor - }; - }, - - injectConsole: function injectConsole(exports, pipe) { - exports.console = Object.freeze({ - log: pipe.emit.bind(null, "console", "log"), - info: pipe.emit.bind(null, "console", "info"), - warn: pipe.emit.bind(null, "console", "warn"), - error: pipe.emit.bind(null, "console", "error"), - debug: pipe.emit.bind(null, "console", "debug"), - exception: pipe.emit.bind(null, "console", "exception"), - trace: pipe.emit.bind(null, "console", "trace") - }); - }, - - injectTimers: function injectTimers(exports, chromeAPI, pipe, console) { - // 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 - let _timers = Object.create(null); - - // Keep a reference to original timeout functions - let { - setTimeout: chromeSetTimeout, - setInterval: chromeSetInterval, - clearTimeout: chromeClearTimeout, - clearInterval: chromeClearInterval - } = chromeAPI.timers; - - function registerTimer(timer) { - let registerMethod = null; - if (timer.kind == "timeout") - registerMethod = chromeSetTimeout; - else if (timer.kind == "interval") - registerMethod = chromeSetInterval; - else - throw new Error("Unknown timer kind: " + timer.kind); - let id = registerMethod(onFire, timer.delay); - function onFire() { - try { - if (timer.kind == "timeout") - delete _timers[id]; - timer.fun.apply(null, timer.args); - } catch(e) { - console.exception(e); - } - } - _timers[id] = timer; - return id; - } - - function unregisterTimer(id) { - if (!(id in _timers)) - return; - let { kind } = _timers[id]; - delete _timers[id]; - if (kind == "timeout") - chromeClearTimeout(id); - else if (kind == "interval") - chromeClearInterval(id); - else - throw new Error("Unknown timer kind: " + kind); - } - - function disableAllTimers() { - Object.keys(_timers).forEach(unregisterTimer); - } - - exports.setTimeout = function ContentScriptSetTimeout(callback, delay) { - return registerTimer({ - kind: "timeout", - fun: callback, - delay: delay, - args: Array.slice(arguments, 2) - }); - }; - exports.clearTimeout = function ContentScriptClearTimeout(id) { - unregisterTimer(id); - }; - - exports.setInterval = function ContentScriptSetInterval(callback, delay) { - return registerTimer({ - kind: "interval", - fun: callback, - delay: delay, - args: Array.slice(arguments, 2) - }); - }; - exports.clearInterval = function ContentScriptClearInterval(id) { - unregisterTimer(id); - }; - - // On page-hide, save a list of all existing timers before disabling them, - // in order to be able to restore them on page-show. - // These events are fired when the page goes in/out of bfcache. - // https://developer.mozilla.org/En/Working_with_BFCache - let frozenTimers = []; - pipe.on("pageshow", function onPageShow() { - frozenTimers.forEach(registerTimer); - }); - pipe.on("pagehide", function onPageHide() { - frozenTimers = []; - for (let id in _timers) - frozenTimers.push(_timers[id]); - disableAllTimers(); - // Some other pagehide listeners may register some timers that won't be - // frozen as this particular pagehide listener is called first. - // So freeze these timers on next cycle. - chromeSetTimeout(function () { - for (let id in _timers) - frozenTimers.push(_timers[id]); - disableAllTimers(); - }, 0); - }); - - // Unregister all timers when the page is destroyed - // (i.e. when it is removed from bfcache) - pipe.on("detach", function clearTimeouts() { - disableAllTimers(); - _timers = {}; - frozenTimers = []; - }); - }, - - injectMessageAPI: function injectMessageAPI(exports, pipe) { - - let { eventEmitter: port, emit : portEmit } = - ContentWorker.createEventEmitter(pipe.emit.bind(null, "event")); - pipe.on("event", portEmit); - - let self = { - port: port, - postMessage: pipe.emit.bind(null, "message"), - on: pipe.on.bind(null), - once: pipe.once.bind(null), - removeListener: pipe.removeListener.bind(null), - }; - Object.defineProperty(exports, "self", { - value: self - }); - - // Deprecated use of on/postMessage from globals - exports.postMessage = function deprecatedPostMessage() { - console.error("DEPRECATED: 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>."); - return self.postMessage.apply(null, arguments); - }; - exports.on = function deprecatedOn() { - console.error("DEPRECATED: 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>."); - return self.on.apply(null, arguments); - }; - - // Deprecated use of `onMessage` from globals - let onMessage = null; - Object.defineProperty(exports, "onMessage", { - get: function () onMessage, - set: function (v) { - if (onMessage) - self.removeListener("message", onMessage); - console.error("DEPRECATED: 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>."); - onMessage = v; - if (typeof onMessage == "function") - self.on("message", onMessage); - } - }); - }, - - injectOptions: function (exports, options) { - Object.defineProperty( exports.self, "options", { value: JSON.parse( options ) }); - }, - - inject: function (exports, chromeAPI, emitToChrome, options) { - let { pipe, onChromeEvent, hasListenerFor } = - ContentWorker.createPipe(emitToChrome); - - ContentWorker.injectConsole(exports, pipe); - ContentWorker.injectTimers(exports, chromeAPI, pipe, exports.console); - ContentWorker.injectMessageAPI(exports, pipe); - if ( options !== undefined ) { - ContentWorker.injectOptions(exports, options); - } - - Object.freeze( exports.self ); - - return { - emitToContent: onChromeEvent, - hasListenerFor: hasListenerFor - }; - } -}); diff --git a/tools/addon-sdk-1.12/lib/sdk/content/content.js b/tools/addon-sdk-1.12/lib/sdk/content/content.js deleted file mode 100644 index 4bffd45..0000000 --- a/tools/addon-sdk-1.12/lib/sdk/content/content.js +++ /dev/null @@ -1,15 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et: */ -/* 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/. */ -"use strict"; - -module.metadata = { - "stability": "unstable" -}; - -exports.Loader = require('./loader').Loader; -exports.Symbiont = require('./symbiont').Symbiont; -exports.Worker = require('./worker').Worker; - diff --git a/tools/addon-sdk-1.12/lib/sdk/content/loader.js b/tools/addon-sdk-1.12/lib/sdk/content/loader.js deleted file mode 100644 index b01675c..0000000 --- a/tools/addon-sdk-1.12/lib/sdk/content/loader.js +++ /dev/null @@ -1,204 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et: */ -/* 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/. */ - -"use strict"; - -module.metadata = { - "stability": "unstable" -}; - -const { EventEmitter } = require('../deprecated/events'); -const { validateOptions } = require('../deprecated/api-utils'); -const { URL } = require('../url'); -const file = require('../io/file'); - -const LOCAL_URI_SCHEMES = ['resource', 'data']; - -// Returns `null` if `value` is `null` or `undefined`, otherwise `value`. -function ensureNull(value) { - return value == null ? null : value; -} - -// map of property validations -const valid = { - contentURL: { - ok: function (value) { - try { - URL(value); - } - catch(e) { - return false; - } - return true; - }, - msg: 'The `contentURL` option must be a valid URL.' - }, - contentScriptFile: { - is: ['undefined', 'null', 'string', 'array'], - map: ensureNull, - ok: function(value) { - if (value === null) - return true; - - value = [].concat(value); - - // Make sure every item is a local file URL. - return value.every(function (item) { - try { - return ~LOCAL_URI_SCHEMES.indexOf(URL(item).scheme); - } - catch(e) { - return false; - } - }); - - }, - msg: 'The `contentScriptFile` option must be a local URL or an array of URLs.' - }, - contentScript: { - is: ['undefined', 'null', 'string', 'array'], - map: ensureNull, - ok: function(value) { - return !Array.isArray(value) || value.every( - function(item) { return typeof item === 'string' } - ); - }, - msg: 'The `contentScript` option must be a string or an array of strings.' - }, - contentScriptWhen: { - is: ['string'], - ok: function(value) { return ~['start', 'ready', 'end'].indexOf(value) }, - map: function(value) { - return value || 'end'; - }, - msg: 'The `contentScriptWhen` option must be either "start", "ready" or "end".' - }, - contentScriptOptions: { - ok: function(value) { - if ( value === undefined ) { return true; } - try { JSON.parse( JSON.stringify( value ) ); } catch(e) { return false; } - return true; - }, - map: function(value) 'undefined' === getTypeOf(value) ? null : value, - msg: 'The contentScriptOptions should be a jsonable value.' - } -}; -exports.validationAttributes = valid; - -/** - * Shortcut function to validate property with validation. - * @param {Object|Number|String} suspect - * value to validate - * @param {Object} validation - * validation rule passed to `api-utils` - */ -function validate(suspect, validation) validateOptions( - { $: suspect }, - { $: validation } -).$ - -function Allow(script) ({ - get script() script, - set script(value) script = !!value -}) - -/** - * Trait is intended to be used in some composition. It provides set of core - * properties and bounded validations to them. Trait is useful for all the - * compositions providing high level APIs for interaction with content. - * Property changes emit `"propertyChange"` events on instances. - */ -const Loader = EventEmitter.compose({ - /** - * Permissions for the content, with the following keys: - * @property {Object} [allow = { script: true }] - * @property {Boolean} [allow.script = true] - * Whether or not to execute script in the content. Defaults to true. - */ - get allow() this._allow || (this._allow = Allow(true)), - set allow(value) this.allow.script = value && value.script, - _allow: null, - /** - * The content to load. Either a string of HTML or a URL. - * @type {String} - */ - get contentURL() this._contentURL, - set contentURL(value) { - value = validate(value, valid.contentURL); - if (this._contentURL != value) { - this._emit('propertyChange', { - contentURL: this._contentURL = value - }); - } - }, - _contentURL: null, - /** - * When to load the content scripts. - * Possible values are "end" (default), which loads them once all page - * contents have been loaded, "ready", which loads them once DOM nodes are - * ready (ie like DOMContentLoaded event), and "start", which loads them once - * the `window` object for the page has been created, but before any scripts - * specified by the page have been loaded. - * Property change emits `propertyChange` event on instance with this key - * and new value. - * @type {'start'|'ready'|'end'} - */ - get contentScriptWhen() this._contentScriptWhen, - set contentScriptWhen(value) { - value = validate(value, valid.contentScriptWhen); - if (value !== this._contentScriptWhen) { - this._emit('propertyChange', { - contentScriptWhen: this._contentScriptWhen = value - }); - } - }, - _contentScriptWhen: 'end', - /** - * Options avalaible from the content script as `self.options`. - * The value of options can be of any type (object, array, string, etc.) - * but only jsonable values will be available as frozen objects from the - * content script. - * Property change emits `propertyChange` event on instance with this key - * and new value. - * @type {Object} - */ - get contentScriptOptions() this._contentScriptOptions, - set contentScriptOptions(value) this._contentScriptOptions = value, - _contentScriptOptions: null, - /** - * The URLs of content scripts. - * Property change emits `propertyChange` event on instance with this key - * and new value. - * @type {String[]} - */ - get contentScriptFile() this._contentScriptFile, - set contentScriptFile(value) { - value = validate(value, valid.contentScriptFile); - if (value != this._contentScriptFile) { - this._emit('propertyChange', { - contentScriptFile: this._contentScriptFile = value - }); - } - }, - _contentScriptFile: null, - /** - * The texts of content script. - * Property change emits `propertyChange` event on instance with this key - * and new value. - * @type {String|undefined} - */ - get contentScript() this._contentScript, - set contentScript(value) { - value = validate(value, valid.contentScript); - if (value != this._contentScript) { - this._emit('propertyChange', { - contentScript: this._contentScript = value - }); - } - }, - _contentScript: null -}); -exports.Loader = Loader; diff --git a/tools/addon-sdk-1.12/lib/sdk/content/symbiont.js b/tools/addon-sdk-1.12/lib/sdk/content/symbiont.js deleted file mode 100644 index 186e9d3..0000000 --- a/tools/addon-sdk-1.12/lib/sdk/content/symbiont.js +++ /dev/null @@ -1,197 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et: */ -/* 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/. */ -"use strict"; - -module.metadata = { - "stability": "unstable" -}; - -const { Worker } = require('./worker'); -const { Loader } = require('./loader'); -const hiddenFrames = require('../frame/hidden-frame'); -const observers = require('../deprecated/observer-service'); -const unload = require('../system/unload'); - -const assetsURI = require('../self').data.url(); - -/** - * This trait is layered on top of `Worker` and in contrast to symbiont - * Worker constructor requires `content` option that represents content - * that will be loaded in the provided frame, if frame is not provided - * Worker will create hidden one. - */ -const Symbiont = Worker.resolve({ - constructor: '_initWorker', - destroy: '_workerDestroy' - }).compose(Loader, { - - /** - * The constructor requires all the options that are required by - * `require('content').Worker` with the difference that the `frame` option - * is optional. If `frame` is not provided, `contentURL` is expected. - * @param {Object} options - * @param {String} options.contentURL - * URL of a content to load into `this._frame` and create worker for. - * @param {Element} [options.frame] - * iframe element that is used to load `options.contentURL` into. - * if frame is not provided hidden iframe will be created. - */ - constructor: function Symbiont(options) { - options = options || {}; - - if ('contentURL' in options) - this.contentURL = options.contentURL; - if ('contentScriptWhen' in options) - this.contentScriptWhen = options.contentScriptWhen; - if ('contentScriptOptions' in options) - this.contentScriptOptions = options.contentScriptOptions; - if ('contentScriptFile' in options) - this.contentScriptFile = options.contentScriptFile; - if ('contentScript' in options) - this.contentScript = options.contentScript; - if ('allow' in options) - this.allow = options.allow; - if ('onError' in options) - this.on('error', options.onError); - if ('onMessage' in options) - this.on('message', options.onMessage); - if ('frame' in options) { - this._initFrame(options.frame); - } - else { - let self = this; - this._hiddenFrame = hiddenFrames.HiddenFrame({ - onReady: function onFrame() { - self._initFrame(this.element); - }, - onUnload: function onUnload() { - // Bug 751211: Remove reference to _frame when hidden frame is - // automatically removed on unload, otherwise we are going to face - // "dead object" exception - self.destroy(); - } - }); - hiddenFrames.add(this._hiddenFrame); - } - - unload.ensure(this._public, "destroy"); - }, - - destroy: function destroy() { - this._workerDestroy(); - this._unregisterListener(); - this._frame = null; - if (this._hiddenFrame) { - hiddenFrames.remove(this._hiddenFrame); - this._hiddenFrame = null; - } - }, - - /** - * XUL iframe or browser elements with attribute `type` being `content`. - * Used to create `ContentSymbiont` from. - * @type {nsIFrame|nsIBrowser} - */ - _frame: null, - - /** - * Listener to the `'frameReady"` event (emitted when `iframe` is ready). - * Removes listener, sets right permissions to the frame and loads content. - */ - _initFrame: function _initFrame(frame) { - if (this._loadListener) - this._unregisterListener(); - - this._frame = frame; - frame.docShell.allowJavascript = this.allow.script; - frame.setAttribute("src", this._contentURL); - - // Inject `addon` object in document if we load a document from - // one of our addon folder and if no content script are defined. bug 612726 - let isDataResource = - typeof this._contentURL == "string" && - this._contentURL.indexOf(assetsURI) == 0; - let hasContentScript = - (Array.isArray(this.contentScript) ? this.contentScript.length > 0 - : !!this.contentScript) || - (Array.isArray(this.contentScriptFile) ? this.contentScriptFile.length > 0 - : !!this.contentScriptFile); - // If we have to inject `addon` we have to do it before document - // script execution, so during `start`: - this._injectInDocument = isDataResource && !hasContentScript; - if (this._injectInDocument) - this.contentScriptWhen = "start"; - - if ((frame.contentDocument.readyState == "complete" || - (frame.contentDocument.readyState == "interactive" && - this.contentScriptWhen != 'end' )) && - frame.contentDocument.location == this._contentURL) { - // In some cases src doesn't change and document is already ready - // (for ex: when the user moves a widget while customizing toolbars.) - this._onInit(); - return; - } - - let self = this; - - if ('start' == this.contentScriptWhen) { - this._loadEvent = 'start'; - observers.add('document-element-inserted', - this._loadListener = function onStart(doc) { - - let window = doc.defaultView; - if (window && window == frame.contentWindow) { - self._unregisterListener(); - self._onInit(); - } - - }); - return; - } - - let eventName = 'end' == this.contentScriptWhen ? 'load' : 'DOMContentLoaded'; - let self = this; - this._loadEvent = eventName; - frame.addEventListener(eventName, - this._loadListener = function _onReady(event) { - - if (event.target != frame.contentDocument) - return; - self._unregisterListener(); - - self._onInit(); - - }, true); - - }, - - /** - * Unregister listener that watchs for document being ready to be injected. - * This listener is registered in `Symbiont._initFrame`. - */ - _unregisterListener: function _unregisterListener() { - if (!this._loadListener) - return; - if (this._loadEvent == "start") { - observers.remove('document-element-inserted', this._loadListener); - } - else { - this._frame.removeEventListener(this._loadEvent, this._loadListener, - true); - } - this._loadListener = null; - }, - - /** - * Called by Symbiont itself when the frame is ready to load - * content scripts according to contentScriptWhen. Overloaded by Panel. - */ - _onInit: function () { - this._initWorker({ window: this._frame.contentWindow }); - } - -}); -exports.Symbiont = Symbiont; diff --git a/tools/addon-sdk-1.12/lib/sdk/content/thumbnail.js b/tools/addon-sdk-1.12/lib/sdk/content/thumbnail.js deleted file mode 100644 index 9e57274..0000000 --- a/tools/addon-sdk-1.12/lib/sdk/content/thumbnail.js +++ /dev/null @@ -1,46 +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/. */ -'use strict'; - -module.metadata = { - 'stability': 'unstable' -}; - -const { Cc, Ci, Cu } = require('chrome'); -const AppShellService = Cc['@mozilla.org/appshell/appShellService;1']. - getService(Ci.nsIAppShellService); - -const NS = 'http://www.w3.org/1999/xhtml'; -const COLOR = 'rgb(255,255,255)'; - -/** - * Creates canvas element with a thumbnail of the passed window. - * @param {Window} window - * @returns {Element} - */ -function getThumbnailCanvasForWindow(window) { - let aspectRatio = 0.5625; // 16:9 - let thumbnail = AppShellService.hiddenDOMWindow.document - .createElementNS(NS, 'canvas'); - thumbnail.mozOpaque = true; - thumbnail.width = Math.ceil(window.screen.availWidth / 5.75); - thumbnail.height = Math.round(thumbnail.width * aspectRatio); - let ctx = thumbnail.getContext('2d'); - let snippetWidth = window.innerWidth * .6; - let scale = thumbnail.width / snippetWidth; - ctx.scale(scale, scale); - ctx.drawWindow(window, window.scrollX, window.scrollY, snippetWidth, - snippetWidth * aspectRatio, COLOR); - return thumbnail; -} -exports.getThumbnailCanvasForWindow = getThumbnailCanvasForWindow; - -/** - * Creates Base64 encoded data URI of the thumbnail for the passed window. - * @param {Window} window - * @returns {String} - */ -exports.getThumbnailURIForWindow = function getThumbnailURIForWindow(window) { - return getThumbnailCanvasForWindow(window).toDataURL() -}; diff --git a/tools/addon-sdk-1.12/lib/sdk/content/worker.js b/tools/addon-sdk-1.12/lib/sdk/content/worker.js deleted file mode 100644 index b2f204c..0000000 --- a/tools/addon-sdk-1.12/lib/sdk/content/worker.js +++ /dev/null @@ -1,582 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et: */ -/* 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/. */ -"use strict"; - -module.metadata = { - "stability": "unstable" -}; - -const { Trait } = require('../deprecated/traits'); -const { EventEmitter, EventEmitterTrait } = require('../deprecated/events'); -const { Ci, Cu, Cc } = require('chrome'); -const timer = require('../timers'); -const { URL } = require('../url'); -const unload = require('../system/unload'); -const observers = require('../deprecated/observer-service'); -const { Cortex } = require('../deprecated/cortex'); -const { sandbox, evaluate, load } = require("../loader/sandbox"); -const { merge } = require('../util/object'); -const xulApp = require("../system/xul-app"); -const USE_JS_PROXIES = !xulApp.versionInRange(xulApp.platformVersion, - "17.0a2", "*"); -const { getTabForWindow } = require('../tabs/helpers'); - -/* Trick the linker in order to ensure shipping these files in the XPI. - require('./content-proxy.js'); - require('./content-worker.js'); - Then, retrieve URL of these files in the XPI: -*/ -let prefix = module.uri.split('worker.js')[0]; -const CONTENT_PROXY_URL = prefix + 'content-proxy.js'; -const CONTENT_WORKER_URL = prefix + 'content-worker.js'; - -const JS_VERSION = '1.8'; - -const ERR_DESTROYED = - "Couldn't find the worker to receive this message. " + - "The script may not be initialized yet, or may already have been unloaded."; - -const ERR_FROZEN = "The page is currently hidden and can no longer be used " + - "until it is visible again."; - -/** - * 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 = {}; - - -const WorkerSandbox = EventEmitter.compose({ - - /** - * Emit a message to the worker content sandbox - */ - emit: function emit() { - // First ensure having a regular array - // (otherwise, `arguments` would be mapped to an object by `stringify`) - let array = Array.slice(arguments); - // 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; - } - // Ensure having an asynchronous behavior - let self = this; - timer.setTimeout(function () { - self._emitToContent(JSON.stringify(array, replacer)); - }, 0); - }, - - /** - * Synchronous version of `emit`. - * /!\ Should only be used when it is strictly mandatory /!\ - * Doesn't ensure passing only JSON values. - * Mainly used by context-menu in order to avoid breaking it. - */ - emitSync: function emitSync() { - let args = Array.slice(arguments); - // Bug 732716: Ensure wrapping xrays sent to the content script - // otherwise it will have access to raw xraywrappers and content script - // will assume it is an user object coming from the content script sandbox - if ("_wrap" in this) - args = args.map(this._wrap); - return this._emitToContent(args); - }, - - /** - * Tells if content script has at least one listener registered for one event, - * through `self.on('xxx', ...)`. - * /!\ Shouldn't be used. Implemented to avoid breaking context-menu API. - */ - hasListenerFor: function hasListenerFor(name) { - return this._hasListenerFor(name); - }, - - /** - * Method called by the worker sandbox when it needs to send a message - */ - _onContentEvent: function onContentEvent(args) { - // As `emit`, we ensure having an asynchronous behavior - let self = this; - timer.setTimeout(function () { - // We emit event to chrome/addon listeners - self._emit.apply(self, JSON.parse(args)); - }, 0); - }, - - /** - * Configures sandbox and loads content scripts into it. - * @param {Worker} worker - * content worker - */ - constructor: function WorkerSandbox(worker) { - this._addonWorker = worker; - - // Ensure that `emit` has always the right `this` - this.emit = this.emit.bind(this); - this.emitSync = this.emitSync.bind(this); - - // We receive a wrapped window, that may be an xraywrapper if it's content - let window = worker._window; - let proto = window; - - // Instantiate trusted code in another Sandbox in order to prevent content - // script from messing with standard classes used by proxy and API code. - let apiSandbox = sandbox(window, { wantXrays: true }); - - // Build content proxies only if the document has a non-system principal - // And only on old firefox versions that doesn't ship bug 738244 - if (USE_JS_PROXIES && XPCNativeWrapper.unwrap(window) !== window) { - apiSandbox.console = console; - // Execute the proxy code - load(apiSandbox, CONTENT_PROXY_URL); - // Get a reference of the window's proxy - proto = apiSandbox.create(window); - // Keep a reference to `wrap` function for `emitSync` usage - this._wrap = apiSandbox.wrap; - } - - // Create the sandbox and bind it to window in order for content scripts to - // have access to all standard globals (window, document, ...) - let content = this._sandbox = sandbox(window, { - sandboxPrototype: proto, - wantXrays: true - }); - // We have to ensure that window.top and window.parent are the exact same - // object than window object, i.e. the sandbox global object. But not - // always, in case of iframes, top and parent are another window object. - let top = window.top === window ? content : content.top; - let parent = window.parent === window ? content : content.parent; - merge(content, { - // We need "this === window === top" to be true in toplevel scope: - get window() content, - get top() top, - get parent() parent, - // 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! - get unsafeWindow() window.wrappedJSObject - }); - - // Load trusted code that will inject content script API. - // We need to expose JS objects defined in same principal in order to - // avoid having any kind of wrapper. - load(apiSandbox, CONTENT_WORKER_URL); - - // prepare a clean `self.options` - let options = 'contentScriptOptions' in worker ? - JSON.stringify( worker.contentScriptOptions ) : - undefined; - - // Then call `inject` method and communicate with this script - // by trading two methods that allow to send events to the other side: - // - `onEvent` called by content script - // - `result.emitToContent` called by addon script - // Bug 758203: We have to explicitely define `__exposedProps__` in order - // to allow access to these chrome object attributes from this sandbox with - // content priviledges - // https://developer.mozilla.org/en/XPConnect_wrappers#Other_security_wrappers - let chromeAPI = { - timers: { - setTimeout: timer.setTimeout, - setInterval: timer.setInterval, - clearTimeout: timer.clearTimeout, - clearInterval: timer.clearInterval, - __exposedProps__: { - setTimeout: 'r', - setInterval: 'r', - clearTimeout: 'r', - clearInterval: 'r' - } - }, - __exposedProps__: { - timers: 'r' - } - }; - let onEvent = this._onContentEvent.bind(this); - // `ContentWorker` is defined in CONTENT_WORKER_URL file - let result = apiSandbox.ContentWorker.inject(content, chromeAPI, onEvent, options); - this._emitToContent = result.emitToContent; - this._hasListenerFor = result.hasListenerFor; - - // Handle messages send by this script: - let self = this; - // console.xxx calls - this.on("console", function consoleListener(kind) { - console[kind].apply(console, Array.slice(arguments, 1)); - }); - - // self.postMessage calls - this.on("message", function postMessage(data) { - // destroyed? - if (self._addonWorker) - self._addonWorker._emit('message', data); - }); - - // self.port.emit calls - this.on("event", function portEmit(name, args) { - // destroyed? - if (self._addonWorker) - self._addonWorker._onContentScriptEvent.apply(self._addonWorker, arguments); - }); - - // Internal feature that is only used by SDK tests: - // Expose unlock key to content script context. - // See `PRIVATE_KEY` definition for more information. - if (apiSandbox && worker._expose_key) - content.UNWRAP_ACCESS_KEY = apiSandbox.UNWRAP_ACCESS_KEY; - - // 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", { - value: content.self - } - ); - } - - // 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 - ); - } - }, - destroy: function destroy() { - this.emitSync("detach"); - this._sandbox = null; - this._addonWorker = null; - this._wrap = null; - }, - - /** - * 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) { - try { - evaluate(this._sandbox, code, filename || 'javascript:' + code); - } - catch(e) { - this._addonWorker._emit('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 uri = URL(contentScriptFile); - if (uri.scheme === 'resource') - load(this._sandbox, String(uri)); - else - throw Error("Unsupported `contentScriptFile` url: " + String(uri)); - } - catch(e) { - this._addonWorker._emit('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 = EventEmitter.compose({ - on: 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); - if (this._frozen) - throw new Error(ERR_FROZEN); - - this._contentWorker.emit("message", 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 - * 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(Array.slice(arguments)) - }); - - // 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 _emit, 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; - } - - if (this._frozen) - throw new Error(ERR_FROZEN); - - // We throw exception when the worker has been destroyed - if (!this._contentWorker) { - throw new Error(ERR_DESTROYED); - } - - // Forward the event to the WorkerSandbox object - this._contentWorker.emit.apply(null, ["event"].concat(args)); - }, - - // Is worker connected to the content worker sandbox ? - _inited: false, - - // Is worker being frozen? i.e related document is frozen in bfcache. - // Content script should not be reachable if frozen. - _frozen: true, - - // 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 ('contentScriptOptions' in options) - this.contentScriptOptions = options.contentScriptOptions; - 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)); - - // Listen to pagehide event in order to freeze the content script - // while the document is frozen in bfcache: - this._window.addEventListener("pageshow", - this._pageShow = this._pageShow.bind(this), - true); - this._window.addEventListener("pagehide", - this._pageHide = this._pageHide.bind(this), - true); - - unload.ensure(this._public, "destroy"); - - // Ensure that worker._port is initialized for contentWorker to be able - // to send use event during WorkerSandbox(this) - this.port; - - // will set this._contentWorker pointing to the private API: - this._contentWorker = WorkerSandbox(this); - - // Mainly enable worker.port.emit to send event to the content worker - this._inited = true; - this._frozen = false; - - // 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; - }, - - _pageShow: function _pageShow() { - this._contentWorker.emitSync("pageshow"); - this._emit("pageshow"); - this._frozen = false; - }, - - _pageHide: function _pageHide() { - this._contentWorker.emitSync("pagehide"); - this._emit("pagehide"); - this._frozen = true; - }, - - get url() { - // this._window will be null after detach - return this._window ? this._window.document.location.href : null; - }, - - get tab() { - // this._window will be null after detach - if (this._window) - return 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(); - }, - - /** - * 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.destroy(); - this._contentWorker = null; - if (this._window) { - this._window.removeEventListener("pageshow", this._pageShow, true); - this._window.removeEventListener("pagehide", this._pageHide, true); - } - 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() { - this._port._emit.apply(this._port, arguments); - }, - - /** - * 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; |