Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / CompilerScriptMapping.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.ScriptSourceMapping}
34  * @param {!WebInspector.DebuggerModel} debuggerModel
35  * @param {!WebInspector.Workspace} workspace
36  * @param {!WebInspector.SimpleWorkspaceProvider} networkWorkspaceProvider
37  */
38 WebInspector.CompilerScriptMapping = function(debuggerModel, workspace, networkWorkspaceProvider)
39 {
40     this._debuggerModel = debuggerModel;
41     this._workspace = workspace;
42     this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAddedToWorkspace, this);
43     this._networkWorkspaceProvider = networkWorkspaceProvider;
44     /** @type {!Object.<string, !WebInspector.SourceMap>} */
45     this._sourceMapForSourceMapURL = {};
46     /** @type {!Object.<string, !Array.<function(?WebInspector.SourceMap)>>} */
47     this._pendingSourceMapLoadingCallbacks = {};
48     /** @type {!Object.<string, !WebInspector.SourceMap>} */
49     this._sourceMapForScriptId = {};
50     /** @type {!Map.<!WebInspector.SourceMap, !WebInspector.Script>} */
51     this._scriptForSourceMap = new Map();
52     /** @type {!StringMap.<!WebInspector.SourceMap>} */
53     this._sourceMapForURL = new StringMap();
54     debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, this._debuggerReset, this);
55 }
56
57 WebInspector.CompilerScriptMapping.prototype = {
58     /**
59      * @param {!WebInspector.RawLocation} rawLocation
60      * @return {?WebInspector.UILocation}
61      */
62     rawLocationToUILocation: function(rawLocation)
63     {
64         var debuggerModelLocation = /** @type {!WebInspector.DebuggerModel.Location} */ (rawLocation);
65         var sourceMap = this._sourceMapForScriptId[debuggerModelLocation.scriptId];
66         if (!sourceMap)
67             return null;
68         var lineNumber = debuggerModelLocation.lineNumber;
69         var columnNumber = debuggerModelLocation.columnNumber || 0;
70         var entry = sourceMap.findEntry(lineNumber, columnNumber);
71         if (!entry || entry.length === 2)
72             return null;
73         var url = /** @type {string} */ (entry[2]);
74         var uiSourceCode = this._workspace.uiSourceCodeForURL(url);
75         if (!uiSourceCode)
76             return null;
77         return new WebInspector.UILocation(uiSourceCode, /** @type {number} */ (entry[3]), /** @type {number} */ (entry[4]));
78     },
79
80     /**
81      * @param {!WebInspector.UISourceCode} uiSourceCode
82      * @param {number} lineNumber
83      * @param {number} columnNumber
84      * @return {?WebInspector.DebuggerModel.Location}
85      */
86     uiLocationToRawLocation: function(uiSourceCode, lineNumber, columnNumber)
87     {
88         if (!uiSourceCode.url)
89             return null;
90         var sourceMap = this._sourceMapForURL.get(uiSourceCode.url);
91         if (!sourceMap)
92             return null;
93         var script = /** @type {!WebInspector.Script} */ (this._scriptForSourceMap.get(sourceMap));
94         console.assert(script);
95         var entry = sourceMap.findEntryReversed(uiSourceCode.url, lineNumber);
96         return this._debuggerModel.createRawLocation(script, /** @type {number} */ (entry[0]), /** @type {number} */ (entry[1]));
97     },
98
99     /**
100      * @param {!WebInspector.Script} script
101      */
102     addScript: function(script)
103     {
104         script.pushSourceMapping(this);
105         this.loadSourceMapForScript(script, sourceMapLoaded.bind(this));
106
107         /**
108          * @param {?WebInspector.SourceMap} sourceMap
109          * @this {WebInspector.CompilerScriptMapping}
110          */
111         function sourceMapLoaded(sourceMap)
112         {
113             if (!sourceMap)
114                 return;
115
116             if (this._scriptForSourceMap.get(sourceMap)) {
117                 this._sourceMapForScriptId[script.scriptId] = sourceMap;
118                 script.updateLocations();
119                 return;
120             }
121
122             this._sourceMapForScriptId[script.scriptId] = sourceMap;
123             this._scriptForSourceMap.put(sourceMap, script);
124
125             var sourceURLs = sourceMap.sources();
126             for (var i = 0; i < sourceURLs.length; ++i) {
127                 var sourceURL = sourceURLs[i];
128                 if (this._sourceMapForURL.get(sourceURL))
129                     continue;
130                 this._sourceMapForURL.put(sourceURL, sourceMap);
131                 if (!this._workspace.hasMappingForURL(sourceURL) && !this._workspace.uiSourceCodeForURL(sourceURL)) {
132                     var contentProvider = sourceMap.sourceContentProvider(sourceURL, WebInspector.resourceTypes.Script);
133                     this._networkWorkspaceProvider.addFileForURL(sourceURL, contentProvider, true);
134                 }
135                 var uiSourceCode = this._workspace.uiSourceCodeForURL(sourceURL);
136                 if (uiSourceCode) {
137                     this._bindUISourceCode(uiSourceCode);
138                     uiSourceCode.isContentScript = script.isContentScript;
139                 } else {
140                     WebInspector.showErrorMessage(WebInspector.UIString("Failed to locate workspace file mapped to URL %s from source map %s", sourceURL, sourceMap.url()));
141                 }
142             }
143             script.updateLocations();
144         }
145     },
146
147     /**
148      * @param {!WebInspector.UISourceCode} uiSourceCode
149      */
150     _bindUISourceCode: function(uiSourceCode)
151     {
152         uiSourceCode.setSourceMapping(this);
153     },
154
155     /**
156      * @param {!WebInspector.UISourceCode} uiSourceCode
157      */
158     _unbindUISourceCode: function(uiSourceCode)
159     {
160         uiSourceCode.setSourceMapping(null);
161     },
162
163     /**
164      * @param {!WebInspector.Event} event
165      */
166     _uiSourceCodeAddedToWorkspace: function(event)
167     {
168         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
169         if (!uiSourceCode.url || !this._sourceMapForURL.get(uiSourceCode.url))
170             return;
171         this._bindUISourceCode(uiSourceCode);
172     },
173
174     /**
175      * @param {!WebInspector.Script} script
176      * @param {function(?WebInspector.SourceMap)} callback
177      */
178     loadSourceMapForScript: function(script, callback)
179     {
180         // script.sourceURL can be a random string, but is generally an absolute path -> complete it to inspected page url for
181         // relative links.
182         if (!script.sourceMapURL) {
183             callback(null);
184             return;
185         }
186         var scriptURL = WebInspector.ParsedURL.completeURL(WebInspector.inspectedPageURL, script.sourceURL);
187         if (!scriptURL) {
188             callback(null);
189             return;
190         }
191         var sourceMapURL = WebInspector.ParsedURL.completeURL(scriptURL, script.sourceMapURL);
192         if (!sourceMapURL) {
193             callback(null);
194             return;
195         }
196
197         var sourceMap = this._sourceMapForSourceMapURL[sourceMapURL];
198         if (sourceMap) {
199             callback(sourceMap);
200             return;
201         }
202
203         var pendingCallbacks = this._pendingSourceMapLoadingCallbacks[sourceMapURL];
204         if (pendingCallbacks) {
205             pendingCallbacks.push(callback);
206             return;
207         }
208
209         pendingCallbacks = [callback];
210         this._pendingSourceMapLoadingCallbacks[sourceMapURL] = pendingCallbacks;
211
212         WebInspector.SourceMap.load(sourceMapURL, scriptURL, sourceMapLoaded.bind(this));
213
214         /**
215          * @param {?WebInspector.SourceMap} sourceMap
216          * @this {WebInspector.CompilerScriptMapping}
217          */
218         function sourceMapLoaded(sourceMap)
219         {
220             var url = /** @type {string} */ (sourceMapURL);
221             var callbacks = this._pendingSourceMapLoadingCallbacks[url];
222             delete this._pendingSourceMapLoadingCallbacks[url];
223             if (!callbacks)
224                 return;
225             if (sourceMap)
226                 this._sourceMapForSourceMapURL[url] = sourceMap;
227             for (var i = 0; i < callbacks.length; ++i)
228                 callbacks[i](sourceMap);
229         }
230     },
231
232     _debuggerReset: function()
233     {
234         /**
235          * @param {!WebInspector.SourceMap} sourceMap
236          * @this {WebInspector.CompilerScriptMapping}
237          */
238         function unbindUISourceCodesForSourceMap(sourceMap)
239         {
240             var sourceURLs = sourceMap.sources();
241             for (var i = 0; i < sourceURLs.length; ++i) {
242                 var sourceURL = sourceURLs[i];
243                 var uiSourceCode = this._workspace.uiSourceCodeForURL(sourceURL);
244                 if (!uiSourceCode)
245                     continue;
246                 this._unbindUISourceCode(uiSourceCode);
247             }
248         }
249
250         this._sourceMapForURL.values().forEach(unbindUISourceCodesForSourceMap.bind(this));
251
252         this._sourceMapForSourceMapURL = {};
253         this._pendingSourceMapLoadingCallbacks = {};
254         this._sourceMapForScriptId = {};
255         this._scriptForSourceMap.clear();
256         this._sourceMapForURL.clear();
257     }
258 }