Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / sdk / 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.NetworkWorkspaceBinding} networkWorkspaceBinding
37  */
38 WebInspector.CompilerScriptMapping = function(debuggerModel, workspace, networkWorkspaceBinding)
39 {
40     this._debuggerModel = debuggerModel;
41     this._workspace = workspace;
42     this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAddedToWorkspace, this);
43     this._networkWorkspaceBinding = networkWorkspaceBinding;
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 uiSourceCode.uiLocation(/** @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._networkWorkspaceBinding.addFileForURL(sourceURL, contentProvider, script.isContentScript());
134                 }
135                 var uiSourceCode = this._workspace.uiSourceCodeForURL(sourceURL);
136                 if (uiSourceCode)
137                     this._bindUISourceCode(uiSourceCode);
138                 else
139                     WebInspector.console.showErrorMessage(WebInspector.UIString("Failed to locate workspace file mapped to URL %s from source map %s", sourceURL, sourceMap.url()));
140             }
141             script.updateLocations();
142         }
143     },
144
145     /**
146      * @return {boolean}
147      */
148     isIdentity: function()
149     {
150         return false;
151     },
152
153     /**
154      * @param {!WebInspector.UISourceCode} uiSourceCode
155      */
156     _bindUISourceCode: function(uiSourceCode)
157     {
158         uiSourceCode.setSourceMapping(this);
159     },
160
161     /**
162      * @param {!WebInspector.UISourceCode} uiSourceCode
163      */
164     _unbindUISourceCode: function(uiSourceCode)
165     {
166         uiSourceCode.setSourceMapping(null);
167     },
168
169     /**
170      * @param {!WebInspector.Event} event
171      */
172     _uiSourceCodeAddedToWorkspace: function(event)
173     {
174         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
175         if (!uiSourceCode.url || !this._sourceMapForURL.get(uiSourceCode.url))
176             return;
177         this._bindUISourceCode(uiSourceCode);
178     },
179
180     /**
181      * @param {!WebInspector.Script} script
182      * @param {function(?WebInspector.SourceMap)} callback
183      */
184     loadSourceMapForScript: function(script, callback)
185     {
186         // script.sourceURL can be a random string, but is generally an absolute path -> complete it to inspected page url for
187         // relative links.
188         if (!script.sourceMapURL) {
189             callback(null);
190             return;
191         }
192         var scriptURL = WebInspector.ParsedURL.completeURL(script.target().resourceTreeModel.inspectedPageURL(), script.sourceURL);
193         if (!scriptURL) {
194             callback(null);
195             return;
196         }
197         var sourceMapURL = WebInspector.ParsedURL.completeURL(scriptURL, script.sourceMapURL);
198         if (!sourceMapURL) {
199             callback(null);
200             return;
201         }
202
203         var sourceMap = this._sourceMapForSourceMapURL[sourceMapURL];
204         if (sourceMap) {
205             callback(sourceMap);
206             return;
207         }
208
209         var pendingCallbacks = this._pendingSourceMapLoadingCallbacks[sourceMapURL];
210         if (pendingCallbacks) {
211             pendingCallbacks.push(callback);
212             return;
213         }
214
215         pendingCallbacks = [callback];
216         this._pendingSourceMapLoadingCallbacks[sourceMapURL] = pendingCallbacks;
217
218         WebInspector.SourceMap.load(sourceMapURL, scriptURL, sourceMapLoaded.bind(this));
219
220         /**
221          * @param {?WebInspector.SourceMap} sourceMap
222          * @this {WebInspector.CompilerScriptMapping}
223          */
224         function sourceMapLoaded(sourceMap)
225         {
226             var url = /** @type {string} */ (sourceMapURL);
227             var callbacks = this._pendingSourceMapLoadingCallbacks[url];
228             delete this._pendingSourceMapLoadingCallbacks[url];
229             if (!callbacks)
230                 return;
231             if (sourceMap)
232                 this._sourceMapForSourceMapURL[url] = sourceMap;
233             for (var i = 0; i < callbacks.length; ++i)
234                 callbacks[i](sourceMap);
235         }
236     },
237
238     _debuggerReset: function()
239     {
240         /**
241          * @param {string} sourceURL
242          * @this {WebInspector.CompilerScriptMapping}
243          */
244         function unbindUISourceCodeForURL(sourceURL)
245         {
246             var uiSourceCode = this._workspace.uiSourceCodeForURL(sourceURL);
247             if (!uiSourceCode)
248                 return;
249             this._unbindUISourceCode(uiSourceCode);
250         }
251
252         this._sourceMapForURL.keys().forEach(unbindUISourceCodeForURL.bind(this));
253
254         this._sourceMapForSourceMapURL = {};
255         this._pendingSourceMapLoadingCallbacks = {};
256         this._sourceMapForScriptId = {};
257         this._scriptForSourceMap.clear();
258         this._sourceMapForURL.clear();
259     }
260 }