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.DebuggerWorkspaceBinding} debuggerWorkspaceBinding | |
37 */ | |
38 WebInspector.ResourceScriptMapping = function(debuggerModel, workspace, debugger
WorkspaceBinding) | |
39 { | |
40 this._target = debuggerModel.target(); | |
41 this._debuggerModel = debuggerModel; | |
42 this._workspace = workspace; | |
43 this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeA
dded, this._uiSourceCodeAdded, this); | |
44 this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeR
emoved, this._uiSourceCodeRemoved, this); | |
45 this._debuggerWorkspaceBinding = debuggerWorkspaceBinding; | |
46 this._boundURLs = new StringSet(); | |
47 | |
48 /** @type {!Map.<!WebInspector.UISourceCode, !WebInspector.ResourceScriptFil
e>} */ | |
49 this._uiSourceCodeToScriptFile = new Map(); | |
50 | |
51 debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.GlobalObjec
tCleared, this._debuggerReset, this); | |
52 } | |
53 | |
54 WebInspector.ResourceScriptMapping.prototype = { | |
55 /** | |
56 * @param {!WebInspector.RawLocation} rawLocation | |
57 * @return {?WebInspector.UILocation} | |
58 */ | |
59 rawLocationToUILocation: function(rawLocation) | |
60 { | |
61 var debuggerModelLocation = /** @type {!WebInspector.DebuggerModel.Locat
ion} */ (rawLocation); | |
62 var script = debuggerModelLocation.script(); | |
63 var uiSourceCode = this._workspaceUISourceCodeForScript(script); | |
64 if (!uiSourceCode) | |
65 return null; | |
66 var scriptFile = this.scriptFile(uiSourceCode); | |
67 if (scriptFile && ((scriptFile.hasDivergedFromVM() && !scriptFile.isMerg
ingToVM()) || scriptFile.isDivergingFromVM())) | |
68 return null; | |
69 return uiSourceCode.uiLocation(debuggerModelLocation.lineNumber, debugge
rModelLocation.columnNumber || 0); | |
70 }, | |
71 | |
72 /** | |
73 * @param {!WebInspector.UISourceCode} uiSourceCode | |
74 * @param {number} lineNumber | |
75 * @param {number} columnNumber | |
76 * @return {?WebInspector.DebuggerModel.Location} | |
77 */ | |
78 uiLocationToRawLocation: function(uiSourceCode, lineNumber, columnNumber) | |
79 { | |
80 var scripts = this._scriptsForUISourceCode(uiSourceCode); | |
81 console.assert(scripts.length); | |
82 return this._debuggerModel.createRawLocation(scripts[0], lineNumber, col
umnNumber); | |
83 }, | |
84 | |
85 /** | |
86 * @param {!WebInspector.Script} script | |
87 */ | |
88 addScript: function(script) | |
89 { | |
90 if (script.isAnonymousScript()) | |
91 return; | |
92 this._debuggerWorkspaceBinding.pushSourceMapping(script, this); | |
93 | |
94 var uiSourceCode = this._workspaceUISourceCodeForScript(script); | |
95 if (!uiSourceCode) | |
96 return; | |
97 | |
98 this._bindUISourceCodeToScripts(uiSourceCode, [script]); | |
99 }, | |
100 | |
101 /** | |
102 * @return {boolean} | |
103 */ | |
104 isIdentity: function() | |
105 { | |
106 return true; | |
107 }, | |
108 | |
109 /** | |
110 * @param {!WebInspector.UISourceCode} uiSourceCode | |
111 * @param {number} lineNumber | |
112 * @return {boolean} | |
113 */ | |
114 uiLineHasMapping: function(uiSourceCode, lineNumber) | |
115 { | |
116 return true; | |
117 }, | |
118 | |
119 /** | |
120 * @param {!WebInspector.UISourceCode} uiSourceCode | |
121 * @return {?WebInspector.ResourceScriptFile} | |
122 */ | |
123 scriptFile: function(uiSourceCode) | |
124 { | |
125 return this._uiSourceCodeToScriptFile.get(uiSourceCode) || null; | |
126 }, | |
127 | |
128 /** | |
129 * @param {!WebInspector.UISourceCode} uiSourceCode | |
130 * @param {?WebInspector.ResourceScriptFile} scriptFile | |
131 */ | |
132 _setScriptFile: function(uiSourceCode, scriptFile) | |
133 { | |
134 if (scriptFile) | |
135 this._uiSourceCodeToScriptFile.put(uiSourceCode, scriptFile); | |
136 else | |
137 this._uiSourceCodeToScriptFile.remove(uiSourceCode); | |
138 }, | |
139 | |
140 /** | |
141 * @param {!WebInspector.Event} event | |
142 */ | |
143 _uiSourceCodeAdded: function(event) | |
144 { | |
145 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data
); | |
146 if (!uiSourceCode.url) | |
147 return; | |
148 if (uiSourceCode.project().isServiceProject()) | |
149 return; | |
150 | |
151 var scripts = this._scriptsForUISourceCode(uiSourceCode); | |
152 if (!scripts.length) | |
153 return; | |
154 | |
155 this._bindUISourceCodeToScripts(uiSourceCode, scripts); | |
156 }, | |
157 | |
158 /** | |
159 * @param {!WebInspector.Event} event | |
160 */ | |
161 _uiSourceCodeRemoved: function(event) | |
162 { | |
163 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data
); | |
164 if (!uiSourceCode.url) | |
165 return; | |
166 if (uiSourceCode.project().isServiceProject()) | |
167 return; | |
168 | |
169 this._unbindUISourceCode(uiSourceCode); | |
170 }, | |
171 | |
172 /** | |
173 * @param {!WebInspector.UISourceCode} uiSourceCode | |
174 */ | |
175 _hasMergedToVM: function(uiSourceCode) | |
176 { | |
177 var scripts = this._scriptsForUISourceCode(uiSourceCode); | |
178 if (!scripts.length) | |
179 return; | |
180 for (var i = 0; i < scripts.length; ++i) | |
181 this._debuggerWorkspaceBinding.updateLocations(scripts[i]); | |
182 }, | |
183 | |
184 /** | |
185 * @param {!WebInspector.UISourceCode} uiSourceCode | |
186 */ | |
187 _hasDivergedFromVM: function(uiSourceCode) | |
188 { | |
189 var scripts = this._scriptsForUISourceCode(uiSourceCode); | |
190 if (!scripts.length) | |
191 return; | |
192 for (var i = 0; i < scripts.length; ++i) | |
193 this._debuggerWorkspaceBinding.updateLocations(scripts[i]); | |
194 }, | |
195 | |
196 /** | |
197 * @param {!WebInspector.Script} script | |
198 * @return {?WebInspector.UISourceCode} | |
199 */ | |
200 _workspaceUISourceCodeForScript: function(script) | |
201 { | |
202 if (script.isAnonymousScript()) | |
203 return null; | |
204 return this._workspace.uiSourceCodeForURL(script.sourceURL); | |
205 }, | |
206 | |
207 /** | |
208 * @param {!WebInspector.UISourceCode} uiSourceCode | |
209 * @return {!Array.<!WebInspector.Script>} | |
210 */ | |
211 _scriptsForUISourceCode: function(uiSourceCode) | |
212 { | |
213 if (!uiSourceCode.url) | |
214 return []; | |
215 return this._debuggerModel.scriptsForSourceURL(uiSourceCode.url); | |
216 }, | |
217 | |
218 /** | |
219 * @param {!WebInspector.UISourceCode} uiSourceCode | |
220 * @param {!Array.<!WebInspector.Script>} scripts | |
221 */ | |
222 _bindUISourceCodeToScripts: function(uiSourceCode, scripts) | |
223 { | |
224 console.assert(scripts.length); | |
225 var scriptFile = new WebInspector.ResourceScriptFile(this, uiSourceCode,
scripts); | |
226 this._setScriptFile(uiSourceCode, scriptFile); | |
227 for (var i = 0; i < scripts.length; ++i) | |
228 this._debuggerWorkspaceBinding.updateLocations(scripts[i]); | |
229 this._debuggerWorkspaceBinding.setSourceMapping(this._target, uiSourceCo
de, this); | |
230 this._boundURLs.add(uiSourceCode.url); | |
231 }, | |
232 | |
233 /** | |
234 * @param {!WebInspector.UISourceCode} uiSourceCode | |
235 */ | |
236 _unbindUISourceCode: function(uiSourceCode) | |
237 { | |
238 var scriptFile = this.scriptFile(uiSourceCode); | |
239 if (scriptFile) { | |
240 scriptFile.dispose(); | |
241 this._setScriptFile(uiSourceCode, null); | |
242 } | |
243 this._debuggerWorkspaceBinding.setSourceMapping(this._target, uiSourceCo
de, null); | |
244 }, | |
245 | |
246 _debuggerReset: function() | |
247 { | |
248 var boundURLs = this._boundURLs.values(); | |
249 for (var i = 0; i < boundURLs.length; ++i) | |
250 { | |
251 var uiSourceCode = this._workspace.uiSourceCodeForURL(boundURLs[i]); | |
252 if (!uiSourceCode) | |
253 continue; | |
254 this._unbindUISourceCode(uiSourceCode); | |
255 } | |
256 this._boundURLs.clear(); | |
257 }, | |
258 | |
259 dispose: function() | |
260 { | |
261 this._debuggerReset(); | |
262 this._workspace.removeEventListener(WebInspector.Workspace.Events.UISour
ceCodeAdded, this._uiSourceCodeAdded, this); | |
263 this._workspace.removeEventListener(WebInspector.Workspace.Events.UISour
ceCodeRemoved, this._uiSourceCodeRemoved, this); | |
264 } | |
265 | |
266 } | |
267 | |
268 /** | |
269 * @constructor | |
270 * @extends {WebInspector.Object} | |
271 * @param {!WebInspector.ResourceScriptMapping} resourceScriptMapping | |
272 * @param {!WebInspector.UISourceCode} uiSourceCode | |
273 * @param {!Array.<!WebInspector.Script>} scripts | |
274 */ | |
275 WebInspector.ResourceScriptFile = function(resourceScriptMapping, uiSourceCode,
scripts) | |
276 { | |
277 console.assert(scripts.length); | |
278 | |
279 this._resourceScriptMapping = resourceScriptMapping; | |
280 this._uiSourceCode = uiSourceCode; | |
281 | |
282 if (this._uiSourceCode.contentType() === WebInspector.resourceTypes.Script) | |
283 this._script = scripts[0]; | |
284 | |
285 this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.Working
CopyChanged, this._workingCopyChanged, this); | |
286 this._update(); | |
287 } | |
288 | |
289 WebInspector.ResourceScriptFile.Events = { | |
290 DidMergeToVM: "DidMergeToVM", | |
291 DidDivergeFromVM: "DidDivergeFromVM", | |
292 } | |
293 | |
294 WebInspector.ResourceScriptFile.prototype = { | |
295 /** | |
296 * @param {function(?string,!DebuggerAgent.SetScriptSourceError=,!WebInspect
or.Script=)=} callback | |
297 */ | |
298 commitLiveEdit: function(callback) | |
299 { | |
300 var target = this._resourceScriptMapping._target; | |
301 /** | |
302 * @param {?string} error | |
303 * @param {!DebuggerAgent.SetScriptSourceError=} errorData | |
304 * @this {WebInspector.ResourceScriptFile} | |
305 */ | |
306 function innerCallback(error, errorData) | |
307 { | |
308 if (!error) | |
309 this._scriptSource = source; | |
310 this._update(); | |
311 if (callback) | |
312 callback(error, errorData, this._script); | |
313 } | |
314 if (!this._script) | |
315 return; | |
316 var source = this._uiSourceCode.workingCopy(); | |
317 target.debuggerModel.setScriptSource(this._script.scriptId, source, inne
rCallback.bind(this)); | |
318 }, | |
319 | |
320 /** | |
321 * @return {boolean} | |
322 */ | |
323 _isDiverged: function() | |
324 { | |
325 if (this._uiSourceCode.isDirty()) | |
326 return true; | |
327 if (!this._script) | |
328 return false; | |
329 if (typeof this._scriptSource === "undefined") | |
330 return false; | |
331 if (!this._uiSourceCode.workingCopy().startsWith(this._scriptSource)) | |
332 return true; | |
333 var suffix = this._uiSourceCode.workingCopy().substr(this._scriptSource.
length); | |
334 return !!suffix.length && !suffix.match(WebInspector.Script.sourceURLReg
ex); | |
335 }, | |
336 | |
337 /** | |
338 * @param {!WebInspector.Event} event | |
339 */ | |
340 _workingCopyChanged: function(event) | |
341 { | |
342 this._update(); | |
343 }, | |
344 | |
345 _update: function() | |
346 { | |
347 if (this._isDiverged() && !this._hasDivergedFromVM) | |
348 this._divergeFromVM(); | |
349 else if (!this._isDiverged() && this._hasDivergedFromVM) | |
350 this._mergeToVM(); | |
351 }, | |
352 | |
353 _divergeFromVM: function() | |
354 { | |
355 this._isDivergingFromVM = true; | |
356 this._resourceScriptMapping._hasDivergedFromVM(this._uiSourceCode); | |
357 delete this._isDivergingFromVM; | |
358 this._hasDivergedFromVM = true; | |
359 this.dispatchEventToListeners(WebInspector.ResourceScriptFile.Events.Did
DivergeFromVM, this._uiSourceCode); | |
360 }, | |
361 | |
362 _mergeToVM: function() | |
363 { | |
364 delete this._hasDivergedFromVM; | |
365 this._isMergingToVM = true; | |
366 this._resourceScriptMapping._hasMergedToVM(this._uiSourceCode); | |
367 delete this._isMergingToVM; | |
368 this.dispatchEventToListeners(WebInspector.ResourceScriptFile.Events.Did
MergeToVM, this._uiSourceCode); | |
369 }, | |
370 | |
371 /** | |
372 * @return {boolean} | |
373 */ | |
374 hasDivergedFromVM: function() | |
375 { | |
376 return this._hasDivergedFromVM; | |
377 }, | |
378 | |
379 /** | |
380 * @return {boolean} | |
381 */ | |
382 isDivergingFromVM: function() | |
383 { | |
384 return this._isDivergingFromVM; | |
385 }, | |
386 | |
387 /** | |
388 * @return {boolean} | |
389 */ | |
390 isMergingToVM: function() | |
391 { | |
392 return this._isMergingToVM; | |
393 }, | |
394 | |
395 checkMapping: function() | |
396 { | |
397 if (!this._script) | |
398 return; | |
399 if (typeof this._scriptSource !== "undefined") | |
400 return; | |
401 this._script.requestContent(callback.bind(this)); | |
402 | |
403 /** | |
404 * @param {?string} source | |
405 * @this {WebInspector.ResourceScriptFile} | |
406 */ | |
407 function callback(source) | |
408 { | |
409 this._scriptSource = source; | |
410 this._update(); | |
411 } | |
412 }, | |
413 | |
414 /** | |
415 * @return {?WebInspector.Target} | |
416 */ | |
417 target: function() | |
418 { | |
419 if (!this._script) | |
420 return null; | |
421 return this._script.target(); | |
422 }, | |
423 | |
424 dispose: function() | |
425 { | |
426 this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.
WorkingCopyChanged, this._workingCopyChanged, this); | |
427 }, | |
428 | |
429 /** | |
430 * @param {string} sourceMapURL | |
431 */ | |
432 addSourceMapURL: function(sourceMapURL) | |
433 { | |
434 if (!this._script) | |
435 return; | |
436 this._script.addSourceMapURL(sourceMapURL); | |
437 }, | |
438 | |
439 __proto__: WebInspector.Object.prototype | |
440 } | |
OLD | NEW |