Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / devtools / front_end / bindings / BreakpointManager.js
blobad89c0f14595fa77a169232230fddc7029ab6b16
1 /*
2 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
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.
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.
31 /**
32 * @constructor
33 * @extends {WebInspector.Object}
34 * @implements {WebInspector.TargetManager.Observer}
35 * @param {?WebInspector.Setting} breakpointsSetting
36 * @param {!WebInspector.Workspace} workspace
37 * @param {!WebInspector.NetworkMapping} networkMapping
38 * @param {!WebInspector.TargetManager} targetManager
39 * @param {!WebInspector.DebuggerWorkspaceBinding} debuggerWorkspaceBinding
41 WebInspector.BreakpointManager = function(breakpointsSetting, workspace, networkMapping, targetManager, debuggerWorkspaceBinding)
43 this._storage = new WebInspector.BreakpointManager.Storage(this, breakpointsSetting);
44 this._workspace = workspace;
45 this._networkMapping = networkMapping;
46 this._targetManager = targetManager;
47 this._debuggerWorkspaceBinding = debuggerWorkspaceBinding;
49 this._breakpointsActive = true;
50 this._breakpointsForUISourceCode = new Map();
51 this._breakpointsForPrimaryUISourceCode = new Map();
52 /** @type {!Multimap.<string, !WebInspector.BreakpointManager.Breakpoint>} */
53 this._provisionalBreakpoints = new Multimap();
55 this._workspace.addEventListener(WebInspector.Workspace.Events.ProjectRemoved, this._projectRemoved, this);
56 this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAdded, this);
57 this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeRemoved, this._uiSourceCodeRemoved, this);
60 WebInspector.BreakpointManager.Events = {
61 BreakpointAdded: "breakpoint-added",
62 BreakpointRemoved: "breakpoint-removed",
63 BreakpointsActiveStateChanged: "BreakpointsActiveStateChanged"
66 /**
67 * @param {string} sourceFileId
68 * @param {number} lineNumber
69 * @param {number} columnNumber
70 * @return {string}
72 WebInspector.BreakpointManager._breakpointStorageId = function(sourceFileId, lineNumber, columnNumber)
74 if (!sourceFileId)
75 return "";
76 return sourceFileId + ":" + lineNumber + ":" + columnNumber;
79 WebInspector.BreakpointManager.prototype = {
80 /**
81 * @param {!WebInspector.UISourceCode} uiSourceCode
82 * @return {string}
84 _sourceFileId: function(uiSourceCode)
86 var networkURL = this._networkMapping.networkURL(uiSourceCode)
87 if (!networkURL)
88 return "";
89 return uiSourceCode.uri();
92 /**
93 * @override
94 * @param {!WebInspector.Target} target
96 targetAdded: function(target)
98 var debuggerModel = WebInspector.DebuggerModel.fromTarget(target);
99 if (debuggerModel && !this._breakpointsActive)
100 debuggerModel.setBreakpointsActive(this._breakpointsActive);
104 * @override
105 * @param {!WebInspector.Target} target
107 targetRemoved: function(target) { },
110 * @param {string} sourceFileId
111 * @return {!Map.<string, !WebInspector.BreakpointManager.Breakpoint>}
113 _provisionalBreakpointsForSourceFileId: function(sourceFileId)
115 var result = new Map();
116 var breakpoints = this._provisionalBreakpoints.get(sourceFileId).valuesArray();
117 for (var i = 0; i < breakpoints.length; ++i)
118 result.set(breakpoints[i]._breakpointStorageId(), breakpoints[i]);
119 return result;
122 removeProvisionalBreakpointsForTest: function()
124 var breakpoints = this._provisionalBreakpoints.valuesArray();
125 for (var i = 0; i < breakpoints.length; ++i)
126 breakpoints[i].remove();
127 this._provisionalBreakpoints.clear();
131 * @param {!WebInspector.UISourceCode} uiSourceCode
133 _restoreBreakpoints: function(uiSourceCode)
135 var sourceFileId = this._sourceFileId(uiSourceCode);
136 if (!sourceFileId)
137 return;
139 this._storage.mute();
140 var breakpointItems = this._storage.breakpointItems(this._sourceFileId(uiSourceCode));
141 var provisionalBreakpoints = this._provisionalBreakpointsForSourceFileId(sourceFileId);
142 for (var i = 0; i < breakpointItems.length; ++i) {
143 var breakpointItem = breakpointItems[i];
144 var itemStorageId = WebInspector.BreakpointManager._breakpointStorageId(breakpointItem.sourceFileId, breakpointItem.lineNumber, breakpointItem.columnNumber);
145 var provisionalBreakpoint = provisionalBreakpoints.get(itemStorageId);
146 if (provisionalBreakpoint) {
147 if (!this._breakpointsForPrimaryUISourceCode.get(uiSourceCode))
148 this._breakpointsForPrimaryUISourceCode.set(uiSourceCode, []);
149 this._breakpointsForPrimaryUISourceCode.get(uiSourceCode).push(provisionalBreakpoint);
150 provisionalBreakpoint._updateBreakpoint();
151 } else {
152 this._innerSetBreakpoint(uiSourceCode, breakpointItem.lineNumber, breakpointItem.columnNumber, breakpointItem.condition, breakpointItem.enabled);
155 this._provisionalBreakpoints.removeAll(sourceFileId);
156 this._storage.unmute();
160 * @param {!WebInspector.Event} event
162 _uiSourceCodeAdded: function(event)
164 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
165 this._restoreBreakpoints(uiSourceCode);
166 if (uiSourceCode.contentType() === WebInspector.resourceTypes.Script || uiSourceCode.contentType() === WebInspector.resourceTypes.Document)
167 uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.SourceMappingChanged, this._uiSourceCodeMappingChanged, this);
171 * @param {!WebInspector.Event} event
173 _uiSourceCodeRemoved: function(event)
175 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
176 this._removeUISourceCode(uiSourceCode);
180 * @param {!WebInspector.Event} event
182 _uiSourceCodeMappingChanged: function(event)
184 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.target);
185 var isIdentity = /** @type {boolean} */ (event.data.isIdentity);
186 var target = /** @type {!WebInspector.Target} */ (event.data.target);
187 if (isIdentity)
188 return;
189 var breakpoints = this._breakpointsForPrimaryUISourceCode.get(uiSourceCode) || [];
190 for (var i = 0; i < breakpoints.length; ++i)
191 breakpoints[i]._updateInDebuggerForTarget(target);
195 * @param {!WebInspector.UISourceCode} uiSourceCode
197 _removeUISourceCode: function(uiSourceCode)
199 var breakpoints = this._breakpointsForPrimaryUISourceCode.get(uiSourceCode) || [];
200 var sourceFileId = this._sourceFileId(uiSourceCode);
201 for (var i = 0; i < breakpoints.length; ++i) {
202 breakpoints[i]._resetLocations();
203 if (breakpoints[i].enabled())
204 this._provisionalBreakpoints.set(sourceFileId, breakpoints[i]);
206 uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.SourceMappingChanged, this._uiSourceCodeMappingChanged, this);
207 this._breakpointsForPrimaryUISourceCode.remove(uiSourceCode);
211 * @param {!WebInspector.UISourceCode} uiSourceCode
212 * @param {number} lineNumber
213 * @param {number} columnNumber
214 * @param {string} condition
215 * @param {boolean} enabled
216 * @return {!WebInspector.BreakpointManager.Breakpoint}
218 setBreakpoint: function(uiSourceCode, lineNumber, columnNumber, condition, enabled)
220 var uiLocation = new WebInspector.UILocation(uiSourceCode, lineNumber, columnNumber);
221 var normalizedLocation = this._debuggerWorkspaceBinding.normalizeUILocation(uiLocation);
222 if (normalizedLocation.id() !== uiLocation.id()) {
223 WebInspector.Revealer.reveal(normalizedLocation);
224 uiLocation = normalizedLocation;
226 this.setBreakpointsActive(true);
227 return this._innerSetBreakpoint(uiLocation.uiSourceCode, uiLocation.lineNumber, uiLocation.columnNumber, condition, enabled);
231 * @param {!WebInspector.UISourceCode} uiSourceCode
232 * @param {number} lineNumber
233 * @param {number} columnNumber
234 * @param {string} condition
235 * @param {boolean} enabled
236 * @return {!WebInspector.BreakpointManager.Breakpoint}
238 _innerSetBreakpoint: function(uiSourceCode, lineNumber, columnNumber, condition, enabled)
240 var breakpoint = this.findBreakpoint(uiSourceCode, lineNumber, columnNumber);
241 if (breakpoint) {
242 breakpoint._updateState(condition, enabled);
243 return breakpoint;
245 var projectId = uiSourceCode.project().id();
246 var path = uiSourceCode.path();
247 var sourceFileId = this._sourceFileId(uiSourceCode);
248 breakpoint = new WebInspector.BreakpointManager.Breakpoint(this, projectId, path, sourceFileId, lineNumber, columnNumber, condition, enabled);
249 if (!this._breakpointsForPrimaryUISourceCode.get(uiSourceCode))
250 this._breakpointsForPrimaryUISourceCode.set(uiSourceCode, []);
251 this._breakpointsForPrimaryUISourceCode.get(uiSourceCode).push(breakpoint);
252 return breakpoint;
256 * @param {!WebInspector.UISourceCode} uiSourceCode
257 * @param {number} lineNumber
258 * @param {number} columnNumber
259 * @return {?WebInspector.BreakpointManager.Breakpoint}
261 findBreakpoint: function(uiSourceCode, lineNumber, columnNumber)
263 var breakpoints = this._breakpointsForUISourceCode.get(uiSourceCode);
264 var lineBreakpoints = breakpoints ? breakpoints.get(String(lineNumber)) : null;
265 var columnBreakpoints = lineBreakpoints ? lineBreakpoints.get(String(columnNumber)) : null;
266 return columnBreakpoints ? columnBreakpoints[0] : null;
270 * @param {!WebInspector.UISourceCode} uiSourceCode
271 * @param {number} lineNumber
272 * @return {?WebInspector.BreakpointManager.Breakpoint}
274 findBreakpointOnLine: function(uiSourceCode, lineNumber)
276 var breakpoints = this._breakpointsForUISourceCode.get(uiSourceCode);
277 var lineBreakpoints = breakpoints ? breakpoints.get(String(lineNumber)) : null;
278 return lineBreakpoints ? lineBreakpoints.valuesArray()[0][0] : null;
282 * @param {!WebInspector.UISourceCode} uiSourceCode
283 * @return {!Array.<!WebInspector.BreakpointManager.Breakpoint>}
285 breakpointsForUISourceCode: function(uiSourceCode)
287 var result = [];
288 var uiSourceCodeBreakpoints = this._breakpointsForUISourceCode.get(uiSourceCode);
289 var breakpoints = uiSourceCodeBreakpoints ? uiSourceCodeBreakpoints.valuesArray() : [];
290 for (var i = 0; i < breakpoints.length; ++i) {
291 var lineBreakpoints = breakpoints[i];
292 var columnBreakpointArrays = lineBreakpoints ? lineBreakpoints.valuesArray() : [];
293 result = result.concat.apply(result, columnBreakpointArrays);
295 return result;
299 * @return {!Array.<!WebInspector.BreakpointManager.Breakpoint>}
301 allBreakpoints: function()
303 var result = [];
304 var uiSourceCodes = this._breakpointsForUISourceCode.keysArray();
305 for (var i = 0; i < uiSourceCodes.length; ++i)
306 result = result.concat(this.breakpointsForUISourceCode(uiSourceCodes[i]));
307 return result;
311 * @param {!WebInspector.UISourceCode} uiSourceCode
312 * @return {!Array.<!{breakpoint: !WebInspector.BreakpointManager.Breakpoint, uiLocation: !WebInspector.UILocation}>}
314 breakpointLocationsForUISourceCode: function(uiSourceCode)
316 var uiSourceCodeBreakpoints = this._breakpointsForUISourceCode.get(uiSourceCode);
317 var lineNumbers = uiSourceCodeBreakpoints ? uiSourceCodeBreakpoints.keysArray() : [];
318 var result = [];
319 for (var i = 0; i < lineNumbers.length; ++i) {
320 var lineBreakpoints = uiSourceCodeBreakpoints.get(lineNumbers[i]);
321 var columnNumbers = lineBreakpoints.keysArray();
322 for (var j = 0; j < columnNumbers.length; ++j) {
323 var columnBreakpoints = lineBreakpoints.get(columnNumbers[j]);
324 var lineNumber = parseInt(lineNumbers[i], 10);
325 var columnNumber = parseInt(columnNumbers[j], 10);
326 for (var k = 0; k < columnBreakpoints.length; ++k) {
327 var breakpoint = columnBreakpoints[k];
328 var uiLocation = uiSourceCode.uiLocation(lineNumber, columnNumber);
329 result.push({breakpoint: breakpoint, uiLocation: uiLocation});
333 return result;
337 * @return {!Array.<!{breakpoint: !WebInspector.BreakpointManager.Breakpoint, uiLocation: !WebInspector.UILocation}>}
339 allBreakpointLocations: function()
341 var result = [];
342 var uiSourceCodes = this._breakpointsForUISourceCode.keysArray();
343 for (var i = 0; i < uiSourceCodes.length; ++i)
344 result = result.concat(this.breakpointLocationsForUISourceCode(uiSourceCodes[i]));
345 return result;
349 * @param {boolean} toggleState
351 toggleAllBreakpoints: function(toggleState)
353 var breakpoints = this.allBreakpoints();
354 for (var i = 0; i < breakpoints.length; ++i)
355 breakpoints[i].setEnabled(toggleState);
358 removeAllBreakpoints: function()
360 var breakpoints = this.allBreakpoints();
361 for (var i = 0; i < breakpoints.length; ++i)
362 breakpoints[i].remove();
365 _projectRemoved: function(event)
367 var project = /** @type {!WebInspector.Project} */ (event.data);
368 var uiSourceCodes = project.uiSourceCodes();
369 for (var i = 0; i < uiSourceCodes.length; ++i)
370 this._removeUISourceCode(uiSourceCodes[i]);
374 * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
375 * @param {boolean} removeFromStorage
377 _removeBreakpoint: function(breakpoint, removeFromStorage)
379 var uiSourceCode = breakpoint.uiSourceCode();
380 var breakpoints = uiSourceCode ? this._breakpointsForPrimaryUISourceCode.get(uiSourceCode) || [] : [];
381 breakpoints.remove(breakpoint);
382 if (removeFromStorage)
383 this._storage._removeBreakpoint(breakpoint);
384 this._provisionalBreakpoints.remove(breakpoint._sourceFileId, breakpoint);
388 * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
389 * @param {!WebInspector.UILocation} uiLocation
391 _uiLocationAdded: function(breakpoint, uiLocation)
393 var breakpoints = this._breakpointsForUISourceCode.get(uiLocation.uiSourceCode);
394 if (!breakpoints) {
395 breakpoints = new Map();
396 this._breakpointsForUISourceCode.set(uiLocation.uiSourceCode, breakpoints);
398 var lineBreakpoints = breakpoints.get(String(uiLocation.lineNumber));
399 if (!lineBreakpoints) {
400 lineBreakpoints = new Map();
401 breakpoints.set(String(uiLocation.lineNumber), lineBreakpoints);
403 var columnBreakpoints = lineBreakpoints.get(String(uiLocation.columnNumber));
404 if (!columnBreakpoints) {
405 columnBreakpoints = [];
406 lineBreakpoints.set(String(uiLocation.columnNumber), columnBreakpoints);
408 columnBreakpoints.push(breakpoint);
409 this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.BreakpointAdded, {breakpoint: breakpoint, uiLocation: uiLocation});
413 * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
414 * @param {!WebInspector.UILocation} uiLocation
416 _uiLocationRemoved: function(breakpoint, uiLocation)
418 var breakpoints = this._breakpointsForUISourceCode.get(uiLocation.uiSourceCode);
419 if (!breakpoints)
420 return;
422 var lineBreakpoints = breakpoints.get(String(uiLocation.lineNumber));
423 if (!lineBreakpoints)
424 return;
425 var columnBreakpoints = lineBreakpoints.get(String(uiLocation.columnNumber));
426 if (!columnBreakpoints)
427 return;
428 columnBreakpoints.remove(breakpoint);
429 if (!columnBreakpoints.length)
430 lineBreakpoints.remove(String(uiLocation.columnNumber));
431 if (!lineBreakpoints.size)
432 breakpoints.remove(String(uiLocation.lineNumber));
433 if (!breakpoints.size)
434 this._breakpointsForUISourceCode.remove(uiLocation.uiSourceCode);
435 this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.BreakpointRemoved, {breakpoint: breakpoint, uiLocation: uiLocation});
439 * @param {boolean} active
441 setBreakpointsActive: function(active)
443 if (this._breakpointsActive === active)
444 return;
446 this._breakpointsActive = active;
447 var debuggerModels = WebInspector.DebuggerModel.instances();
448 for (var i = 0; i < debuggerModels.length; ++i)
449 debuggerModels[i].setBreakpointsActive(active);
451 this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.BreakpointsActiveStateChanged, active);
455 * @return {boolean}
457 breakpointsActive: function()
459 return this._breakpointsActive;
462 __proto__: WebInspector.Object.prototype
466 * @constructor
467 * @implements {WebInspector.TargetManager.Observer}
468 * @param {!WebInspector.BreakpointManager} breakpointManager
469 * @param {string} projectId
470 * @param {string} path
471 * @param {string} sourceFileId
472 * @param {number} lineNumber
473 * @param {number} columnNumber
474 * @param {string} condition
475 * @param {boolean} enabled
477 WebInspector.BreakpointManager.Breakpoint = function(breakpointManager, projectId, path, sourceFileId, lineNumber, columnNumber, condition, enabled)
479 this._breakpointManager = breakpointManager;
480 this._projectId = projectId;
481 this._path = path;
482 this._lineNumber = lineNumber;
483 this._columnNumber = columnNumber;
484 this._sourceFileId = sourceFileId;
486 /** @type {!Object.<string, number>} */
487 this._numberOfDebuggerLocationForUILocation = {};
489 // Force breakpoint update.
490 /** @type {string} */ this._condition;
491 /** @type {boolean} */ this._enabled;
492 /** @type {boolean} */ this._isRemoved;
493 /** @type {!WebInspector.UILocation|undefined} */ this._fakePrimaryLocation;
495 this._currentState = null;
496 /** @type {!Map.<!WebInspector.Target, !WebInspector.BreakpointManager.TargetBreakpoint>}*/
497 this._targetBreakpoints = new Map();
498 this._updateState(condition, enabled);
499 this._breakpointManager._targetManager.observeTargets(this);
502 WebInspector.BreakpointManager.Breakpoint.prototype = {
504 * @override
505 * @param {!WebInspector.Target} target
507 targetAdded: function(target)
509 var debuggerModel = WebInspector.DebuggerModel.fromTarget(target);
510 if (!debuggerModel)
511 return;
512 var networkMapping = this._breakpointManager._networkMapping;
513 var debuggerWorkspaceBinding = this._breakpointManager._debuggerWorkspaceBinding;
514 this._targetBreakpoints.set(target, new WebInspector.BreakpointManager.TargetBreakpoint(debuggerModel, this, networkMapping, debuggerWorkspaceBinding));
518 * @override
519 * @param {!WebInspector.Target} target
521 targetRemoved: function(target)
523 var debuggerModel = WebInspector.DebuggerModel.fromTarget(target);
524 if (!debuggerModel)
525 return;
526 var targetBreakpoint = this._targetBreakpoints.remove(target);
527 targetBreakpoint._cleanUpAfterDebuggerIsGone();
528 targetBreakpoint._removeEventListeners();
532 * @return {string}
534 projectId: function()
536 return this._projectId;
540 * @return {string}
542 path: function()
544 return this._path;
548 * @return {number}
550 lineNumber: function()
552 return this._lineNumber;
556 * @return {number}
558 columnNumber: function()
560 return this._columnNumber;
564 * @return {?WebInspector.UISourceCode}
566 uiSourceCode: function()
568 return this._breakpointManager._workspace.uiSourceCode(this._projectId, this._path);
572 * @param {?WebInspector.UILocation} oldUILocation
573 * @param {!WebInspector.UILocation} newUILocation
575 _replaceUILocation: function(oldUILocation, newUILocation)
577 if (this._isRemoved)
578 return;
580 this._removeUILocation(oldUILocation, true);
581 this._removeFakeBreakpointAtPrimaryLocation();
583 if (!this._numberOfDebuggerLocationForUILocation[newUILocation.id()])
584 this._numberOfDebuggerLocationForUILocation[newUILocation.id()] = 0;
586 if (++this._numberOfDebuggerLocationForUILocation[newUILocation.id()] === 1)
587 this._breakpointManager._uiLocationAdded(this, newUILocation);
591 * @param {?WebInspector.UILocation} uiLocation
592 * @param {boolean=} muteCreationFakeBreakpoint
594 _removeUILocation: function(uiLocation, muteCreationFakeBreakpoint)
596 if (!uiLocation || --this._numberOfDebuggerLocationForUILocation[uiLocation.id()] !== 0)
597 return;
599 delete this._numberOfDebuggerLocationForUILocation[uiLocation.id()];
600 this._breakpointManager._uiLocationRemoved(this, uiLocation);
601 if (!muteCreationFakeBreakpoint)
602 this._fakeBreakpointAtPrimaryLocation();
606 * @return {boolean}
608 enabled: function()
610 return this._enabled;
614 * @param {boolean} enabled
616 setEnabled: function(enabled)
618 this._updateState(this._condition, enabled);
622 * @return {string}
624 condition: function()
626 return this._condition;
630 * @param {string} condition
632 setCondition: function(condition)
634 this._updateState(condition, this._enabled);
638 * @param {string} condition
639 * @param {boolean} enabled
641 _updateState: function(condition, enabled)
643 if (this._enabled === enabled && this._condition === condition)
644 return;
645 this._enabled = enabled;
646 this._condition = condition;
647 this._breakpointManager._storage._updateBreakpoint(this);
648 this._updateBreakpoint();
651 _updateBreakpoint: function()
653 this._removeFakeBreakpointAtPrimaryLocation();
654 this._fakeBreakpointAtPrimaryLocation();
655 var targetBreakpoints = this._targetBreakpoints.valuesArray();
656 for (var i = 0; i < targetBreakpoints.length; ++i)
657 targetBreakpoints[i]._scheduleUpdateInDebugger();
661 * @param {boolean=} keepInStorage
663 remove: function(keepInStorage)
666 this._isRemoved = true;
667 var removeFromStorage = !keepInStorage;
668 this._removeFakeBreakpointAtPrimaryLocation();
669 var targetBreakpoints = this._targetBreakpoints.valuesArray();
670 for (var i = 0; i < targetBreakpoints.length; ++i) {
671 targetBreakpoints[i]._scheduleUpdateInDebugger();
672 targetBreakpoints[i]._removeEventListeners();
675 this._breakpointManager._removeBreakpoint(this, removeFromStorage);
676 this._breakpointManager._targetManager.unobserveTargets(this);
680 * @param {!WebInspector.Target} target
682 _updateInDebuggerForTarget: function(target)
684 this._targetBreakpoints.get(target)._scheduleUpdateInDebugger();
688 * @return {string}
690 _breakpointStorageId: function()
692 return WebInspector.BreakpointManager._breakpointStorageId(this._sourceFileId, this._lineNumber, this._columnNumber);
695 _fakeBreakpointAtPrimaryLocation: function()
697 if (this._isRemoved || !Object.isEmpty(this._numberOfDebuggerLocationForUILocation) || this._fakePrimaryLocation)
698 return;
700 var uiSourceCode = this._breakpointManager._workspace.uiSourceCode(this._projectId, this._path);
701 if (!uiSourceCode)
702 return;
704 this._fakePrimaryLocation = uiSourceCode.uiLocation(this._lineNumber, this._columnNumber);
705 if (this._fakePrimaryLocation)
706 this._breakpointManager._uiLocationAdded(this, this._fakePrimaryLocation);
709 _removeFakeBreakpointAtPrimaryLocation: function()
711 if (this._fakePrimaryLocation) {
712 this._breakpointManager._uiLocationRemoved(this, this._fakePrimaryLocation);
713 delete this._fakePrimaryLocation;
717 _resetLocations: function()
719 this._removeFakeBreakpointAtPrimaryLocation();
720 var targetBreakpoints = this._targetBreakpoints.valuesArray();
721 for (var i = 0; i < targetBreakpoints.length; ++i)
722 targetBreakpoints[i]._resetLocations();
727 * @constructor
728 * @extends {WebInspector.SDKObject}
729 * @param {!WebInspector.DebuggerModel} debuggerModel
730 * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
731 * @param {!WebInspector.NetworkMapping} networkMapping
732 * @param {!WebInspector.DebuggerWorkspaceBinding} debuggerWorkspaceBinding
734 WebInspector.BreakpointManager.TargetBreakpoint = function(debuggerModel, breakpoint, networkMapping, debuggerWorkspaceBinding)
736 WebInspector.SDKObject.call(this, debuggerModel.target());
737 this._debuggerModel = debuggerModel;
738 this._breakpoint = breakpoint;
739 this._networkMapping = networkMapping;
740 this._debuggerWorkspaceBinding = debuggerWorkspaceBinding;
742 /** @type {!Array.<!WebInspector.DebuggerWorkspaceBinding.Location>} */
743 this._liveLocations = [];
745 /** @type {!Object.<string, !WebInspector.UILocation>} */
746 this._uiLocations = {};
747 this._debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerWasDisabled, this._cleanUpAfterDebuggerIsGone, this);
748 this._debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerWasEnabled, this._scheduleUpdateInDebugger, this);
749 this._hasPendingUpdate = false;
750 this._isUpdating = false;
751 this._cancelCallback = false;
752 this._currentState = null;
753 if (this._debuggerModel.debuggerEnabled())
754 this._scheduleUpdateInDebugger();
757 WebInspector.BreakpointManager.TargetBreakpoint.prototype = {
759 _resetLocations: function()
761 var uiLocations = Object.values(this._uiLocations);
762 for (var i = 0; i < uiLocations.length; ++i)
763 this._breakpoint._removeUILocation(uiLocations[i]);
765 this._uiLocations = {};
767 for (var i = 0; i < this._liveLocations.length; ++i)
768 this._liveLocations[i].dispose();
769 this._liveLocations = [];
772 _scheduleUpdateInDebugger: function()
774 if (this._isUpdating) {
775 this._hasPendingUpdate = true;
776 return;
779 this._isUpdating = true;
780 this._updateInDebugger(this._didUpdateInDebugger.bind(this));
783 _didUpdateInDebugger: function()
785 this._isUpdating = false;
786 if (this._hasPendingUpdate) {
787 this._hasPendingUpdate = false;
788 this._scheduleUpdateInDebugger();
793 * @return {boolean}
795 _scriptDiverged: function()
797 var uiSourceCode = this._breakpoint.uiSourceCode();
798 if (!uiSourceCode)
799 return false;
800 var scriptFile = this._debuggerWorkspaceBinding.scriptFile(uiSourceCode, this.target());
801 return !!scriptFile && scriptFile.hasDivergedFromVM();
806 * @param {function()} callback
808 _updateInDebugger: function(callback)
810 if (this.target().isDetached()) {
811 this._cleanUpAfterDebuggerIsGone();
812 callback();
813 return;
816 var uiSourceCode = this._breakpoint.uiSourceCode();
817 var lineNumber = this._breakpoint._lineNumber;
818 var columnNumber = this._breakpoint._columnNumber;
819 var condition = this._breakpoint.condition();
821 var debuggerLocation = uiSourceCode ? this._debuggerWorkspaceBinding.uiLocationToRawLocation(this.target(), uiSourceCode, lineNumber, columnNumber) : null;
822 var newState;
823 if (this._breakpoint._isRemoved || !this._breakpoint.enabled() || this._scriptDiverged())
824 newState = null;
825 else if (debuggerLocation) {
826 var script = debuggerLocation.script();
827 if (script.sourceURL)
828 newState = new WebInspector.BreakpointManager.Breakpoint.State(script.sourceURL, null, debuggerLocation.lineNumber, debuggerLocation.columnNumber, condition);
829 else
830 newState = new WebInspector.BreakpointManager.Breakpoint.State(null, debuggerLocation.scriptId, debuggerLocation.lineNumber, debuggerLocation.columnNumber, condition);
831 } else if (this._breakpoint._currentState && this._breakpoint._currentState.url) {
832 var position = this._breakpoint._currentState;
833 newState = new WebInspector.BreakpointManager.Breakpoint.State(position.url, null, position.lineNumber, position.columnNumber, condition);
834 } else if (uiSourceCode) {
835 var networkURL = this._networkMapping.networkURL(uiSourceCode);
836 if (networkURL)
837 newState = new WebInspector.BreakpointManager.Breakpoint.State(networkURL, null, lineNumber, columnNumber, condition);
839 if (this._debuggerId && WebInspector.BreakpointManager.Breakpoint.State.equals(newState, this._currentState)) {
840 callback();
841 return;
844 this._breakpoint._currentState = newState;
846 if (this._debuggerId) {
847 this._resetLocations();
848 this._debuggerModel.removeBreakpoint(this._debuggerId, this._didRemoveFromDebugger.bind(this, callback));
849 this._scheduleUpdateInDebugger();
850 this._currentState = null;
851 return;
854 if (!newState) {
855 callback();
856 return;
859 var updateCallback = this._didSetBreakpointInDebugger.bind(this, callback);
860 if (newState.url)
861 this._debuggerModel.setBreakpointByURL(newState.url, newState.lineNumber, newState.columnNumber, this._breakpoint.condition(), updateCallback);
862 else if (newState.scriptId)
863 this._debuggerModel.setBreakpointBySourceId(/** @type {!WebInspector.DebuggerModel.Location} */ (debuggerLocation), condition, updateCallback);
865 this._currentState = newState;
869 * @param {function()} callback
870 * @param {?DebuggerAgent.BreakpointId} breakpointId
871 * @param {!Array.<!WebInspector.DebuggerModel.Location>} locations
873 _didSetBreakpointInDebugger: function(callback, breakpointId, locations)
875 if (this._cancelCallback) {
876 this._cancelCallback = false;
877 callback();
878 return;
881 if (!breakpointId) {
882 this._breakpoint.remove(true);
883 callback();
884 return;
887 this._debuggerId = breakpointId;
888 this._debuggerModel.addBreakpointListener(this._debuggerId, this._breakpointResolved, this);
889 for (var i = 0; i < locations.length; ++i) {
890 if (!this._addResolvedLocation(locations[i]))
891 break;
893 callback();
897 * @param {function()} callback
899 _didRemoveFromDebugger: function(callback)
901 if (this._cancelCallback) {
902 this._cancelCallback = false;
903 callback();
904 return;
907 this._resetLocations();
908 this._debuggerModel.removeBreakpointListener(this._debuggerId, this._breakpointResolved, this);
909 delete this._debuggerId;
910 callback();
914 * @param {!WebInspector.Event} event
916 _breakpointResolved: function(event)
918 this._addResolvedLocation(/** @type {!WebInspector.DebuggerModel.Location}*/ (event.data));
922 * @param {!WebInspector.DebuggerModel.Location} location
923 * @param {!WebInspector.UILocation} uiLocation
925 _locationUpdated: function(location, uiLocation)
927 var oldUILocation = this._uiLocations[location.id()] || null;
928 this._uiLocations[location.id()] = uiLocation;
929 this._breakpoint._replaceUILocation(oldUILocation, uiLocation);
933 * @param {!WebInspector.DebuggerModel.Location} location
934 * @return {boolean}
936 _addResolvedLocation: function(location)
938 var uiLocation = this._debuggerWorkspaceBinding.rawLocationToUILocation(location);
939 var breakpoint = this._breakpoint._breakpointManager.findBreakpoint(uiLocation.uiSourceCode, uiLocation.lineNumber, uiLocation.columnNumber);
940 if (breakpoint && breakpoint !== this._breakpoint) {
941 // location clash
942 this._breakpoint.remove();
943 return false;
945 this._liveLocations.push(this._debuggerWorkspaceBinding.createLiveLocation(location, this._locationUpdated.bind(this, location)));
946 return true;
949 _cleanUpAfterDebuggerIsGone: function()
951 if (this._isUpdating)
952 this._cancelCallback = true;
954 this._resetLocations();
955 this._currentState = null;
956 if (this._debuggerId)
957 this._didRemoveFromDebugger(function() {});
960 _removeEventListeners: function()
962 this._debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.DebuggerWasDisabled, this._cleanUpAfterDebuggerIsGone, this);
963 this._debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.DebuggerWasEnabled, this._scheduleUpdateInDebugger, this);
966 __proto__: WebInspector.SDKObject.prototype
970 * @constructor
971 * @param {?string} url
972 * @param {?string} scriptId
973 * @param {number} lineNumber
974 * @param {number} columnNumber
975 * @param {string} condition
977 WebInspector.BreakpointManager.Breakpoint.State = function(url, scriptId, lineNumber, columnNumber, condition)
979 this.url = url;
980 this.scriptId = scriptId;
981 this.lineNumber = lineNumber;
982 this.columnNumber = columnNumber;
983 this.condition = condition;
987 * @param {?WebInspector.BreakpointManager.Breakpoint.State|undefined} stateA
988 * @param {?WebInspector.BreakpointManager.Breakpoint.State|undefined} stateB
989 * @return {boolean}
991 WebInspector.BreakpointManager.Breakpoint.State.equals = function(stateA, stateB)
993 if (!stateA || !stateB)
994 return false;
996 if (stateA.scriptId || stateB.scriptId)
997 return false;
999 return stateA.url === stateB.url && stateA.lineNumber === stateB.lineNumber && stateA.columnNumber === stateB.columnNumber && stateA.condition === stateB.condition;
1003 * @constructor
1004 * @param {!WebInspector.BreakpointManager} breakpointManager
1005 * @param {?WebInspector.Setting} setting
1007 WebInspector.BreakpointManager.Storage = function(breakpointManager, setting)
1009 this._breakpointManager = breakpointManager;
1010 this._setting = setting || WebInspector.settings.createLocalSetting("breakpoints", []);
1011 var breakpoints = this._setting.get();
1012 /** @type {!Object.<string, !WebInspector.BreakpointManager.Storage.Item>} */
1013 this._breakpoints = {};
1014 for (var i = 0; i < breakpoints.length; ++i) {
1015 var breakpoint = /** @type {!WebInspector.BreakpointManager.Storage.Item} */ (breakpoints[i]);
1016 breakpoint.columnNumber = breakpoint.columnNumber || 0;
1017 this._breakpoints[breakpoint.sourceFileId + ":" + breakpoint.lineNumber + ":" + breakpoint.columnNumber] = breakpoint;
1021 WebInspector.BreakpointManager.Storage.prototype = {
1022 mute: function()
1024 this._muted = true;
1027 unmute: function()
1029 delete this._muted;
1033 * @param {string} sourceFileId
1034 * @return {!Array.<!WebInspector.BreakpointManager.Storage.Item>}
1036 breakpointItems: function(sourceFileId)
1038 var result = [];
1039 for (var id in this._breakpoints) {
1040 var breakpoint = this._breakpoints[id];
1041 if (breakpoint.sourceFileId === sourceFileId)
1042 result.push(breakpoint);
1044 return result;
1048 * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
1050 _updateBreakpoint: function(breakpoint)
1052 if (this._muted || !breakpoint._breakpointStorageId())
1053 return;
1054 this._breakpoints[breakpoint._breakpointStorageId()] = new WebInspector.BreakpointManager.Storage.Item(breakpoint);
1055 this._save();
1059 * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
1061 _removeBreakpoint: function(breakpoint)
1063 if (this._muted)
1064 return;
1065 delete this._breakpoints[breakpoint._breakpointStorageId()];
1066 this._save();
1069 _save: function()
1071 var breakpointsArray = [];
1072 for (var id in this._breakpoints)
1073 breakpointsArray.push(this._breakpoints[id]);
1074 this._setting.set(breakpointsArray);
1079 * @constructor
1080 * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
1082 WebInspector.BreakpointManager.Storage.Item = function(breakpoint)
1084 this.sourceFileId = breakpoint._sourceFileId;
1085 this.lineNumber = breakpoint.lineNumber();
1086 this.columnNumber = breakpoint.columnNumber();
1087 this.condition = breakpoint.condition();
1088 this.enabled = breakpoint.enabled();
1091 /** @type {!WebInspector.BreakpointManager} */
1092 WebInspector.breakpointManager;