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 * @param {!WebInspector.Setting} breakpointStorage 35 * @param {!WebInspector.DebuggerModel} debuggerModel 36 * @param {!WebInspector.Workspace} workspace 37 */ 38 WebInspector.BreakpointManager = function(breakpointStorage, debuggerModel, workspace) 39 { 40 this._storage = new WebInspector.BreakpointManager.Storage(this, breakpointStorage); 41 this._debuggerModel = debuggerModel; 42 this._workspace = workspace; 43 44 this._breakpointForDebuggerId = {}; 45 this._breakpointsForUISourceCode = new Map(); 46 this._breakpointsForPrimaryUISourceCode = new Map(); 47 this._sourceFilesWithRestoredBreakpoints = {}; 48 49 this._debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointResolved, this._breakpointResolved, this); 50 this._workspace.addEventListener(WebInspector.Workspace.Events.ProjectWillReset, this._projectWillReset, this); 51 this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAdded, this); 52 this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeRemoved, this._uiSourceCodeRemoved, this); 53 } 54 55 WebInspector.BreakpointManager.Events = { 56 BreakpointAdded: "breakpoint-added", 57 BreakpointRemoved: "breakpoint-removed" 58 } 59 60 WebInspector.BreakpointManager._sourceFileId = function(uiSourceCode) 61 { 62 if (!uiSourceCode.url) 63 return ""; 64 var deobfuscatedPrefix = uiSourceCode.formatted() ? "deobfuscated:" : ""; 65 return deobfuscatedPrefix + uiSourceCode.uri(); 66 } 67 68 /** 69 * @param {string} sourceFileId 70 * @param {number} lineNumber 71 * @return {string} 72 */ 73 WebInspector.BreakpointManager._breakpointStorageId = function(sourceFileId, lineNumber) 74 { 75 if (!sourceFileId) 76 return ""; 77 return sourceFileId + ":" + lineNumber; 78 } 79 80 WebInspector.BreakpointManager.prototype = { 81 /** 82 * @param {string} sourceFileId 83 */ 84 _provisionalBreakpointsForSourceFileId: function(sourceFileId) 85 { 86 var result = new StringMap(); 87 for (var debuggerId in this._breakpointForDebuggerId) { 88 var breakpoint = this._breakpointForDebuggerId[debuggerId]; 89 if (breakpoint._sourceFileId === sourceFileId) 90 result.put(breakpoint._breakpointStorageId(), breakpoint); 91 } 92 return result; 93 }, 94 95 /** 96 * @param {!WebInspector.UISourceCode} uiSourceCode 97 */ 98 _restoreBreakpoints: function(uiSourceCode) 99 { 100 var sourceFileId = WebInspector.BreakpointManager._sourceFileId(uiSourceCode); 101 if (!sourceFileId || this._sourceFilesWithRestoredBreakpoints[sourceFileId]) 102 return; 103 this._sourceFilesWithRestoredBreakpoints[sourceFileId] = true; 104 105 this._storage.mute(); 106 var breakpointItems = this._storage.breakpointItems(uiSourceCode); 107 var provisionalBreakpoints = this._provisionalBreakpointsForSourceFileId(sourceFileId); 108 for (var i = 0; i < breakpointItems.length; ++i) { 109 var breakpointItem = breakpointItems[i]; 110 var itemStorageId = WebInspector.BreakpointManager._breakpointStorageId(breakpointItem.sourceFileId, breakpointItem.lineNumber); 111 var provisionalBreakpoint = provisionalBreakpoints.get(itemStorageId); 112 if (provisionalBreakpoint) { 113 if (!this._breakpointsForPrimaryUISourceCode.get(uiSourceCode)) 114 this._breakpointsForPrimaryUISourceCode.put(uiSourceCode, []); 115 this._breakpointsForPrimaryUISourceCode.get(uiSourceCode).push(provisionalBreakpoint); 116 provisionalBreakpoint._updateInDebugger(); 117 } else { 118 this._innerSetBreakpoint(uiSourceCode, breakpointItem.lineNumber, breakpointItem.condition, breakpointItem.enabled); 119 } 120 } 121 this._storage.unmute(); 122 }, 123 124 /** 125 * @param {!WebInspector.Event} event 126 */ 127 _uiSourceCodeAdded: function(event) 128 { 129 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data); 130 this._restoreBreakpoints(uiSourceCode); 131 if (uiSourceCode.contentType() === WebInspector.resourceTypes.Script || uiSourceCode.contentType() === WebInspector.resourceTypes.Document) { 132 uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.SourceMappingChanged, this._uiSourceCodeMappingChanged, this); 133 uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.FormattedChanged, this._uiSourceCodeFormatted, this); 134 } 135 }, 136 137 /** 138 * @param {!WebInspector.Event} event 139 */ 140 _uiSourceCodeFormatted: function(event) 141 { 142 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.target); 143 this._restoreBreakpoints(uiSourceCode); 144 }, 145 146 /** 147 * @param {!WebInspector.Event} event 148 */ 149 _uiSourceCodeRemoved: function(event) 150 { 151 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data); 152 this._removeUISourceCode(uiSourceCode); 153 }, 154 155 /** 156 * @param {!WebInspector.Event} event 157 */ 158 _uiSourceCodeMappingChanged: function(event) 159 { 160 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.target); 161 var breakpoints = this._breakpointsForPrimaryUISourceCode.get(uiSourceCode) || []; 162 for (var i = 0; i < breakpoints.length; ++i) 163 breakpoints[i]._updateInDebugger(); 164 }, 165 166 /** 167 * @param {!WebInspector.UISourceCode} uiSourceCode 168 */ 169 _removeUISourceCode: function(uiSourceCode) 170 { 171 var breakpoints = this._breakpointsForPrimaryUISourceCode.get(uiSourceCode) || []; 172 for (var i = 0; i < breakpoints.length; ++i) 173 breakpoints[i]._resetLocations(); 174 var sourceFileId = WebInspector.BreakpointManager._sourceFileId(uiSourceCode); 175 delete this._sourceFilesWithRestoredBreakpoints[sourceFileId]; 176 uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.FormattedChanged, this._uiSourceCodeFormatted, this); 177 uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.SourceMappingChanged, this._uiSourceCodeMappingChanged, this); 178 this._breakpointsForPrimaryUISourceCode.remove(uiSourceCode); 179 }, 180 181 /** 182 * @param {!WebInspector.UISourceCode} uiSourceCode 183 * @param {number} lineNumber 184 * @param {string} condition 185 * @param {boolean} enabled 186 * @return {!WebInspector.BreakpointManager.Breakpoint} 187 */ 188 setBreakpoint: function(uiSourceCode, lineNumber, condition, enabled) 189 { 190 this._debuggerModel.setBreakpointsActive(true); 191 return this._innerSetBreakpoint(uiSourceCode, lineNumber, condition, enabled); 192 }, 193 194 /** 195 * @param {!WebInspector.UISourceCode} uiSourceCode 196 * @param {number} lineNumber 197 * @param {string} condition 198 * @param {boolean} enabled 199 * @return {!WebInspector.BreakpointManager.Breakpoint} 200 */ 201 _innerSetBreakpoint: function(uiSourceCode, lineNumber, condition, enabled) 202 { 203 var breakpoint = this.findBreakpoint(uiSourceCode, lineNumber); 204 if (breakpoint) { 205 breakpoint._updateBreakpoint(condition, enabled); 206 return breakpoint; 207 } 208 var projectId = uiSourceCode.project().id(); 209 var path = uiSourceCode.path(); 210 var sourceFileId = WebInspector.BreakpointManager._sourceFileId(uiSourceCode); 211 breakpoint = new WebInspector.BreakpointManager.Breakpoint(this, projectId, path, sourceFileId, lineNumber, condition, enabled); 212 if (!this._breakpointsForPrimaryUISourceCode.get(uiSourceCode)) 213 this._breakpointsForPrimaryUISourceCode.put(uiSourceCode, []); 214 this._breakpointsForPrimaryUISourceCode.get(uiSourceCode).push(breakpoint); 215 return breakpoint; 216 }, 217 218 /** 219 * @param {!WebInspector.UISourceCode} uiSourceCode 220 * @param {number} lineNumber 221 * @return {?WebInspector.BreakpointManager.Breakpoint} 222 */ 223 findBreakpoint: function(uiSourceCode, lineNumber) 224 { 225 var breakpoints = this._breakpointsForUISourceCode.get(uiSourceCode); 226 var lineBreakpoints = breakpoints ? breakpoints[lineNumber] : null; 227 return lineBreakpoints ? lineBreakpoints[0] : null; 228 }, 229 230 /** 231 * @param {!WebInspector.UISourceCode} uiSourceCode 232 * @return {!Array.<!WebInspector.BreakpointManager.Breakpoint>} 233 */ 234 breakpointsForUISourceCode: function(uiSourceCode) 235 { 236 var breakpoints = this._breakpointsForUISourceCode.get(uiSourceCode); 237 var allLineBreakpoints = breakpoints ? Object.values(breakpoints) : []; 238 var result = []; 239 for (var i = 0; i < allLineBreakpoints.length; ++i) 240 result = result.concat(allLineBreakpoints[i]); 241 return result; 242 }, 243 244 /** 245 * @return {!Array.<!WebInspector.BreakpointManager.Breakpoint>} 246 */ 247 allBreakpoints: function() 248 { 249 var result = []; 250 var uiSourceCodes = this._breakpointsForUISourceCode.keys(); 251 for (var i = 0; i < uiSourceCodes.length; ++i) 252 result = result.concat(this.breakpointsForUISourceCode(uiSourceCodes[i])); 253 return result; 254 }, 255 256 /** 257 * @param {!WebInspector.UISourceCode} uiSourceCode 258 * @return {!Array.<{breakpoint: !WebInspector.BreakpointManager.Breakpoint, uiLocation: !WebInspector.UILocation}>} 259 */ 260 breakpointLocationsForUISourceCode: function(uiSourceCode) 261 { 262 var breakpoints = this._breakpointsForUISourceCode.get(uiSourceCode); 263 var breakpointLines = breakpoints ? Object.keys(breakpoints) : []; 264 var result = []; 265 for (var i = 0; i < breakpointLines.length; ++i) { 266 var lineNumber = parseInt(breakpointLines[i], 10); 267 if (isNaN(lineNumber)) 268 continue; 269 var lineBreakpoints = breakpoints[lineNumber]; 270 for (var j = 0; j < lineBreakpoints.length; ++j) { 271 var breakpoint = lineBreakpoints[j]; 272 var uiLocation = new WebInspector.UILocation(uiSourceCode, lineNumber, 0); 273 result.push({breakpoint: breakpoint, uiLocation: uiLocation}); 274 } 275 } 276 return result; 277 }, 278 279 /** 280 * @return {!Array.<{breakpoint: !WebInspector.BreakpointManager.Breakpoint, uiLocation: !WebInspector.UILocation}>} 281 */ 282 allBreakpointLocations: function() 283 { 284 var result = []; 285 var uiSourceCodes = this._breakpointsForUISourceCode.keys(); 286 for (var i = 0; i < uiSourceCodes.length; ++i) 287 result = result.concat(this.breakpointLocationsForUISourceCode(uiSourceCodes[i])); 288 return result; 289 }, 290 291 /** 292 * @param {boolean} toggleState 293 */ 294 toggleAllBreakpoints: function(toggleState) 295 { 296 var breakpoints = this.allBreakpoints(); 297 for (var i = 0; i < breakpoints.length; ++i) 298 breakpoints[i].setEnabled(toggleState); 299 }, 300 301 removeAllBreakpoints: function() 302 { 303 var breakpoints = this.allBreakpoints(); 304 for (var i = 0; i < breakpoints.length; ++i) 305 breakpoints[i].remove(); 306 }, 307 308 removeProvisionalBreakpoints: function() 309 { 310 for (var debuggerId in this._breakpointForDebuggerId) 311 this._debuggerModel.removeBreakpoint(debuggerId); 312 }, 313 314 _projectWillReset: function(event) 315 { 316 var project = /** @type {!WebInspector.Project} */ (event.data); 317 var uiSourceCodes = project.uiSourceCodes(); 318 for (var i = 0; i < uiSourceCodes.length; ++i) 319 this._removeUISourceCode(uiSourceCodes[i]); 320 }, 321 322 _breakpointResolved: function(event) 323 { 324 var breakpointId = /** @type {!DebuggerAgent.BreakpointId} */ (event.data.breakpointId); 325 var location = /** @type {!WebInspector.DebuggerModel.Location} */ (event.data.location); 326 var breakpoint = this._breakpointForDebuggerId[breakpointId]; 327 if (!breakpoint) 328 return; 329 breakpoint._addResolvedLocation(location); 330 }, 331 332 /** 333 * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint 334 * @param {boolean} removeFromStorage 335 */ 336 _removeBreakpoint: function(breakpoint, removeFromStorage) 337 { 338 var uiSourceCode = breakpoint.uiSourceCode(); 339 var breakpoints = uiSourceCode ? this._breakpointsForPrimaryUISourceCode.get(uiSourceCode) || [] : []; 340 var index = breakpoints.indexOf(breakpoint); 341 if (index > -1) 342 breakpoints.splice(index, 1); 343 console.assert(!breakpoint._debuggerId) 344 if (removeFromStorage) 345 this._storage._removeBreakpoint(breakpoint); 346 }, 347 348 /** 349 * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint 350 * @param {!WebInspector.UILocation} uiLocation 351 */ 352 _uiLocationAdded: function(breakpoint, uiLocation) 353 { 354 var breakpoints = this._breakpointsForUISourceCode.get(uiLocation.uiSourceCode); 355 if (!breakpoints) { 356 breakpoints = {}; 357 this._breakpointsForUISourceCode.put(uiLocation.uiSourceCode, breakpoints); 358 } 359 360 var lineBreakpoints = breakpoints[uiLocation.lineNumber]; 361 if (!lineBreakpoints) { 362 lineBreakpoints = []; 363 breakpoints[uiLocation.lineNumber] = lineBreakpoints; 364 } 365 366 lineBreakpoints.push(breakpoint); 367 this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.BreakpointAdded, {breakpoint: breakpoint, uiLocation: uiLocation}); 368 }, 369 370 /** 371 * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint 372 * @param {!WebInspector.UILocation} uiLocation 373 */ 374 _uiLocationRemoved: function(breakpoint, uiLocation) 375 { 376 var breakpoints = this._breakpointsForUISourceCode.get(uiLocation.uiSourceCode); 377 if (!breakpoints) 378 return; 379 380 var lineBreakpoints = breakpoints[uiLocation.lineNumber]; 381 if (!lineBreakpoints) 382 return; 383 384 lineBreakpoints.remove(breakpoint); 385 if (!lineBreakpoints.length) 386 delete breakpoints[uiLocation.lineNumber]; 387 if (Object.keys(breakpoints).length === 0) 388 this._breakpointsForUISourceCode.remove(uiLocation.uiSourceCode); 389 this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.BreakpointRemoved, {breakpoint: breakpoint, uiLocation: uiLocation}); 390 }, 391 392 __proto__: WebInspector.Object.prototype 393 } 394 395 /** 396 * @constructor 397 * @param {!WebInspector.BreakpointManager} breakpointManager 398 * @param {string} projectId 399 * @param {string} path 400 * @param {string} sourceFileId 401 * @param {number} lineNumber 402 * @param {string} condition 403 * @param {boolean} enabled 404 */ 405 WebInspector.BreakpointManager.Breakpoint = function(breakpointManager, projectId, path, sourceFileId, lineNumber, condition, enabled) 406 { 407 this._breakpointManager = breakpointManager; 408 this._projectId = projectId; 409 this._path = path; 410 this._lineNumber = lineNumber; 411 this._sourceFileId = sourceFileId; 412 /** @type {!Array.<!WebInspector.Script.Location>} */ 413 this._liveLocations = []; 414 /** @type {!Object.<string, !WebInspector.UILocation>} */ 415 this._uiLocations = {}; 416 417 // Force breakpoint update. 418 /** @type {string} */ this._condition; 419 /** @type {boolean} */ this._enabled; 420 this._updateBreakpoint(condition, enabled); 421 } 422 423 WebInspector.BreakpointManager.Breakpoint.prototype = { 424 /** 425 * @return {string} 426 */ 427 projectId: function() 428 { 429 return this._projectId; 430 }, 431 432 /** 433 * @return {string} 434 */ 435 path: function() 436 { 437 return this._path; 438 }, 439 440 /** 441 * @return {number} 442 */ 443 lineNumber: function() 444 { 445 return this._lineNumber; 446 }, 447 448 /** 449 * @return {?WebInspector.UISourceCode} 450 */ 451 uiSourceCode: function() 452 { 453 return this._breakpointManager._workspace.uiSourceCode(this._projectId, this._path); 454 }, 455 456 /** 457 * @param {!WebInspector.DebuggerModel.Location} location 458 */ 459 _addResolvedLocation: function(location) 460 { 461 this._liveLocations.push(this._breakpointManager._debuggerModel.createLiveLocation(location, this._locationUpdated.bind(this, location))); 462 }, 463 464 /** 465 * @param {!WebInspector.DebuggerModel.Location} location 466 * @param {!WebInspector.UILocation} uiLocation 467 */ 468 _locationUpdated: function(location, uiLocation) 469 { 470 var stringifiedLocation = location.scriptId + ":" + location.lineNumber + ":" + location.columnNumber; 471 var oldUILocation = /** @type {!WebInspector.UILocation} */ (this._uiLocations[stringifiedLocation]); 472 if (oldUILocation) 473 this._breakpointManager._uiLocationRemoved(this, oldUILocation); 474 if (this._uiLocations[""]) { 475 var defaultLocation = this._uiLocations[""]; 476 delete this._uiLocations[""]; 477 this._breakpointManager._uiLocationRemoved(this, defaultLocation); 478 } 479 this._uiLocations[stringifiedLocation] = uiLocation; 480 this._breakpointManager._uiLocationAdded(this, uiLocation); 481 }, 482 483 /** 484 * @return {boolean} 485 */ 486 enabled: function() 487 { 488 return this._enabled; 489 }, 490 491 /** 492 * @param {boolean} enabled 493 */ 494 setEnabled: function(enabled) 495 { 496 this._updateBreakpoint(this._condition, enabled); 497 }, 498 499 /** 500 * @return {string} 501 */ 502 condition: function() 503 { 504 return this._condition; 505 }, 506 507 /** 508 * @param {string} condition 509 */ 510 setCondition: function(condition) 511 { 512 this._updateBreakpoint(condition, this._enabled); 513 }, 514 515 /** 516 * @param {string} condition 517 * @param {boolean} enabled 518 */ 519 _updateBreakpoint: function(condition, enabled) 520 { 521 if (this._enabled === enabled && this._condition === condition) 522 return; 523 this._removeFromDebugger(); 524 this._enabled = enabled; 525 this._condition = condition; 526 this._breakpointManager._storage._updateBreakpoint(this); 527 this._fakeBreakpointAtPrimaryLocation(); 528 this._updateInDebugger(); 529 }, 530 531 _updateInDebugger: function() 532 { 533 var uiSourceCode = this.uiSourceCode(); 534 if (!uiSourceCode || !uiSourceCode.hasSourceMapping()) 535 return; 536 var scriptFile = uiSourceCode && uiSourceCode.scriptFile(); 537 if (this._enabled && !(scriptFile && scriptFile.hasDivergedFromVM())) 538 this._setInDebugger(); 539 }, 540 541 /** 542 * @param {boolean=} keepInStorage 543 */ 544 remove: function(keepInStorage) 545 { 546 var removeFromStorage = !keepInStorage; 547 this._resetLocations(); 548 this._removeFromDebugger(); 549 this._breakpointManager._removeBreakpoint(this, removeFromStorage); 550 }, 551 552 _setInDebugger: function() 553 { 554 this._removeFromDebugger(); 555 var uiSourceCode = this._breakpointManager._workspace.uiSourceCode(this._projectId, this._path); 556 if (!uiSourceCode) 557 return; 558 var rawLocation = uiSourceCode.uiLocationToRawLocation(this._lineNumber, 0); 559 var debuggerModelLocation = /** @type {!WebInspector.DebuggerModel.Location} */ (rawLocation); 560 if (debuggerModelLocation) 561 this._breakpointManager._debuggerModel.setBreakpointByScriptLocation(debuggerModelLocation, this._condition, this._didSetBreakpointInDebugger.bind(this)); 562 else if (uiSourceCode.url) 563 this._breakpointManager._debuggerModel.setBreakpointByURL(uiSourceCode.url, this._lineNumber, 0, this._condition, this._didSetBreakpointInDebugger.bind(this)); 564 }, 565 566 /** 567 * @this {WebInspector.BreakpointManager.Breakpoint} 568 * @param {?DebuggerAgent.BreakpointId} breakpointId 569 * @param {!Array.<!WebInspector.DebuggerModel.Location>} locations 570 */ 571 _didSetBreakpointInDebugger: function(breakpointId, locations) 572 { 573 if (!breakpointId) { 574 this._resetLocations(); 575 this._breakpointManager._removeBreakpoint(this, false); 576 return; 577 } 578 579 this._debuggerId = breakpointId; 580 this._breakpointManager._breakpointForDebuggerId[breakpointId] = this; 581 582 if (!locations.length) { 583 this._fakeBreakpointAtPrimaryLocation(); 584 return; 585 } 586 587 this._resetLocations(); 588 for (var i = 0; i < locations.length; ++i) { 589 var script = this._breakpointManager._debuggerModel.scriptForId(locations[i].scriptId); 590 var uiLocation = script.rawLocationToUILocation(locations[i].lineNumber, locations[i].columnNumber); 591 if (this._breakpointManager.findBreakpoint(uiLocation.uiSourceCode, uiLocation.lineNumber)) { 592 // location clash 593 this.remove(); 594 return; 595 } 596 } 597 598 for (var i = 0; i < locations.length; ++i) 599 this._addResolvedLocation(locations[i]); 600 }, 601 602 _removeFromDebugger: function() 603 { 604 if (!this._debuggerId) 605 return; 606 this._breakpointManager._debuggerModel.removeBreakpoint(this._debuggerId); 607 delete this._breakpointManager._breakpointForDebuggerId[this._debuggerId]; 608 delete this._debuggerId; 609 }, 610 611 _resetLocations: function() 612 { 613 for (var stringifiedLocation in this._uiLocations) 614 this._breakpointManager._uiLocationRemoved(this, this._uiLocations[stringifiedLocation]); 615 616 for (var i = 0; i < this._liveLocations.length; ++i) 617 this._liveLocations[i].dispose(); 618 this._liveLocations = []; 619 620 this._uiLocations = {}; 621 }, 622 623 /** 624 * @return {string} 625 */ 626 _breakpointStorageId: function() 627 { 628 return WebInspector.BreakpointManager._breakpointStorageId(this._sourceFileId, this._lineNumber); 629 }, 630 631 _fakeBreakpointAtPrimaryLocation: function() 632 { 633 this._resetLocations(); 634 var uiSourceCode = this._breakpointManager._workspace.uiSourceCode(this._projectId, this._path); 635 if (!uiSourceCode) 636 return; 637 var uiLocation = new WebInspector.UILocation(uiSourceCode, this._lineNumber, 0); 638 this._uiLocations[""] = uiLocation; 639 this._breakpointManager._uiLocationAdded(this, uiLocation); 640 } 641 } 642 643 /** 644 * @constructor 645 * @param {!WebInspector.BreakpointManager} breakpointManager 646 * @param {!WebInspector.Setting} setting 647 */ 648 WebInspector.BreakpointManager.Storage = function(breakpointManager, setting) 649 { 650 this._breakpointManager = breakpointManager; 651 this._setting = setting; 652 var breakpoints = this._setting.get(); 653 /** @type {!Object.<string, !WebInspector.BreakpointManager.Storage.Item>} */ 654 this._breakpoints = {}; 655 for (var i = 0; i < breakpoints.length; ++i) { 656 var breakpoint = /** @type {!WebInspector.BreakpointManager.Storage.Item} */ (breakpoints[i]); 657 this._breakpoints[breakpoint.sourceFileId + ":" + breakpoint.lineNumber] = breakpoint; 658 } 659 } 660 661 WebInspector.BreakpointManager.Storage.prototype = { 662 mute: function() 663 { 664 this._muted = true; 665 }, 666 667 unmute: function() 668 { 669 delete this._muted; 670 }, 671 672 /** 673 * @param {!WebInspector.UISourceCode} uiSourceCode 674 * @return {!Array.<!WebInspector.BreakpointManager.Storage.Item>} 675 */ 676 breakpointItems: function(uiSourceCode) 677 { 678 var result = []; 679 var sourceFileId = WebInspector.BreakpointManager._sourceFileId(uiSourceCode); 680 for (var id in this._breakpoints) { 681 var breakpoint = this._breakpoints[id]; 682 if (breakpoint.sourceFileId === sourceFileId) 683 result.push(breakpoint); 684 } 685 return result; 686 }, 687 688 /** 689 * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint 690 */ 691 _updateBreakpoint: function(breakpoint) 692 { 693 if (this._muted || !breakpoint._breakpointStorageId()) 694 return; 695 this._breakpoints[breakpoint._breakpointStorageId()] = new WebInspector.BreakpointManager.Storage.Item(breakpoint); 696 this._save(); 697 }, 698 699 /** 700 * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint 701 */ 702 _removeBreakpoint: function(breakpoint) 703 { 704 if (this._muted) 705 return; 706 delete this._breakpoints[breakpoint._breakpointStorageId()]; 707 this._save(); 708 }, 709 710 _save: function() 711 { 712 var breakpointsArray = []; 713 for (var id in this._breakpoints) 714 breakpointsArray.push(this._breakpoints[id]); 715 this._setting.set(breakpointsArray); 716 } 717 } 718 719 /** 720 * @constructor 721 * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint 722 */ 723 WebInspector.BreakpointManager.Storage.Item = function(breakpoint) 724 { 725 this.sourceFileId = breakpoint._sourceFileId; 726 this.lineNumber = breakpoint.lineNumber(); 727 this.condition = breakpoint.condition(); 728 this.enabled = breakpoint.enabled(); 729 } 730 731 /** @type {!WebInspector.BreakpointManager} */ 732 WebInspector.breakpointManager; 733