Home | History | Annotate | Download | only in bindings
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 /**
      6  * @constructor
      7  * @implements {WebInspector.TargetManager.Observer}
      8  * @param {!WebInspector.TargetManager} targetManager
      9  * @param {!WebInspector.Workspace} workspace
     10  * @param {!WebInspector.NetworkWorkspaceBinding} networkWorkspaceBinding
     11  */
     12 WebInspector.DebuggerWorkspaceBinding = function(targetManager, workspace, networkWorkspaceBinding)
     13 {
     14     this._workspace = workspace;
     15     this._networkWorkspaceBinding = networkWorkspaceBinding;
     16 
     17     /** @type {!Map.<!WebInspector.Target, !WebInspector.DebuggerWorkspaceBinding.TargetData>} */
     18     this._targetToData = new Map();
     19     targetManager.observeTargets(this);
     20 
     21     targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.GlobalObjectCleared, this._globalObjectCleared, this);
     22     targetManager.addModelListener(WebInspector.DebuggerModel, WebInspector.DebuggerModel.Events.DebuggerResumed, this._debuggerResumed, this);
     23     workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeRemoved, this._uiSourceCodeRemoved, this);
     24     workspace.addEventListener(WebInspector.Workspace.Events.ProjectRemoved, this._projectRemoved, this);
     25 }
     26 
     27 WebInspector.DebuggerWorkspaceBinding.prototype = {
     28     /**
     29      * @param {!WebInspector.Target} target
     30      */
     31     targetAdded: function(target)
     32     {
     33         this._targetToData.set(target, new WebInspector.DebuggerWorkspaceBinding.TargetData(target, this));
     34     },
     35 
     36     /**
     37      * @param {!WebInspector.Target} target
     38      */
     39     targetRemoved: function(target)
     40     {
     41         var targetData = this._targetToData.get(target);
     42         targetData._dispose();
     43         this._targetToData.remove(target);
     44     },
     45 
     46     /**
     47      * @param {!WebInspector.Event} event
     48      */
     49     _uiSourceCodeRemoved: function(event)
     50     {
     51         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
     52         var targetDatas = this._targetToData.values();
     53         for (var i = 0; i < targetDatas.length; ++i)
     54             targetDatas[i]._uiSourceCodeRemoved(uiSourceCode);
     55     },
     56 
     57     /**
     58      * @param {!WebInspector.Event} event
     59      */
     60     _projectRemoved: function(event)
     61     {
     62         var project = /** @type {!WebInspector.Project} */ (event.data);
     63         var targetDatas = this._targetToData.values();
     64         var uiSourceCodes = project.uiSourceCodes();
     65         for (var i = 0; i < targetDatas.length; ++i) {
     66             for (var j = 0; j < uiSourceCodes.length; ++j)
     67                 targetDatas[i]._uiSourceCodeRemoved(uiSourceCodes[j]);
     68         }
     69     },
     70 
     71     /**
     72      * @param {!WebInspector.Script} script
     73      * @param {!WebInspector.DebuggerSourceMapping} sourceMapping
     74      */
     75     pushSourceMapping: function(script, sourceMapping)
     76     {
     77         var info = this._ensureInfoForScript(script);
     78         info._pushSourceMapping(sourceMapping);
     79     },
     80 
     81     /**
     82      * @param {!WebInspector.Script} script
     83      * @return {!WebInspector.DebuggerSourceMapping}
     84      */
     85     popSourceMapping: function(script)
     86     {
     87         var info = this._infoForScript(script.target(), script.scriptId);
     88         console.assert(info);
     89         return info._popSourceMapping();
     90     },
     91 
     92     /**
     93      * @param {!WebInspector.Target} target
     94      * @param {!WebInspector.UISourceCode} uiSourceCode
     95      * @param {?WebInspector.DebuggerSourceMapping} sourceMapping
     96      */
     97     setSourceMapping: function(target, uiSourceCode, sourceMapping)
     98     {
     99         var data = this._targetToData.get(target);
    100         if (data)
    101             data._setSourceMapping(uiSourceCode, sourceMapping);
    102     },
    103 
    104     /**
    105      * @param {!WebInspector.Script} script
    106      */
    107     updateLocations: function(script)
    108     {
    109         var info = this._infoForScript(script.target(), script.scriptId);
    110         if (info)
    111             info._updateLocations();
    112     },
    113 
    114     /**
    115      * @param {!WebInspector.DebuggerModel.Location} rawLocation
    116      * @param {function(!WebInspector.UILocation):(boolean|undefined)} updateDelegate
    117      * @return {!WebInspector.DebuggerWorkspaceBinding.Location}
    118      */
    119     createLiveLocation: function(rawLocation, updateDelegate)
    120     {
    121         var info = this._infoForScript(rawLocation.target(), rawLocation.scriptId);
    122         console.assert(info);
    123         var location = new WebInspector.DebuggerWorkspaceBinding.Location(info._script, rawLocation, this, updateDelegate);
    124         info._addLocation(location);
    125         return location;
    126     },
    127 
    128     /**
    129      * @param {!WebInspector.DebuggerModel.CallFrame} callFrame
    130      * @param {function(!WebInspector.UILocation):(boolean|undefined)} updateDelegate
    131      * @return {!WebInspector.DebuggerWorkspaceBinding.Location}
    132      */
    133     createCallFrameLiveLocation: function(callFrame, updateDelegate)
    134     {
    135         var target = callFrame.target();
    136         this._ensureInfoForScript(callFrame.script)
    137         var location = this.createLiveLocation(callFrame.location(), updateDelegate);
    138         this._registerCallFrameLiveLocation(target, location);
    139         return location;
    140     },
    141 
    142     /**
    143      * @param {!WebInspector.DebuggerModel.Location} rawLocation
    144      * @return {!WebInspector.UILocation}
    145      */
    146     rawLocationToUILocation: function(rawLocation)
    147     {
    148         var info = this._infoForScript(rawLocation.target(), rawLocation.scriptId);
    149         console.assert(info);
    150         return info._rawLocationToUILocation(rawLocation);
    151     },
    152 
    153     /**
    154      * @param {!WebInspector.Target} target
    155      * @param {!WebInspector.UISourceCode} uiSourceCode
    156      * @param {number} lineNumber
    157      * @param {number} columnNumber
    158      * @return {?WebInspector.DebuggerModel.Location}
    159      */
    160     uiLocationToRawLocation: function(target, uiSourceCode, lineNumber, columnNumber)
    161     {
    162         var targetData = this._targetToData.get(target);
    163         return targetData ? /** @type {?WebInspector.DebuggerModel.Location} */ (targetData._uiLocationToRawLocation(uiSourceCode, lineNumber, columnNumber)) : null;
    164     },
    165 
    166     /**
    167      * @param {!WebInspector.UISourceCode} uiSourceCode
    168      * @param {number} lineNumber
    169      * @param {number} columnNumber
    170      * @return {!Array.<!WebInspector.DebuggerModel.Location>}
    171      */
    172     uiLocationToRawLocations: function(uiSourceCode, lineNumber, columnNumber)
    173     {
    174         var result = [];
    175         var targetDatas = this._targetToData.values();
    176         for (var i = 0; i < targetDatas.length; ++i) {
    177             var rawLocation = targetDatas[i]._uiLocationToRawLocation(uiSourceCode, lineNumber, columnNumber);
    178             if (rawLocation)
    179                 result.push(rawLocation);
    180         }
    181         return result;
    182     },
    183 
    184     /**
    185      * @param {!WebInspector.UISourceCode} uiSourceCode
    186      * @param {number} lineNumber
    187      * @return {boolean}
    188      */
    189     uiLineHasMapping: function(uiSourceCode, lineNumber)
    190     {
    191         var targetDatas = this._targetToData.values();
    192         for (var i = 0; i < targetDatas.length; ++i) {
    193             if (!targetDatas[i]._uiLineHasMapping(uiSourceCode, lineNumber))
    194                 return false;
    195         }
    196         return true;
    197     },
    198 
    199     /**
    200      * @param {!WebInspector.Target} target
    201      * @return {?WebInspector.LiveEditSupport}
    202      */
    203     liveEditSupport: function(target)
    204     {
    205         var targetData = this._targetToData.get(target);
    206         return targetData ? targetData._liveEditSupport : null;
    207     },
    208 
    209     /**
    210      * @param {!WebInspector.UISourceCode} uiSourceCode
    211      * @param {!WebInspector.Target} target
    212      * @return {?WebInspector.ResourceScriptFile}
    213      */
    214     scriptFile: function(uiSourceCode, target)
    215     {
    216         var targetData = this._targetToData.get(target);
    217         return targetData ? targetData._resourceMapping.scriptFile(uiSourceCode) : null;
    218     },
    219 
    220     /**
    221      * @param {!WebInspector.Event} event
    222      */
    223     _globalObjectCleared: function(event)
    224     {
    225         var debuggerModel = /** @type {!WebInspector.DebuggerModel} */ (event.target);
    226         this._reset(debuggerModel.target());
    227     },
    228 
    229     /**
    230      * @param {!WebInspector.Target} target
    231      */
    232     _reset: function(target)
    233     {
    234         var targetData = this._targetToData.get(target);
    235         targetData.callFrameLocations.values().forEach(function(location) { location.dispose(); });
    236         targetData.callFrameLocations.clear();
    237     },
    238 
    239     /**
    240      * @param {!WebInspector.Script} script
    241      * @return {!WebInspector.DebuggerWorkspaceBinding.ScriptInfo}
    242      */
    243     _ensureInfoForScript: function(script)
    244     {
    245         var scriptDataMap = this._targetToData.get(script.target()).scriptDataMap;
    246         var info = scriptDataMap.get(script.scriptId);
    247         if (!info) {
    248             info = new WebInspector.DebuggerWorkspaceBinding.ScriptInfo(script);
    249             scriptDataMap.set(script.scriptId, info);
    250         }
    251         return info;
    252     },
    253 
    254 
    255     /**
    256      * @param {!WebInspector.Target} target
    257      * @param {string} scriptId
    258      * @return {?WebInspector.DebuggerWorkspaceBinding.ScriptInfo}
    259      */
    260     _infoForScript: function(target, scriptId)
    261     {
    262         var data = this._targetToData.get(target);
    263         if (!data)
    264             return null;
    265         return data.scriptDataMap.get(scriptId) || null;
    266     },
    267 
    268     /**
    269      * @param {!WebInspector.Target} target
    270      * @param {!WebInspector.DebuggerWorkspaceBinding.Location} location
    271      */
    272     _registerCallFrameLiveLocation: function(target, location)
    273     {
    274         var locations = this._targetToData.get(target).callFrameLocations;
    275         locations.add(location);
    276     },
    277 
    278     /**
    279      * @param {!WebInspector.DebuggerWorkspaceBinding.Location} location
    280      */
    281     _removeLiveLocation: function(location)
    282     {
    283         var info = this._infoForScript(location._script.target(), location._script.scriptId);
    284         if (info)
    285             info._removeLocation(location);
    286     },
    287 
    288     /**
    289      * @param {!WebInspector.Event} event
    290      */
    291     _debuggerResumed: function(event)
    292     {
    293         var debuggerModel = /** @type {!WebInspector.DebuggerModel} */ (event.target);
    294         this._reset(debuggerModel.target());
    295     }
    296 }
    297 
    298 /**
    299  * @constructor
    300  * @param {!WebInspector.Target} target
    301  * @param {!WebInspector.DebuggerWorkspaceBinding} debuggerWorkspaceBinding
    302  */
    303 WebInspector.DebuggerWorkspaceBinding.TargetData = function(target, debuggerWorkspaceBinding)
    304 {
    305     this._target = target;
    306 
    307     /** @type {!StringMap.<!WebInspector.DebuggerWorkspaceBinding.ScriptInfo>} */
    308     this.scriptDataMap = new StringMap();
    309 
    310     /** @type {!Set.<!WebInspector.DebuggerWorkspaceBinding.Location>} */
    311     this.callFrameLocations = new Set();
    312 
    313     var debuggerModel = target.debuggerModel;
    314     var workspace = debuggerWorkspaceBinding._workspace;
    315 
    316     this._liveEditSupport = new WebInspector.LiveEditSupport(target, workspace, debuggerWorkspaceBinding);
    317     this._defaultMapping = new WebInspector.DefaultScriptMapping(debuggerModel, workspace, debuggerWorkspaceBinding);
    318     this._resourceMapping = new WebInspector.ResourceScriptMapping(debuggerModel, workspace, debuggerWorkspaceBinding);
    319     this._compilerMapping = new WebInspector.CompilerScriptMapping(debuggerModel, workspace, debuggerWorkspaceBinding._networkWorkspaceBinding, debuggerWorkspaceBinding);
    320 
    321     /** @type {!WebInspector.LiveEditSupport} */
    322     this._liveEditSupport = new WebInspector.LiveEditSupport(target, workspace, debuggerWorkspaceBinding);
    323 
    324     /** @type {!Map.<!WebInspector.UISourceCode, !WebInspector.DebuggerSourceMapping>} */
    325     this._uiSourceCodeToSourceMapping = new Map();
    326 
    327     debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.ParsedScriptSource, this._parsedScriptSource, this);
    328     debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.FailedToParseScriptSource, this._parsedScriptSource, this);
    329 }
    330 
    331 WebInspector.DebuggerWorkspaceBinding.TargetData.prototype = {
    332     /**
    333      * @param {!WebInspector.Event} event
    334      */
    335     _parsedScriptSource: function(event)
    336     {
    337         var script = /** @type {!WebInspector.Script} */ (event.data);
    338         this._defaultMapping.addScript(script);
    339 
    340         if (script.isSnippet()) {
    341             WebInspector.scriptSnippetModel.addScript(script);
    342             return;
    343         }
    344 
    345         this._resourceMapping.addScript(script);
    346 
    347         if (WebInspector.settings.jsSourceMapsEnabled.get())
    348             this._compilerMapping.addScript(script);
    349     },
    350 
    351     /**
    352      * @param {!WebInspector.UISourceCode} uiSourceCode
    353      * @param {?WebInspector.DebuggerSourceMapping} sourceMapping
    354      */
    355     _setSourceMapping: function(uiSourceCode, sourceMapping)
    356     {
    357         if (this._uiSourceCodeToSourceMapping.get(uiSourceCode) === sourceMapping)
    358             return;
    359 
    360         if (sourceMapping)
    361             this._uiSourceCodeToSourceMapping.set(uiSourceCode, sourceMapping);
    362         else
    363             this._uiSourceCodeToSourceMapping.remove(uiSourceCode);
    364 
    365         uiSourceCode.dispatchEventToListeners(WebInspector.UISourceCode.Events.SourceMappingChanged, {target: this._target, isIdentity: sourceMapping ? sourceMapping.isIdentity() : false});
    366     },
    367 
    368     /**
    369      * @param {!WebInspector.UISourceCode} uiSourceCode
    370      * @param {number} lineNumber
    371      * @param {number} columnNumber
    372      * @return {?WebInspector.DebuggerModel.Location}
    373      */
    374     _uiLocationToRawLocation: function(uiSourceCode, lineNumber, columnNumber)
    375     {
    376         var sourceMapping = this._uiSourceCodeToSourceMapping.get(uiSourceCode);
    377         return sourceMapping ? sourceMapping.uiLocationToRawLocation(uiSourceCode, lineNumber, columnNumber) : null;
    378     },
    379 
    380     /**
    381      * @param {!WebInspector.UISourceCode} uiSourceCode
    382      * @param {number} lineNumber
    383      * @return {boolean}
    384      */
    385     _uiLineHasMapping: function(uiSourceCode, lineNumber)
    386     {
    387         var sourceMapping = this._uiSourceCodeToSourceMapping.get(uiSourceCode);
    388         return sourceMapping ? sourceMapping.uiLineHasMapping(uiSourceCode, lineNumber) : true;
    389     },
    390 
    391     /**
    392      * @param {!WebInspector.UISourceCode} uiSourceCode
    393      */
    394     _uiSourceCodeRemoved: function(uiSourceCode)
    395     {
    396         this._uiSourceCodeToSourceMapping.remove(uiSourceCode);
    397     },
    398 
    399     _dispose: function()
    400     {
    401         this._compilerMapping.dispose();
    402         this._resourceMapping.dispose();
    403         this._defaultMapping.dispose();
    404         this._uiSourceCodeToSourceMapping.clear();
    405     }
    406 }
    407 
    408 /**
    409  * @constructor
    410  * @param {!WebInspector.Script} script
    411  */
    412 WebInspector.DebuggerWorkspaceBinding.ScriptInfo = function(script)
    413 {
    414     this._script = script;
    415 
    416     /** @type {!Array.<!WebInspector.DebuggerSourceMapping>} */
    417     this._sourceMappings = [];
    418 
    419     /** @type {!Set.<!WebInspector.LiveLocation>} */
    420     this._locations = new Set();
    421 }
    422 
    423 WebInspector.DebuggerWorkspaceBinding.ScriptInfo.prototype = {
    424     /**
    425      * @param {!WebInspector.DebuggerSourceMapping} sourceMapping
    426      */
    427     _pushSourceMapping: function(sourceMapping)
    428     {
    429         this._sourceMappings.push(sourceMapping);
    430         this._updateLocations();
    431     },
    432 
    433     /**
    434      * @return {!WebInspector.DebuggerSourceMapping}
    435      */
    436     _popSourceMapping: function()
    437     {
    438         var sourceMapping = this._sourceMappings.pop();
    439         this._updateLocations();
    440         return sourceMapping;
    441     },
    442 
    443     /**
    444      * @param {!WebInspector.LiveLocation} location
    445      */
    446     _addLocation: function(location)
    447     {
    448         this._locations.add(location);
    449         location.update();
    450     },
    451 
    452     /**
    453      * @param {!WebInspector.LiveLocation} location
    454      */
    455     _removeLocation: function(location)
    456     {
    457         this._locations.remove(location);
    458     },
    459 
    460     _updateLocations: function()
    461     {
    462         var items = this._locations.values();
    463         for (var i = 0; i < items.length; ++i)
    464             items[i].update();
    465     },
    466 
    467     /**
    468      * @param {!WebInspector.DebuggerModel.Location} rawLocation
    469      * @return {!WebInspector.UILocation}
    470      */
    471     _rawLocationToUILocation: function(rawLocation)
    472     {
    473         var uiLocation;
    474         for (var i = this._sourceMappings.length - 1; !uiLocation && i >= 0; --i)
    475             uiLocation = this._sourceMappings[i].rawLocationToUILocation(rawLocation);
    476         console.assert(uiLocation, "Script raw location cannot be mapped to any UI location.");
    477         return /** @type {!WebInspector.UILocation} */ (uiLocation);
    478     }
    479 }
    480 
    481 
    482 /**
    483  * @constructor
    484  * @extends {WebInspector.LiveLocation}
    485  * @param {!WebInspector.Script} script
    486  * @param {!WebInspector.DebuggerModel.Location} rawLocation
    487  * @param {!WebInspector.DebuggerWorkspaceBinding} binding
    488  * @param {function(!WebInspector.UILocation):(boolean|undefined)} updateDelegate
    489  */
    490 WebInspector.DebuggerWorkspaceBinding.Location = function(script, rawLocation, binding, updateDelegate)
    491 {
    492     WebInspector.LiveLocation.call(this, updateDelegate);
    493     this._script = script;
    494     this._rawLocation = rawLocation;
    495     this._binding = binding;
    496 }
    497 
    498 WebInspector.DebuggerWorkspaceBinding.Location.prototype = {
    499     /**
    500      * @return {!WebInspector.UILocation}
    501      */
    502     uiLocation: function()
    503     {
    504         var debuggerModelLocation = this._rawLocation;
    505         return this._binding.rawLocationToUILocation(debuggerModelLocation);
    506     },
    507 
    508     dispose: function()
    509     {
    510         WebInspector.LiveLocation.prototype.dispose.call(this);
    511         this._binding._removeLiveLocation(this);
    512     },
    513 
    514     __proto__: WebInspector.LiveLocation.prototype
    515 }
    516 
    517 /**
    518  * @interface
    519  */
    520 WebInspector.DebuggerSourceMapping = function()
    521 {
    522 }
    523 
    524 WebInspector.DebuggerSourceMapping.prototype = {
    525     /**
    526      * @param {!WebInspector.DebuggerModel.Location} rawLocation
    527      * @return {?WebInspector.UILocation}
    528      */
    529     rawLocationToUILocation: function(rawLocation) { },
    530 
    531     /**
    532      * @param {!WebInspector.UISourceCode} uiSourceCode
    533      * @param {number} lineNumber
    534      * @param {number} columnNumber
    535      * @return {?WebInspector.DebuggerModel.Location}
    536      */
    537     uiLocationToRawLocation: function(uiSourceCode, lineNumber, columnNumber) { },
    538 
    539     /**
    540      * @return {boolean}
    541      */
    542     isIdentity: function() { },
    543 
    544     /**
    545      * @param {!WebInspector.UISourceCode} uiSourceCode
    546      * @param {number} lineNumber
    547      * @return {boolean}
    548      */
    549     uiLineHasMapping: function(uiSourceCode, lineNumber) { }
    550 }
    551 
    552 /**
    553  * @type {!WebInspector.DebuggerWorkspaceBinding}
    554  */
    555 WebInspector.debuggerWorkspaceBinding;
    556