Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / bindings / ResourceScriptMapping.js
1 /*
2  * Copyright (C) 2012 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 /**
32  * @constructor
33  * @implements {WebInspector.DebuggerSourceMapping}
34  * @param {!WebInspector.DebuggerModel} debuggerModel
35  * @param {!WebInspector.Workspace} workspace
36  * @param {!WebInspector.DebuggerWorkspaceBinding} debuggerWorkspaceBinding
37  */
38 WebInspector.ResourceScriptMapping = function(debuggerModel, workspace, debuggerWorkspaceBinding)
39 {
40     this._target = debuggerModel.target();
41     this._debuggerModel = debuggerModel;
42     this._workspace = workspace;
43     this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAdded, this);
44     this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeRemoved, this._uiSourceCodeRemoved, this);
45     this._debuggerWorkspaceBinding = debuggerWorkspaceBinding;
46     /** @type {!Set.<string>} */
47     this._boundURLs = new Set();
48
49     /** @type {!Map.<!WebInspector.UISourceCode, !WebInspector.ResourceScriptFile>} */
50     this._uiSourceCodeToScriptFile = new Map();
51
52     debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, this._debuggerReset, this);
53 }
54
55 WebInspector.ResourceScriptMapping.prototype = {
56     /**
57      * @param {!WebInspector.DebuggerModel.Location} rawLocation
58      * @return {?WebInspector.UILocation}
59      */
60     rawLocationToUILocation: function(rawLocation)
61     {
62         var debuggerModelLocation = /** @type {!WebInspector.DebuggerModel.Location} */ (rawLocation);
63         var script = debuggerModelLocation.script();
64         var uiSourceCode = this._workspaceUISourceCodeForScript(script);
65         if (!uiSourceCode)
66             return null;
67         var scriptFile = this.scriptFile(uiSourceCode);
68         if (scriptFile && ((scriptFile.hasDivergedFromVM() && !scriptFile.isMergingToVM()) || scriptFile.isDivergingFromVM()))
69             return null;
70         var lineNumber = debuggerModelLocation.lineNumber - (script.isInlineScriptWithSourceURL() ? script.lineOffset : 0);
71         var columnNumber = debuggerModelLocation.columnNumber || 0;
72         if (script.isInlineScriptWithSourceURL() && !lineNumber && columnNumber)
73             columnNumber -= script.columnOffset;
74         return uiSourceCode.uiLocation(lineNumber, columnNumber);
75     },
76
77     /**
78      * @param {!WebInspector.UISourceCode} uiSourceCode
79      * @param {number} lineNumber
80      * @param {number} columnNumber
81      * @return {?WebInspector.DebuggerModel.Location}
82      */
83     uiLocationToRawLocation: function(uiSourceCode, lineNumber, columnNumber)
84     {
85         var scripts = this._scriptsForUISourceCode(uiSourceCode);
86         console.assert(scripts.length);
87         var script = scripts[0];
88         if (script.isInlineScriptWithSourceURL())
89             return this._debuggerModel.createRawLocation(script, lineNumber + script.lineOffset, lineNumber ? columnNumber : columnNumber + script.columnOffset);
90         return this._debuggerModel.createRawLocation(script, lineNumber, columnNumber);
91     },
92
93     /**
94      * @param {!WebInspector.Script} script
95      */
96     addScript: function(script)
97     {
98         if (script.isAnonymousScript())
99             return;
100         this._debuggerWorkspaceBinding.pushSourceMapping(script, this);
101
102         var uiSourceCode = this._workspaceUISourceCodeForScript(script);
103         if (!uiSourceCode)
104             return;
105
106         this._bindUISourceCodeToScripts(uiSourceCode, [script]);
107     },
108
109     /**
110      * @return {boolean}
111      */
112     isIdentity: function()
113     {
114         return true;
115     },
116
117     /**
118      * @param {!WebInspector.UISourceCode} uiSourceCode
119      * @param {number} lineNumber
120      * @return {boolean}
121      */
122     uiLineHasMapping: function(uiSourceCode, lineNumber)
123     {
124         return true;
125     },
126
127     /**
128      * @param {!WebInspector.UISourceCode} uiSourceCode
129      * @return {?WebInspector.ResourceScriptFile}
130      */
131     scriptFile: function(uiSourceCode)
132     {
133         return this._uiSourceCodeToScriptFile.get(uiSourceCode) || null;
134     },
135
136     /**
137      * @param {!WebInspector.UISourceCode} uiSourceCode
138      * @param {?WebInspector.ResourceScriptFile} scriptFile
139      */
140     _setScriptFile: function(uiSourceCode, scriptFile)
141     {
142         if (scriptFile)
143             this._uiSourceCodeToScriptFile.set(uiSourceCode, scriptFile);
144         else
145             this._uiSourceCodeToScriptFile.remove(uiSourceCode);
146     },
147
148     /**
149      * @param {!WebInspector.Event} event
150      */
151     _uiSourceCodeAdded: function(event)
152     {
153         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
154         if (!uiSourceCode.url)
155             return;
156         if (uiSourceCode.project().isServiceProject())
157             return;
158
159         var scripts = this._scriptsForUISourceCode(uiSourceCode);
160         if (!scripts.length)
161             return;
162
163         this._bindUISourceCodeToScripts(uiSourceCode, scripts);
164     },
165
166     /**
167      * @param {!WebInspector.Event} event
168      */
169     _uiSourceCodeRemoved: function(event)
170     {
171         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
172         if (!uiSourceCode.url)
173             return;
174         if (uiSourceCode.project().isServiceProject())
175             return;
176
177         this._unbindUISourceCode(uiSourceCode);
178     },
179
180     /**
181      * @param {!WebInspector.UISourceCode} uiSourceCode
182      */
183     _hasMergedToVM: function(uiSourceCode)
184     {
185         var scripts = this._scriptsForUISourceCode(uiSourceCode);
186         if (!scripts.length)
187             return;
188         for (var i = 0; i < scripts.length; ++i)
189             this._debuggerWorkspaceBinding.updateLocations(scripts[i]);
190     },
191
192     /**
193      * @param {!WebInspector.UISourceCode} uiSourceCode
194      */
195     _hasDivergedFromVM: function(uiSourceCode)
196     {
197         var scripts = this._scriptsForUISourceCode(uiSourceCode);
198         if (!scripts.length)
199             return;
200         for (var i = 0; i < scripts.length; ++i)
201             this._debuggerWorkspaceBinding.updateLocations(scripts[i]);
202     },
203
204     /**
205      * @param {!WebInspector.Script} script
206      * @return {?WebInspector.UISourceCode}
207      */
208     _workspaceUISourceCodeForScript: function(script)
209     {
210         if (script.isAnonymousScript())
211             return null;
212         return this._workspace.uiSourceCodeForURL(script.sourceURL);
213     },
214
215     /**
216      * @param {!WebInspector.UISourceCode} uiSourceCode
217      * @return {!Array.<!WebInspector.Script>}
218      */
219     _scriptsForUISourceCode: function(uiSourceCode)
220     {
221         if (!uiSourceCode.url)
222             return [];
223         return this._debuggerModel.scriptsForSourceURL(uiSourceCode.url);
224     },
225
226     /**
227      * @param {!WebInspector.UISourceCode} uiSourceCode
228      * @param {!Array.<!WebInspector.Script>} scripts
229      */
230     _bindUISourceCodeToScripts: function(uiSourceCode, scripts)
231     {
232         console.assert(scripts.length);
233         var scriptFile = new WebInspector.ResourceScriptFile(this, uiSourceCode, scripts);
234         this._setScriptFile(uiSourceCode, scriptFile);
235         for (var i = 0; i < scripts.length; ++i)
236             this._debuggerWorkspaceBinding.updateLocations(scripts[i]);
237         this._debuggerWorkspaceBinding.setSourceMapping(this._target, uiSourceCode, this);
238         this._boundURLs.add(uiSourceCode.url);
239     },
240
241     /**
242      * @param {!WebInspector.UISourceCode} uiSourceCode
243      */
244     _unbindUISourceCode: function(uiSourceCode)
245     {
246         var scriptFile = this.scriptFile(uiSourceCode);
247         if (scriptFile) {
248             scriptFile.dispose();
249             this._setScriptFile(uiSourceCode, null);
250         }
251         this._debuggerWorkspaceBinding.setSourceMapping(this._target, uiSourceCode, null);
252     },
253
254     _debuggerReset: function()
255     {
256         var boundURLs = this._boundURLs.valuesArray();
257         for (var i = 0; i < boundURLs.length; ++i)
258         {
259             var uiSourceCode = this._workspace.uiSourceCodeForURL(boundURLs[i]);
260             if (!uiSourceCode)
261                 continue;
262             this._unbindUISourceCode(uiSourceCode);
263         }
264         this._boundURLs.clear();
265     },
266
267     dispose: function()
268     {
269         this._debuggerReset();
270         this._workspace.removeEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAdded, this);
271         this._workspace.removeEventListener(WebInspector.Workspace.Events.UISourceCodeRemoved, this._uiSourceCodeRemoved, this);
272     }
273
274 }
275
276 /**
277  * @constructor
278  * @extends {WebInspector.Object}
279  * @param {!WebInspector.ResourceScriptMapping} resourceScriptMapping
280  * @param {!WebInspector.UISourceCode} uiSourceCode
281  * @param {!Array.<!WebInspector.Script>} scripts
282  */
283 WebInspector.ResourceScriptFile = function(resourceScriptMapping, uiSourceCode, scripts)
284 {
285     console.assert(scripts.length);
286
287     this._resourceScriptMapping = resourceScriptMapping;
288     this._uiSourceCode = uiSourceCode;
289
290     if (this._uiSourceCode.contentType() === WebInspector.resourceTypes.Script)
291         this._script = scripts[0];
292
293     this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._workingCopyChanged, this);
294     this._update();
295 }
296
297 WebInspector.ResourceScriptFile.Events = {
298     DidMergeToVM: "DidMergeToVM",
299     DidDivergeFromVM: "DidDivergeFromVM",
300 }
301
302 WebInspector.ResourceScriptFile.prototype = {
303     /**
304      * @param {function(?string,!DebuggerAgent.SetScriptSourceError=,!WebInspector.Script=)=} callback
305      */
306     commitLiveEdit: function(callback)
307     {
308         var target = this._resourceScriptMapping._target;
309         /**
310          * @param {?string} error
311          * @param {!DebuggerAgent.SetScriptSourceError=} errorData
312          * @this {WebInspector.ResourceScriptFile}
313          */
314         function innerCallback(error, errorData)
315         {
316             if (!error)
317                 this._scriptSource = source;
318             this._update();
319             if (callback)
320                 callback(error, errorData, this._script);
321         }
322         if (!this._script)
323             return;
324         var source = this._uiSourceCode.workingCopy();
325         target.debuggerModel.setScriptSource(this._script.scriptId, source, innerCallback.bind(this));
326     },
327
328     /**
329      * @return {boolean}
330      */
331     _isDiverged: function()
332     {
333         if (this._uiSourceCode.isDirty())
334             return true;
335         if (!this._script)
336             return false;
337         if (typeof this._scriptSource === "undefined")
338             return false;
339         if (!this._uiSourceCode.workingCopy().startsWith(this._scriptSource))
340             return true;
341         var suffix = this._uiSourceCode.workingCopy().substr(this._scriptSource.length);
342         return !!suffix.length && !suffix.match(WebInspector.Script.sourceURLRegex);
343     },
344
345     /**
346      * @param {!WebInspector.Event} event
347      */
348     _workingCopyChanged: function(event)
349     {
350         this._update();
351     },
352
353     _update: function()
354     {
355         if (this._isDiverged() && !this._hasDivergedFromVM)
356             this._divergeFromVM();
357         else if (!this._isDiverged() && this._hasDivergedFromVM)
358             this._mergeToVM();
359     },
360
361     _divergeFromVM: function()
362     {
363         this._isDivergingFromVM = true;
364         this._resourceScriptMapping._hasDivergedFromVM(this._uiSourceCode);
365         delete this._isDivergingFromVM;
366         this._hasDivergedFromVM = true;
367         this.dispatchEventToListeners(WebInspector.ResourceScriptFile.Events.DidDivergeFromVM, this._uiSourceCode);
368     },
369
370     _mergeToVM: function()
371     {
372         delete this._hasDivergedFromVM;
373         this._isMergingToVM = true;
374         this._resourceScriptMapping._hasMergedToVM(this._uiSourceCode);
375         delete this._isMergingToVM;
376         this.dispatchEventToListeners(WebInspector.ResourceScriptFile.Events.DidMergeToVM, this._uiSourceCode);
377     },
378
379     /**
380      * @return {boolean}
381      */
382     hasDivergedFromVM: function()
383     {
384         return this._hasDivergedFromVM;
385     },
386
387     /**
388      * @return {boolean}
389      */
390     isDivergingFromVM: function()
391     {
392         return this._isDivergingFromVM;
393     },
394
395     /**
396      * @return {boolean}
397      */
398     isMergingToVM: function()
399     {
400         return this._isMergingToVM;
401     },
402
403     checkMapping: function()
404     {
405         if (!this._script)
406             return;
407         if (typeof this._scriptSource !== "undefined")
408             return;
409         this._script.requestContent(callback.bind(this));
410
411         /**
412          * @param {?string} source
413          * @this {WebInspector.ResourceScriptFile}
414          */
415         function callback(source)
416         {
417             this._scriptSource = source;
418             this._update();
419         }
420     },
421
422     /**
423      * @return {?WebInspector.Target}
424      */
425     target: function()
426     {
427         if (!this._script)
428             return null;
429         return this._script.target();
430     },
431
432     dispose: function()
433     {
434         this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.WorkingCopyChanged, this._workingCopyChanged, this);
435     },
436
437     /**
438      * @param {string} sourceMapURL
439      */
440     addSourceMapURL: function(sourceMapURL)
441     {
442         if (!this._script)
443             return;
444         this._script.addSourceMapURL(sourceMapURL);
445     },
446
447     __proto__: WebInspector.Object.prototype
448 }