summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/devtools/front_end/sdk/BreakpointManager.js
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/WebKit/Source/devtools/front_end/sdk/BreakpointManager.js')
-rw-r--r--chromium/third_party/WebKit/Source/devtools/front_end/sdk/BreakpointManager.js908
1 files changed, 908 insertions, 0 deletions
diff --git a/chromium/third_party/WebKit/Source/devtools/front_end/sdk/BreakpointManager.js b/chromium/third_party/WebKit/Source/devtools/front_end/sdk/BreakpointManager.js
new file mode 100644
index 00000000000..69f3d155ad9
--- /dev/null
+++ b/chromium/third_party/WebKit/Source/devtools/front_end/sdk/BreakpointManager.js
@@ -0,0 +1,908 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.Object}
+ * @param {!WebInspector.Setting} breakpointStorage
+ * @param {!WebInspector.Workspace} workspace
+ * @param {!WebInspector.TargetManager} targetManager
+ */
+WebInspector.BreakpointManager = function(breakpointStorage, workspace, targetManager)
+{
+ this._storage = new WebInspector.BreakpointManager.Storage(this, breakpointStorage);
+ this._workspace = workspace;
+ this._targetManager = targetManager;
+
+ this._breakpointsForUISourceCode = new Map();
+ this._breakpointsForPrimaryUISourceCode = new Map();
+ /** @type {!StringMultimap.<!WebInspector.BreakpointManager.Breakpoint>} */
+ this._provisionalBreakpoints = new StringMultimap();
+
+ this._workspace.addEventListener(WebInspector.Workspace.Events.ProjectRemoved, this._projectRemoved, this);
+ this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAdded, this);
+ this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeRemoved, this._uiSourceCodeRemoved, this);
+}
+
+WebInspector.BreakpointManager.Events = {
+ BreakpointAdded: "breakpoint-added",
+ BreakpointRemoved: "breakpoint-removed"
+}
+
+WebInspector.BreakpointManager._sourceFileId = function(uiSourceCode)
+{
+ if (!uiSourceCode.url)
+ return "";
+ return uiSourceCode.uri();
+}
+
+/**
+ * @param {string} sourceFileId
+ * @param {number} lineNumber
+ * @param {number} columnNumber
+ * @return {string}
+ */
+WebInspector.BreakpointManager._breakpointStorageId = function(sourceFileId, lineNumber, columnNumber)
+{
+ if (!sourceFileId)
+ return "";
+ return sourceFileId + ":" + lineNumber + ":" + columnNumber;
+}
+
+WebInspector.BreakpointManager.prototype = {
+
+ /**
+ * @param {string} sourceFileId
+ * @return {!StringMap.<!WebInspector.BreakpointManager.Breakpoint>}
+ */
+ _provisionalBreakpointsForSourceFileId: function(sourceFileId)
+ {
+ var result = new StringMap();
+ var breakpoints = this._provisionalBreakpoints.get(sourceFileId).values();
+ for (var i = 0; i < breakpoints.length; ++i)
+ result.put(breakpoints[i]._breakpointStorageId(), breakpoints[i]);
+ return result;
+ },
+
+ removeProvisionalBreakpointsForTest: function()
+ {
+ var breakpoints = this._provisionalBreakpoints.values();
+ for (var i = 0; i < breakpoints.length; ++i)
+ breakpoints[i].remove();
+ this._provisionalBreakpoints.clear();
+ },
+
+ /**
+ * @param {!WebInspector.UISourceCode} uiSourceCode
+ */
+ _restoreBreakpoints: function(uiSourceCode)
+ {
+ var sourceFileId = WebInspector.BreakpointManager._sourceFileId(uiSourceCode);
+ if (!sourceFileId)
+ return;
+
+ this._storage.mute();
+ var breakpointItems = this._storage.breakpointItems(uiSourceCode);
+ var provisionalBreakpoints = this._provisionalBreakpointsForSourceFileId(sourceFileId);
+ for (var i = 0; i < breakpointItems.length; ++i) {
+ var breakpointItem = breakpointItems[i];
+ var itemStorageId = WebInspector.BreakpointManager._breakpointStorageId(breakpointItem.sourceFileId, breakpointItem.lineNumber, breakpointItem.columnNumber);
+ var provisionalBreakpoint = provisionalBreakpoints.get(itemStorageId);
+ if (provisionalBreakpoint) {
+ if (!this._breakpointsForPrimaryUISourceCode.get(uiSourceCode))
+ this._breakpointsForPrimaryUISourceCode.put(uiSourceCode, []);
+ this._breakpointsForPrimaryUISourceCode.get(uiSourceCode).push(provisionalBreakpoint);
+ provisionalBreakpoint._updateBreakpoint();
+ } else {
+ this._innerSetBreakpoint(uiSourceCode, breakpointItem.lineNumber, breakpointItem.columnNumber, breakpointItem.condition, breakpointItem.enabled);
+ }
+ }
+ this._provisionalBreakpoints.removeAll(sourceFileId);
+ this._storage.unmute();
+ },
+
+ /**
+ * @param {!WebInspector.Event} event
+ */
+ _uiSourceCodeAdded: function(event)
+ {
+ var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
+ this._restoreBreakpoints(uiSourceCode);
+ if (uiSourceCode.contentType() === WebInspector.resourceTypes.Script || uiSourceCode.contentType() === WebInspector.resourceTypes.Document)
+ uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.SourceMappingChanged, this._uiSourceCodeMappingChanged, this);
+ },
+
+ /**
+ * @param {!WebInspector.Event} event
+ */
+ _uiSourceCodeRemoved: function(event)
+ {
+ var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
+ this._removeUISourceCode(uiSourceCode);
+ },
+
+ /**
+ * @param {!WebInspector.Event} event
+ */
+ _uiSourceCodeMappingChanged: function(event)
+ {
+ var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.target);
+ var isIdentity = /** @type {boolean} */ (event.data.isIdentity);
+ var target = /** @type {!WebInspector.Target} */ (event.data.target);
+ if (isIdentity)
+ return;
+ var breakpoints = this._breakpointsForPrimaryUISourceCode.get(uiSourceCode) || [];
+ for (var i = 0; i < breakpoints.length; ++i)
+ breakpoints[i]._updateInDebuggerForTarget(target);
+ },
+
+ /**
+ * @param {!WebInspector.UISourceCode} uiSourceCode
+ */
+ _removeUISourceCode: function(uiSourceCode)
+ {
+ var breakpoints = this._breakpointsForPrimaryUISourceCode.get(uiSourceCode) || [];
+ var sourceFileId = WebInspector.BreakpointManager._sourceFileId(uiSourceCode);
+ for (var i = 0; i < breakpoints.length; ++i) {
+ breakpoints[i]._resetLocations();
+ if (breakpoints[i].enabled())
+ this._provisionalBreakpoints.put(sourceFileId, breakpoints[i]);
+ }
+ uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.SourceMappingChanged, this._uiSourceCodeMappingChanged, this);
+ this._breakpointsForPrimaryUISourceCode.remove(uiSourceCode);
+ },
+
+ /**
+ * @param {!WebInspector.UISourceCode} uiSourceCode
+ * @param {number} lineNumber
+ * @param {number} columnNumber
+ * @param {string} condition
+ * @param {boolean} enabled
+ * @return {!WebInspector.BreakpointManager.Breakpoint}
+ */
+ setBreakpoint: function(uiSourceCode, lineNumber, columnNumber, condition, enabled)
+ {
+ var targets = this._targetManager.targets();
+ for (var i = 0; i < targets.length; ++i)
+ targets[i].debuggerModel.setBreakpointsActive(true);
+ return this._innerSetBreakpoint(uiSourceCode, lineNumber, columnNumber, condition, enabled);
+ },
+
+ /**
+ * @param {!WebInspector.UISourceCode} uiSourceCode
+ * @param {number} lineNumber
+ * @param {number} columnNumber
+ * @param {string} condition
+ * @param {boolean} enabled
+ * @return {!WebInspector.BreakpointManager.Breakpoint}
+ */
+ _innerSetBreakpoint: function(uiSourceCode, lineNumber, columnNumber, condition, enabled)
+ {
+ var breakpoint = this.findBreakpoint(uiSourceCode, lineNumber, columnNumber);
+ if (breakpoint) {
+ breakpoint._updateState(condition, enabled);
+ return breakpoint;
+ }
+ var projectId = uiSourceCode.project().id();
+ var path = uiSourceCode.path();
+ var sourceFileId = WebInspector.BreakpointManager._sourceFileId(uiSourceCode);
+ breakpoint = new WebInspector.BreakpointManager.Breakpoint(this, projectId, path, sourceFileId, lineNumber, columnNumber, condition, enabled);
+ if (!this._breakpointsForPrimaryUISourceCode.get(uiSourceCode))
+ this._breakpointsForPrimaryUISourceCode.put(uiSourceCode, []);
+ this._breakpointsForPrimaryUISourceCode.get(uiSourceCode).push(breakpoint);
+ return breakpoint;
+ },
+
+ /**
+ * @param {!WebInspector.UISourceCode} uiSourceCode
+ * @param {number} lineNumber
+ * @param {number} columnNumber
+ * @return {?WebInspector.BreakpointManager.Breakpoint}
+ */
+ findBreakpoint: function(uiSourceCode, lineNumber, columnNumber)
+ {
+ var breakpoints = this._breakpointsForUISourceCode.get(uiSourceCode);
+ var lineBreakpoints = breakpoints ? breakpoints.get(String(lineNumber)) : null;
+ var columnBreakpoints = lineBreakpoints ? lineBreakpoints.get(String(columnNumber)) : null;
+ return columnBreakpoints ? columnBreakpoints[0] : null;
+ },
+
+ /**
+ * @param {!WebInspector.UISourceCode} uiSourceCode
+ * @param {number} lineNumber
+ * @return {?WebInspector.BreakpointManager.Breakpoint}
+ */
+ findBreakpointOnLine: function(uiSourceCode, lineNumber)
+ {
+ var breakpoints = this._breakpointsForUISourceCode.get(uiSourceCode);
+ var lineBreakpoints = breakpoints ? breakpoints.get(String(lineNumber)) : null;
+ return lineBreakpoints ? lineBreakpoints.values()[0][0] : null;
+ },
+
+ /**
+ * @param {!WebInspector.UISourceCode} uiSourceCode
+ * @return {!Array.<!WebInspector.BreakpointManager.Breakpoint>}
+ */
+ breakpointsForUISourceCode: function(uiSourceCode)
+ {
+ var result = [];
+ var uiSourceCodeBreakpoints = this._breakpointsForUISourceCode.get(uiSourceCode);
+ var breakpoints = uiSourceCodeBreakpoints ? uiSourceCodeBreakpoints.values() : [];
+ for (var i = 0; i < breakpoints.length; ++i) {
+ var lineBreakpoints = breakpoints[i];
+ var columnBreakpointArrays = lineBreakpoints ? lineBreakpoints.values() : [];
+ result = result.concat.apply(result, columnBreakpointArrays);
+ }
+ return result;
+ },
+
+ /**
+ * @return {!Array.<!WebInspector.BreakpointManager.Breakpoint>}
+ */
+ allBreakpoints: function()
+ {
+ var result = [];
+ var uiSourceCodes = this._breakpointsForUISourceCode.keys();
+ for (var i = 0; i < uiSourceCodes.length; ++i)
+ result = result.concat(this.breakpointsForUISourceCode(uiSourceCodes[i]));
+ return result;
+ },
+
+ /**
+ * @param {!WebInspector.UISourceCode} uiSourceCode
+ * @return {!Array.<!{breakpoint: !WebInspector.BreakpointManager.Breakpoint, uiLocation: !WebInspector.UILocation}>}
+ */
+ breakpointLocationsForUISourceCode: function(uiSourceCode)
+ {
+ var uiSourceCodeBreakpoints = this._breakpointsForUISourceCode.get(uiSourceCode);
+ var lineNumbers = uiSourceCodeBreakpoints ? uiSourceCodeBreakpoints.keys() : [];
+ var result = [];
+ for (var i = 0; i < lineNumbers.length; ++i) {
+ var lineBreakpoints = uiSourceCodeBreakpoints.get(lineNumbers[i]);
+ var columnNumbers = lineBreakpoints.keys();
+ for (var j = 0; j < columnNumbers.length; ++j) {
+ var columnBreakpoints = lineBreakpoints.get(columnNumbers[j]);
+ var lineNumber = parseInt(lineNumbers[i], 10);
+ var columnNumber = parseInt(columnNumbers[j], 10);
+ for (var k = 0; k < columnBreakpoints.length; ++k) {
+ var breakpoint = columnBreakpoints[k];
+ var uiLocation = uiSourceCode.uiLocation(lineNumber, columnNumber);
+ result.push({breakpoint: breakpoint, uiLocation: uiLocation});
+ }
+ }
+ }
+ return result;
+ },
+
+ /**
+ * @return {!Array.<!{breakpoint: !WebInspector.BreakpointManager.Breakpoint, uiLocation: !WebInspector.UILocation}>}
+ */
+ allBreakpointLocations: function()
+ {
+ var result = [];
+ var uiSourceCodes = this._breakpointsForUISourceCode.keys();
+ for (var i = 0; i < uiSourceCodes.length; ++i)
+ result = result.concat(this.breakpointLocationsForUISourceCode(uiSourceCodes[i]));
+ return result;
+ },
+
+ /**
+ * @param {boolean} toggleState
+ */
+ toggleAllBreakpoints: function(toggleState)
+ {
+ var breakpoints = this.allBreakpoints();
+ for (var i = 0; i < breakpoints.length; ++i)
+ breakpoints[i].setEnabled(toggleState);
+ },
+
+ removeAllBreakpoints: function()
+ {
+ var breakpoints = this.allBreakpoints();
+ for (var i = 0; i < breakpoints.length; ++i)
+ breakpoints[i].remove();
+ },
+
+ _projectRemoved: function(event)
+ {
+ var project = /** @type {!WebInspector.Project} */ (event.data);
+ var uiSourceCodes = project.uiSourceCodes();
+ for (var i = 0; i < uiSourceCodes.length; ++i)
+ this._removeUISourceCode(uiSourceCodes[i]);
+ },
+
+ /**
+ * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
+ * @param {boolean} removeFromStorage
+ */
+ _removeBreakpoint: function(breakpoint, removeFromStorage)
+ {
+ var uiSourceCode = breakpoint.uiSourceCode();
+ var breakpoints = uiSourceCode ? this._breakpointsForPrimaryUISourceCode.get(uiSourceCode) || [] : [];
+ breakpoints.remove(breakpoint);
+ if (removeFromStorage)
+ this._storage._removeBreakpoint(breakpoint);
+ this._provisionalBreakpoints.remove(breakpoint._sourceFileId, breakpoint);
+ },
+
+ /**
+ * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
+ * @param {!WebInspector.UILocation} uiLocation
+ */
+ _uiLocationAdded: function(breakpoint, uiLocation)
+ {
+ var breakpoints = this._breakpointsForUISourceCode.get(uiLocation.uiSourceCode);
+ if (!breakpoints) {
+ breakpoints = new StringMap();
+ this._breakpointsForUISourceCode.put(uiLocation.uiSourceCode, breakpoints);
+ }
+ var lineBreakpoints = breakpoints.get(String(uiLocation.lineNumber));
+ if (!lineBreakpoints) {
+ lineBreakpoints = new StringMap();
+ breakpoints.put(String(uiLocation.lineNumber), lineBreakpoints);
+ }
+ var columnBreakpoints = lineBreakpoints.get(String(uiLocation.columnNumber));
+ if (!columnBreakpoints) {
+ columnBreakpoints = [];
+ lineBreakpoints.put(String(uiLocation.columnNumber), columnBreakpoints);
+ }
+ columnBreakpoints.push(breakpoint);
+ this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.BreakpointAdded, {breakpoint: breakpoint, uiLocation: uiLocation});
+ },
+
+ /**
+ * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
+ * @param {!WebInspector.UILocation} uiLocation
+ */
+ _uiLocationRemoved: function(breakpoint, uiLocation)
+ {
+ var breakpoints = this._breakpointsForUISourceCode.get(uiLocation.uiSourceCode);
+ if (!breakpoints)
+ return;
+
+ var lineBreakpoints = breakpoints.get(String(uiLocation.lineNumber));
+ if (!lineBreakpoints)
+ return;
+ var columnBreakpoints = lineBreakpoints.get(String(uiLocation.columnNumber));
+ if (!columnBreakpoints)
+ return;
+ columnBreakpoints.remove(breakpoint);
+ if (!columnBreakpoints.length)
+ lineBreakpoints.remove(String(uiLocation.columnNumber));
+ if (!lineBreakpoints.size())
+ breakpoints.remove(String(uiLocation.lineNumber));
+ if (!breakpoints.size())
+ this._breakpointsForUISourceCode.remove(uiLocation.uiSourceCode);
+ this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.BreakpointRemoved, {breakpoint: breakpoint, uiLocation: uiLocation});
+ },
+
+ __proto__: WebInspector.Object.prototype
+}
+
+/**
+ * @constructor
+ * @implements {WebInspector.TargetManager.Observer}
+ * @param {!WebInspector.BreakpointManager} breakpointManager
+ * @param {string} projectId
+ * @param {string} path
+ * @param {string} sourceFileId
+ * @param {number} lineNumber
+ * @param {number} columnNumber
+ * @param {string} condition
+ * @param {boolean} enabled
+ */
+WebInspector.BreakpointManager.Breakpoint = function(breakpointManager, projectId, path, sourceFileId, lineNumber, columnNumber, condition, enabled)
+{
+ this._breakpointManager = breakpointManager;
+ this._projectId = projectId;
+ this._path = path;
+ this._lineNumber = lineNumber;
+ this._columnNumber = columnNumber;
+ this._sourceFileId = sourceFileId;
+
+ /** @type {!Object.<string, number>} */
+ this._numberOfDebuggerLocationForUILocation = {};
+
+ // Force breakpoint update.
+ /** @type {string} */ this._condition;
+ /** @type {boolean} */ this._enabled;
+ /** @type {boolean} */ this._isRemoved;
+ /** @type {!WebInspector.UILocation|undefined} */ this._fakePrimaryLocation;
+
+ /** @type {!Map.<!WebInspector.Target, !WebInspector.BreakpointManager.TargetBreakpoint>}*/
+ this._targetBreakpoints = new Map();
+ this._updateState(condition, enabled);
+ this._breakpointManager._targetManager.observeTargets(this);
+}
+
+WebInspector.BreakpointManager.Breakpoint.prototype = {
+ /**
+ * @param {!WebInspector.Target} target
+ */
+ targetAdded: function(target)
+ {
+ this._targetBreakpoints.put(target, new WebInspector.BreakpointManager.TargetBreakpoint(target, this));
+ },
+
+ /**
+ * @param {!WebInspector.Target} target
+ */
+ targetRemoved: function(target)
+ {
+ var targetBreakpoint = this._targetBreakpoints.remove(target);
+ targetBreakpoint._cleanUpAfterDebuggerIsGone();
+ targetBreakpoint._removeEventListeners();
+ },
+
+ /**
+ * @return {string}
+ */
+ projectId: function()
+ {
+ return this._projectId;
+ },
+
+ /**
+ * @return {string}
+ */
+ path: function()
+ {
+ return this._path;
+ },
+
+ /**
+ * @return {number}
+ */
+ lineNumber: function()
+ {
+ return this._lineNumber;
+ },
+
+ /**
+ * @return {number}
+ */
+ columnNumber: function()
+ {
+ return this._columnNumber;
+ },
+
+ /**
+ * @return {?WebInspector.UISourceCode}
+ */
+ uiSourceCode: function()
+ {
+ return this._breakpointManager._workspace.uiSourceCode(this._projectId, this._path);
+ },
+
+ /**
+ * @param {?WebInspector.UILocation} oldUILocation
+ * @param {!WebInspector.UILocation} newUILocation
+ */
+ _replaceUILocation: function(oldUILocation, newUILocation)
+ {
+ if (this._isRemoved)
+ return;
+
+ this._removeUILocation(oldUILocation, true);
+ this._removeFakeBreakpointAtPrimaryLocation();
+
+ if (!this._numberOfDebuggerLocationForUILocation[newUILocation.id()])
+ this._numberOfDebuggerLocationForUILocation[newUILocation.id()] = 0;
+
+ if (++this._numberOfDebuggerLocationForUILocation[newUILocation.id()] === 1)
+ this._breakpointManager._uiLocationAdded(this, newUILocation);
+ },
+
+ /**
+ * @param {?WebInspector.UILocation} uiLocation
+ * @param {boolean=} muteCreationFakeBreakpoint
+ */
+ _removeUILocation: function(uiLocation, muteCreationFakeBreakpoint)
+ {
+ if (!uiLocation || --this._numberOfDebuggerLocationForUILocation[uiLocation.id()] !== 0)
+ return;
+
+ delete this._numberOfDebuggerLocationForUILocation[uiLocation.id()];
+ this._breakpointManager._uiLocationRemoved(this, uiLocation);
+ if (!muteCreationFakeBreakpoint)
+ this._fakeBreakpointAtPrimaryLocation();
+ },
+
+ /**
+ * @return {boolean}
+ */
+ enabled: function()
+ {
+ return this._enabled;
+ },
+
+ /**
+ * @param {boolean} enabled
+ */
+ setEnabled: function(enabled)
+ {
+ this._updateState(this._condition, enabled);
+ },
+
+ /**
+ * @return {string}
+ */
+ condition: function()
+ {
+ return this._condition;
+ },
+
+ /**
+ * @param {string} condition
+ */
+ setCondition: function(condition)
+ {
+ this._updateState(condition, this._enabled);
+ },
+
+ /**
+ * @param {string} condition
+ * @param {boolean} enabled
+ */
+ _updateState: function(condition, enabled)
+ {
+ if (this._enabled === enabled && this._condition === condition)
+ return;
+ this._enabled = enabled;
+ this._condition = condition;
+ this._breakpointManager._storage._updateBreakpoint(this);
+ this._updateBreakpoint();
+ },
+
+ _updateBreakpoint: function()
+ {
+ this._removeFakeBreakpointAtPrimaryLocation();
+ this._fakeBreakpointAtPrimaryLocation();
+ var targetBreakpoints = this._targetBreakpoints.values();
+ for (var i = 0; i < targetBreakpoints.length; ++i)
+ targetBreakpoints[i]._updateInDebugger();
+ },
+
+ /**
+ * @param {boolean=} keepInStorage
+ */
+ remove: function(keepInStorage)
+ {
+ this._isRemoved = true;
+ var removeFromStorage = !keepInStorage;
+ this._removeFakeBreakpointAtPrimaryLocation();
+ var targetBreakpoints = this._targetBreakpoints.values();
+ for (var i = 0; i < targetBreakpoints.length; ++i) {
+ targetBreakpoints[i]._removeFromDebugger();
+ targetBreakpoints[i]._removeEventListeners();
+ }
+
+ this._breakpointManager._removeBreakpoint(this, removeFromStorage);
+ this._breakpointManager._targetManager.unobserveTargets(this);
+ },
+
+ /**
+ * @param {!WebInspector.Target} target
+ */
+ _updateInDebuggerForTarget: function(target)
+ {
+ this._targetBreakpoints.get(target)._updateInDebugger();
+ },
+
+ /**
+ * @return {string}
+ */
+ _breakpointStorageId: function()
+ {
+ return WebInspector.BreakpointManager._breakpointStorageId(this._sourceFileId, this._lineNumber, this._columnNumber);
+ },
+
+ _fakeBreakpointAtPrimaryLocation: function()
+ {
+ if (this._isRemoved || !Object.isEmpty(this._numberOfDebuggerLocationForUILocation) || this._fakePrimaryLocation)
+ return;
+
+ var uiSourceCode = this._breakpointManager._workspace.uiSourceCode(this._projectId, this._path);
+ if (!uiSourceCode)
+ return;
+
+ this._fakePrimaryLocation = uiSourceCode.uiLocation(this._lineNumber, this._columnNumber);
+ this._breakpointManager._uiLocationAdded(this, this._fakePrimaryLocation);
+ },
+
+ _removeFakeBreakpointAtPrimaryLocation: function()
+ {
+ if (this._fakePrimaryLocation) {
+ this._breakpointManager._uiLocationRemoved(this, this._fakePrimaryLocation);
+ delete this._fakePrimaryLocation;
+ }
+ },
+
+ _resetLocations: function()
+ {
+ this._removeFakeBreakpointAtPrimaryLocation();
+ var targetBreakpoints = this._targetBreakpoints.values();
+ for (var i = 0; i < targetBreakpoints.length; ++i)
+ targetBreakpoints[i]._resetLocations();
+ }
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.TargetAware}
+ * @param {!WebInspector.Target} target
+ * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
+ */
+WebInspector.BreakpointManager.TargetBreakpoint = function(target, breakpoint)
+{
+ WebInspector.TargetAware.call(this, target);
+ this._breakpoint = breakpoint;
+ /** @type {!Array.<!WebInspector.Script.Location>} */
+ this._liveLocations = [];
+
+ /** @type {!Object.<string, !WebInspector.UILocation>} */
+ this._uiLocations = {};
+ target.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerWasDisabled, this._cleanUpAfterDebuggerIsGone, this);
+ target.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerWasEnabled, this._updateInDebugger, this);
+ if (target.debuggerModel.debuggerEnabled())
+ this._updateInDebugger();
+}
+
+WebInspector.BreakpointManager.TargetBreakpoint.prototype = {
+
+ _resetLocations: function()
+ {
+ var uiLocations = Object.values(this._uiLocations);
+ for (var i = 0; i < uiLocations.length; ++i)
+ this._breakpoint._removeUILocation(uiLocations[i]);
+
+ this._uiLocations = {};
+
+ for (var i = 0; i < this._liveLocations.length; ++i)
+ this._liveLocations[i].dispose();
+ this._liveLocations = [];
+ },
+
+ /**
+ * @param {boolean=} callbackImmediately
+ */
+ _removeFromDebugger: function(callbackImmediately)
+ {
+ this._resetLocations();
+ if (!this._debuggerId)
+ return;
+ var debuggerId = this._debuggerId;
+ this.target().debuggerModel.removeBreakpoint(this._debuggerId, callbackImmediately ? undefined : didRemoveFromDebugger.bind(this));
+
+ /**
+ * @this {WebInspector.BreakpointManager.TargetBreakpoint}
+ */
+ function didRemoveFromDebugger()
+ {
+ if (this._debuggerId === debuggerId)
+ this._didRemoveFromDebugger();
+ }
+ if (callbackImmediately)
+ this._didRemoveFromDebugger();
+ },
+
+ _updateInDebugger: function()
+ {
+ this._removeFromDebugger();
+ var uiSourceCode = this._breakpoint.uiSourceCode();
+ if (!uiSourceCode || !this._breakpoint._enabled)
+ return;
+ var scriptFile = uiSourceCode.scriptFileForTarget(this._target);
+ if (scriptFile && scriptFile.hasDivergedFromVM())
+ return;
+
+ var lineNumber = this._breakpoint._lineNumber;
+ var columnNumber = this._breakpoint._columnNumber;
+ var rawLocation = uiSourceCode.uiLocationToRawLocation(this._target, lineNumber, columnNumber);
+ var debuggerModelLocation = /** @type {!WebInspector.DebuggerModel.Location} */ (rawLocation);
+ var condition = this._breakpoint.condition();
+ if (debuggerModelLocation)
+ this.target().debuggerModel.setBreakpointByScriptLocation(debuggerModelLocation, condition, this._didSetBreakpointInDebugger.bind(this));
+ else if (uiSourceCode.url)
+ this.target().debuggerModel.setBreakpointByURL(uiSourceCode.url, lineNumber, columnNumber, condition, this._didSetBreakpointInDebugger.bind(this));
+ },
+
+ /**
+ * @param {?DebuggerAgent.BreakpointId} breakpointId
+ * @param {!Array.<!WebInspector.DebuggerModel.Location>} locations
+ */
+ _didSetBreakpointInDebugger: function(breakpointId, locations)
+ {
+ if (!breakpointId) {
+ this._breakpoint.remove(true);
+ return;
+ }
+
+ if (this._debuggerId)
+ this._removeFromDebugger(true);
+
+ this._debuggerId = breakpointId;
+ this.target().debuggerModel.addBreakpointListener(this._debuggerId, this._breakpointResolved, this);
+ for (var i = 0; i < locations.length; ++i)
+ if (!this._addResolvedLocation(locations[i]))
+ return;
+ },
+
+ _didRemoveFromDebugger: function()
+ {
+ this.target().debuggerModel.removeBreakpointListener(this._debuggerId, this._breakpointResolved, this);
+ delete this._debuggerId;
+ },
+
+ /**
+ * @param {!WebInspector.Event} event
+ */
+ _breakpointResolved: function(event)
+ {
+ this._addResolvedLocation(/** @type {!WebInspector.DebuggerModel.Location}*/ (event.data));
+ },
+
+ /**
+ * @param {!WebInspector.DebuggerModel.Location} location
+ * @param {!WebInspector.UILocation} uiLocation
+ */
+ _locationUpdated: function(location, uiLocation)
+ {
+ var oldUILocation = this._uiLocations[location.id()] || null;
+ this._uiLocations[location.id()] = uiLocation;
+ this._breakpoint._replaceUILocation(oldUILocation, uiLocation);
+ },
+
+ /**
+ * @param {!WebInspector.DebuggerModel.Location} location
+ * @return {boolean}
+ */
+ _addResolvedLocation: function(location)
+ {
+ var script = location.script();
+ var uiLocation = script.rawLocationToUILocation(location.lineNumber, location.columnNumber);
+ var breakpoint = this._breakpoint._breakpointManager.findBreakpoint(uiLocation.uiSourceCode, uiLocation.lineNumber, uiLocation.columnNumber);
+ if (breakpoint && breakpoint != this._breakpoint) {
+ // location clash
+ this._breakpoint.remove();
+ return false;
+ }
+ this._liveLocations.push(location.createLiveLocation(this._locationUpdated.bind(this, location)));
+ return true;
+ },
+
+ _cleanUpAfterDebuggerIsGone: function()
+ {
+ this._resetLocations();
+ if (this._debuggerId)
+ this._didRemoveFromDebugger();
+ },
+
+ _removeEventListeners: function()
+ {
+ this.target().debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.DebuggerWasDisabled, this._cleanUpAfterDebuggerIsGone, this);
+ this.target().debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.DebuggerWasEnabled, this._updateInDebugger, this);
+ },
+
+ __proto__: WebInspector.TargetAware.prototype
+}
+
+/**
+ * @constructor
+ * @param {!WebInspector.BreakpointManager} breakpointManager
+ * @param {!WebInspector.Setting} setting
+ */
+WebInspector.BreakpointManager.Storage = function(breakpointManager, setting)
+{
+ this._breakpointManager = breakpointManager;
+ this._setting = setting;
+ var breakpoints = this._setting.get();
+ /** @type {!Object.<string, !WebInspector.BreakpointManager.Storage.Item>} */
+ this._breakpoints = {};
+ for (var i = 0; i < breakpoints.length; ++i) {
+ var breakpoint = /** @type {!WebInspector.BreakpointManager.Storage.Item} */ (breakpoints[i]);
+ breakpoint.columnNumber = breakpoint.columnNumber || 0;
+ this._breakpoints[breakpoint.sourceFileId + ":" + breakpoint.lineNumber + ":" + breakpoint.columnNumber] = breakpoint;
+ }
+}
+
+WebInspector.BreakpointManager.Storage.prototype = {
+ mute: function()
+ {
+ this._muted = true;
+ },
+
+ unmute: function()
+ {
+ delete this._muted;
+ },
+
+ /**
+ * @param {!WebInspector.UISourceCode} uiSourceCode
+ * @return {!Array.<!WebInspector.BreakpointManager.Storage.Item>}
+ */
+ breakpointItems: function(uiSourceCode)
+ {
+ var result = [];
+ var sourceFileId = WebInspector.BreakpointManager._sourceFileId(uiSourceCode);
+ for (var id in this._breakpoints) {
+ var breakpoint = this._breakpoints[id];
+ if (breakpoint.sourceFileId === sourceFileId)
+ result.push(breakpoint);
+ }
+ return result;
+ },
+
+ /**
+ * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
+ */
+ _updateBreakpoint: function(breakpoint)
+ {
+ if (this._muted || !breakpoint._breakpointStorageId())
+ return;
+ this._breakpoints[breakpoint._breakpointStorageId()] = new WebInspector.BreakpointManager.Storage.Item(breakpoint);
+ this._save();
+ },
+
+ /**
+ * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
+ */
+ _removeBreakpoint: function(breakpoint)
+ {
+ if (this._muted)
+ return;
+ delete this._breakpoints[breakpoint._breakpointStorageId()];
+ this._save();
+ },
+
+ _save: function()
+ {
+ var breakpointsArray = [];
+ for (var id in this._breakpoints)
+ breakpointsArray.push(this._breakpoints[id]);
+ this._setting.set(breakpointsArray);
+ }
+}
+
+/**
+ * @constructor
+ * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
+ */
+WebInspector.BreakpointManager.Storage.Item = function(breakpoint)
+{
+ this.sourceFileId = breakpoint._sourceFileId;
+ this.lineNumber = breakpoint.lineNumber();
+ this.columnNumber = breakpoint.columnNumber();
+ this.condition = breakpoint.condition();
+ this.enabled = breakpoint.enabled();
+}
+
+/** @type {!WebInspector.BreakpointManager} */
+WebInspector.breakpointManager;