OLD | NEW |
| (Empty) |
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 * @param {!WebInspector.DebuggerWorkspaceBinding} debuggerWorkspaceBinding | |
38 */ | |
39 WebInspector.CompilerScriptMapping = function(debuggerModel, workspace, networkW
orkspaceBinding, debuggerWorkspaceBinding) | |
40 { | |
41 this._target = debuggerModel.target(); | |
42 this._debuggerModel = debuggerModel; | |
43 this._workspace = workspace; | |
44 this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeA
dded, this._uiSourceCodeAddedToWorkspace, this); | |
45 this._networkWorkspaceBinding = networkWorkspaceBinding; | |
46 this._debuggerWorkspaceBinding = debuggerWorkspaceBinding; | |
47 | |
48 /** @type {!Object.<string, !WebInspector.SourceMap>} */ | |
49 this._sourceMapForSourceMapURL = {}; | |
50 /** @type {!Object.<string, !Array.<function(?WebInspector.SourceMap)>>} */ | |
51 this._pendingSourceMapLoadingCallbacks = {}; | |
52 /** @type {!Object.<string, !WebInspector.SourceMap>} */ | |
53 this._sourceMapForScriptId = {}; | |
54 /** @type {!Map.<!WebInspector.SourceMap, !WebInspector.Script>} */ | |
55 this._scriptForSourceMap = new Map(); | |
56 /** @type {!StringMap.<!WebInspector.SourceMap>} */ | |
57 this._sourceMapForURL = new StringMap(); | |
58 debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.GlobalObjec
tCleared, this._debuggerReset, this); | |
59 } | |
60 | |
61 WebInspector.CompilerScriptMapping.prototype = { | |
62 /** | |
63 * @param {!WebInspector.RawLocation} rawLocation | |
64 * @return {?WebInspector.UILocation} | |
65 */ | |
66 rawLocationToUILocation: function(rawLocation) | |
67 { | |
68 var debuggerModelLocation = /** @type {!WebInspector.DebuggerModel.Locat
ion} */ (rawLocation); | |
69 var sourceMap = this._sourceMapForScriptId[debuggerModelLocation.scriptI
d]; | |
70 if (!sourceMap) | |
71 return null; | |
72 var lineNumber = debuggerModelLocation.lineNumber; | |
73 var columnNumber = debuggerModelLocation.columnNumber || 0; | |
74 var entry = sourceMap.findEntry(lineNumber, columnNumber); | |
75 if (!entry || entry.length === 2) | |
76 return null; | |
77 var url = /** @type {string} */ (entry[2]); | |
78 var uiSourceCode = this._workspace.uiSourceCodeForURL(url); | |
79 if (!uiSourceCode) | |
80 return null; | |
81 return uiSourceCode.uiLocation(/** @type {number} */ (entry[3]), /** @ty
pe {number} */ (entry[4])); | |
82 }, | |
83 | |
84 /** | |
85 * @param {!WebInspector.UISourceCode} uiSourceCode | |
86 * @param {number} lineNumber | |
87 * @param {number} columnNumber | |
88 * @return {?WebInspector.DebuggerModel.Location} | |
89 */ | |
90 uiLocationToRawLocation: function(uiSourceCode, lineNumber, columnNumber) | |
91 { | |
92 if (!uiSourceCode.url) | |
93 return null; | |
94 var sourceMap = this._sourceMapForURL.get(uiSourceCode.url); | |
95 if (!sourceMap) | |
96 return null; | |
97 var script = /** @type {!WebInspector.Script} */ (this._scriptForSourceM
ap.get(sourceMap)); | |
98 console.assert(script); | |
99 var mappingSearchLinesCount = 5; | |
100 // We do not require precise (breakpoint) location but limit the number
of lines to search or mapping. | |
101 var entry = sourceMap.findEntryReversed(uiSourceCode.url, lineNumber, ma
ppingSearchLinesCount); | |
102 if (!entry) | |
103 return null; | |
104 return this._debuggerModel.createRawLocation(script, /** @type {number}
*/ (entry[0]), /** @type {number} */ (entry[1])); | |
105 }, | |
106 | |
107 /** | |
108 * @param {!WebInspector.Script} script | |
109 */ | |
110 addScript: function(script) | |
111 { | |
112 this._debuggerWorkspaceBinding.pushSourceMapping(script, this); | |
113 script.addEventListener(WebInspector.Script.Events.SourceMapURLAdded, th
is._sourceMapURLAdded.bind(this)); | |
114 this._processScript(script); | |
115 }, | |
116 | |
117 /** | |
118 * @param {!WebInspector.Event} event | |
119 */ | |
120 _sourceMapURLAdded: function(event) | |
121 { | |
122 var script = /** @type {!WebInspector.Script} */ (event.target); | |
123 this._processScript(script); | |
124 }, | |
125 | |
126 /** | |
127 * @param {!WebInspector.Script} script | |
128 */ | |
129 _processScript: function(script) | |
130 { | |
131 this.loadSourceMapForScript(script, sourceMapLoaded.bind(this)); | |
132 | |
133 /** | |
134 * @param {?WebInspector.SourceMap} sourceMap | |
135 * @this {WebInspector.CompilerScriptMapping} | |
136 */ | |
137 function sourceMapLoaded(sourceMap) | |
138 { | |
139 if (!sourceMap) | |
140 return; | |
141 | |
142 if (this._scriptForSourceMap.get(sourceMap)) { | |
143 this._sourceMapForScriptId[script.scriptId] = sourceMap; | |
144 this._debuggerWorkspaceBinding.updateLocations(script); | |
145 return; | |
146 } | |
147 | |
148 this._sourceMapForScriptId[script.scriptId] = sourceMap; | |
149 this._scriptForSourceMap.put(sourceMap, script); | |
150 | |
151 var sourceURLs = sourceMap.sources(); | |
152 for (var i = 0; i < sourceURLs.length; ++i) { | |
153 var sourceURL = sourceURLs[i]; | |
154 if (this._sourceMapForURL.get(sourceURL)) | |
155 continue; | |
156 this._sourceMapForURL.put(sourceURL, sourceMap); | |
157 if (!this._workspace.hasMappingForURL(sourceURL) && !this._works
pace.uiSourceCodeForURL(sourceURL)) { | |
158 var contentProvider = sourceMap.sourceContentProvider(source
URL, WebInspector.resourceTypes.Script); | |
159 this._networkWorkspaceBinding.addFileForURL(sourceURL, conte
ntProvider, script.isContentScript()); | |
160 } | |
161 var uiSourceCode = this._workspace.uiSourceCodeForURL(sourceURL)
; | |
162 if (uiSourceCode) | |
163 this._bindUISourceCode(uiSourceCode); | |
164 else | |
165 WebInspector.console.error(WebInspector.UIString("Failed to
locate workspace file mapped to URL %s from source map %s", sourceURL, sourceMap
.url())); | |
166 } | |
167 this._debuggerWorkspaceBinding.updateLocations(script); | |
168 } | |
169 }, | |
170 | |
171 /** | |
172 * @return {boolean} | |
173 */ | |
174 isIdentity: function() | |
175 { | |
176 return false; | |
177 }, | |
178 | |
179 /** | |
180 * @param {!WebInspector.UISourceCode} uiSourceCode | |
181 * @param {number} lineNumber | |
182 * @return {boolean} | |
183 */ | |
184 uiLineHasMapping: function(uiSourceCode, lineNumber) | |
185 { | |
186 if (!uiSourceCode.url) | |
187 return true; | |
188 var sourceMap = this._sourceMapForURL.get(uiSourceCode.url); | |
189 if (!sourceMap) | |
190 return true; | |
191 return !!sourceMap.findEntryReversed(uiSourceCode.url, lineNumber, 0); | |
192 }, | |
193 | |
194 /** | |
195 * @param {!WebInspector.UISourceCode} uiSourceCode | |
196 */ | |
197 _bindUISourceCode: function(uiSourceCode) | |
198 { | |
199 this._debuggerWorkspaceBinding.setSourceMapping(this._target, uiSourceCo
de, this); | |
200 }, | |
201 | |
202 /** | |
203 * @param {!WebInspector.UISourceCode} uiSourceCode | |
204 */ | |
205 _unbindUISourceCode: function(uiSourceCode) | |
206 { | |
207 this._debuggerWorkspaceBinding.setSourceMapping(this._target, uiSourceCo
de, null); | |
208 }, | |
209 | |
210 /** | |
211 * @param {!WebInspector.Event} event | |
212 */ | |
213 _uiSourceCodeAddedToWorkspace: function(event) | |
214 { | |
215 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data
); | |
216 if (!uiSourceCode.url || !this._sourceMapForURL.get(uiSourceCode.url)) | |
217 return; | |
218 this._bindUISourceCode(uiSourceCode); | |
219 }, | |
220 | |
221 /** | |
222 * @param {!WebInspector.Script} script | |
223 * @param {function(?WebInspector.SourceMap)} callback | |
224 */ | |
225 loadSourceMapForScript: function(script, callback) | |
226 { | |
227 // script.sourceURL can be a random string, but is generally an absolute
path -> complete it to inspected page url for | |
228 // relative links. | |
229 if (!script.sourceMapURL) { | |
230 callback(null); | |
231 return; | |
232 } | |
233 var scriptURL = WebInspector.ParsedURL.completeURL(script.target().resou
rceTreeModel.inspectedPageURL(), script.sourceURL); | |
234 if (!scriptURL) { | |
235 callback(null); | |
236 return; | |
237 } | |
238 var sourceMapURL = WebInspector.ParsedURL.completeURL(scriptURL, script.
sourceMapURL); | |
239 if (!sourceMapURL) { | |
240 callback(null); | |
241 return; | |
242 } | |
243 | |
244 var sourceMap = this._sourceMapForSourceMapURL[sourceMapURL]; | |
245 if (sourceMap) { | |
246 callback(sourceMap); | |
247 return; | |
248 } | |
249 | |
250 var pendingCallbacks = this._pendingSourceMapLoadingCallbacks[sourceMapU
RL]; | |
251 if (pendingCallbacks) { | |
252 pendingCallbacks.push(callback); | |
253 return; | |
254 } | |
255 | |
256 pendingCallbacks = [callback]; | |
257 this._pendingSourceMapLoadingCallbacks[sourceMapURL] = pendingCallbacks; | |
258 | |
259 WebInspector.SourceMap.load(sourceMapURL, scriptURL, sourceMapLoaded.bin
d(this)); | |
260 | |
261 /** | |
262 * @param {?WebInspector.SourceMap} sourceMap | |
263 * @this {WebInspector.CompilerScriptMapping} | |
264 */ | |
265 function sourceMapLoaded(sourceMap) | |
266 { | |
267 var url = /** @type {string} */ (sourceMapURL); | |
268 var callbacks = this._pendingSourceMapLoadingCallbacks[url]; | |
269 delete this._pendingSourceMapLoadingCallbacks[url]; | |
270 if (!callbacks) | |
271 return; | |
272 if (sourceMap) | |
273 this._sourceMapForSourceMapURL[url] = sourceMap; | |
274 for (var i = 0; i < callbacks.length; ++i) | |
275 callbacks[i](sourceMap); | |
276 } | |
277 }, | |
278 | |
279 _debuggerReset: function() | |
280 { | |
281 /** | |
282 * @param {string} sourceURL | |
283 * @this {WebInspector.CompilerScriptMapping} | |
284 */ | |
285 function unbindUISourceCodeForURL(sourceURL) | |
286 { | |
287 var uiSourceCode = this._workspace.uiSourceCodeForURL(sourceURL); | |
288 if (!uiSourceCode) | |
289 return; | |
290 this._unbindUISourceCode(uiSourceCode); | |
291 } | |
292 | |
293 this._sourceMapForURL.keys().forEach(unbindUISourceCodeForURL.bind(this)
); | |
294 | |
295 this._sourceMapForSourceMapURL = {}; | |
296 this._pendingSourceMapLoadingCallbacks = {}; | |
297 this._sourceMapForScriptId = {}; | |
298 this._scriptForSourceMap.clear(); | |
299 this._sourceMapForURL.clear(); | |
300 }, | |
301 | |
302 dispose: function() | |
303 { | |
304 this._workspace.removeEventListener(WebInspector.Workspace.Events.UISour
ceCodeAdded, this._uiSourceCodeAddedToWorkspace, this); | |
305 } | |
306 } | |
OLD | NEW |