491be2106c76af0e92d39c0a726c5510bc15508d
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / bindings / DebuggerWorkspaceBinding.js
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;