]> git.donarmstrong.com Git - dactyl.git/blobdiff - common/modules/base.jsm
Import r6923 from upstream hg supporting Firefox up to 22.0a1
[dactyl.git] / common / modules / base.jsm
index 51d2f0d757ca93bd5fa1d5579fc2fb76b4bc2360..589c8042478c4c948821c6761d9202e592da283d 100644 (file)
@@ -1,13 +1,12 @@
-// Copyright (c) 2009-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2009-2012 Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
-/* use strict */
+"use strict";
 
 var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
 
-Cu.import("resource://dactyl/bootstrap.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
 try {
     var ctypes;
     Cu.import("resource://gre/modules/ctypes.jsm");
@@ -21,122 +20,27 @@ let { __lookupGetter__, __lookupSetter__, __defineGetter__, __defineSetter__,
 if (typeof XPCSafeJSObjectWrapper === "undefined")
     this.XPCSafeJSObjectWrapper = XPCNativeWrapper;
 
-if (!XPCNativeWrapper.unwrap)
-    XPCNativeWrapper.unwrap = function unwrap(obj) {
-        if (hasOwnProperty.call(obj, "wrappedJSObject"))
-            return obj.wrappedJSObject;
-        return obj;
-    };
-if (!Object.create)
-    Object.create = function create(proto, props) {
-        let obj = { __proto__: proto };
-        for (let k in properties(props || {}))
-            Object.defineProperty(obj, k, props[k]);
-        return obj;
-    };
-if (!Object.defineProperty)
-    Object.defineProperty = function defineProperty(obj, prop, desc) {
-        try {
-            let value = desc.value;
-            if ("value" in desc)
-                if (desc.writable && !__lookupGetter__.call(obj, prop)
-                                  && !__lookupSetter__.call(obj, prop))
-                    try {
-                        obj[prop] = value;
-                    }
-                    catch (e if e instanceof TypeError) {}
-                else {
-                    __defineGetter__.call(obj, prop, function () value);
-                    if (desc.writable)
-                        __defineSetter__.call(obj, prop, function (val) { value = val; });
-                }
+let getGlobalForObject = Cu.getGlobalForObject || function (obj) obj.__parent__;
 
-            if ("get" in desc)
-                __defineGetter__.call(obj, prop, desc.get);
-            if ("set" in desc)
-                __defineSetter__.call(obj, prop, desc.set);
-        }
-        catch (e) {
-            throw e.stack ? e : Error(e);
-        }
-    };
-if (!Object.defineProperties)
-    Object.defineProperties = function defineProperties(obj, props) {
-        for (let [k, v] in Iterator(props))
-            Object.defineProperty(obj, k, v);
-    };
-if (!Object.freeze)
-    Object.freeze = function freeze(obj) {};
-if (!Object.getPropertyDescriptor)
-    Object.getPropertyDescriptor = function getPropertyDescriptor(obj, prop) {
-        try {
-            let desc = {
-                configurable: true,
-                enumerable: propertyIsEnumerable.call(obj, prop)
-            };
-            var get = __lookupGetter__.call(obj, prop),
-                set = __lookupSetter__.call(obj, prop);
-            if (!get && !set) {
-                desc.value = obj[prop];
-                desc.writable = true;
-            }
-            if (get)
-                desc.get = get;
-            if (set)
-                desc.set = set;
-            return desc;
-        }
-        catch (e) {
-            throw e.stack ? e : Error(e);
-        }
-    };
-if (!Object.getOwnPropertyDescriptor)
-    Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(obj, prop) {
-        if (hasOwnProperty.call(obj, prop))
-            return Object.getPropertyDescriptor(obj, prop);
-    };
-if (!Object.getOwnPropertyNames)
-    Object.getOwnPropertyNames = function getOwnPropertyNames(obj, _debugger) {
-        try {
-            // This is an ugly and unfortunately necessary hack.
-            if (hasOwnProperty.call(obj, "__iterator__")) {
-                var oldIter = obj.__iterator__;
-                delete obj.__iterator__;
-            }
-            let res = [k for (k in obj) if (hasOwnProperty.call(obj, k))];
-            if (oldIter !== undefined) {
-                obj.__iterator__ = oldIter;
-                res.push("__iterator__");
-            }
-            return res;
-        }
-        catch (e) {
-            throw e.stack ? e : Error(e);
-        }
-    };
-if (!Object.getPrototypeOf)
-    Object.getPrototypeOf = function getPrototypeOf(obj) obj.__proto__;
-if (!Object.keys)
-    Object.keys = function keys(obj)
-        Object.getOwnPropertyNames(obj).filter(function (k) propertyIsEnumerable.call(obj, k));
+function require(module, target) JSMLoader.load(module, target);
 
-let getGlobalForObject = Cu.getGlobalForObject || function (obj) obj.__parent__;
+function lazyRequire(module, names, target) {
+    for each (let name in names)
+        memoize(target || this, name, function (name) require(module)[name]);
+}
 
-let jsmodules = {
-    lazyRequire: function lazyRequire(module, names, target) {
-        for each (let name in names)
-            memoize(target || this, name, function (name) require(module)[name]);
-    }
-};
+let jsmodules = { lazyRequire: lazyRequire };
 jsmodules.jsmodules = jsmodules;
 
+function toString() "[module-global " + this.NAME + "]";
+
 let use = {};
 let loaded = {};
 let currentModule;
 let global = this;
 function defineModule(name, params, module) {
     if (!module)
-        module = getGlobalForObject(params);
+        module = this;
 
     module.NAME = name;
     module.EXPORTED_SYMBOLS = params.exports || [];
@@ -147,8 +51,7 @@ function defineModule(name, params, module) {
     defineModule.prefix += "  ";
 
     for (let [, mod] in Iterator(params.require || []))
-        require(module, mod, null, name);
-    module.__proto__ = jsmodules;
+        require(mod, module);
 
     module._lastModule = currentModule;
     currentModule = module;
@@ -159,7 +62,7 @@ defineModule.loadLog = [];
 Object.defineProperty(defineModule.loadLog, "push", {
     value: function (val) {
         val = defineModule.prefix + val;
-        if (false)
+        if (true)
             defineModule.dump(val + "\n");
         this[this.length] = Date.now() + " " + val;
     }
@@ -196,11 +99,11 @@ function endModule() {
     defineModule.loadLog.push("(End   " + currentModule.NAME + ")");
 
     loaded[currentModule.NAME] = 1;
-    require(jsmodules, currentModule.NAME);
+    require(currentModule.NAME, jsmodules);
     currentModule = currentModule._lastModule;
 }
 
-function require(obj, name, from, targetName) {
+function require_(obj, name, from, targetName) {
     try {
         if (arguments.length === 1)
             [obj, name] = [{}, obj];
@@ -230,18 +133,47 @@ function require(obj, name, from, targetName) {
 defineModule("base", {
     // sed -n 's/^(const|var|function) ([a-zA-Z0-9_]+).*/      "\2",/p' base.jsm | sort | fmt
     exports: [
-        "ErrorBase", "Cc", "Ci", "Class", "Cr", "Cu", "Module", "JSMLoader", "Object",
+        "ErrorBase", "Cc", "Ci", "Class", "Cr", "Cu", "Finished", "Module", "JSMLoader",
         "Set", "Struct", "StructBase", "Timer", "UTF8", "XPCOM", "XPCOMShim", "XPCOMUtils",
         "XPCSafeJSObjectWrapper", "array", "bind", "call", "callable", "ctypes", "curry",
         "debuggerProperties", "defineModule", "deprecated", "endModule", "forEach", "isArray",
-        "isGenerator", "isinstance", "isObject", "isString", "isSubclass", "iter", "iterAll",
-        "iterOwnProperties", "keys", "memoize", "octal", "properties", "require", "set", "update",
-        "values", "withCallerGlobal"
+        "isGenerator", "isinstance", "isObject", "isString", "isSubclass", "isXML", "iter",
+        "iterAll", "iterOwnProperties", "keys", "literal", "memoize", "octal", "properties",
+        "require", "set", "update", "values", "update_"
     ]
-}, this);
+});
 
+this.lazyRequire("cache", ["cache"]);
+this.lazyRequire("config", ["config"]);
 this.lazyRequire("messages", ["_", "Messages"]);
-this.lazyRequire("util", ["util"]);
+this.lazyRequire("services", ["services"]);
+this.lazyRequire("storage", ["File"]);
+this.lazyRequire("util", ["FailedAssertion", "util"]);
+
+function literal(/* comment */) {
+    let { caller } = Components.stack;
+    while (caller && caller.language != 2)
+        caller = caller.caller;
+
+    let file = caller.filename.replace(/.* -> /, "");
+    let key = "literal:" + file + ":" + caller.line;
+
+    let source = File.readURL(file);
+
+    let match = RegExp("(?:.*\\n){" + (caller.lineNumber - 1) + "}" +
+                       ".*literal\\(/\\*([^]*?)\\*/\\)").exec(source);
+    return match[1];
+
+    // Later...
+    return cache.get(key, function () {
+        let source = cache.get("literal:" + file,
+                               function () util.httpGet(file).responseText);
+
+        let match = RegExp("(?:.*\\n){" + (caller.lineNumber - 1) + "}" +
+                           ".*literal\\(/\\*([^]*?)\\*/\\)").exec(source);
+        return match[1];
+    });
+}
 
 /**
  * Returns a list of all of the top-level properties of an object, by
@@ -269,7 +201,6 @@ function debuggerProperties(obj) {
  * @returns {Generator}
  */
 function prototype(obj)
-    /* Temporary hack: */ typeof obj === "xml" || obj.__proto__ !== obj.__proto__ ? null :
     obj.__proto__ || Object.getPrototypeOf(obj) ||
     XPCNativeWrapper.unwrap(obj).__proto__ ||
     Object.getPrototypeOf(XPCNativeWrapper.unwrap(obj));
@@ -286,10 +217,42 @@ function properties(obj, prototypes, debugger_) {
     }
     catch (e) {}
 
+    function props(obj) {
+        // Grr.
+        try {
+            return Object.getOwnPropertyNames(obj);
+        }
+        catch (e) {
+            if (e.result === Cr.NS_ERROR_FAILURE) {
+                // This is being thrown for PDF.js content windows,
+                // currently.
+                let filter = function filter(prop) {
+                    try {
+                        return prop in obj;
+                    }
+                    catch (e) {
+                        util.reportError("Filtering properties for " +
+                                         String.quote(obj) + ", " +
+                                         "error checking presence of " +
+                                         String.quote(prop) + ": " + e);
+                    }
+                    return false;
+                };
+                return array.uniq([k for (k in obj)].concat(
+                    Object.getOwnPropertyNames(
+                              XPCNativeWrapper.unwrap(obj))
+                          .filter(filter)))
+            }
+            else if (!e.stack) {
+                throw Error(e);
+            }
+        }
+    }
+
     for (; obj; obj = prototypes && prototype(obj)) {
         try {
-            if (sandbox.Object.getOwnPropertyNames || !debugger_ || !services.debugger.isOn)
-                var iter = (v for each (v in Object.getOwnPropertyNames(obj)));
+            if (!debugger_ || !services.debugger.isOn)
+                var iter = (v for each (v in props(obj)));
         }
         catch (e) {}
         if (!iter)
@@ -331,8 +294,8 @@ function deprecated(alternative, fn) {
 deprecated.warn = function warn(func, name, alternative, frame) {
     if (!func.seenCaller)
         func.seenCaller = Set([
-            "resource://dactyl" + JSMLoader.suffix + "/javascript.jsm",
-            "resource://dactyl" + JSMLoader.suffix + "/util.jsm"
+            "resource://dactyl/javascript.jsm",
+            "resource://dactyl/util.jsm"
         ]);
 
     frame = frame || Components.stack.caller.caller;
@@ -570,6 +533,12 @@ function isinstance(object, interfaces) {
  */
 function isObject(obj) typeof obj === "object" && obj != null || obj instanceof Ci.nsISupports;
 
+/**
+ * Returns true if obje is an E4X XML object.
+ * @deprecated
+ */
+function isXML(obj) typeof obj === "xml";
+
 /**
  * Returns true if and only if its sole argument is an
  * instance of the builtin Array type. The array may come from
@@ -653,20 +622,8 @@ function memoize(obj, key, getter) {
     }
 }
 
-let sandbox = Cu.Sandbox(this);
+let sandbox = Cu.Sandbox(Cc["@mozilla.org/systemprincipal;1"].createInstance());
 sandbox.__proto__ = this;
-/**
- * Wraps a function so that when called, the global object of the caller
- * is prepended to its arguments.
- */
-// Hack to get around lack of access to caller in strict mode.
-var withCallerGlobal = Cu.evalInSandbox(<![CDATA[
-    (function withCallerGlobal(fn)
-        function withCallerGlobal_wrapped()
-            fn.apply(this,
-                     [Class.objectGlobal(withCallerGlobal_wrapped.caller)]
-                        .concat(Array.slice(arguments))))
-]]>, Cu.Sandbox(this), "1.8");
 
 /**
  * Updates an object with the properties of another object. Getters
@@ -699,7 +656,7 @@ function update(target) {
                 if (typeof desc.value === "function" && target.__proto__ && !(desc.value instanceof Ci.nsIDOMElement /* wtf? */)) {
                     let func = desc.value.wrapped || desc.value;
                     if (!func.superapply) {
-                        func.__defineGetter__("super", function () Object.getPrototypeOf(target)[k]);
+                        func.__defineGetter__("super", function get_super() Object.getPrototypeOf(target)[k]);
                         func.superapply = function superapply(self, args)
                             let (meth = Object.getPrototypeOf(target)[k])
                                 meth && meth.apply(self, args);
@@ -714,6 +671,33 @@ function update(target) {
     }
     return target;
 }
+function update_(target) {
+    for (let i = 1; i < arguments.length; i++) {
+        let src = arguments[i];
+        Object.getOwnPropertyNames(src || {}).forEach(function (k) {
+            let desc = Object.getOwnPropertyDescriptor(src, k);
+            if (desc.value instanceof Class.Property)
+                desc = desc.value.init(k, target) || desc.value;
+
+            try {
+                if (typeof desc.value === "function" && target.__proto__ && !(desc.value instanceof Ci.nsIDOMElement /* wtf? */)) {
+                    let func = desc.value.wrapped || desc.value;
+                    if (!func.superapply) {
+                        func.__defineGetter__("super", function get_super_() Object.getPrototypeOf(target)[k]);
+                        func.superapply = function super_apply(self, args)
+                            let (meth = Object.getPrototypeOf(target)[k])
+                                meth && meth.apply(self, args);
+                        func.supercall = function super_call(self)
+                            func.superapply(self, Array.slice(arguments, 1));
+                    }
+                }
+                Object.defineProperty(target, k, desc);
+            }
+            catch (e) {}
+        });
+    }
+    return target;
+}
 
 /**
  * @constructor Class
@@ -751,6 +735,7 @@ function Class() {
         var Constructor = function Constructor() {
             var self = Object.create(Constructor.prototype);
             self.instance = self;
+            self.globalInstance = self;
 
             if ("_metaInit_" in self && self._metaInit_)
                 self._metaInit_.apply(self, arguments);
@@ -759,17 +744,18 @@ function Class() {
             return res !== undefined ? res : self;
         };
     else
-        var Constructor = eval(String.replace(<![CDATA[
-            (function constructor(PARAMS) {
-                var self = Object.create(Constructor.prototype);
-                self.instance = self;
-
-                if ("_metaInit_" in self && self._metaInit_)
-                    self._metaInit_.apply(self, arguments);
-
-                var res = self.init.apply(self, arguments);
-                return res !== undefined ? res : self;
-            })]]>,
+        var Constructor = eval(String.replace('\n\
+            (function constructor(PARAMS) {                      \n\
+                var self = Object.create(Constructor.prototype); \n\
+                self.instance = self;                            \n\
+                self.globalInstance = self;                      \n\
+                                                                 \n\
+                if ("_metaInit_" in self && self._metaInit_)     \n\
+                    self._metaInit_.apply(self, arguments);      \n\
+                                                                 \n\
+                var res = self.init.apply(self, arguments);      \n\
+                return res !== undefined ? res : self;           \n\
+            })',
             "constructor", (name || superclass.className).replace(/\W/g, "_"))
                 .replace("PARAMS", /^function .*?\((.*?)\)/.exec(args[0] && args[0].init || Class.prototype.init)[1]
                                                            .replace(/\b(self|res|Constructor)\b/g, "$1_")));
@@ -1126,6 +1112,12 @@ var ErrorBase = Class("ErrorBase", Error, {
     toString: function () String(this.message)
 });
 
+/**
+ * An Error subclass to throw in order to stop sourcing a plugin without
+ * printing a stack trace.
+ */
+var Finished = Class("Finished", ErrorBase);
+
 /**
  * Constructs a new Module class and instantiates an instance into the current
  * module global object.
@@ -1424,7 +1416,8 @@ function iter(obj, iface) {
     }
     else if (isinstance(obj, [Ci.nsIDOMHTMLCollection, Ci.nsIDOMNodeList]))
         res = array.iterItems(obj);
-    else if (obj instanceof Ci.nsIDOMNamedNodeMap)
+    else if (Ci.nsIDOMNamedNodeMap && obj instanceof Ci.nsIDOMNamedNodeMap ||
+             Ci.nsIDOMMozNamedAttrMap && obj instanceof Ci.nsIDOMMozNamedAttrMap)
         res = (function () {
             for (let i = 0; i < obj.length; i++)
                 yield [obj.name, obj];