Changeset 65434 in webkit


Ignore:
Timestamp:
Aug 16, 2010 9:33:36 AM (14 years ago)
Author:
pfeldman@chromium.org
Message:

2010-08-16 Pavel Feldman <pfeldman@chromium.org>

Reviewed by Yury Semikhatsky.

Web Inspector: Make InjectedScript proto-based.
https://bugs.webkit.org/show_bug.cgi?id=44028

  • inspector/front-end/InjectedScript.js: (injectedScriptConstructor): (injectedScriptConstructor.):

2010-08-16 Pavel Feldman <pfeldman@chromium.org>

Reviewed by Yury Semikhatsky.

Web Inspector: Make InjectedScript proto-based.
https://bugs.webkit.org/show_bug.cgi?id=44028
Drive-by test fix.

  • http/tests/inspector-enabled/console-log-before-frame-navigation.html:
  • http/tests/inspector-enabled/resources/console-log-before-frame-navigation.js: Removed.
  • http/tests/inspector-enabled/resources/console-log-frame-before-navigation.html:
Location:
trunk
Files:
1 deleted
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r65431 r65434  
     12010-08-16  Pavel Feldman  <pfeldman@chromium.org>
     2
     3        Reviewed by Yury Semikhatsky.
     4
     5        Web Inspector: Make InjectedScript proto-based.
     6        https://bugs.webkit.org/show_bug.cgi?id=44028
     7        Drive-by test fix.
     8
     9        * http/tests/inspector-enabled/console-log-before-frame-navigation.html:
     10        * http/tests/inspector-enabled/resources/console-log-before-frame-navigation.js: Removed.
     11        * http/tests/inspector-enabled/resources/console-log-frame-before-navigation.html:
     12
    1132010-08-16  Csaba Osztrogonác  <ossy@webkit.org>
    214
  • trunk/LayoutTests/http/tests/inspector-enabled/console-log-before-frame-navigation-expected.txt

    r56841 r65434  
    33
    44
    5 Showing Web Inspector...
    65Received console messages:
    76Message[0]:
    87URL: http://127.0.0.1:8000/inspector-enabled/resources/console-log-frame-before-navigation.html
    9 Message: 2010 [object HTMLHtmlElement]
     8Message: 2010 HTMLHtmlElement
    109TEST COMPLETE.
    1110
  • trunk/LayoutTests/http/tests/inspector-enabled/console-log-before-frame-navigation.html

    r56708 r65434  
    22<html>
    33<head>
    4 <link rel="stylesheet" href="../../js-test-resources/js-test-style.css">
    5 <script src="../../js-test-resources/js-test-pre.js"></script>
    64<script src="../inspector/inspector-test.js"></script>
    7 <script src="resources/console-log-before-frame-navigation.js"></script>
     5<script>
     6function doit()
     7{
     8    function callback(result)
     9    {
     10        output("Received console messages:");
     11        for (var i = 0; i < result.length; ++i) {
     12            var r = result[i];
     13            output("Message[" + i + "]:");
     14            output("URL: " + r.url);
     15            output("Message: " + r.message);
     16        }
     17        notifyDone();
     18        output("TEST COMPLETE.");
     19    }
     20    evaluateInWebInspector("frontend_dumpConsoleMessages", callback);
     21}
     22
     23function receiveMessage(event) {
     24    if (event.data != "frameReloaded") {
     25        testFailed("Unexpected message: " + event.data);
     26        if (window.layoutTestController)
     27            layoutTestController.notifyDone();
     28        return;
     29    }
     30    if (window.layoutTestController)
     31        layoutTestController.showWebInspector();
     32    onload();
     33}
     34
     35window.addEventListener("message", receiveMessage, false);
     36// Frontend functions.
     37
     38function frontend_dumpConsoleMessages()
     39{
     40    var result = [];
     41    var messages = WebInspector.console.messages;
     42    for (var i = 0; i < messages.length; ++i) {
     43        var m = messages[i];
     44        result.push({ message: m.message, url: m.url});
     45    }
     46    return result;
     47}
     48</script>
     49
    850</head>
    9 <body onload="onload()">
     51<body>
    1052<p>
    1153Tests that Web Inspector won't crash if there are messages written to console from a frame which has already navigated to a page from a different domain.
    1254</p>
    1355<iframe id="theFrame" src="resources/console-log-frame-before-navigation.html"></iframe>
    14 <p id="description"></p>
    15 <div id="console"></div>
    1656</body>
    1757</html>
  • trunk/LayoutTests/http/tests/inspector-enabled/resources/console-log-frame-before-navigation.html

    r56841 r65434  
    66
    77  setTimeout(function() {
    8     document.location = "http://localhost:8000/inspector-enabled/resources/console-log-frame-after-navigation.html";
     8    document.location = "console-log-frame-after-navigation.html";
    99  }, 0);
    1010}
  • trunk/WebCore/ChangeLog

    r65432 r65434  
     12010-08-16  Pavel Feldman  <pfeldman@chromium.org>
     2
     3        Reviewed by Yury Semikhatsky.
     4
     5        Web Inspector: Make InjectedScript proto-based.
     6        https://bugs.webkit.org/show_bug.cgi?id=44028
     7
     8        * inspector/front-end/InjectedScript.js:
     9        (injectedScriptConstructor):
     10        (injectedScriptConstructor.):
     11
    1122010-08-16  Csaba Osztrogonác  <ossy@webkit.org>
    213
  • trunk/WebCore/inspector/front-end/InjectedScript.js

    r65423 r65434  
    2929var injectedScriptConstructor = (function (InjectedScriptHost, inspectedWindow, injectedScriptId, jsEngine) {
    3030
    31 var InjectedScript = {};
    32 
    33 InjectedScript.lastBoundObjectId = 1;
    34 InjectedScript.idToWrappedObject = {};
    35 InjectedScript.objectGroups = {};
    36 
    37 InjectedScript.wrapObjectForConsole = function(object, canAccessInspectedWindow)
     31var InjectedScript = function()
    3832{
    39     if (canAccessInspectedWindow)
    40         return InjectedScript.wrapObject(object, "console");
    41     var result = {};
    42     result.type = typeof object;
    43     result.description = InjectedScript._toString(object);
    44     return result;
    45 }
    46 
    47 InjectedScript.wrapObject = function(object, objectGroupName)
    48 {
    49     try {
    50         var objectId;
    51         if (typeof object === "object" || typeof object === "function" || InjectedScript._isHTMLAllCollection(object)) {
    52             var id = InjectedScript.lastBoundObjectId++;
    53             objectId = id;
    54             InjectedScript.idToWrappedObject[id] = object;
    55 
    56             var group = InjectedScript.objectGroups[objectGroupName];
    57             if (!group) {
    58                 group = [];
    59                 InjectedScript.objectGroups[objectGroupName] = group;
     33    this._lastBoundObjectId = 1;
     34    this._idToWrappedObject = {};
     35    this._objectGroups = {};
     36}
     37
     38InjectedScript.prototype = {
     39    wrapObjectForConsole: function(object, canAccessInspectedWindow)
     40    {
     41        if (canAccessInspectedWindow)
     42            return this._wrapObject(object, "console");
     43        var result = {};
     44        result.type = typeof object;
     45        result.description = this._toString(object);
     46        return result;
     47    },
     48
     49    _wrapObject: function(object, objectGroupName)
     50    {
     51        try {
     52            var objectId;
     53            if (typeof object === "object" || typeof object === "function" || this._isHTMLAllCollection(object)) {
     54                var id = this._lastBoundObjectId++;
     55                objectId = id;
     56                this._idToWrappedObject[id] = object;
     57   
     58                var group = this._objectGroups[objectGroupName];
     59                if (!group) {
     60                    group = [];
     61                    this._objectGroups[objectGroupName] = group;
     62                }
     63                group.push(id);
     64                objectId = new InjectedScript.RemoteObjectId(InjectedScript.RemoteObjectId.Type.JsObject, id);
    6065            }
    61             group.push(id);
    62             objectId = new InjectedScript.RemoteObjectId(InjectedScript.RemoteObjectId.Type.JsObject, id);
    63         }
    64         return InjectedScript.RemoteObject.fromObject(object, objectId);
    65     } catch (e) {
    66         return InjectedScript.RemoteObject.fromObject("[ Exception: " + e.toString() + " ]");
    67     }
    68 };
    69 
    70 InjectedScript.unwrapObject = function(objectId) {
    71     return InjectedScript.idToWrappedObject[objectId];
    72 };
    73 
    74 InjectedScript.releaseWrapperObjectGroup = function(objectGroupName) {
    75     var group = InjectedScript.objectGroups[objectGroupName];
    76     if (!group)
    77         return;
    78     for (var i = 0; i < group.length; i++)
    79         delete InjectedScript.idToWrappedObject[group[i]];
    80     delete InjectedScript.objectGroups[objectGroupName];
    81 };
    82 
    83 InjectedScript.dispatch = function(methodName, args)
    84 {
    85     var argsArray = eval("(" + args + ")");
    86     var result = InjectedScript[methodName].apply(InjectedScript, argsArray);
    87     if (typeof result === "undefined") {
    88         inspectedWindow.console.error("Web Inspector error: InjectedScript.%s returns undefined", methodName);
    89         result = null;
    90     }
    91     return result;
    92 }
    93 
    94 InjectedScript.getPrototypes = function(nodeId)
    95 {
    96     var node = InjectedScript._nodeForId(nodeId);
    97     if (!node)
    98         return false;
    99 
    100     var result = [];
    101     var prototype = node;
    102     var prototypeId = new InjectedScript.RemoteObjectId(InjectedScript.RemoteObjectId.Type.Node, nodeId);
    103     do {
    104         result.push(InjectedScript.RemoteObject.fromObject(prototype, prototypeId));
    105         prototype = prototype.__proto__;
    106         prototypeId = InjectedScript.RemoteObjectId.deriveProperty(prototypeId, "__proto__");
    107     } while (prototype)
    108 
    109     return result;
    110 }
    111 
    112 InjectedScript.getProperties = function(objectId, ignoreHasOwnProperty, abbreviate)
    113 {
    114     var object = InjectedScript._objectForId(objectId);
    115     if (!InjectedScript._isDefined(object))
    116         return false;
    117     var properties = [];
    118    
    119     var propertyNames = ignoreHasOwnProperty ? InjectedScript._getPropertyNames(object) : Object.getOwnPropertyNames(object);
    120     if (!ignoreHasOwnProperty && object.__proto__)
    121         propertyNames.push("__proto__");
    122 
    123     // Go over properties, prepare results.
    124     for (var i = 0; i < propertyNames.length; ++i) {
    125         var propertyName = propertyNames[i];
    126 
    127         var property = {};
    128         property.name = propertyName + "";
    129         var isGetter = object["__lookupGetter__"] && object.__lookupGetter__(propertyName);
    130         if (!isGetter) {
    131             try {
    132                 var childObject = object[propertyName];
    133                 var childObjectId = InjectedScript.RemoteObjectId.deriveProperty(objectId, propertyName);
    134                 var childObjectProxy = new InjectedScript.RemoteObject.fromObject(childObject, childObjectId, abbreviate);
    135                 property.value = childObjectProxy;
    136             } catch(e) {
    137                 property.value = new InjectedScript.RemoteObject.fromException(e);
     66            return InjectedScript.RemoteObject.fromObject(object, objectId);
     67        } catch (e) {
     68            return InjectedScript.RemoteObject.fromObject("[ Exception: " + e.toString() + " ]");
     69        }
     70    },
     71
     72    releaseWrapperObjectGroup: function(objectGroupName)
     73    {
     74        var group = this._objectGroups[objectGroupName];
     75        if (!group)
     76            return;
     77        for (var i = 0; i < group.length; i++)
     78            delete this._idToWrappedObject[group[i]];
     79        delete this._objectGroups[objectGroupName];
     80    },
     81
     82    dispatch: function(methodName, args)
     83    {
     84        var argsArray = eval("(" + args + ")");
     85        var result = this[methodName].apply(this, argsArray);
     86        if (typeof result === "undefined") {
     87            inspectedWindow.console.error("Web Inspector error: InjectedScript.%s returns undefined", methodName);
     88            result = null;
     89        }
     90        return result;
     91    },
     92
     93    getPrototypes: function(nodeId)
     94    {
     95        var node = this._nodeForId(nodeId);
     96        if (!node)
     97            return false;
     98   
     99        var result = [];
     100        var prototype = node;
     101        var prototypeId = new InjectedScript.RemoteObjectId(InjectedScript.RemoteObjectId.Type.Node, nodeId);
     102        do {
     103            result.push(InjectedScript.RemoteObject.fromObject(prototype, prototypeId));
     104            prototype = prototype.__proto__;
     105            prototypeId = InjectedScript.RemoteObjectId.deriveProperty(prototypeId, "__proto__");
     106        } while (prototype)
     107   
     108        return result;
     109    },
     110
     111    getProperties: function(objectId, ignoreHasOwnProperty, abbreviate)
     112    {
     113        var object = this._objectForId(objectId);
     114        if (!this._isDefined(object))
     115            return false;
     116        var properties = [];
     117       
     118        var propertyNames = ignoreHasOwnProperty ? this._getPropertyNames(object) : Object.getOwnPropertyNames(object);
     119        if (!ignoreHasOwnProperty && object.__proto__)
     120            propertyNames.push("__proto__");
     121   
     122        // Go over properties, prepare results.
     123        for (var i = 0; i < propertyNames.length; ++i) {
     124            var propertyName = propertyNames[i];
     125   
     126            var property = {};
     127            property.name = propertyName + "";
     128            var isGetter = object["__lookupGetter__"] && object.__lookupGetter__(propertyName);
     129            if (!isGetter) {
     130                try {
     131                    var childObject = object[propertyName];
     132                    var childObjectId = InjectedScript.RemoteObjectId.deriveProperty(objectId, propertyName);
     133                    var childObjectProxy = new InjectedScript.RemoteObject.fromObject(childObject, childObjectId, abbreviate);
     134                    property.value = childObjectProxy;
     135                } catch(e) {
     136                    property.value = new InjectedScript.RemoteObject.fromException(e);
     137                }
     138            } else {
     139                // FIXME: this should show something like "getter" (bug 16734).
     140                property.value = new InjectedScript.RemoteObject.fromObject("\u2014"); // em dash
     141                property.isGetter = true;
    138142            }
    139         } else {
    140             // FIXME: this should show something like "getter" (bug 16734).
    141             property.value = new InjectedScript.RemoteObject.fromObject("\u2014"); // em dash
    142             property.isGetter = true;
    143         }
    144         properties.push(property);
    145     }
    146     return properties;
    147 }
    148 
    149 InjectedScript.setPropertyValue = function(objectId, propertyName, expression)
    150 {
    151     var object = InjectedScript._objectForId(objectId);
    152     if (!InjectedScript._isDefined(object))
    153         return false;
    154 
    155     var expressionLength = expression.length;
    156     if (!expressionLength) {
    157         delete object[propertyName];
    158         return !(propertyName in object);
    159     }
    160 
    161     try {
    162         // Surround the expression in parenthesis so the result of the eval is the result
    163         // of the whole expression not the last potential sub-expression.
    164 
    165         // There is a regression introduced here: eval is now happening against global object,
    166         // not call frame while on a breakpoint.
    167         // TODO: bring evaluation against call frame back.
    168         var result = inspectedWindow.eval("(" + expression + ")");
    169         // Store the result in the property.
    170         object[propertyName] = result;
    171         return true;
    172     } catch(e) {
     143            properties.push(property);
     144        }
     145        return properties;
     146    },
     147
     148    setPropertyValue: function(objectId, propertyName, expression)
     149    {
     150        var object = this._objectForId(objectId);
     151        if (!this._isDefined(object))
     152            return false;
     153   
     154        var expressionLength = expression.length;
     155        if (!expressionLength) {
     156            delete object[propertyName];
     157            return !(propertyName in object);
     158        }
     159   
    173160        try {
    174             var result = inspectedWindow.eval("\"" + expression.replace(/"/g, "\\\"") + "\"");
     161            // Surround the expression in parenthesis so the result of the eval is the result
     162            // of the whole expression not the last potential sub-expression.
     163   
     164            // There is a regression introduced here: eval is now happening against global object,
     165            // not call frame while on a breakpoint.
     166            // TODO: bring evaluation against call frame back.
     167            var result = inspectedWindow.eval("(" + expression + ")");
     168            // Store the result in the property.
    175169            object[propertyName] = result;
    176170            return true;
    177171        } catch(e) {
     172            try {
     173                var result = inspectedWindow.eval("\"" + expression.replace(/"/g, "\\\"") + "\"");
     174                object[propertyName] = result;
     175                return true;
     176            } catch(e) {
     177                return false;
     178            }
     179        }
     180    },
     181
     182    _populatePropertyNames: function(object, resultSet)
     183    {
     184        for (var o = object; o; o = o.__proto__) {
     185            try {
     186                var names = Object.getOwnPropertyNames(o);
     187                for (var i = 0; i < names.length; ++i)
     188                    resultSet[names[i]] = true;
     189            } catch (e) {
     190            }
     191        }
     192    },
     193
     194    _getPropertyNames: function(object, resultSet)
     195    {
     196        var propertyNameSet = {};
     197        this._populatePropertyNames(object, propertyNameSet);
     198        return Object.keys(propertyNameSet);
     199    },
     200
     201    getCompletions: function(expression, includeInspectorCommandLineAPI, callFrameId)
     202    {
     203        var props = {};
     204        try {
     205            var expressionResult;
     206            // Evaluate on call frame if call frame id is available.
     207            if (typeof callFrameId === "number") {
     208                var callFrame = this._callFrameForId(callFrameId);
     209                if (!callFrame)
     210                    return props;
     211                if (expression)
     212                    expressionResult = this._evaluateOn(callFrame.evaluate, callFrame, expression, true);
     213                else {
     214                    // Evaluate into properties in scope of the selected call frame.
     215                    var scopeChain = callFrame.scopeChain;
     216                    for (var i = 0; i < scopeChain.length; ++i)
     217                        this._populatePropertyNames(scopeChain[i], props);
     218                }
     219            } else {
     220                if (!expression)
     221                    expression = "this";
     222                expressionResult = this._evaluateOn(inspectedWindow.eval, inspectedWindow, expression, false);
     223            }
     224            if (typeof expressionResult === "object")
     225                this._populatePropertyNames(expressionResult, props);
     226   
     227            if (includeInspectorCommandLineAPI) {
     228                for (var prop in this._commandLineAPI)
     229                    props[prop] = true;
     230            }
     231        } catch(e) {
     232        }
     233        return props;
     234    },
     235
     236    evaluate: function(expression, objectGroup)
     237    {
     238        return this._evaluateAndWrap(inspectedWindow.eval, inspectedWindow, expression, objectGroup);
     239    },
     240
     241    _evaluateAndWrap: function(evalFunction, object, expression, objectGroup, dontUseCommandLineAPI)
     242    {
     243        try {
     244            return this._wrapObject(this._evaluateOn(evalFunction, object, expression, dontUseCommandLineAPI), objectGroup);
     245        } catch (e) {
     246            return InjectedScript.RemoteObject.fromException(e);
     247        }
     248    },
     249
     250    _evaluateOn: function(evalFunction, object, expression, dontUseCommandLineAPI)
     251    {
     252        if (!dontUseCommandLineAPI) {
     253            // Only install command line api object for the time of evaluation.
     254   
     255            // Surround the expression in with statements to inject our command line API so that
     256            // the window object properties still take more precedent than our API functions.
     257            inspectedWindow.console._commandLineAPI = this._commandLineAPI;
     258   
     259            expression = "with (window.console._commandLineAPI) { with (window) {\n" + expression + "\n} }";
     260        }
     261   
     262        var value = evalFunction.call(object, expression);
     263   
     264        if (!dontUseCommandLineAPI)
     265            delete inspectedWindow.console._commandLineAPI;
     266   
     267        // When evaluating on call frame error is not thrown, but returned as a value.
     268        if (this._type(value) === "error")
     269            throw value.toString();
     270   
     271        return value;
     272    },
     273
     274    getNodeId: function(node)
     275    {
     276        return InjectedScriptHost.pushNodePathToFrontend(node, false, false);
     277    },
     278
     279    callFrames: function()
     280    {
     281        var callFrame = InjectedScriptHost.currentCallFrame();
     282        if (!callFrame)
    178283            return false;
    179         }
     284   
     285        var result = [];
     286        var depth = 0;
     287        do {
     288            result.push(new InjectedScript.CallFrameProxy(depth++, callFrame));
     289            callFrame = callFrame.caller;
     290        } while (callFrame);
     291        return result;
     292    },
     293
     294    evaluateInCallFrame: function(callFrameId, code, objectGroup)
     295    {
     296        var callFrame = this._callFrameForId(callFrameId);
     297        if (!callFrame)
     298            return false;
     299        return this._evaluateAndWrap(callFrame.evaluate, callFrame, code, objectGroup, true);
     300    },
     301
     302    _callFrameForId: function(id)
     303    {
     304        var callFrame = InjectedScriptHost.currentCallFrame();
     305        while (--id >= 0 && callFrame)
     306            callFrame = callFrame.caller;
     307        return callFrame;
     308    },
     309
     310    _nodeForId: function(nodeId)
     311    {
     312        if (!nodeId)
     313            return null;
     314        return InjectedScriptHost.nodeForId(nodeId);
     315    },
     316
     317    _objectForId: function(objectId)
     318    {
     319        // There are three types of object ids used:
     320        // - numbers point to DOM Node via the InspectorDOMAgent mapping
     321        // - strings point to console objects cached in InspectorController for lazy evaluation upon them
     322        // - objects contain complex ids and are currently used for scoped objects
     323        var object;
     324        if (objectId.type === InjectedScript.RemoteObjectId.Type.Node)
     325            object = this._nodeForId(objectId.value);
     326        else if (objectId.type === InjectedScript.RemoteObjectId.Type.JsObject)
     327            object = this._idToWrappedObject[objectId.value];
     328        else if (objectId.type === InjectedScript.RemoteObjectId.Type.ScopeObject) {
     329            var callFrame = this._callFrameForId(objectId.value.callFrame);
     330            if (objectId.thisObject)
     331                object = callFrame.thisObject;
     332            else
     333                object = callFrame.scopeChain[objectId.value.chainIndex];
     334        } else
     335            return objectId;
     336   
     337        var path = objectId.path;
     338   
     339        // Follow the property path.
     340        for (var i = 0; this._isDefined(object) && path && i < path.length; ++i)
     341            object = object[path[i]];
     342   
     343        return object;
     344    },
     345
     346    pushNodeToFrontend: function(objectId)
     347    {
     348        var object = this._objectForId(objectId);
     349        if (!object || this._type(object) !== "node")
     350            return false;
     351        return InjectedScriptHost.pushNodePathToFrontend(object, false, false);
     352    },
     353
     354    evaluateOnSelf: function(funcBody, args)
     355    {
     356        var func = window.eval("(" + funcBody + ")");
     357        return func.apply(this, args || []);
     358    },
     359
     360    _isDefined: function(object)
     361    {
     362        return object || this._isHTMLAllCollection(object);
     363    },
     364
     365    _isHTMLAllCollection: function(object)
     366    {
     367        // document.all is reported as undefined, but we still want to process it.
     368        return (typeof object === "undefined") && inspectedWindow.HTMLAllCollection && object instanceof inspectedWindow.HTMLAllCollection;
     369    },
     370
     371    _type: function(obj)
     372    {
     373        if (obj === null)
     374            return "null";
     375
     376        var type = typeof obj;
     377        if (type !== "object" && type !== "function") {
     378            // FIXME(33716): typeof document.all is always 'undefined'.
     379            if (this._isHTMLAllCollection(obj))
     380                return "array";
     381            return type;
     382        }
     383
     384        // If owning frame has navigated to somewhere else window properties will be undefined.
     385        // In this case just return result of the typeof.
     386        if (!inspectedWindow.document)
     387            return type;
     388
     389        if (obj instanceof inspectedWindow.Node)
     390            return (obj.nodeType === undefined ? type : "node");
     391        if (obj instanceof inspectedWindow.String)
     392            return "string";
     393        if (obj instanceof inspectedWindow.Array)
     394            return "array";
     395        if (obj instanceof inspectedWindow.Boolean)
     396            return "boolean";
     397        if (obj instanceof inspectedWindow.Number)
     398            return "number";
     399        if (obj instanceof inspectedWindow.Date)
     400            return "date";
     401        if (obj instanceof inspectedWindow.RegExp)
     402            return "regexp";
     403        // FireBug's array detection.
     404        if (isFinite(obj.length) && typeof obj.splice === "function")
     405            return "array";
     406        if (isFinite(obj.length) && typeof obj.callee === "function") // arguments.
     407            return "array";
     408        if (obj instanceof inspectedWindow.NodeList)
     409            return "array";
     410        if (obj instanceof inspectedWindow.HTMLCollection)
     411            return "array";
     412        if (obj instanceof inspectedWindow.Error)
     413            return "error";
     414        return type;
     415    },
     416
     417    _describe: function(obj, abbreviated)
     418    {
     419        var type = this._type(obj);
     420
     421        switch (type) {
     422        case "object":
     423        case "node":
     424        case "array":
     425            var className = this._className(obj);
     426            if (typeof obj.length === "number")
     427                className += "[" + obj.length + "]";
     428            return className;
     429        case "string":
     430            if (!abbreviated)
     431                return obj;
     432            if (obj.length > 100)
     433                return "\"" + obj.substring(0, 100) + "\u2026\"";
     434            return "\"" + obj + "\"";
     435        case "function":
     436            var objectText = this._toString(obj);
     437            if (abbreviated)
     438                objectText = /.*/.exec(objectText)[0].replace(/ +$/g, "");
     439            return objectText;
     440        default:
     441            return this._toString(obj);
     442        }
     443    },
     444
     445    _toString: function(obj)
     446    {
     447        // We don't use String(obj) because inspectedWindow.String is undefined if owning frame navigated to another page.
     448        return "" + obj;
     449    },
     450
     451    _className: function(obj)
     452    {
     453        // We can't use the same code for fetching class names of the dom bindings prototype chain.
     454        // Both of the methods below result in "Object" names on the foreign engine bindings.
     455        // I gave up and am using a check below to distinguish between the egine bingings.
     456
     457        if (jsEngine == "JSC") {
     458            var str = inspectedWindow.Object ? inspectedWindow.Object.prototype.toString.call(obj) : this._toString(obj);
     459            return str.replace(/^\[object (.*)\]$/i, "$1");
     460        } else {
     461            // V8
     462            return obj.constructor && obj.constructor.name || "Object";
     463        }
     464    },
     465
     466    _logEvent: function(event)
     467    {
     468        console.log(event.type, event);
     469    },
     470
     471    _normalizeEventTypes: function(types)
     472    {
     473        if (typeof types === "undefined")
     474            types = [ "mouse", "key", "load", "unload", "abort", "error", "select", "change", "submit", "reset", "focus", "blur", "resize", "scroll" ];
     475        else if (typeof types === "string")
     476            types = [ types ];
     477
     478        var result = [];
     479        for (var i = 0; i < types.length; i++) {
     480            if (types[i] === "mouse")
     481                result.splice(0, 0, "mousedown", "mouseup", "click", "dblclick", "mousemove", "mouseover", "mouseout");
     482            else if (types[i] === "key")
     483                result.splice(0, 0, "keydown", "keyup", "keypress");
     484            else
     485                result.push(types[i]);
     486        }
     487        return result;
     488    },
     489
     490    _inspectedNode: function(num)
     491    {
     492        var nodeId = InjectedScriptHost.inspectedNode(num);
     493        return this._nodeForId(nodeId);
     494    },
     495
     496    _bindToScript: function(func)
     497    {
     498        var args = Array.prototype.slice.call(arguments, 1);
     499        function bound()
     500        {
     501            return func.apply(injectedScript, args.concat(Array.prototype.slice.call(arguments)));
     502        }
     503        bound.toString = function() {
     504            return "bound: " + func;
     505        };
     506        return bound;
    180507    }
    181508}
    182509
    183 InjectedScript._populatePropertyNames = function(object, resultSet)
    184 {
    185     for (var o = object; o; o = o.__proto__) {
    186         try {
    187             var names = Object.getOwnPropertyNames(o);
    188             for (var i = 0; i < names.length; ++i)
    189                 resultSet[names[i]] = true;
    190         } catch (e) {
    191         }
    192     }
    193 }
    194 
    195 InjectedScript._getPropertyNames = function(object, resultSet)
    196 {
    197     var propertyNameSet = {};
    198     InjectedScript._populatePropertyNames(object, propertyNameSet);
    199     return Object.keys(propertyNameSet);
    200 }
    201 
    202 InjectedScript.getCompletions = function(expression, includeInspectorCommandLineAPI, callFrameId)
    203 {
    204     var props = {};
    205     try {
    206         var expressionResult;
    207         // Evaluate on call frame if call frame id is available.
    208         if (typeof callFrameId === "number") {
    209             var callFrame = InjectedScript._callFrameForId(callFrameId);
    210             if (!callFrame)
    211                 return props;
    212             if (expression)
    213                 expressionResult = InjectedScript._evaluateOn(callFrame.evaluate, callFrame, expression, true);
    214             else {
    215                 // Evaluate into properties in scope of the selected call frame.
    216                 var scopeChain = callFrame.scopeChain;
    217                 for (var i = 0; i < scopeChain.length; ++i)
    218                     InjectedScript._populatePropertyNames(scopeChain[i], props);
    219             }
    220         } else {
    221             if (!expression)
    222                 expression = "this";
    223             expressionResult = InjectedScript._evaluateOn(inspectedWindow.eval, inspectedWindow, expression, false);
    224         }
    225         if (typeof expressionResult === "object")
    226             InjectedScript._populatePropertyNames(expressionResult, props);
    227 
    228         if (includeInspectorCommandLineAPI) {
    229             for (var prop in InjectedScript._commandLineAPI)
    230                 props[prop] = true;
    231         }
    232     } catch(e) {
    233     }
    234     return props;
    235 }
    236 
    237 InjectedScript.evaluate = function(expression, objectGroup)
    238 {
    239     return InjectedScript._evaluateAndWrap(inspectedWindow.eval, inspectedWindow, expression, objectGroup);
    240 }
    241 
    242 InjectedScript._evaluateAndWrap = function(evalFunction, object, expression, objectGroup, dontUseCommandLineAPI)
    243 {
    244     try {
    245         return InjectedScript.wrapObject(InjectedScript._evaluateOn(evalFunction, object, expression, dontUseCommandLineAPI), objectGroup);
    246     } catch (e) {
    247         return InjectedScript.RemoteObject.fromException(e);
    248     }
    249 }
    250 
    251 InjectedScript._evaluateOn = function(evalFunction, object, expression, dontUseCommandLineAPI)
    252 {
    253     if (!dontUseCommandLineAPI) {
    254         // Only install command line api object for the time of evaluation.
    255 
    256         // Surround the expression in with statements to inject our command line API so that
    257         // the window object properties still take more precedent than our API functions.
    258         inspectedWindow.console._commandLineAPI = InjectedScript._commandLineAPI;
    259 
    260         expression = "with (window.console._commandLineAPI) { with (window) {\n" + expression + "\n} }";
    261     }
    262 
    263     var value = evalFunction.call(object, expression);
    264 
    265     if (!dontUseCommandLineAPI)
    266         delete inspectedWindow.console._commandLineAPI;
    267 
    268     // When evaluating on call frame error is not thrown, but returned as a value.
    269     if (InjectedScript._type(value) === "error")
    270         throw value.toString();
    271 
    272     return value;
    273 }
    274 
    275 InjectedScript.getNodeId = function(node)
    276 {
    277     return InjectedScriptHost.pushNodePathToFrontend(node, false, false);
    278 }
    279 
    280 InjectedScript.callFrames = function()
    281 {
    282     var callFrame = InjectedScriptHost.currentCallFrame();
    283     if (!callFrame)
    284         return false;
    285 
    286     var result = [];
    287     var depth = 0;
    288     do {
    289         result.push(new InjectedScript.CallFrameProxy(depth++, callFrame));
    290         callFrame = callFrame.caller;
    291     } while (callFrame);
    292     return result;
    293 }
    294 
    295 InjectedScript.evaluateInCallFrame = function(callFrameId, code, objectGroup)
    296 {
    297     var callFrame = InjectedScript._callFrameForId(callFrameId);
    298     if (!callFrame)
    299         return false;
    300     return InjectedScript._evaluateAndWrap(callFrame.evaluate, callFrame, code, objectGroup, true);
    301 }
    302 
    303 InjectedScript._callFrameForId = function(id)
    304 {
    305     var callFrame = InjectedScriptHost.currentCallFrame();
    306     while (--id >= 0 && callFrame)
    307         callFrame = callFrame.caller;
    308     return callFrame;
    309 }
    310 
    311 InjectedScript._nodeForId = function(nodeId)
    312 {
    313     if (!nodeId)
    314         return null;
    315     return InjectedScriptHost.nodeForId(nodeId);
    316 }
    317 
    318 InjectedScript._objectForId = function(objectId)
    319 {
    320     // There are three types of object ids used:
    321     // - numbers point to DOM Node via the InspectorDOMAgent mapping
    322     // - strings point to console objects cached in InspectorController for lazy evaluation upon them
    323     // - objects contain complex ids and are currently used for scoped objects
    324     var object;
    325     if (objectId.type === InjectedScript.RemoteObjectId.Type.Node)
    326         object = InjectedScript._nodeForId(objectId.value);
    327     else if (objectId.type === InjectedScript.RemoteObjectId.Type.JsObject)
    328         object = InjectedScript.unwrapObject(objectId.value);
    329     else if (objectId.type === InjectedScript.RemoteObjectId.Type.ScopeObject) {
    330         var callFrame = InjectedScript._callFrameForId(objectId.value.callFrame);
    331         if (objectId.thisObject)
    332             object = callFrame.thisObject;
    333         else
    334             object = callFrame.scopeChain[objectId.value.chainIndex];
    335     } else
    336         return objectId;
    337 
    338     var path = objectId.path;
    339 
    340     // Follow the property path.
    341     for (var i = 0; InjectedScript._isDefined(object) && path && i < path.length; ++i)
    342         object = object[path[i]];
    343 
    344     return object;
    345 }
    346 
    347 InjectedScript.pushNodeToFrontend = function(objectId)
    348 {
    349     var object = InjectedScript._objectForId(objectId);
    350     if (!object || InjectedScript._type(object) !== "node")
    351         return false;
    352     return InjectedScriptHost.pushNodePathToFrontend(object, false, false);
    353 }
     510var injectedScript = new InjectedScript();
    354511
    355512// FIXME: RemoteObjectId and RemoteObject structs must match the WebInspector.* ones. Should reuse same file instead.
     
    390547InjectedScript.RemoteObject.fromObject = function(object, objectId, abbreviate)
    391548{
    392     var type = InjectedScript._type(object);
     549    var type = injectedScript._type(object);
    393550    var rawType = typeof object;
    394551    var hasChildren = (rawType === "object" && object !== null && (Object.getOwnPropertyNames(object).length || !!object.__proto__)) || rawType === "function";
    395552    var description = "";
    396553    try {
    397         var description = InjectedScript._describe(object, abbreviate);
     554        var description = injectedScript._describe(object, abbreviate);
    398555        return new InjectedScript.RemoteObject(objectId, type, description, hasChildren);
    399556    } catch (e) {
    400557        return InjectedScript.RemoteObject.fromException(e);
    401558    }
    402 }
    403 
    404 InjectedScript.evaluateOnSelf = function(funcBody, args)
    405 {
    406     var func = window.eval("(" + funcBody + ")");
    407     return func.apply(this, args || []);
    408559}
    409560
     
    466617}
    467618
    468 InjectedScript._isDefined = function(object)
    469 {
    470     return object || InjectedScript._isHTMLAllCollection(object);
    471 }
    472 
    473 InjectedScript._isHTMLAllCollection = function(object)
    474 {
    475     // document.all is reported as undefined, but we still want to process it.
    476     return (typeof object === "undefined") && inspectedWindow.HTMLAllCollection && object instanceof inspectedWindow.HTMLAllCollection;
    477 }
    478 
    479 InjectedScript._type = function(obj)
    480 {
    481     if (obj === null)
    482         return "null";
    483 
    484     var type = typeof obj;
    485     if (type !== "object" && type !== "function") {
    486         // FIXME(33716): typeof document.all is always 'undefined'.
    487         if (InjectedScript._isHTMLAllCollection(obj))
    488             return "array";
    489         return type;
    490     }
    491 
    492     // If owning frame has navigated to somewhere else window properties will be undefined.
    493     // In this case just return result of the typeof.
    494     if (!inspectedWindow.document)
    495         return type;
    496 
    497     if (obj instanceof inspectedWindow.Node)
    498         return (obj.nodeType === undefined ? type : "node");
    499     if (obj instanceof inspectedWindow.String)
    500         return "string";
    501     if (obj instanceof inspectedWindow.Array)
    502         return "array";
    503     if (obj instanceof inspectedWindow.Boolean)
    504         return "boolean";
    505     if (obj instanceof inspectedWindow.Number)
    506         return "number";
    507     if (obj instanceof inspectedWindow.Date)
    508         return "date";
    509     if (obj instanceof inspectedWindow.RegExp)
    510         return "regexp";
    511     // FireBug's array detection.
    512     if (isFinite(obj.length) && typeof obj.splice === "function")
    513         return "array";
    514     if (isFinite(obj.length) && typeof obj.callee === "function") // arguments.
    515         return "array";
    516     if (obj instanceof inspectedWindow.NodeList)
    517         return "array";
    518     if (obj instanceof inspectedWindow.HTMLCollection)
    519         return "array";
    520     if (obj instanceof inspectedWindow.Error)
    521         return "error";
    522     return type;
    523 }
    524 
    525 InjectedScript._describe = function(obj, abbreviated)
    526 {
    527     var type = InjectedScript._type(obj);
    528 
    529     switch (type) {
    530     case "object":
    531     case "node":
    532     case "array":
    533         var className = InjectedScript._className(obj);
    534         if (typeof obj.length === "number")
    535             className += "[" + obj.length + "]";
    536         return className;
    537     case "string":
    538         if (!abbreviated)
    539             return obj;
    540         if (obj.length > 100)
    541             return "\"" + obj.substring(0, 100) + "\u2026\"";
    542         return "\"" + obj + "\"";
    543     case "function":
    544         var objectText = InjectedScript._toString(obj);
    545         if (abbreviated)
    546             objectText = /.*/.exec(objectText)[0].replace(/ +$/g, "");
    547         return objectText;
    548     default:
    549         return InjectedScript._toString(obj);
    550     }
    551 }
    552 
    553 InjectedScript._toString = function(obj)
    554 {
    555     // We don't use String(obj) because inspectedWindow.String is undefined if owning frame navigated to another page.
    556     return "" + obj;
    557 }
    558 
    559 InjectedScript._className = function(obj)
    560 {
    561     // We can't use the same code for fetching class names of the dom bindings prototype chain.
    562     // Both of the methods below result in "Object" names on the foreign engine bindings.
    563     // I gave up and am using a check below to distinguish between the egine bingings.
    564 
    565     if (jsEngine == "JSC") {
    566         var str = inspectedWindow.Object ? inspectedWindow.Object.prototype.toString.call(obj) : InjectedScript._toString(obj);
    567         return str.replace(/^\[object (.*)\]$/i, "$1");
    568     } else {
    569         // V8
    570         return obj.constructor && obj.constructor.name || "Object";
    571     }
    572 }
    573 
    574 InjectedScript._logEvent = function(event)
    575 {
    576     console.log(event.type, event);
    577 }
    578 
    579 InjectedScript._normalizeEventTypes = function(types)
    580 {
    581     if (typeof types === "undefined")
    582         types = [ "mouse", "key", "load", "unload", "abort", "error", "select", "change", "submit", "reset", "focus", "blur", "resize", "scroll" ];
    583     else if (typeof types === "string")
    584         types = [ types ];
    585 
    586     var result = [];
    587     for (var i = 0; i < types.length; i++) {
    588         if (types[i] === "mouse")
    589             result.splice(0, 0, "mousedown", "mouseup", "click", "dblclick", "mousemove", "mouseover", "mouseout");
    590         else if (types[i] === "key")
    591             result.splice(0, 0, "keydown", "keyup", "keypress");
    592         else
    593             result.push(types[i]);
    594     }
    595     return result;
    596 }
    597 
    598 InjectedScript._inspectedNode = function(num)
    599 {
    600     var nodeId = InjectedScriptHost.inspectedNode(num);
    601     return InjectedScript._nodeForId(nodeId);
    602 }
    603 
    604619function CommandLineAPI()
    605620{
     621    for (var i = 0; i < 5; ++i)
     622        this.__defineGetter__("$" + i, injectedScript._bindToScript(injectedScript._inspectedNode, i));
    606623}
    607624
     
    670687        if (!object || !object.addEventListener || !object.removeEventListener)
    671688            return;
    672         types = InjectedScript._normalizeEventTypes(types);
     689        types = injectedScript._normalizeEventTypes(types);
    673690        for (var i = 0; i < types.length; ++i) {
    674             object.removeEventListener(types[i], InjectedScript._logEvent, false);
    675             object.addEventListener(types[i], InjectedScript._logEvent, false);
     691            object.removeEventListener(types[i], injectedScript._logEvent, false);
     692            object.addEventListener(types[i], injectedScript._logEvent, false);
    676693        }
    677694    },
     
    681698        if (!object || !object.addEventListener || !object.removeEventListener)
    682699            return;
    683         types = InjectedScript._normalizeEventTypes(types);
     700        types = injectedScript._normalizeEventTypes(types);
    684701        for (var i = 0; i < types.length; ++i)
    685             object.removeEventListener(types[i], InjectedScript._logEvent, false);
     702            object.removeEventListener(types[i], injectedScript._logEvent, false);
    686703    },
    687704
     
    692709
    693710        inspectedWindow.console.log(object);
    694         if (InjectedScript._type(object) === "node")
     711        if (injectedScript._type(object) === "node")
    695712            InjectedScriptHost.pushNodePathToFrontend(object, false, true);
    696713        else {
    697             switch (InjectedScript._describe(object)) {
     714            switch (injectedScript._describe(object)) {
    698715                case "Database":
    699716                    InjectedScriptHost.selectDatabase(object);
     
    708725    copy: function(object)
    709726    {
    710         if (InjectedScript._type(object) === "node") {
     727        if (injectedScript._type(object) === "node") {
    711728            var nodeId = InjectedScriptHost.pushNodePathToFrontend(object, false, false);
    712729            InjectedScriptHost.copyNode(nodeId);
     
    718735    {
    719736        InjectedScriptHost.clearConsoleMessages();
    720     },
    721 
    722     get $0()
    723     {
    724         return InjectedScript._inspectedNode(0);
    725     },
    726 
    727     get $1()
    728     {
    729         return InjectedScript._inspectedNode(1);
    730     },
    731 
    732     get $2()
    733     {
    734         return InjectedScript._inspectedNode(2);
    735     },
    736 
    737     get $3()
    738     {
    739         return InjectedScript._inspectedNode(3);
    740     },
    741 
    742     get $4()
    743     {
    744         return InjectedScript._inspectedNode(4);
    745737    }
    746738}
    747739
    748 InjectedScript._commandLineAPI = new CommandLineAPI();
    749 
    750 return InjectedScript;
     740injectedScript._commandLineAPI = new CommandLineAPI();
     741return injectedScript;
    751742});
Note: See TracChangeset for help on using the changeset viewer.