blob: 69f3d155ad9e3ee2efbe1abc59163414c6701fda [file] [log] [blame]
/*
* 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;