OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2011 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 * @extends {WebInspector.Object} | |
34 * @implements {WebInspector.TargetManager.Observer} | |
35 * @param {!WebInspector.Setting} breakpointStorage | |
36 * @param {!WebInspector.Workspace} workspace | |
37 * @param {!WebInspector.TargetManager} targetManager | |
38 * @param {!WebInspector.DebuggerWorkspaceBinding} debuggerWorkspaceBinding | |
39 */ | |
40 WebInspector.BreakpointManager = function(breakpointStorage, workspace, targetMa
nager, debuggerWorkspaceBinding) | |
41 { | |
42 this._storage = new WebInspector.BreakpointManager.Storage(this, breakpointS
torage); | |
43 this._workspace = workspace; | |
44 this._targetManager = targetManager; | |
45 this._debuggerWorkspaceBinding = debuggerWorkspaceBinding; | |
46 | |
47 this._breakpointsActive = true; | |
48 this._breakpointsForUISourceCode = new Map(); | |
49 this._breakpointsForPrimaryUISourceCode = new Map(); | |
50 /** @type {!StringMultimap.<!WebInspector.BreakpointManager.Breakpoint>} */ | |
51 this._provisionalBreakpoints = new StringMultimap(); | |
52 | |
53 this._workspace.addEventListener(WebInspector.Workspace.Events.ProjectRemove
d, this._projectRemoved, this); | |
54 this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeA
dded, this._uiSourceCodeAdded, this); | |
55 this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeR
emoved, this._uiSourceCodeRemoved, this); | |
56 } | |
57 | |
58 WebInspector.BreakpointManager.Events = { | |
59 BreakpointAdded: "breakpoint-added", | |
60 BreakpointRemoved: "breakpoint-removed", | |
61 BreakpointsActiveStateChanged: "BreakpointsActiveStateChanged" | |
62 } | |
63 | |
64 WebInspector.BreakpointManager._sourceFileId = function(uiSourceCode) | |
65 { | |
66 if (!uiSourceCode.url) | |
67 return ""; | |
68 return uiSourceCode.uri(); | |
69 } | |
70 | |
71 /** | |
72 * @param {string} sourceFileId | |
73 * @param {number} lineNumber | |
74 * @param {number} columnNumber | |
75 * @return {string} | |
76 */ | |
77 WebInspector.BreakpointManager._breakpointStorageId = function(sourceFileId, lin
eNumber, columnNumber) | |
78 { | |
79 if (!sourceFileId) | |
80 return ""; | |
81 return sourceFileId + ":" + lineNumber + ":" + columnNumber; | |
82 } | |
83 | |
84 WebInspector.BreakpointManager.prototype = { | |
85 /** | |
86 * @param {!WebInspector.Target} target | |
87 */ | |
88 targetAdded: function(target) { | |
89 if (!this._breakpointsActive) | |
90 target.debuggerAgent().setBreakpointsActive(this._breakpointsActive)
; | |
91 }, | |
92 | |
93 /** | |
94 * @param {!WebInspector.Target} target | |
95 */ | |
96 targetRemoved: function(target) { }, | |
97 | |
98 /** | |
99 * @param {string} sourceFileId | |
100 * @return {!StringMap.<!WebInspector.BreakpointManager.Breakpoint>} | |
101 */ | |
102 _provisionalBreakpointsForSourceFileId: function(sourceFileId) | |
103 { | |
104 var result = new StringMap(); | |
105 var breakpoints = this._provisionalBreakpoints.get(sourceFileId).values(
); | |
106 for (var i = 0; i < breakpoints.length; ++i) | |
107 result.put(breakpoints[i]._breakpointStorageId(), breakpoints[i]); | |
108 return result; | |
109 }, | |
110 | |
111 removeProvisionalBreakpointsForTest: function() | |
112 { | |
113 var breakpoints = this._provisionalBreakpoints.values(); | |
114 for (var i = 0; i < breakpoints.length; ++i) | |
115 breakpoints[i].remove(); | |
116 this._provisionalBreakpoints.clear(); | |
117 }, | |
118 | |
119 /** | |
120 * @param {!WebInspector.UISourceCode} uiSourceCode | |
121 */ | |
122 _restoreBreakpoints: function(uiSourceCode) | |
123 { | |
124 var sourceFileId = WebInspector.BreakpointManager._sourceFileId(uiSource
Code); | |
125 if (!sourceFileId) | |
126 return; | |
127 | |
128 this._storage.mute(); | |
129 var breakpointItems = this._storage.breakpointItems(uiSourceCode); | |
130 var provisionalBreakpoints = this._provisionalBreakpointsForSourceFileId
(sourceFileId); | |
131 for (var i = 0; i < breakpointItems.length; ++i) { | |
132 var breakpointItem = breakpointItems[i]; | |
133 var itemStorageId = WebInspector.BreakpointManager._breakpointStorag
eId(breakpointItem.sourceFileId, breakpointItem.lineNumber, breakpointItem.colum
nNumber); | |
134 var provisionalBreakpoint = provisionalBreakpoints.get(itemStorageId
); | |
135 if (provisionalBreakpoint) { | |
136 if (!this._breakpointsForPrimaryUISourceCode.get(uiSourceCode)) | |
137 this._breakpointsForPrimaryUISourceCode.put(uiSourceCode, []
); | |
138 this._breakpointsForPrimaryUISourceCode.get(uiSourceCode).push(p
rovisionalBreakpoint); | |
139 provisionalBreakpoint._updateBreakpoint(); | |
140 } else { | |
141 this._innerSetBreakpoint(uiSourceCode, breakpointItem.lineNumber
, breakpointItem.columnNumber, breakpointItem.condition, breakpointItem.enabled)
; | |
142 } | |
143 } | |
144 this._provisionalBreakpoints.removeAll(sourceFileId); | |
145 this._storage.unmute(); | |
146 }, | |
147 | |
148 /** | |
149 * @param {!WebInspector.Event} event | |
150 */ | |
151 _uiSourceCodeAdded: function(event) | |
152 { | |
153 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data
); | |
154 this._restoreBreakpoints(uiSourceCode); | |
155 if (uiSourceCode.contentType() === WebInspector.resourceTypes.Script ||
uiSourceCode.contentType() === WebInspector.resourceTypes.Document) | |
156 uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.Sourc
eMappingChanged, this._uiSourceCodeMappingChanged, this); | |
157 }, | |
158 | |
159 /** | |
160 * @param {!WebInspector.Event} event | |
161 */ | |
162 _uiSourceCodeRemoved: function(event) | |
163 { | |
164 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data
); | |
165 this._removeUISourceCode(uiSourceCode); | |
166 }, | |
167 | |
168 /** | |
169 * @param {!WebInspector.Event} event | |
170 */ | |
171 _uiSourceCodeMappingChanged: function(event) | |
172 { | |
173 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.targ
et); | |
174 var isIdentity = /** @type {boolean} */ (event.data.isIdentity); | |
175 var target = /** @type {!WebInspector.Target} */ (event.data.target); | |
176 if (isIdentity) | |
177 return; | |
178 var breakpoints = this._breakpointsForPrimaryUISourceCode.get(uiSourceCo
de) || []; | |
179 for (var i = 0; i < breakpoints.length; ++i) | |
180 breakpoints[i]._updateInDebuggerForTarget(target); | |
181 }, | |
182 | |
183 /** | |
184 * @param {!WebInspector.UISourceCode} uiSourceCode | |
185 */ | |
186 _removeUISourceCode: function(uiSourceCode) | |
187 { | |
188 var breakpoints = this._breakpointsForPrimaryUISourceCode.get(uiSourceCo
de) || []; | |
189 var sourceFileId = WebInspector.BreakpointManager._sourceFileId(uiSource
Code); | |
190 for (var i = 0; i < breakpoints.length; ++i) { | |
191 breakpoints[i]._resetLocations(); | |
192 if (breakpoints[i].enabled()) | |
193 this._provisionalBreakpoints.put(sourceFileId, breakpoints[i]); | |
194 } | |
195 uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.Source
MappingChanged, this._uiSourceCodeMappingChanged, this); | |
196 this._breakpointsForPrimaryUISourceCode.remove(uiSourceCode); | |
197 }, | |
198 | |
199 /** | |
200 * @param {!WebInspector.UISourceCode} uiSourceCode | |
201 * @param {number} lineNumber | |
202 * @param {number} columnNumber | |
203 * @param {string} condition | |
204 * @param {boolean} enabled | |
205 * @return {!WebInspector.BreakpointManager.Breakpoint} | |
206 */ | |
207 setBreakpoint: function(uiSourceCode, lineNumber, columnNumber, condition, e
nabled) | |
208 { | |
209 this.setBreakpointsActive(true); | |
210 return this._innerSetBreakpoint(uiSourceCode, lineNumber, columnNumber,
condition, enabled); | |
211 }, | |
212 | |
213 /** | |
214 * @param {!WebInspector.UISourceCode} uiSourceCode | |
215 * @param {number} lineNumber | |
216 * @param {number} columnNumber | |
217 * @param {string} condition | |
218 * @param {boolean} enabled | |
219 * @return {!WebInspector.BreakpointManager.Breakpoint} | |
220 */ | |
221 _innerSetBreakpoint: function(uiSourceCode, lineNumber, columnNumber, condit
ion, enabled) | |
222 { | |
223 var breakpoint = this.findBreakpoint(uiSourceCode, lineNumber, columnNum
ber); | |
224 if (breakpoint) { | |
225 breakpoint._updateState(condition, enabled); | |
226 return breakpoint; | |
227 } | |
228 var projectId = uiSourceCode.project().id(); | |
229 var path = uiSourceCode.path(); | |
230 var sourceFileId = WebInspector.BreakpointManager._sourceFileId(uiSource
Code); | |
231 breakpoint = new WebInspector.BreakpointManager.Breakpoint(this, project
Id, path, sourceFileId, lineNumber, columnNumber, condition, enabled); | |
232 if (!this._breakpointsForPrimaryUISourceCode.get(uiSourceCode)) | |
233 this._breakpointsForPrimaryUISourceCode.put(uiSourceCode, []); | |
234 this._breakpointsForPrimaryUISourceCode.get(uiSourceCode).push(breakpoin
t); | |
235 return breakpoint; | |
236 }, | |
237 | |
238 /** | |
239 * @param {!WebInspector.UISourceCode} uiSourceCode | |
240 * @param {number} lineNumber | |
241 * @param {number} columnNumber | |
242 * @return {?WebInspector.BreakpointManager.Breakpoint} | |
243 */ | |
244 findBreakpoint: function(uiSourceCode, lineNumber, columnNumber) | |
245 { | |
246 var breakpoints = this._breakpointsForUISourceCode.get(uiSourceCode); | |
247 var lineBreakpoints = breakpoints ? breakpoints.get(String(lineNumber))
: null; | |
248 var columnBreakpoints = lineBreakpoints ? lineBreakpoints.get(String(col
umnNumber)) : null; | |
249 return columnBreakpoints ? columnBreakpoints[0] : null; | |
250 }, | |
251 | |
252 /** | |
253 * @param {!WebInspector.UISourceCode} uiSourceCode | |
254 * @param {number} lineNumber | |
255 * @return {?WebInspector.BreakpointManager.Breakpoint} | |
256 */ | |
257 findBreakpointOnLine: function(uiSourceCode, lineNumber) | |
258 { | |
259 var breakpoints = this._breakpointsForUISourceCode.get(uiSourceCode); | |
260 var lineBreakpoints = breakpoints ? breakpoints.get(String(lineNumber))
: null; | |
261 return lineBreakpoints ? lineBreakpoints.values()[0][0] : null; | |
262 }, | |
263 | |
264 /** | |
265 * @param {!WebInspector.UISourceCode} uiSourceCode | |
266 * @return {!Array.<!WebInspector.BreakpointManager.Breakpoint>} | |
267 */ | |
268 breakpointsForUISourceCode: function(uiSourceCode) | |
269 { | |
270 var result = []; | |
271 var uiSourceCodeBreakpoints = this._breakpointsForUISourceCode.get(uiSou
rceCode); | |
272 var breakpoints = uiSourceCodeBreakpoints ? uiSourceCodeBreakpoints.valu
es() : []; | |
273 for (var i = 0; i < breakpoints.length; ++i) { | |
274 var lineBreakpoints = breakpoints[i]; | |
275 var columnBreakpointArrays = lineBreakpoints ? lineBreakpoints.value
s() : []; | |
276 result = result.concat.apply(result, columnBreakpointArrays); | |
277 } | |
278 return result; | |
279 }, | |
280 | |
281 /** | |
282 * @return {!Array.<!WebInspector.BreakpointManager.Breakpoint>} | |
283 */ | |
284 allBreakpoints: function() | |
285 { | |
286 var result = []; | |
287 var uiSourceCodes = this._breakpointsForUISourceCode.keys(); | |
288 for (var i = 0; i < uiSourceCodes.length; ++i) | |
289 result = result.concat(this.breakpointsForUISourceCode(uiSourceCodes
[i])); | |
290 return result; | |
291 }, | |
292 | |
293 /** | |
294 * @param {!WebInspector.UISourceCode} uiSourceCode | |
295 * @return {!Array.<!{breakpoint: !WebInspector.BreakpointManager.Breakpoint
, uiLocation: !WebInspector.UILocation}>} | |
296 */ | |
297 breakpointLocationsForUISourceCode: function(uiSourceCode) | |
298 { | |
299 var uiSourceCodeBreakpoints = this._breakpointsForUISourceCode.get(uiSou
rceCode); | |
300 var lineNumbers = uiSourceCodeBreakpoints ? uiSourceCodeBreakpoints.keys
() : []; | |
301 var result = []; | |
302 for (var i = 0; i < lineNumbers.length; ++i) { | |
303 var lineBreakpoints = uiSourceCodeBreakpoints.get(lineNumbers[i]); | |
304 var columnNumbers = lineBreakpoints.keys(); | |
305 for (var j = 0; j < columnNumbers.length; ++j) { | |
306 var columnBreakpoints = lineBreakpoints.get(columnNumbers[j]); | |
307 var lineNumber = parseInt(lineNumbers[i], 10); | |
308 var columnNumber = parseInt(columnNumbers[j], 10); | |
309 for (var k = 0; k < columnBreakpoints.length; ++k) { | |
310 var breakpoint = columnBreakpoints[k]; | |
311 var uiLocation = uiSourceCode.uiLocation(lineNumber, columnN
umber); | |
312 result.push({breakpoint: breakpoint, uiLocation: uiLocation}
); | |
313 } | |
314 } | |
315 } | |
316 return result; | |
317 }, | |
318 | |
319 /** | |
320 * @return {!Array.<!{breakpoint: !WebInspector.BreakpointManager.Breakpoint
, uiLocation: !WebInspector.UILocation}>} | |
321 */ | |
322 allBreakpointLocations: function() | |
323 { | |
324 var result = []; | |
325 var uiSourceCodes = this._breakpointsForUISourceCode.keys(); | |
326 for (var i = 0; i < uiSourceCodes.length; ++i) | |
327 result = result.concat(this.breakpointLocationsForUISourceCode(uiSou
rceCodes[i])); | |
328 return result; | |
329 }, | |
330 | |
331 /** | |
332 * @param {boolean} toggleState | |
333 */ | |
334 toggleAllBreakpoints: function(toggleState) | |
335 { | |
336 var breakpoints = this.allBreakpoints(); | |
337 for (var i = 0; i < breakpoints.length; ++i) | |
338 breakpoints[i].setEnabled(toggleState); | |
339 }, | |
340 | |
341 removeAllBreakpoints: function() | |
342 { | |
343 var breakpoints = this.allBreakpoints(); | |
344 for (var i = 0; i < breakpoints.length; ++i) | |
345 breakpoints[i].remove(); | |
346 }, | |
347 | |
348 _projectRemoved: function(event) | |
349 { | |
350 var project = /** @type {!WebInspector.Project} */ (event.data); | |
351 var uiSourceCodes = project.uiSourceCodes(); | |
352 for (var i = 0; i < uiSourceCodes.length; ++i) | |
353 this._removeUISourceCode(uiSourceCodes[i]); | |
354 }, | |
355 | |
356 /** | |
357 * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint | |
358 * @param {boolean} removeFromStorage | |
359 */ | |
360 _removeBreakpoint: function(breakpoint, removeFromStorage) | |
361 { | |
362 var uiSourceCode = breakpoint.uiSourceCode(); | |
363 var breakpoints = uiSourceCode ? this._breakpointsForPrimaryUISourceCode
.get(uiSourceCode) || [] : []; | |
364 breakpoints.remove(breakpoint); | |
365 if (removeFromStorage) | |
366 this._storage._removeBreakpoint(breakpoint); | |
367 this._provisionalBreakpoints.remove(breakpoint._sourceFileId, breakpoint
); | |
368 }, | |
369 | |
370 /** | |
371 * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint | |
372 * @param {!WebInspector.UILocation} uiLocation | |
373 */ | |
374 _uiLocationAdded: function(breakpoint, uiLocation) | |
375 { | |
376 var breakpoints = this._breakpointsForUISourceCode.get(uiLocation.uiSour
ceCode); | |
377 if (!breakpoints) { | |
378 breakpoints = new StringMap(); | |
379 this._breakpointsForUISourceCode.put(uiLocation.uiSourceCode, breakp
oints); | |
380 } | |
381 var lineBreakpoints = breakpoints.get(String(uiLocation.lineNumber)); | |
382 if (!lineBreakpoints) { | |
383 lineBreakpoints = new StringMap(); | |
384 breakpoints.put(String(uiLocation.lineNumber), lineBreakpoints); | |
385 } | |
386 var columnBreakpoints = lineBreakpoints.get(String(uiLocation.columnNumb
er)); | |
387 if (!columnBreakpoints) { | |
388 columnBreakpoints = []; | |
389 lineBreakpoints.put(String(uiLocation.columnNumber), columnBreakpoin
ts); | |
390 } | |
391 columnBreakpoints.push(breakpoint); | |
392 this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.Brea
kpointAdded, {breakpoint: breakpoint, uiLocation: uiLocation}); | |
393 }, | |
394 | |
395 /** | |
396 * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint | |
397 * @param {!WebInspector.UILocation} uiLocation | |
398 */ | |
399 _uiLocationRemoved: function(breakpoint, uiLocation) | |
400 { | |
401 var breakpoints = this._breakpointsForUISourceCode.get(uiLocation.uiSour
ceCode); | |
402 if (!breakpoints) | |
403 return; | |
404 | |
405 var lineBreakpoints = breakpoints.get(String(uiLocation.lineNumber)); | |
406 if (!lineBreakpoints) | |
407 return; | |
408 var columnBreakpoints = lineBreakpoints.get(String(uiLocation.columnNumb
er)); | |
409 if (!columnBreakpoints) | |
410 return; | |
411 columnBreakpoints.remove(breakpoint); | |
412 if (!columnBreakpoints.length) | |
413 lineBreakpoints.remove(String(uiLocation.columnNumber)); | |
414 if (!lineBreakpoints.size()) | |
415 breakpoints.remove(String(uiLocation.lineNumber)); | |
416 if (!breakpoints.size()) | |
417 this._breakpointsForUISourceCode.remove(uiLocation.uiSourceCode); | |
418 this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.Brea
kpointRemoved, {breakpoint: breakpoint, uiLocation: uiLocation}); | |
419 }, | |
420 | |
421 /** | |
422 * @param {boolean} active | |
423 */ | |
424 setBreakpointsActive: function(active) | |
425 { | |
426 if (this._breakpointsActive === active) | |
427 return; | |
428 | |
429 this._breakpointsActive = active; | |
430 var targets = WebInspector.targetManager.targets(); | |
431 for (var i = 0; i < targets.length; ++i) | |
432 targets[i].debuggerAgent().setBreakpointsActive(active); | |
433 | |
434 this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.Brea
kpointsActiveStateChanged, active); | |
435 }, | |
436 | |
437 /** | |
438 * @return {boolean} | |
439 */ | |
440 breakpointsActive: function() | |
441 { | |
442 return this._breakpointsActive; | |
443 }, | |
444 | |
445 __proto__: WebInspector.Object.prototype | |
446 } | |
447 | |
448 /** | |
449 * @constructor | |
450 * @implements {WebInspector.TargetManager.Observer} | |
451 * @param {!WebInspector.BreakpointManager} breakpointManager | |
452 * @param {string} projectId | |
453 * @param {string} path | |
454 * @param {string} sourceFileId | |
455 * @param {number} lineNumber | |
456 * @param {number} columnNumber | |
457 * @param {string} condition | |
458 * @param {boolean} enabled | |
459 */ | |
460 WebInspector.BreakpointManager.Breakpoint = function(breakpointManager, projectI
d, path, sourceFileId, lineNumber, columnNumber, condition, enabled) | |
461 { | |
462 this._breakpointManager = breakpointManager; | |
463 this._projectId = projectId; | |
464 this._path = path; | |
465 this._lineNumber = lineNumber; | |
466 this._columnNumber = columnNumber; | |
467 this._sourceFileId = sourceFileId; | |
468 | |
469 /** @type {!Object.<string, number>} */ | |
470 this._numberOfDebuggerLocationForUILocation = {}; | |
471 | |
472 // Force breakpoint update. | |
473 /** @type {string} */ this._condition; | |
474 /** @type {boolean} */ this._enabled; | |
475 /** @type {boolean} */ this._isRemoved; | |
476 /** @type {!WebInspector.UILocation|undefined} */ this._fakePrimaryLocation; | |
477 | |
478 this._currentState = null; | |
479 /** @type {!Map.<!WebInspector.Target, !WebInspector.BreakpointManager.Targe
tBreakpoint>}*/ | |
480 this._targetBreakpoints = new Map(); | |
481 this._updateState(condition, enabled); | |
482 this._breakpointManager._targetManager.observeTargets(this); | |
483 } | |
484 | |
485 WebInspector.BreakpointManager.Breakpoint.prototype = { | |
486 /** | |
487 * @param {!WebInspector.Target} target | |
488 */ | |
489 targetAdded: function(target) | |
490 { | |
491 this._targetBreakpoints.put(target, new WebInspector.BreakpointManager.T
argetBreakpoint(target, this, this._breakpointManager._debuggerWorkspaceBinding)
); | |
492 }, | |
493 | |
494 /** | |
495 * @param {!WebInspector.Target} target | |
496 */ | |
497 targetRemoved: function(target) | |
498 { | |
499 var targetBreakpoint = this._targetBreakpoints.remove(target); | |
500 targetBreakpoint._cleanUpAfterDebuggerIsGone(); | |
501 targetBreakpoint._removeEventListeners(); | |
502 }, | |
503 | |
504 /** | |
505 * @return {string} | |
506 */ | |
507 projectId: function() | |
508 { | |
509 return this._projectId; | |
510 }, | |
511 | |
512 /** | |
513 * @return {string} | |
514 */ | |
515 path: function() | |
516 { | |
517 return this._path; | |
518 }, | |
519 | |
520 /** | |
521 * @return {number} | |
522 */ | |
523 lineNumber: function() | |
524 { | |
525 return this._lineNumber; | |
526 }, | |
527 | |
528 /** | |
529 * @return {number} | |
530 */ | |
531 columnNumber: function() | |
532 { | |
533 return this._columnNumber; | |
534 }, | |
535 | |
536 /** | |
537 * @return {?WebInspector.UISourceCode} | |
538 */ | |
539 uiSourceCode: function() | |
540 { | |
541 return this._breakpointManager._workspace.uiSourceCode(this._projectId,
this._path); | |
542 }, | |
543 | |
544 /** | |
545 * @param {?WebInspector.UILocation} oldUILocation | |
546 * @param {!WebInspector.UILocation} newUILocation | |
547 */ | |
548 _replaceUILocation: function(oldUILocation, newUILocation) | |
549 { | |
550 if (this._isRemoved) | |
551 return; | |
552 | |
553 this._removeUILocation(oldUILocation, true); | |
554 this._removeFakeBreakpointAtPrimaryLocation(); | |
555 | |
556 if (!this._numberOfDebuggerLocationForUILocation[newUILocation.id()]) | |
557 this._numberOfDebuggerLocationForUILocation[newUILocation.id()] = 0; | |
558 | |
559 if (++this._numberOfDebuggerLocationForUILocation[newUILocation.id()] ==
= 1) | |
560 this._breakpointManager._uiLocationAdded(this, newUILocation); | |
561 }, | |
562 | |
563 /** | |
564 * @param {?WebInspector.UILocation} uiLocation | |
565 * @param {boolean=} muteCreationFakeBreakpoint | |
566 */ | |
567 _removeUILocation: function(uiLocation, muteCreationFakeBreakpoint) | |
568 { | |
569 if (!uiLocation || --this._numberOfDebuggerLocationForUILocation[uiLocat
ion.id()] !== 0) | |
570 return; | |
571 | |
572 delete this._numberOfDebuggerLocationForUILocation[uiLocation.id()]; | |
573 this._breakpointManager._uiLocationRemoved(this, uiLocation); | |
574 if (!muteCreationFakeBreakpoint) | |
575 this._fakeBreakpointAtPrimaryLocation(); | |
576 }, | |
577 | |
578 /** | |
579 * @return {boolean} | |
580 */ | |
581 enabled: function() | |
582 { | |
583 return this._enabled; | |
584 }, | |
585 | |
586 /** | |
587 * @param {boolean} enabled | |
588 */ | |
589 setEnabled: function(enabled) | |
590 { | |
591 this._updateState(this._condition, enabled); | |
592 }, | |
593 | |
594 /** | |
595 * @return {string} | |
596 */ | |
597 condition: function() | |
598 { | |
599 return this._condition; | |
600 }, | |
601 | |
602 /** | |
603 * @param {string} condition | |
604 */ | |
605 setCondition: function(condition) | |
606 { | |
607 this._updateState(condition, this._enabled); | |
608 }, | |
609 | |
610 /** | |
611 * @param {string} condition | |
612 * @param {boolean} enabled | |
613 */ | |
614 _updateState: function(condition, enabled) | |
615 { | |
616 if (this._enabled === enabled && this._condition === condition) | |
617 return; | |
618 this._enabled = enabled; | |
619 this._condition = condition; | |
620 this._breakpointManager._storage._updateBreakpoint(this); | |
621 this._updateBreakpoint(); | |
622 }, | |
623 | |
624 _updateBreakpoint: function() | |
625 { | |
626 this._removeFakeBreakpointAtPrimaryLocation(); | |
627 this._fakeBreakpointAtPrimaryLocation(); | |
628 var targetBreakpoints = this._targetBreakpoints.values(); | |
629 for (var i = 0; i < targetBreakpoints.length; ++i) | |
630 targetBreakpoints[i]._scheduleUpdateInDebugger(); | |
631 }, | |
632 | |
633 /** | |
634 * @param {boolean=} keepInStorage | |
635 */ | |
636 remove: function(keepInStorage) | |
637 { | |
638 | |
639 this._isRemoved = true; | |
640 var removeFromStorage = !keepInStorage; | |
641 this._removeFakeBreakpointAtPrimaryLocation(); | |
642 var targetBreakpoints = this._targetBreakpoints.values(); | |
643 for (var i = 0; i < targetBreakpoints.length; ++i) { | |
644 targetBreakpoints[i]._scheduleUpdateInDebugger(); | |
645 targetBreakpoints[i]._removeEventListeners(); | |
646 } | |
647 | |
648 this._breakpointManager._removeBreakpoint(this, removeFromStorage); | |
649 this._breakpointManager._targetManager.unobserveTargets(this); | |
650 }, | |
651 | |
652 /** | |
653 * @param {!WebInspector.Target} target | |
654 */ | |
655 _updateInDebuggerForTarget: function(target) | |
656 { | |
657 this._targetBreakpoints.get(target)._scheduleUpdateInDebugger(); | |
658 }, | |
659 | |
660 /** | |
661 * @return {string} | |
662 */ | |
663 _breakpointStorageId: function() | |
664 { | |
665 return WebInspector.BreakpointManager._breakpointStorageId(this._sourceF
ileId, this._lineNumber, this._columnNumber); | |
666 }, | |
667 | |
668 _fakeBreakpointAtPrimaryLocation: function() | |
669 { | |
670 if (this._isRemoved || !Object.isEmpty(this._numberOfDebuggerLocationFor
UILocation) || this._fakePrimaryLocation) | |
671 return; | |
672 | |
673 var uiSourceCode = this._breakpointManager._workspace.uiSourceCode(this.
_projectId, this._path); | |
674 if (!uiSourceCode) | |
675 return; | |
676 | |
677 this._fakePrimaryLocation = uiSourceCode.uiLocation(this._lineNumber, th
is._columnNumber); | |
678 this._breakpointManager._uiLocationAdded(this, this._fakePrimaryLocation
); | |
679 }, | |
680 | |
681 _removeFakeBreakpointAtPrimaryLocation: function() | |
682 { | |
683 if (this._fakePrimaryLocation) { | |
684 this._breakpointManager._uiLocationRemoved(this, this._fakePrimaryLo
cation); | |
685 delete this._fakePrimaryLocation; | |
686 } | |
687 }, | |
688 | |
689 _resetLocations: function() | |
690 { | |
691 this._removeFakeBreakpointAtPrimaryLocation(); | |
692 var targetBreakpoints = this._targetBreakpoints.values(); | |
693 for (var i = 0; i < targetBreakpoints.length; ++i) | |
694 targetBreakpoints[i]._resetLocations(); | |
695 } | |
696 } | |
697 | |
698 /** | |
699 * @constructor | |
700 * @extends {WebInspector.SDKObject} | |
701 * @param {!WebInspector.Target} target | |
702 * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint | |
703 * @param {!WebInspector.DebuggerWorkspaceBinding} debuggerWorkspaceBinding | |
704 */ | |
705 WebInspector.BreakpointManager.TargetBreakpoint = function(target, breakpoint, d
ebuggerWorkspaceBinding) | |
706 { | |
707 WebInspector.SDKObject.call(this, target); | |
708 this._breakpoint = breakpoint; | |
709 this._debuggerWorkspaceBinding = debuggerWorkspaceBinding; | |
710 | |
711 /** @type {!Array.<!WebInspector.DebuggerWorkspaceBinding.Location>} */ | |
712 this._liveLocations = []; | |
713 | |
714 /** @type {!Object.<string, !WebInspector.UILocation>} */ | |
715 this._uiLocations = {}; | |
716 target.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.Debu
ggerWasDisabled, this._cleanUpAfterDebuggerIsGone, this); | |
717 target.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.Debu
ggerWasEnabled, this._scheduleUpdateInDebugger, this); | |
718 this._hasPendingUpdate = false; | |
719 this._isUpdating = false; | |
720 this._cancelCallback = false; | |
721 this._currentState = null; | |
722 if (target.debuggerModel.debuggerEnabled()) | |
723 this._scheduleUpdateInDebugger(); | |
724 } | |
725 | |
726 WebInspector.BreakpointManager.TargetBreakpoint.prototype = { | |
727 | |
728 /** | |
729 * @return {!WebInspector.DebuggerModel} | |
730 */ | |
731 _debuggerModel: function() | |
732 { | |
733 return this.target().debuggerModel; | |
734 }, | |
735 | |
736 _resetLocations: function() | |
737 { | |
738 var uiLocations = Object.values(this._uiLocations); | |
739 for (var i = 0; i < uiLocations.length; ++i) | |
740 this._breakpoint._removeUILocation(uiLocations[i]); | |
741 | |
742 this._uiLocations = {}; | |
743 | |
744 for (var i = 0; i < this._liveLocations.length; ++i) | |
745 this._liveLocations[i].dispose(); | |
746 this._liveLocations = []; | |
747 }, | |
748 | |
749 _scheduleUpdateInDebugger: function() | |
750 { | |
751 if (this._isUpdating) { | |
752 this._hasPendingUpdate = true; | |
753 return; | |
754 } | |
755 | |
756 this._isUpdating = true; | |
757 this._updateInDebugger(this._didUpdateInDebugger.bind(this)); | |
758 }, | |
759 | |
760 _didUpdateInDebugger: function() | |
761 { | |
762 this._isUpdating = false; | |
763 if (this._hasPendingUpdate) { | |
764 this._hasPendingUpdate = false; | |
765 this._scheduleUpdateInDebugger(); | |
766 } | |
767 }, | |
768 | |
769 /** | |
770 * @return {boolean} | |
771 */ | |
772 _scriptDiverged: function() | |
773 { | |
774 var uiSourceCode = this._breakpoint.uiSourceCode(); | |
775 if (!uiSourceCode) | |
776 return false; | |
777 var scriptFile = this._debuggerWorkspaceBinding.scriptFile(uiSourceCode,
this.target()); | |
778 return !!scriptFile && scriptFile.hasDivergedFromVM(); | |
779 | |
780 }, | |
781 | |
782 /** | |
783 * @param {function()} callback | |
784 */ | |
785 _updateInDebugger: function(callback) | |
786 { | |
787 if (this.target().isDetached()) { | |
788 this._cleanUpAfterDebuggerIsGone(); | |
789 callback(); | |
790 return; | |
791 } | |
792 | |
793 var uiSourceCode = this._breakpoint.uiSourceCode(); | |
794 var lineNumber = this._breakpoint._lineNumber; | |
795 var columnNumber = this._breakpoint._columnNumber; | |
796 var condition = this._breakpoint.condition(); | |
797 | |
798 var debuggerLocation = uiSourceCode ? this._debuggerWorkspaceBinding.uiL
ocationToRawLocation(this.target(), uiSourceCode, lineNumber, columnNumber) : nu
ll; | |
799 var newState; | |
800 if (this._breakpoint._isRemoved || !this._breakpoint.enabled() || this._
scriptDiverged()) | |
801 newState = null; | |
802 else if (debuggerLocation) { | |
803 var script = debuggerLocation.script(); | |
804 if (script.sourceURL) | |
805 newState = new WebInspector.BreakpointManager.Breakpoint.State(s
cript.sourceURL, null, debuggerLocation.lineNumber, debuggerLocation.columnNumbe
r, condition); | |
806 else | |
807 newState = new WebInspector.BreakpointManager.Breakpoint.State(n
ull, debuggerLocation.scriptId, debuggerLocation.lineNumber, debuggerLocation.co
lumnNumber, condition) | |
808 } else if (this._breakpoint._currentState && this._breakpoint._currentSt
ate.url) { | |
809 var position = this._breakpoint._currentState; | |
810 newState = new WebInspector.BreakpointManager.Breakpoint.State(posit
ion.url, null, position.lineNumber, position.columnNumber, condition); | |
811 } else if (uiSourceCode && uiSourceCode.url) | |
812 newState = new WebInspector.BreakpointManager.Breakpoint.State(uiSou
rceCode.url, null, lineNumber, columnNumber, condition); | |
813 | |
814 if (this._debuggerId && WebInspector.BreakpointManager.Breakpoint.State.
equals(newState, this._currentState)) { | |
815 callback(); | |
816 return; | |
817 } | |
818 | |
819 this._breakpoint._currentState = newState; | |
820 | |
821 if (this._debuggerId) { | |
822 this._resetLocations(); | |
823 this._debuggerModel().removeBreakpoint(this._debuggerId, this._didRe
moveFromDebugger.bind(this, callback)); | |
824 this._scheduleUpdateInDebugger(); | |
825 this._currentState = null; | |
826 return; | |
827 } | |
828 | |
829 if (!newState) { | |
830 callback(); | |
831 return; | |
832 } | |
833 | |
834 var updateCallback = this._didSetBreakpointInDebugger.bind(this, callbac
k); | |
835 if (newState.url) | |
836 this._debuggerModel().setBreakpointByURL(newState.url, newState.line
Number, newState.columnNumber, this._breakpoint.condition(), updateCallback); | |
837 else if (newState.scriptId) | |
838 this._debuggerModel().setBreakpointBySourceId(/** @type {!WebInspect
or.DebuggerModel.Location} */ (debuggerLocation), condition, updateCallback); | |
839 | |
840 this._currentState = newState; | |
841 }, | |
842 | |
843 /** | |
844 * @param {function()} callback | |
845 * @param {?DebuggerAgent.BreakpointId} breakpointId | |
846 * @param {!Array.<!WebInspector.DebuggerModel.Location>} locations | |
847 */ | |
848 _didSetBreakpointInDebugger: function(callback, breakpointId, locations) | |
849 { | |
850 if (this._cancelCallback) { | |
851 this._cancelCallback = false; | |
852 callback(); | |
853 return; | |
854 } | |
855 | |
856 if (!breakpointId) { | |
857 this._breakpoint.remove(true); | |
858 callback(); | |
859 return; | |
860 } | |
861 | |
862 this._debuggerId = breakpointId; | |
863 this.target().debuggerModel.addBreakpointListener(this._debuggerId, this
._breakpointResolved, this); | |
864 for (var i = 0; i < locations.length; ++i) { | |
865 if (!this._addResolvedLocation(locations[i])) | |
866 break; | |
867 } | |
868 callback(); | |
869 }, | |
870 | |
871 /** | |
872 * @param {function()} callback | |
873 */ | |
874 _didRemoveFromDebugger: function(callback) | |
875 { | |
876 if (this._cancelCallback) { | |
877 this._cancelCallback = false; | |
878 callback(); | |
879 return; | |
880 } | |
881 | |
882 this._resetLocations(); | |
883 this.target().debuggerModel.removeBreakpointListener(this._debuggerId, t
his._breakpointResolved, this); | |
884 delete this._debuggerId; | |
885 callback(); | |
886 }, | |
887 | |
888 /** | |
889 * @param {!WebInspector.Event} event | |
890 */ | |
891 _breakpointResolved: function(event) | |
892 { | |
893 this._addResolvedLocation(/** @type {!WebInspector.DebuggerModel.Locatio
n}*/ (event.data)); | |
894 }, | |
895 | |
896 /** | |
897 * @param {!WebInspector.DebuggerModel.Location} location | |
898 * @param {!WebInspector.UILocation} uiLocation | |
899 */ | |
900 _locationUpdated: function(location, uiLocation) | |
901 { | |
902 var oldUILocation = this._uiLocations[location.id()] || null; | |
903 this._uiLocations[location.id()] = uiLocation; | |
904 this._breakpoint._replaceUILocation(oldUILocation, uiLocation); | |
905 }, | |
906 | |
907 /** | |
908 * @param {!WebInspector.DebuggerModel.Location} location | |
909 * @return {boolean} | |
910 */ | |
911 _addResolvedLocation: function(location) | |
912 { | |
913 var uiLocation = this._debuggerWorkspaceBinding.rawLocationToUILocation(
location); | |
914 var breakpoint = this._breakpoint._breakpointManager.findBreakpoint(uiLo
cation.uiSourceCode, uiLocation.lineNumber, uiLocation.columnNumber); | |
915 if (breakpoint && breakpoint !== this._breakpoint) { | |
916 // location clash | |
917 this._breakpoint.remove(); | |
918 return false; | |
919 } | |
920 this._liveLocations.push(this._debuggerWorkspaceBinding.createLiveLocati
on(location, this._locationUpdated.bind(this, location))); | |
921 return true; | |
922 }, | |
923 | |
924 _cleanUpAfterDebuggerIsGone: function() | |
925 { | |
926 if (this._isUpdating) | |
927 this._cancelCallback = true; | |
928 | |
929 this._resetLocations(); | |
930 this._currentState = null; | |
931 if (this._debuggerId) | |
932 this._didRemoveFromDebugger(function() {}); | |
933 }, | |
934 | |
935 _removeEventListeners: function() | |
936 { | |
937 this.target().debuggerModel.removeEventListener(WebInspector.DebuggerMod
el.Events.DebuggerWasDisabled, this._cleanUpAfterDebuggerIsGone, this); | |
938 this.target().debuggerModel.removeEventListener(WebInspector.DebuggerMod
el.Events.DebuggerWasEnabled, this._scheduleUpdateInDebugger, this); | |
939 }, | |
940 | |
941 __proto__: WebInspector.SDKObject.prototype | |
942 } | |
943 | |
944 /** | |
945 * @constructor | |
946 * @param {?string} url | |
947 * @param {?string} scriptId | |
948 * @param {number} lineNumber | |
949 * @param {number} columnNumber | |
950 * @param {string} condition | |
951 */ | |
952 WebInspector.BreakpointManager.Breakpoint.State = function(url, scriptId, lineNu
mber, columnNumber, condition) | |
953 { | |
954 this.url = url; | |
955 this.scriptId = scriptId; | |
956 this.lineNumber = lineNumber; | |
957 this.columnNumber = columnNumber; | |
958 this.condition = condition; | |
959 } | |
960 | |
961 /** | |
962 * @param {?WebInspector.BreakpointManager.Breakpoint.State|undefined} stateA | |
963 * @param {?WebInspector.BreakpointManager.Breakpoint.State|undefined} stateB | |
964 * @return {boolean} | |
965 */ | |
966 WebInspector.BreakpointManager.Breakpoint.State.equals = function(stateA, stateB
) | |
967 { | |
968 if (!stateA || !stateB) | |
969 return false; | |
970 | |
971 if (stateA.scriptId || stateB.scriptId) | |
972 return false; | |
973 | |
974 return stateA.url === stateB.url && stateA.lineNumber === stateB.lineNumber
&& stateA.columnNumber === stateB.columnNumber && stateA.condition === stateB.co
ndition; | |
975 } | |
976 | |
977 /** | |
978 * @constructor | |
979 * @param {!WebInspector.BreakpointManager} breakpointManager | |
980 * @param {!WebInspector.Setting} setting | |
981 */ | |
982 WebInspector.BreakpointManager.Storage = function(breakpointManager, setting) | |
983 { | |
984 this._breakpointManager = breakpointManager; | |
985 this._setting = setting; | |
986 var breakpoints = this._setting.get(); | |
987 /** @type {!Object.<string, !WebInspector.BreakpointManager.Storage.Item>} *
/ | |
988 this._breakpoints = {}; | |
989 for (var i = 0; i < breakpoints.length; ++i) { | |
990 var breakpoint = /** @type {!WebInspector.BreakpointManager.Storage.Item
} */ (breakpoints[i]); | |
991 breakpoint.columnNumber = breakpoint.columnNumber || 0; | |
992 this._breakpoints[breakpoint.sourceFileId + ":" + breakpoint.lineNumber
+ ":" + breakpoint.columnNumber] = breakpoint; | |
993 } | |
994 } | |
995 | |
996 WebInspector.BreakpointManager.Storage.prototype = { | |
997 mute: function() | |
998 { | |
999 this._muted = true; | |
1000 }, | |
1001 | |
1002 unmute: function() | |
1003 { | |
1004 delete this._muted; | |
1005 }, | |
1006 | |
1007 /** | |
1008 * @param {!WebInspector.UISourceCode} uiSourceCode | |
1009 * @return {!Array.<!WebInspector.BreakpointManager.Storage.Item>} | |
1010 */ | |
1011 breakpointItems: function(uiSourceCode) | |
1012 { | |
1013 var result = []; | |
1014 var sourceFileId = WebInspector.BreakpointManager._sourceFileId(uiSource
Code); | |
1015 for (var id in this._breakpoints) { | |
1016 var breakpoint = this._breakpoints[id]; | |
1017 if (breakpoint.sourceFileId === sourceFileId) | |
1018 result.push(breakpoint); | |
1019 } | |
1020 return result; | |
1021 }, | |
1022 | |
1023 /** | |
1024 * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint | |
1025 */ | |
1026 _updateBreakpoint: function(breakpoint) | |
1027 { | |
1028 if (this._muted || !breakpoint._breakpointStorageId()) | |
1029 return; | |
1030 this._breakpoints[breakpoint._breakpointStorageId()] = new WebInspector.
BreakpointManager.Storage.Item(breakpoint); | |
1031 this._save(); | |
1032 }, | |
1033 | |
1034 /** | |
1035 * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint | |
1036 */ | |
1037 _removeBreakpoint: function(breakpoint) | |
1038 { | |
1039 if (this._muted) | |
1040 return; | |
1041 delete this._breakpoints[breakpoint._breakpointStorageId()]; | |
1042 this._save(); | |
1043 }, | |
1044 | |
1045 _save: function() | |
1046 { | |
1047 var breakpointsArray = []; | |
1048 for (var id in this._breakpoints) | |
1049 breakpointsArray.push(this._breakpoints[id]); | |
1050 this._setting.set(breakpointsArray); | |
1051 } | |
1052 } | |
1053 | |
1054 /** | |
1055 * @constructor | |
1056 * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint | |
1057 */ | |
1058 WebInspector.BreakpointManager.Storage.Item = function(breakpoint) | |
1059 { | |
1060 this.sourceFileId = breakpoint._sourceFileId; | |
1061 this.lineNumber = breakpoint.lineNumber(); | |
1062 this.columnNumber = breakpoint.columnNumber(); | |
1063 this.condition = breakpoint.condition(); | |
1064 this.enabled = breakpoint.enabled(); | |
1065 } | |
1066 | |
1067 /** @type {!WebInspector.BreakpointManager} */ | |
1068 WebInspector.breakpointManager; | |
OLD | NEW |