Changeset 266074 in webkit


Ignore:
Timestamp:
Aug 24, 2020, 10:34:12 AM (5 years ago)
Author:
Devin Rousso
Message:

Web Inspector: allow event breakpoints to be configured
https://bugs.webkit.org/show_bug.cgi?id=215362
<rdar://problem/66932921>

Reviewed by Brian Burg.

Source/JavaScriptCore:

This allows developers to do things like:

  • only pause when window.event.type is a certain value
  • ignore the first N pauses
  • evaluate JavaScript whenever an event listener is invoked without pausing
  • inspector/protocol/DOM.json:

Add an options paramater to DOM.setBreakpointForEventListener to allow configuration.

  • inspector/protocol/DOMDebugger.json:

Add an options paramater to DOMDebugger.setEventBreakpoint to allow configuration.

  • debugger/Breakpoint.h:

(JSC::Breakpoint::id const): Added.
(JSC::Breakpoint::sourceID const): Added.
(JSC::Breakpoint::lineNumber const): Added.
(JSC::Breakpoint::columnNumber const): Added.
(JSC::Breakpoint::condition const): Added.
(JSC::Breakpoint::actions const): Added.
(JSC::Breakpoint::isAutoContinue const): Added.
(JSC::Breakpoint::resetHitCount): Added.
(JSC::Breakpoint::isLinked const): Added.
(JSC::Breakpoint::isResolved const): Added.
(JSC::BreakpointsList::~BreakpointsList): Deleted.

  • debugger/Breakpoint.cpp: Added.

(JSC::Breakpoint::Action::Action): Added.
(JSC::Breakpoint::create): Added.
(JSC::Breakpoint::Breakpoint): Added.
(JSC::Breakpoint::link): Added.
(JSC::Breakpoint::resolve): Added.
(JSC::Breakpoint::shouldPause): Added.
Unify JSC::Breakpoint and Inspector::ScriptBreakpoint.

  • debugger/DebuggerPrimitives.h:
  • debugger/Debugger.h:
  • debugger/Debugger.cpp:

(JSC::Debugger::Debugger):
(JSC::Debugger::addObserver): Added.
(JSC::Debugger::removeObserver): Added.
(JSC::Debugger::canDispatchFunctionToObservers const): Added.
(JSC::Debugger::dispatchFunctionToObservers): Added.
(JSC::Debugger::sourceParsed): Added.
(JSC::Debugger::toggleBreakpoint):
(JSC::Debugger::applyBreakpoints):
(JSC::Debugger::resolveBreakpoint):
(JSC::Debugger::setBreakpoint):
(JSC::Debugger::removeBreakpoint):
(JSC::Debugger::didHitBreakpoint): Added.
(JSC::Debugger::clearBreakpoints):
(JSC::Debugger::evaluateBreakpointCondition): Added.
(JSC::Debugger::evaluateBreakpointActions): Added.
(JSC::Debugger::schedulePauseAtNextOpportunity): Added.
(JSC::Debugger::cancelPauseAtNextOpportunity): Added.
(JSC::Debugger::schedulePauseForSpecialBreakpoint): Added.
(JSC::Debugger::cancelPauseForSpecialBreakpoint): Added.
(JSC::Debugger::continueProgram):
(JSC::Debugger::stepNextExpression):
(JSC::Debugger::stepIntoStatement):
(JSC::Debugger::stepOverStatement):
(JSC::Debugger::stepOutOfFunction):
(JSC::Debugger::pauseIfNeeded):
(JSC::Debugger::handlePause): Added.
(JSC::Debugger::exceptionOrCaughtValue): Added.
(JSC::Debugger::atExpression):
(JSC::Debugger::clearNextPauseState):
(JSC::Debugger::willRunMicrotask): Added.
(JSC::Debugger::didRunMicrotask): Added.
(JSC::Debugger::hasBreakpoint): Deleted.
(JSC::Debugger::setPauseOnNextStatement): Deleted.
Unify JSC::Debugger and Inspector::ScriptDebugServer to simplify breakpoint logic.
Introduce the concept of a "special breakpoint", which is essentially a JSC::Breakpoint
that is expected to pause at the next opportunity but isn't tied to a particular location.
As an example, whenever an event breakpoint is hit, instead of just pausing at the next
opportunity, the newly managed JSC::Breakpoint is used as a "special breakpoint", allowing
for it's configuration (ie.g. condition, ignore count, actions, auto-continue) to be used.

  • inspector/agents/InspectorDebuggerAgent.h:
  • inspector/agents/InspectorDebuggerAgent.cpp:

(Inspector::objectGroupForBreakpointAction):
(Inspector::breakpointActionTypeForString): Added.
(Inspector::parseBreakpointOptions): Added.
(Inspector::InspectorDebuggerAgent::ProtocolBreakpoint::fromPayload): Added.
(Inspector::InspectorDebuggerAgent::ProtocolBreakpoint::ProtocolBreakpoint): Added.
(Inspector::InspectorDebuggerAgent::ProtocolBreakpoint::createDebuggerBreakpoint const): Added.
(Inspector::InspectorDebuggerAgent::ProtocolBreakpoint::matchesScriptURL const): Added.
(Inspector::InspectorDebuggerAgent::debuggerBreakpointFromPayload): Added.
(Inspector::InspectorDebuggerAgent::enable):
(Inspector::InspectorDebuggerAgent::disable):
(Inspector::InspectorDebuggerAgent::buildBreakpointPauseReason):
(Inspector::InspectorDebuggerAgent::handleConsoleAssert):
(Inspector::InspectorDebuggerAgent::didScheduleAsyncCall):
(Inspector::buildDebuggerLocation):
(Inspector::InspectorDebuggerAgent::setBreakpointByUrl):
(Inspector::InspectorDebuggerAgent::setBreakpoint):
(Inspector::InspectorDebuggerAgent::didSetBreakpoint):
(Inspector::InspectorDebuggerAgent::resolveBreakpoint):
(Inspector::InspectorDebuggerAgent::removeBreakpoint):
(Inspector::InspectorDebuggerAgent::continueToLocation):
(Inspector::InspectorDebuggerAgent::schedulePauseAtNextOpportunity): Added.
(Inspector::InspectorDebuggerAgent::cancelPauseAtNextOpportunity): Added.
(Inspector::InspectorDebuggerAgent::schedulePauseForSpecialBreakpoint): Added.
(Inspector::InspectorDebuggerAgent::cancelPauseForSpecialBreakpoint): Added.
(Inspector::InspectorDebuggerAgent::pause):
(Inspector::InspectorDebuggerAgent::resume):
(Inspector::InspectorDebuggerAgent::didBecomeIdle):
(Inspector::InspectorDebuggerAgent::sourceMapURLForScript):
(Inspector::InspectorDebuggerAgent::didParseSource):
(Inspector::InspectorDebuggerAgent::willRunMicrotask):
(Inspector::InspectorDebuggerAgent::didRunMicrotask):
(Inspector::InspectorDebuggerAgent::didPause):
(Inspector::InspectorDebuggerAgent::breakpointActionSound):
(Inspector::InspectorDebuggerAgent::breakpointActionProbe):
(Inspector::InspectorDebuggerAgent::clearInspectorBreakpointState):
(Inspector::InspectorDebuggerAgent::clearDebuggerBreakpointState):
(Inspector::matches): Deleted.
(Inspector::buildObjectForBreakpointCookie): Deleted.
(Inspector::InspectorDebuggerAgent::breakpointActionsFromProtocol): Deleted.
(Inspector::InspectorDebuggerAgent::schedulePauseOnNextStatement): Deleted.
(Inspector::InspectorDebuggerAgent::cancelPauseOnNextStatement): Deleted.
Create a private ProtocolBreakpoint class that holds the data sent by the frontend. This
is necessary because breakpoints in the frontend have a potentially one-to-many relationship
with breakpoints in the backend, as the same script can be loaded many times on a page. Each
of those scripts is independent, however, and can execute differently, meaning that the same
breakpoint for each script also needs a different state (e.g. ignore count). As such, the
ProtocolBreakpoint is effectively a template that is actualized whenever a new script is
parsed that matches the URL of the ProtocolBreakpoint to create a JSC::Breakpoint that
is used by the JSC::Debugger. ProtocolBreakpoint also parses breakpoint configurations.

  • inspector/InspectorEnvironment.h:
  • inspector/JSGlobalObjectScriptDebugServer.h:
  • inspector/JSGlobalObjectScriptDebugServer.cpp:

(Inspector::JSGlobalObjectScriptDebugServer::JSGlobalObjectScriptDebugServer):
(Inspector::JSGlobalObjectScriptDebugServer::attachDebugger):
(Inspector::JSGlobalObjectScriptDebugServer::detachDebugger):
(Inspector::JSGlobalObjectScriptDebugServer::runEventLoopWhilePaused):

  • inspector/agents/InspectorAuditAgent.h:
  • inspector/agents/InspectorAuditAgent.cpp:

(Inspector::InspectorAuditAgent::run):

  • inspector/agents/InspectorRuntimeAgent.h:
  • inspector/agents/InspectorRuntimeAgent.cpp:

(Inspector::setPauseOnExceptionsState):
(Inspector::InspectorRuntimeAgent::evaluate):
(Inspector::InspectorRuntimeAgent::callFunctionOn):
(Inspector::InspectorRuntimeAgent::getPreview):
(Inspector::InspectorRuntimeAgent::getProperties):
(Inspector::InspectorRuntimeAgent::getDisplayableProperties):

  • inspector/agents/InspectorScriptProfilerAgent.cpp:
  • inspector/agents/JSGlobalObjectDebuggerAgent.h:

Replace Inspector::ScriptDebugServer with JSC::Debugger.

  • runtime/JSMicrotask.cpp:

(JSC::JSMicrotask::run):
Drive-by: r248894 mistakenly omitted the call to notify the debugger that the microtask ran.

  • inspector/ScriptBreakpoint.h: Removed.
  • inspector/ScriptDebugListener.h: Removed.
  • inspector/ScriptDebugServer.h: Removed.
  • inspector/ScriptDebugServer.cpp: Removed.
  • CMakeLists.txt:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Sources.txt:

Source/WebCore:

This allows developers to do things like:

  • only pause when window.event.type is a certain value
  • ignore the first N pauses
  • evaluate JavaScript whenever an event listener is invoked without pausing

Tests: inspector/dom/breakpoint-for-event-listener.html

inspector/dom-debugger/event-animation-frame-breakpoints.html
inspector/dom-debugger/event-interval-breakpoints.html
inspector/dom-debugger/event-listener-breakpoints.html
inspector/dom-debugger/event-timeout-breakpoints.html

  • inspector/agents/InspectorDOMAgent.h:
  • inspector/agents/InspectorDOMAgent.cpp:

(WebCore::InspectorDOMAgent::getEventListenersForNode):
(WebCore::InspectorDOMAgent::setBreakpointForEventListener):
(WebCore::InspectorDOMAgent::removeBreakpointForEventListener):
(WebCore::InspectorDOMAgent::buildObjectForEventListener):
(WebCore::InspectorDOMAgent::breakpointForEventListener):
(WebCore::InspectorDOMAgent::hasBreakpointForEventListener): Deleted.

  • inspector/agents/InspectorDOMDebuggerAgent.h:
  • inspector/agents/InspectorDOMDebuggerAgent.cpp:

(WebCore::InspectorDOMDebuggerAgent::disable):
(WebCore::InspectorDOMDebuggerAgent::mainFrameNavigated):
(WebCore::InspectorDOMDebuggerAgent::setEventBreakpoint):
(WebCore::InspectorDOMDebuggerAgent::removeEventBreakpoint):
(WebCore::InspectorDOMDebuggerAgent::willHandleEvent):
(WebCore::InspectorDOMDebuggerAgent::didHandleEvent):
(WebCore::InspectorDOMDebuggerAgent::willFireTimer):
(WebCore::InspectorDOMDebuggerAgent::didFireTimer):

  • inspector/agents/page/PageDOMDebuggerAgent.h:
  • inspector/agents/page/PageDOMDebuggerAgent.cpp:

(WebCore::PageDOMDebuggerAgent::disable):
(WebCore::PageDOMDebuggerAgent::mainFrameNavigated):
(WebCore::PageDOMDebuggerAgent::willFireAnimationFrame):
(WebCore::PageDOMDebuggerAgent::didFireAnimationFrame):
(WebCore::PageDOMDebuggerAgent::setAnimationFrameBreakpoint):

  • inspector/agents/worker/WorkerDOMDebuggerAgent.h:
  • inspector/agents/worker/WorkerDOMDebuggerAgent.cpp:

(WebCore::WorkerDOMDebuggerAgent::setAnimationFrameBreakpoint):
Keep a JSC::Breakpoint for each event breakpoint instead of a simple bool, allowing for
configuration when the breakpoint is first set. When any of these breakpoints are hit, pass
it to the JSC::Debugger as a "special breakpoint", which behaves the same as "pause ASAP"
but also supports a condition, an ignore count, actions, and auto-continue. Reset the hit
count for any of these "special breakpoints" that persist across Web Inspector sessions
when the main frame navigates.

  • inspector/PageScriptDebugServer.h:
  • inspector/PageScriptDebugServer.cpp:

(WebCore::PageScriptDebugServer::PageScriptDebugServer):
(WebCore::PageScriptDebugServer::attachDebugger):
(WebCore::PageScriptDebugServer::detachDebugger):
(WebCore::PageScriptDebugServer::didPause):
(WebCore::PageScriptDebugServer::didContinue):
(WebCore::PageScriptDebugServer::runEventLoopWhilePaused):
(WebCore::PageScriptDebugServer::runEventLoopWhilePausedInternal):
(WebCore::PageScriptDebugServer::isContentScript const):
(WebCore::PageScriptDebugServer::reportException const):

  • inspector/WorkerScriptDebugServer.h:
  • inspector/WorkerScriptDebugServer.cpp:

(WebCore::WorkerScriptDebugServer::WorkerScriptDebugServer):
(WebCore::WorkerScriptDebugServer::attachDebugger):
(WebCore::WorkerScriptDebugServer::detachDebugger):
(WebCore::WorkerScriptDebugServer::runEventLoopWhilePaused):
(WebCore::WorkerScriptDebugServer::reportException const):

  • inspector/agents/page/PageDebuggerAgent.h:
  • inspector/agents/page/PageDebuggerAgent.cpp:

(WebCore::PageDebuggerAgent::sourceMapURLForScript):
Replace Inspector::ScriptDebugServer with JSC::Debugger.

  • inspector/TimelineRecordFactory.h:
  • inspector/TimelineRecordFactory.cpp:

(WebCore::TimelineRecordFactory::createProbeSampleData):

  • inspector/agents/InspectorTimelineAgent.h:
  • inspector/agents/InspectorTimelineAgent.cpp:

(WebCore::InspectorTimelineAgent::internalStart):
(WebCore::InspectorTimelineAgent::internalStop):
(WebCore::InspectorTimelineAgent::breakpointActionProbe):
Replace Inspector::ScriptBreakpoint with JSC::Breakpoint.

  • inspector/InspectorInstrumentation.h:

(WebCore::InspectorInstrumentation::didHandleEvent):
(WebCore::InspectorInstrumentation::didFireTimer):

  • inspector/InspectorInstrumentation.cpp:

(WebCore::InspectorInstrumentation::didHandleEventImpl):
(WebCore::InspectorInstrumentation::didFireTimerImpl):
(WebCore::InspectorInstrumentation::didCommitLoadImpl):
(WebCore::InspectorInstrumentation::didFireAnimationFrameImpl):

  • dom/EventTarget.cpp:

(WebCore::EventTarget::innerInvokeEventListeners):

  • page/DOMTimer.cpp:

(WebCore::DOMTimer::fired):
When notifying Web Inspector that activity did occur, include all information previously
included when notifying Web Inspector that that activity was about to occur so that Web
Inspector can know whether a pause for the "special breakpoint" for that activity is still
scheduled and if so cancel it.

Source/WebInspectorUI:

This allows developers to do things like:

  • only pause when window.event.type is a certain value
  • ignore the first N pauses
  • evaluate JavaScript whenever an event listener is invoked without pausing
  • UserInterface/Models/Breakpoint.js:

(WI.Breakpoint):
(WI.Breakpoint.prototype.toJSON):
(WI.Breakpoint.prototype.get special): Added.
(WI.Breakpoint.prototype.get removable): Added.
(WI.Breakpoint.prototype.get editable): Added.
(WI.Breakpoint.prototype.set condition):
(WI.Breakpoint.prototype.get ignoreCount):
(WI.Breakpoint.prototype.set ignoreCount):
(WI.Breakpoint.prototype.get autoContinue):
(WI.Breakpoint.prototype.set autoContinue):
(WI.Breakpoint.prototype.get actions):
(WI.Breakpoint.prototype.get probeActions):
(WI.Breakpoint.prototype.cycleToNextMode):
(WI.Breakpoint.prototype.createAction):
(WI.Breakpoint.prototype.recreateAction):
(WI.Breakpoint.prototype.removeAction):
(WI.Breakpoint.prototype.clearActions):
(WI.Breakpoint.prototype.remove): Added.
(WI.Breakpoint.prototype.optionsToProtocol): Added.
(WI.Breakpoint.prototype.breakpointActionDidChange):
(WI.Breakpoint.fromJSON): Deleted.
(WI.Breakpoint.prototype.get sourceCodeLocation): Deleted.
(WI.Breakpoint.prototype.get contentIdentifier): Deleted.
(WI.Breakpoint.prototype.get scriptIdentifier): Deleted.
(WI.Breakpoint.prototype.get target): Deleted.
(WI.Breakpoint.prototype.get identifier): Deleted.
(WI.Breakpoint.prototype.set identifier): Deleted.
(WI.Breakpoint.prototype.get resolved): Deleted.
(WI.Breakpoint.prototype.set resolved): Deleted.
(WI.Breakpoint.prototype.saveIdentityToCookie): Deleted.
(WI.Breakpoint.prototype._isSpecial): Deleted.
(WI.Breakpoint.prototype._sourceCodeLocationLocationChanged): Deleted.
(WI.Breakpoint.prototype._sourceCodeLocationDisplayLocationChanged): Deleted.

  • UserInterface/Models/DOMBreakpoint.js:

(WI.DOMBreakpoint):
(WI.DOMBreakpoint.fromJSON): Added.
(WI.DOMBreakpoint.prototype.remove): Added.
(WI.DOMBreakpoint.prototype.toJSON):
(WI.DOMBreakpoint.deserialize): Deleted.
(WI.DOMBreakpoint.prototype.get disabled): Deleted.
(WI.DOMBreakpoint.prototype.set disabled): Deleted.

  • UserInterface/Models/EventBreakpoint.js:

(WI.EventBreakpoint):
(WI.EventBreakpoint.fromJSON): Added.
(WI.EventBreakpoint.prototype.get special): Added.
(WI.EventBreakpoint.prototype.get editable): Added.
(WI.EventBreakpoint.prototype.remove): Added.
(WI.EventBreakpoint.prototype.saveIdentityToCookie):
(WI.EventBreakpoint.prototype.toJSON):
(WI.EventBreakpoint.deserialize): Deleted.
(WI.EventBreakpoint.prototype.get disabled): Deleted.
(WI.EventBreakpoint.prototype.set disabled): Deleted.

  • UserInterface/Models/JavaScriptBreakpoint.js: Copied from UserInterface/Models/Breakpoint.js.

(WI.JavaScriptBreakpoint):
(WI.JavaScriptBreakpoint.fromJSON):
(WI.JavaScriptBreakpoint.prototype.toJSON):
(WI.JavaScriptBreakpoint.prototype.get sourceCodeLocation):
(WI.JavaScriptBreakpoint.prototype.get contentIdentifier):
(WI.JavaScriptBreakpoint.prototype.get scriptIdentifier):
(WI.JavaScriptBreakpoint.prototype.get target):
(WI.JavaScriptBreakpoint.prototype.get special): Added.
(WI.JavaScriptBreakpoint.prototype.get removable): Added.
(WI.JavaScriptBreakpoint.prototype.get editable): Added.
(WI.JavaScriptBreakpoint.prototype.get identifier):
(WI.JavaScriptBreakpoint.prototype.set identifier):
(WI.JavaScriptBreakpoint.prototype.get resolved):
(WI.JavaScriptBreakpoint.prototype.set resolved):
(WI.JavaScriptBreakpoint.prototype.remove): Added.
(WI.JavaScriptBreakpoint.prototype.saveIdentityToCookie):
(WI.JavaScriptBreakpoint.prototype._isSpecial):
(WI.JavaScriptBreakpoint.prototype._sourceCodeLocationLocationChanged):
(WI.JavaScriptBreakpoint.prototype._sourceCodeLocationDisplayLocationChanged):

  • UserInterface/Models/URLBreakpoint.js:

(WI.URLBreakpoint):
(WI.URLBreakpoint.fromJSON): Added.
(WI.URLBreakpoint.prototype.get special): Added.
(WI.URLBreakpoint.prototype.remove): Added.
(WI.URLBreakpoint.prototype.toJSON):
(WI.URLBreakpoint.deserialize): Deleted.
(WI.URLBreakpoint.prototype.get disabled): Deleted.
(WI.URLBreakpoint.prototype.set disabled): Deleted.
Rename WI.Breakpoint to WI.JavaScriptBreakpoint and use WI.Breakpoint as a new common
base class for all breakpoint types, allowing more logic to be shared (e.g. disabled state).
Additionally, breakpoints are now able to

  • determine whether or not they're
    • special
    • removable
    • editable (i.e. configurable)
  • remove themselves

without the caller needing to know what manager to consult with.

  • UserInterface/Controllers/DOMManager.js:

(WI.DOMManager):
(WI.DOMManager.supportsEventListenerBreakpointConfiguration): Added.
(WI.DOMManager.prototype.setBreakpointForEventListener):
(WI.DOMManager.prototype.removeBreakpointForEventListener):
(WI.DOMManager.prototype._setEventBreakpoint): Added.
(WI.DOMManager.prototype._removeEventBreakpoint): Added.
(WI.DOMManager.prototype._handleEventBreakpointEditablePropertyChanged): Added.
(WI.DOMManager.prototype._handleEventBreakpointActionsChanged): Added.
(WI.DOMManager.prototype._updateEventBreakpoint): Deleted.
Keep track of configuration changes for specific listener breakpoints.

  • UserInterface/Controllers/DOMDebuggerManager.js:

(WI.DOMDebuggerManager):
(WI.DOMDebuggerManager.prototype.initializeTarget):
(WI.DOMDebuggerManager.prototype.addDOMBreakpoint):
(WI.DOMDebuggerManager.prototype.removeDOMBreakpoint):
(WI.DOMDebuggerManager.prototype.addEventBreakpoint):
(WI.DOMDebuggerManager.prototype.removeEventBreakpoint):
(WI.DOMDebuggerManager.prototype.addURLBreakpoint):
(WI.DOMDebuggerManager.prototype.removeURLBreakpoint):
(WI.DOMDebuggerManager.prototype._commandArgumentsForEventBreakpoint): Added.
(WI.DOMDebuggerManager.prototype._setEventBreakpoint): Added.
(WI.DOMDebuggerManager.prototype._removeEventBreakpoint): Added.
(WI.DOMDebuggerManager.prototype._handleEventBreakpointDisabledStateChanged): Added.
(WI.DOMDebuggerManager.prototype._handleEventBreakpointEditablePropertyChanged): Added.
(WI.DOMDebuggerManager.prototype._handleEventBreakpointActionsChanged): Added.
(WI.DOMDebuggerManager.prototype.isBreakpointSpecial): Deleted.
(WI.DOMDebuggerManager.prototype._updateEventBreakpoint): Deleted.
Keep track of configuration changes for special event breakpoints.
Store special event breakpoints inside WI.objectStores.eventBreakpoints.

  • UserInterface/Controllers/DebuggerManager.js:

(WI.DebuggerManager):
(WI.DebuggerManager.prototype.addBreakpoint):
(WI.DebuggerManager.prototype.removeBreakpoint):
(WI.DebuggerManager.prototype.addProbesForBreakpoint): Added.
(WI.DebuggerManager.prototype.removeProbesForBreakpoint): Added.
(WI.DebuggerManager.prototype.updateProbesForBreakpoint): Added.
(WI.DebuggerManager.prototype._setBreakpoint):
(WI.DebuggerManager.prototype._breakpointEditablePropertyDidChange):
(WI.DebuggerManager.prototype._handleBreakpointActionsDidChange):
(WI.DebuggerManager.prototype.isBreakpointRemovable): Deleted.
(WI.DebuggerManager.prototype.isBreakpointSpecial): Deleted.
(WI.DebuggerManager.prototype.isBreakpointEditable): Deleted.
(WI.DebuggerManager.prototype._debuggerBreakpointActionType): Deleted.
(WI.DebuggerManager.prototype._debuggerBreakpointOptions): Deleted.
(WI.DebuggerManager.prototype._addProbesForBreakpoint): Deleted.
(WI.DebuggerManager.prototype._removeProbesForBreakpoint): Deleted.
(WI.DebuggerManager.prototype._updateProbesForBreakpoint): Deleted.
Replace WI.Breakpoint with WI.JavaScriptBreakpoint.
Probes now support WI.EventBreakpoint in addition to WI.JavaScriptBreakpoint.

  • UserInterface/Controllers/BreakpointPopoverController.js:

(WI.BreakpointPopoverController.prototype.appendContextMenuItems):
(WI.BreakpointPopoverController.prototype._createPopoverContent):
Allow any breakpoint instead of only WI.JavaScriptBreakpoint.
Drive-by: the existing ignoreCount value wasn't being used to populate the <input>.

  • UserInterface/Views/BreakpointTreeElement.js:

(WI.BreakpointTreeElement.prototype.ondelete):
(WI.BreakpointTreeElement.prototype.get listenerSet): Added.
(WI.BreakpointTreeElement.prototype.updateStatus): Added.
(WI.BreakpointTreeElement.prototype.updateTitles): Added.
(WI.BreakpointTreeElement.prototype.get breakpoint): Deleted.
(WI.BreakpointTreeElement.prototype.get filterableData): Deleted.
(WI.BreakpointTreeElement.prototype._updateTitles): Deleted.
(WI.BreakpointTreeElement.prototype._updateStatus): Deleted.
(WI.BreakpointTreeElement.prototype._breakpointLocationDidChange): Deleted.

  • UserInterface/Views/BreakpointTreeElement.css:

(.item.breakpoint .status > .status-image):
(.item.breakpoint.paused .icon): Added.
(@media (prefers-color-scheme: dark) .item.breakpoint.paused .icon): Added.
(.item.breakpoint .status > .status-image.resolved): Deleted.
(body:not(.window-inactive, .window-docked-inactive) .tree-outline:focus-within .item.breakpoint.selected .status > .status-image.resolved): Deleted.
(.item.breakpoint .subtitle.formatted-location): Deleted.
(.breakpoint-debugger-statement-icon .icon): Deleted.
(.breakpoint-exception-icon .icon): Deleted.
(.breakpoint-assertion-icon .icon): Deleted.
(.breakpoint-microtask-icon .icon): Deleted.
(.breakpoint-paused-icon .icon): Deleted.
(.breakpoint-generic-line-icon .icon): Deleted.
(.breakpoint-generic-line-icon .icon > span): Deleted.
(.data-updated.breakpoint-generic-line-icon .icon > span): Deleted.
(@media (prefers-color-scheme: dark) .breakpoint-debugger-statement-icon .icon): Deleted.
(@media (prefers-color-scheme: dark) .breakpoint-exception-icon .icon): Deleted.
(@media (prefers-color-scheme: dark) .breakpoint-assertion-icon .icon): Deleted.
(@media (prefers-color-scheme: dark) .breakpoint-microtask-icon .icon): Deleted.
(@media (prefers-color-scheme: dark) .breakpoint-paused-icon .icon): Deleted.
(@media (prefers-color-scheme: dark) .breakpoint-generic-line-icon .icon): Deleted.

  • UserInterface/Views/DOMBreakpointTreeElement.js:

(WI.DOMBreakpointTreeElement):
(WI.DOMBreakpointTreeElement.prototype.onattach): Deleted.
(WI.DOMBreakpointTreeElement.prototype.ondetach): Deleted.
(WI.DOMBreakpointTreeElement.prototype.ondelete): Deleted.
(WI.DOMBreakpointTreeElement.prototype.onenter): Deleted.
(WI.DOMBreakpointTreeElement.prototype.onspace): Deleted.
(WI.DOMBreakpointTreeElement.prototype.populateContextMenu): Deleted.
(WI.DOMBreakpointTreeElement.prototype._statusImageElementClicked): Deleted.
(WI.DOMBreakpointTreeElement.prototype._statusImageElementFocused): Deleted.
(WI.DOMBreakpointTreeElement.prototype._statusImageElementMouseDown): Deleted.
(WI.DOMBreakpointTreeElement.prototype._toggleBreakpoint): Deleted.
(WI.DOMBreakpointTreeElement.prototype._updateStatus): Deleted.

  • UserInterface/Views/DOMBreakpointTreeElement.css:

(.item.breakpoint.dom.subtree-modified:not(.paused) .icon): Added.
(.item.breakpoint.dom.attribute-modified:not(.paused) .icon): Added.
(.item.breakpoint.dom.node-removed:not(.paused) .icon): Added.
(@media (prefers-color-scheme: dark) .item.breakpoint.dom.subtree-modified:not(.paused) .icon): Added.
(@media (prefers-color-scheme: dark) .item.breakpoint.dom.attribute-modified:not(.paused) .icon): Added.
(@media (prefers-color-scheme: dark) .item.breakpoint.dom.node-removed:not(.paused) .icon): Added.
(.breakpoint.dom.breakpoint-for-subtree-modified:not(.breakpoint-paused-icon) .icon): Deleted.
(.breakpoint.dom.breakpoint-for-attribute-modified:not(.breakpoint-paused-icon) .icon): Deleted.
(.breakpoint.dom.breakpoint-for-node-removed:not(.breakpoint-paused-icon) .icon): Deleted.
(@media (prefers-color-scheme: dark) .breakpoint.dom.breakpoint-for-subtree-modified:not(.breakpoint-paused-icon) .icon): Deleted.
(@media (prefers-color-scheme: dark) .breakpoint.dom.breakpoint-for-attribute-modified:not(.breakpoint-paused-icon) .icon): Deleted.
(@media (prefers-color-scheme: dark) .breakpoint.dom.breakpoint-for-node-removed:not(.breakpoint-paused-icon) .icon): Deleted.

  • UserInterface/Views/EventBreakpointTreeElement.js:

(WI.EventBreakpointTreeElement):
(WI.EventBreakpointTreeElement.prototype.onattach): Deleted.
(WI.EventBreakpointTreeElement.prototype.ondetach): Deleted.
(WI.EventBreakpointTreeElement.prototype.ondelete): Deleted.
(WI.EventBreakpointTreeElement.prototype.onenter): Deleted.
(WI.EventBreakpointTreeElement.prototype.onspace): Deleted.
(WI.EventBreakpointTreeElement.prototype.populateContextMenu): Deleted.
(WI.EventBreakpointTreeElement.prototype._statusImageElementClicked): Deleted.
(WI.EventBreakpointTreeElement.prototype._statusImageElementFocused): Deleted.
(WI.EventBreakpointTreeElement.prototype._statusImageElementMouseDown): Deleted.
(WI.EventBreakpointTreeElement.prototype._toggleBreakpoint): Deleted.
(WI.EventBreakpointTreeElement.prototype._updateStatus): Deleted.

  • UserInterface/Views/EventBreakpointTreeElement.css:

(.item.breakpoint.event.animation-frame:not(.paused) .icon): Added.
(.item.breakpoint.event.interval:not(.paused) .icon): Added.
(.item.breakpoint.event.listener:not(.paused) .icon): Added.
(.item.breakpoint.event.timeout:not(.paused) .icon): Added.
(@media(prefers-color-scheme: dark) .item.breakpoint.event.animation-frame:not(.paused) .icon): Added.
(@media(prefers-color-scheme: dark) .item.breakpoint.event.interval:not(.paused) .icon): Added.
(@media(prefers-color-scheme: dark) .item.breakpoint.event.listener:not(.paused) .icon): Added.
(@media(prefers-color-scheme: dark) .item.breakpoint.event.timeout:not(.paused) .icon): Added.
(.breakpoint.event.breakpoint-for-animation-frame:not(.breakpoint-paused-icon) .icon): Deleted.
(.breakpoint.event.breakpoint-for-interval:not(.breakpoint-paused-icon) .icon): Deleted.
(.breakpoint.event.breakpoint-for-listener:not(.breakpoint-paused-icon) .icon): Deleted.
(.breakpoint.event.breakpoint-for-timeout:not(.breakpoint-paused-icon) .icon): Deleted.
(@media(prefers-color-scheme: dark) .breakpoint.event.breakpoint-for-animation-frame:not(.breakpoint-paused-icon) .icon): Deleted.
(@media(prefers-color-scheme: dark) .breakpoint.event.breakpoint-for-interval:not(.breakpoint-paused-icon) .icon): Deleted.
(@media(prefers-color-scheme: dark) .breakpoint.event.breakpoint-for-listener:not(.breakpoint-paused-icon) .icon): Deleted.
(@media(prefers-color-scheme: dark) .breakpoint.event.breakpoint-for-timeout:not(.breakpoint-paused-icon) .icon): Deleted.

  • UserInterface/Views/JavaScriptBreakpointTreeElement.js: Copied from Source/WebInspectorUI/UserInterface/Views/BreakpointTreeElement.js.

(WI.JavaScriptBreakpointTreeElement):
(WI.JavaScriptBreakpointTreeElement.prototype.get filterableData):
(WI.JavaScriptBreakpointTreeElement.prototype.updateStatus): Added.
(WI.JavaScriptBreakpointTreeElement.prototype.updateTitles): Added.
(WI.JavaScriptBreakpointTreeElement.prototype._breakpointLocationDidChange):

  • UserInterface/Views/JavaScriptBreakpointTreeElement.css: Copied from Source/WebInspectorUI/UserInterface/Views/BreakpointTreeElement.css.

(.item.breakpoint.javascript .status > .status-image): Added.
(.item.breakpoint.javascript .status > .status-image.resolved): Added.
(body:not(.window-inactive, .window-docked-inactive) .tree-outline:focus-within .item.breakpoint.javascript.selected .status > .status-image.resolved): Added.
(.item.breakpoint.javascript .subtitle.formatted-location): Added.
(.item.breakpoint.javascript.line .icon): Added.
(.item.breakpoint.javascript.line .icon > span): Added.
(.data-updated.item.breakpoint.javascript.line .icon > span): Added.
(.item.breakpoint.javascript.debugger-statement .icon): Added.
(.item.breakpoint.javascript.exception .icon): Added.
(.item.breakpoint.javascript.assertion .icon): Added.
(.item.breakpoint.javascript.microtask .icon): Added.
(@media (prefers-color-scheme: dark) .item.breakpoint.javascript.line .icon): Added.
(@media (prefers-color-scheme: dark) .item.breakpoint.javascript.debugger-statement .icon): Added.
(@media (prefers-color-scheme: dark) .item.breakpoint.javascript.exception .icon): Added.
(@media (prefers-color-scheme: dark) .item.breakpoint.javascript.assertion .icon): Added.
(@media (prefers-color-scheme: dark) .item.breakpoint.javascript.microtask .icon): Added.

  • UserInterface/Views/URLBreakpointTreeElement.js:

(WI.URLBreakpointTreeElement):
(WI.URLBreakpointTreeElement.prototype.onattach): Deleted.
(WI.URLBreakpointTreeElement.prototype.ondetach): Deleted.
(WI.URLBreakpointTreeElement.prototype.ondelete): Deleted.
(WI.URLBreakpointTreeElement.prototype.onenter): Deleted.
(WI.URLBreakpointTreeElement.prototype.onspace): Deleted.
(WI.URLBreakpointTreeElement.prototype.populateContextMenu): Deleted.
(WI.URLBreakpointTreeElement.prototype._statusImageElementClicked): Deleted.
(WI.URLBreakpointTreeElement.prototype._statusImageElementFocused): Deleted.
(WI.URLBreakpointTreeElement.prototype._statusImageElementMouseDown): Deleted.
(WI.URLBreakpointTreeElement.prototype._toggleBreakpoint): Deleted.
(WI.URLBreakpointTreeElement.prototype._updateStatus): Deleted.

  • UserInterface/Views/URLBreakpointTreeElement.css:

(.item.breakpoint.url .subtitle): Added.
(.item.breakpoint.url:not(.paused) .icon): Added.
(@media (prefers-color-scheme: dark) .item.breakpoint.url:not(.paused) .icon): Added.
(.breakpoint.url .subtitle): Deleted.
(.breakpoint.url:not(.breakpoint-paused-icon) .icon): Deleted.
(@media (prefers-color-scheme: dark) .breakpoint.url:not(.breakpoint-paused-icon) .icon): Deleted.
Rename WI.BreakpointTreeElement to WI.JavaScriptBreakpointTreeElement and use
WI.BreakpointTreeElement as a new common base class for all breakpoint tree elements,
allowing more logic and styles to be shared (e.g. disabled state).

  • UserInterface/Views/SourcesNavigationSidebarPanel.js:

(WI.SourcesNavigationSidebarPanel):
(WI.SourcesNavigationSidebarPanel.prototype.closed):
(WI.SourcesNavigationSidebarPanel.prototype._insertDebuggerTreeElement):
(WI.SourcesNavigationSidebarPanel.prototype._compareJavaScriptBreakpointTreeElements): Added.
(WI.SourcesNavigationSidebarPanel.prototype._addBreakpoint):
(WI.SourcesNavigationSidebarPanel.prototype._removeAllBreakpoints):
(WI.SourcesNavigationSidebarPanel.prototype._breakpointsBeneathTreeElement):
(WI.SourcesNavigationSidebarPanel.prototype._addIssue):
(WI.SourcesNavigationSidebarPanel.prototype._updatePauseReasonSection):
(WI.SourcesNavigationSidebarPanel.prototype._handleTreeSelectionDidChange):
(WI.SourcesNavigationSidebarPanel.prototype._handleBreakpointElementAddedOrRemoved):
(WI.SourcesNavigationSidebarPanel.prototype._populateCreateBreakpointContextMenu.addToggleForSpecialEventBreakpoint):
(WI.SourcesNavigationSidebarPanel.prototype._populateCreateBreakpointContextMenu):
(WI.SourcesNavigationSidebarPanel.prototype._handleDebuggerObjectDisplayLocationDidChange):
(WI.SourcesNavigationSidebarPanel.prototype._compareBreakpointTreeElements): Deleted.

  • UserInterface/Models/ProbeSet.js:

(WI.ProbeSet):
(WI.ProbeSet.prototype.createProbe):
(WI.ProbeSet.prototype.willRemove):

  • UserInterface/Controllers/TimelineManager.js:

(WI.TimelineManager.prototype._processRecord):

  • UserInterface/Views/ProbeSetDetailsSection.js:

(WI.ProbeSetDetailsSection):

  • UserInterface/Views/ProbeDetailsSidebarPanel.js:

(WI.ProbeDetailsSidebarPanel.prototype.inspect):

  • UserInterface/Views/SourceCodeTextEditor.js:

(WI.SourceCodeTextEditor):
(WI.SourceCodeTextEditor.prototype.close):
(WI.SourceCodeTextEditor.prototype.textEditorBreakpointAdded):

  • UserInterface/Views/TextResourceContentView.js:

(WI.TextResourceContentView.prototype.get supplementalRepresentedObjects):
(WI.TextResourceContentView.prototype._probeSetsChanged):
Probes now support WI.EventBreakpoint in addition to WI.JavaScriptBreakpoint.

  • UserInterface/Views/ContentView.js:

(WI.ContentView.createFromRepresentedObject):
(WI.ContentView.resolvedRepresentedObjectForRepresentedObject):
(WI.ContentView.isViewable):

  • UserInterface/Views/ContextMenuUtilities.js:

(WI.appendContextMenuItemsForSourceCode):
Replace WI.Breakpoint with WI.JavaScriptBreakpoint.

  • UserInterface/Views/DOMTreeContentView.js:

(WI.DOMTreeContentView):
Replace WI.DOMBreakpoint with WI.Breakpoint.

  • UserInterface/Views/EventListenerSectionGroup.js:

(WI.EventListenerSectionGroup):

  • UserInterface/Views/EventListenerSectionGroup.css:

(.event-listener-section > .content input[type="checkbox"] + .go-to-arrow): Added.
(.event-listener-section > .content input[type="checkbox"]:not(:checked) + .go-to-arrow): Added.
Add a go-to arrow next to the Breakpoint checkbox that reveals the WI.EventBreakpoint in
the Sources Tab.

  • UserInterface/Views/BreakpointActionView.js:

(WI.BreakpointActionView.prototype._appendActionButtonClicked):
Drive-by: minor code cleanup.

  • UserInterface/Views/CallFrameTreeElement.js:

(WI.CallFrameTreeElement.prototype.populateContextMenu):
Drive-by: include source code location context menu items.

  • UserInterface/Base/Setting.js:
  • UserInterface/Main.html:
  • UserInterface/Test.html:

LayoutTests:

  • inspector/dom-debugger/resources/event-breakpoint-utilities.js:

(TestPage.registerInitializer.InspectorTest.EventBreakpoint.addBreakpointOptionsTestCases): Added.
(TestPage.registerInitializer.InspectorTest.EventBreakpoint.async teardown):
(TestPage.registerInitializer.InspectorTest.EventBreakpoint.createBreakpoint):
(TestPage.registerInitializer.InspectorTest.EventBreakpoint.removeBreakpoint):

  • inspector/dom/breakpoint-for-event-listener.html:
  • inspector/dom/breakpoint-for-event-listener-expected.txt:
  • inspector/dom-debugger/event-animation-frame-breakpoints.html:
  • inspector/dom-debugger/event-animation-frame-breakpoints-expected.txt:
  • inspector/dom-debugger/event-interval-breakpoints.html:
  • inspector/dom-debugger/event-interval-breakpoints-expected.txt:
  • inspector/dom-debugger/event-listener-breakpoints.html:
  • inspector/dom-debugger/event-listener-breakpoints-expected.txt:
  • inspector/dom-debugger/event-timeout-breakpoints.html:
  • inspector/dom-debugger/event-timeout-breakpoints-expected.txt:

Add tests for new event breakpoint configuration options.

  • http/tests/inspector/debugger/debugger-test.js:

(TestPage.registerInitializer.InspectorTest.startTracingBreakpoints):

  • http/tests/inspector/resources/probe-test.js:

(TestPage.registerInitializer.ProtocolTest.Probe.installTracingListeners):

  • inspector/debugger/breakpoint-action-eval.html:
  • inspector/debugger/breakpoint-action-log.html:
  • inspector/debugger/breakpoint-columns.html:
  • inspector/debugger/breakpoint-scope.html:
  • inspector/debugger/debugger-stack-overflow.html:
  • inspector/debugger/pause-reason.html:
  • inspector/debugger/probe-manager-add-remove-actions.html:
  • inspector/debugger/stepping/stepping-through-autoContinue-breakpoint.html:
  • inspector/debugger/tail-deleted-frames-this-value.html:
  • inspector/debugger/tail-recursion.html:
  • inspector/worker/debugger-pause.html:
  • inspector/worker/debugger-shared-breakpoint.html:

Update existing breakpoint tests to use new model objects.

Location:
trunk
Files:
3 added
4 deleted
107 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r266073 r266074  
     12020-08-24  Devin Rousso  <drousso@apple.com>
     2
     3        Web Inspector: allow event breakpoints to be configured
     4        https://bugs.webkit.org/show_bug.cgi?id=215362
     5        <rdar://problem/66932921>
     6
     7        Reviewed by Brian Burg.
     8
     9        * inspector/dom-debugger/resources/event-breakpoint-utilities.js:
     10        (TestPage.registerInitializer.InspectorTest.EventBreakpoint.addBreakpointOptionsTestCases): Added.
     11        (TestPage.registerInitializer.InspectorTest.EventBreakpoint.async teardown):
     12        (TestPage.registerInitializer.InspectorTest.EventBreakpoint.createBreakpoint):
     13        (TestPage.registerInitializer.InspectorTest.EventBreakpoint.removeBreakpoint):
     14        * inspector/dom/breakpoint-for-event-listener.html:
     15        * inspector/dom/breakpoint-for-event-listener-expected.txt:
     16        * inspector/dom-debugger/event-animation-frame-breakpoints.html:
     17        * inspector/dom-debugger/event-animation-frame-breakpoints-expected.txt:
     18        * inspector/dom-debugger/event-interval-breakpoints.html:
     19        * inspector/dom-debugger/event-interval-breakpoints-expected.txt:
     20        * inspector/dom-debugger/event-listener-breakpoints.html:
     21        * inspector/dom-debugger/event-listener-breakpoints-expected.txt:
     22        * inspector/dom-debugger/event-timeout-breakpoints.html:
     23        * inspector/dom-debugger/event-timeout-breakpoints-expected.txt:
     24        Add tests for new event breakpoint configuration options.
     25
     26        * http/tests/inspector/debugger/debugger-test.js:
     27        (TestPage.registerInitializer.InspectorTest.startTracingBreakpoints):
     28        * http/tests/inspector/resources/probe-test.js:
     29        (TestPage.registerInitializer.ProtocolTest.Probe.installTracingListeners):
     30        * inspector/debugger/breakpoint-action-eval.html:
     31        * inspector/debugger/breakpoint-action-log.html:
     32        * inspector/debugger/breakpoint-columns.html:
     33        * inspector/debugger/breakpoint-scope.html:
     34        * inspector/debugger/debugger-stack-overflow.html:
     35        * inspector/debugger/pause-reason.html:
     36        * inspector/debugger/probe-manager-add-remove-actions.html:
     37        * inspector/debugger/stepping/stepping-through-autoContinue-breakpoint.html:
     38        * inspector/debugger/tail-deleted-frames-this-value.html:
     39        * inspector/debugger/tail-recursion.html:
     40        * inspector/worker/debugger-pause.html:
     41        * inspector/worker/debugger-shared-breakpoint.html:
     42        Update existing breakpoint tests to use new model objects.
     43
    1442020-08-24  Hector Lopez  <hector_i_lopez@apple.com>
    245
  • trunk/LayoutTests/http/tests/inspector/debugger/debugger-test.js

    r236845 r266074  
    1414    });
    1515
    16     WI.Breakpoint.addEventListener(WI.Breakpoint.Event.DisabledStateDidChange, function(event) {
     16    WI.JavaScriptBreakpoint.addEventListener(WI.Breakpoint.Event.DisabledStateDidChange, function(event) {
    1717        var breakpoint = event.target;
    18         console.assert(breakpoint instanceof WI.Breakpoint, "Unexpected object type!");
     18        console.assert(breakpoint instanceof WI.JavaScriptBreakpoint, "Unexpected object type!");
    1919
    2020        InspectorTest.log("Breakpoint disabled state changed: " + breakpoint.disabled);
    2121    });
    2222
    23     WI.Breakpoint.addEventListener(WI.Breakpoint.Event.ResolvedStateDidChange, function(event) {
     23    WI.JavaScriptBreakpoint.addEventListener(WI.JavaScriptBreakpoint.Event.ResolvedStateDidChange, function(event) {
    2424        var breakpoint = event.target;
    25         console.assert(breakpoint instanceof WI.Breakpoint, "Unexpected object type!");
     25        console.assert(breakpoint instanceof WI.JavaScriptBreakpoint, "Unexpected object type!");
    2626
    2727        InspectorTest.log("Breakpoint resolved state changed: " + breakpoint.resolved);
    2828    });
    2929
    30     WI.Breakpoint.addEventListener(WI.Breakpoint.Event.AutoContinueDidChange, function(event) {
     30    WI.JavaScriptBreakpoint.addEventListener(WI.Breakpoint.Event.AutoContinueDidChange, function(event) {
    3131        var breakpoint = event.target;
    32         console.assert(breakpoint instanceof WI.Breakpoint, "Unexpected object type!");
     32        console.assert(breakpoint instanceof WI.JavaScriptBreakpoint, "Unexpected object type!");
    3333
    3434        InspectorTest.log("Breakpoint autocontinue state changed: " + breakpoint.autoContinue);
    3535    });
    3636
    37     WI.Breakpoint.addEventListener(WI.Breakpoint.Event.ConditionDidChange, function(event) {
     37    WI.JavaScriptBreakpoint.addEventListener(WI.Breakpoint.Event.ConditionDidChange, function(event) {
    3838        var breakpoint = event.target;
    39         console.assert(breakpoint instanceof WI.Breakpoint, "Unexpected object type!");
     39        console.assert(breakpoint instanceof WI.JavaScriptBreakpoint, "Unexpected object type!");
    4040
    4141        InspectorTest.log("Breakpoint condition changed: " + breakpoint.condition);
    4242    });
    4343
    44     WI.Breakpoint.addEventListener(WI.Breakpoint.Event.ActionsDidChange, function(event) {
     44    WI.JavaScriptBreakpoint.addEventListener(WI.Breakpoint.Event.ActionsDidChange, function(event) {
    4545        var breakpoint = event.target;
    46         console.assert(breakpoint instanceof WI.Breakpoint, "Unexpected object type!");
     46        console.assert(breakpoint instanceof WI.JavaScriptBreakpoint, "Unexpected object type!");
    4747
    4848        InspectorTest.log("Breakpoint actions changed. New count: " + breakpoint.actions.length);
  • trunk/LayoutTests/http/tests/inspector/resources/probe-test.js

    r236845 r266074  
    6161    });
    6262
    63     WI.Breakpoint.addEventListener(WI.Breakpoint.Event.DisabledStateDidChange, function(event) {
     63    WI.JavaScriptBreakpoint.addEventListener(WI.Breakpoint.Event.DisabledStateDidChange, function(event) {
    6464        var breakpoint = event.target;
    65         console.assert(breakpoint instanceof WI.Breakpoint, "Unexpected object type!");
     65        console.assert(breakpoint instanceof WI.JavaScriptBreakpoint, "Unexpected object type!");
    6666
    6767        InspectorTest.log("Breakpoint disabled state changed: " + breakpoint.disabled);
    6868    });
    6969
    70     WI.Breakpoint.addEventListener(WI.Breakpoint.Event.ResolvedStateDidChange, function(event) {
     70    WI.JavaScriptBreakpoint.addEventListener(WI.JavaScriptBreakpoint.Event.ResolvedStateDidChange, function(event) {
    7171        var breakpoint = event.target;
    72         console.assert(breakpoint instanceof WI.Breakpoint, "Unexpected object type!");
     72        console.assert(breakpoint instanceof WI.JavaScriptBreakpoint, "Unexpected object type!");
    7373
    7474        InspectorTest.log("Breakpoint resolved state changed: " + breakpoint.resolved);
    7575    });
    7676
    77     WI.Breakpoint.addEventListener(WI.Breakpoint.Event.AutoContinueDidChange, function(event) {
     77    WI.JavaScriptBreakpoint.addEventListener(WI.Breakpoint.Event.AutoContinueDidChange, function(event) {
    7878        var breakpoint = event.target;
    79         console.assert(breakpoint instanceof WI.Breakpoint, "Unexpected object type!");
     79        console.assert(breakpoint instanceof WI.JavaScriptBreakpoint, "Unexpected object type!");
    8080
    8181        InspectorTest.log("Breakpoint autocontinue state changed: " + breakpoint.autoContinue);
    8282    });
    8383
    84     WI.Breakpoint.addEventListener(WI.Breakpoint.Event.ConditionDidChange, function(event) {
     84    WI.JavaScriptBreakpoint.addEventListener(WI.Breakpoint.Event.ConditionDidChange, function(event) {
    8585        var breakpoint = event.target;
    86         console.assert(breakpoint instanceof WI.Breakpoint, "Unexpected object type!");
     86        console.assert(breakpoint instanceof WI.JavaScriptBreakpoint, "Unexpected object type!");
    8787
    8888        InspectorTest.log("Breakpoint condition changed: " + breakpoint.condition);
    8989    });
    9090
    91     WI.Breakpoint.addEventListener(WI.Breakpoint.Event.ActionsDidChange, function(event) {
     91    WI.JavaScriptBreakpoint.addEventListener(WI.Breakpoint.Event.ActionsDidChange, function(event) {
    9292        var breakpoint = event.target;
    93         console.assert(breakpoint instanceof WI.Breakpoint, "Unexpected object type!");
     93        console.assert(breakpoint instanceof WI.JavaScriptBreakpoint, "Unexpected object type!");
    9494
    9595        InspectorTest.log("Breakpoint actions changed. New count: " + breakpoint.actions.length);
  • trunk/LayoutTests/inspector/debugger/breakpoint-action-eval.html

    r251485 r266074  
    2929        var location = scriptObject.createSourceCodeLocation(4, 0);
    3030        // Create the breakpoint and its actions before sending anything to the backend.
    31         var breakpoint = new WI.Breakpoint(location);
     31        var breakpoint = new WI.JavaScriptBreakpoint(location);
    3232        breakpoint.autoContinue = true;
    33         breakpoint.createAction(WI.BreakpointAction.Type.Evaluate, null, "action(a, b)");
     33        breakpoint.createAction(WI.BreakpointAction.Type.Evaluate, {data: "action(a, b)"});
    3434
    3535        WI.debuggerManager.addBreakpoint(breakpoint);
  • trunk/LayoutTests/inspector/debugger/breakpoint-action-log.html

    r251485 r266074  
    2525
    2626                let location = scriptObject.createSourceCodeLocation(4, 0);
    27                 let breakpoint = new WI.Breakpoint(location);
     27                let breakpoint = new WI.JavaScriptBreakpoint(location);
    2828                breakpoint.autoContinue = true;
    2929
    3030                function addLogAction(data) {
    31                     breakpoint.createAction(WI.BreakpointAction.Type.Log, breakpoint.actions.lastValue, data);
     31                    breakpoint.createAction(WI.BreakpointAction.Type.Log, {data});
    3232                }
    3333
  • trunk/LayoutTests/inspector/debugger/breakpoint-columns.html

    r220119 r266074  
    3939       
    4040        var location = currentScripts[testInfo.scriptIndex].createSourceCodeLocation(testInfo.line, testInfo.column);
    41         var breakpoint = new WI.Breakpoint(location);
     41        var breakpoint = new WI.JavaScriptBreakpoint(location);
    4242
    4343        WI.debuggerManager.addBreakpoint(breakpoint);
  • trunk/LayoutTests/inspector/debugger/breakpoint-scope.html

    r237571 r266074  
    3030        var testInfo = testInfoList[currentTestIndex];
    3131        var location = scriptObject.createSourceCodeLocation(testInfo.line, testInfo.column);
    32         var breakpoint = new WI.Breakpoint(location);
     32        var breakpoint = new WI.JavaScriptBreakpoint(location);
    3333
    3434        WI.debuggerManager.addBreakpoint(breakpoint);
  • trunk/LayoutTests/inspector/debugger/debugger-stack-overflow.html

    r220119 r266074  
    1616        let testInfo = {line: 8, column: 8};
    1717        let location = scriptObject.createSourceCodeLocation(testInfo.line, testInfo.column);
    18         let breakpoint = new WI.Breakpoint(location);
     18        let breakpoint = new WI.JavaScriptBreakpoint(location);
    1919        WI.debuggerManager.addBreakpoint(breakpoint);
    2020        InspectorTest.evaluateInPage("start()");
  • trunk/LayoutTests/inspector/debugger/pause-reason.html

    r236540 r266074  
    1717            continue;
    1818        let sourceCodeLocation = script.createSourceCodeLocation(3, 0);
    19         let breakpoint = new WI.Breakpoint(sourceCodeLocation);
     19        let breakpoint = new WI.JavaScriptBreakpoint(sourceCodeLocation);
    2020        WI.debuggerManager.addBreakpoint(breakpoint);
    2121        break;
  • trunk/LayoutTests/inspector/debugger/probe-manager-add-remove-actions.html

    r251485 r266074  
    3434            var location = scriptObject.createSourceCodeLocation(4, 0);
    3535            // Create the breakpoint and its actions before sending anything to the backend.
    36             var breakpoint = new WI.Breakpoint(location);
     36            var breakpoint = new WI.JavaScriptBreakpoint(location);
    3737            breakpoint.autoContinue = true;
    3838            for (var i of [0, 1])
    39                 breakpoint.createAction(WI.BreakpointAction.Type.Probe, null, "a");
     39                breakpoint.createAction(WI.BreakpointAction.Type.Probe, {data: "a"});
    4040
    4141            WI.debuggerManager.addBreakpoint(breakpoint);
    4242
    43             breakpoint.addEventListener(WI.Breakpoint.Event.ResolvedStateDidChange, function() {
     43            breakpoint.addEventListener(WI.JavaScriptBreakpoint.Event.ResolvedStateDidChange, function() {
    4444                InspectorTest.expectThat(breakpoint.resolved, "Breakpoint should be resolved.");
    4545            });
  • trunk/LayoutTests/inspector/debugger/stepping/stepping-through-autoContinue-breakpoint.html

    r236766 r266074  
    2525            let script = WI.networkManager.mainFrame.mainResource.scripts[0];
    2626            var location = script.createSourceCodeLocation(8, 0);
    27             var breakpoint = new WI.Breakpoint(location);
     27            var breakpoint = new WI.JavaScriptBreakpoint(location);
    2828            breakpoint.autoContinue = true;
    29             breakpoint.createAction(WI.BreakpointAction.Type.Evaluate, null, "alert(1.5);");
     29            breakpoint.createAction(WI.BreakpointAction.Type.Evaluate, {data: "alert(1.5);"});
    3030            WI.debuggerManager.addBreakpoint(breakpoint);
    3131
  • trunk/LayoutTests/inspector/debugger/tail-deleted-frames-this-value.html

    r249445 r266074  
    1616        let testInfo = {line: 3, column: 4};
    1717        let location = scriptObject.createSourceCodeLocation(testInfo.line, testInfo.column);
    18         let breakpoint = new WI.Breakpoint(location);
     18        let breakpoint = new WI.JavaScriptBreakpoint(location);
    1919        WI.debuggerManager.addBreakpoint(breakpoint);
    2020        InspectorTest.evaluateInPage("startABC()");
  • trunk/LayoutTests/inspector/debugger/tail-recursion.html

    r237571 r266074  
    2525        for (let testInfo of testInfos) {
    2626            let location = scriptObject.createSourceCodeLocation(testInfo.line, testInfo.column);
    27             let breakpoint = new WI.Breakpoint(location);
     27            let breakpoint = new WI.JavaScriptBreakpoint(location);
    2828            WI.debuggerManager.addBreakpoint(breakpoint);
    2929        }
  • trunk/LayoutTests/inspector/dom-debugger/event-animation-frame-breakpoints-expected.txt

    r248201 r266074  
     1CONSOLE MESSAGE: BREAKPOINT ACTION LOG 1
     2CONSOLE MESSAGE: BREAKPOINT ACTION LOG 2
     3CONSOLE MESSAGE: BREAKPOINT ACTION LOG 3
     4CONSOLE MESSAGE: BREAKPOINT ACTION LOG 4
    15Tests for Event AnimationFrame breakpoints.
    26
     
    48== Running test suite: DOMDebugger.Event.AnimationFrame
    59-- Running test case: DOMDebugger.Event.AnimationFrame.AddBreakpoint
     10Creating "animation-frame" Event Breakpoint...
    611Adding "animation-frame" Event Breakpoint...
    712Firing "requestAnimationFrame" on window...
     
    1621
    1722-- Running test case: DOMDebugger.Event.AnimationFrame.AddDisabledBreakpoint
     23Creating "animation-frame" Event Breakpoint...
    1824Adding "animation-frame" Event Breakpoint...
    1925Disabling "animation-frame" Event Breakpoint...
     
    2329
    2430-- Running test case: DOMDebugger.Event.AnimationFrame.RemoveBreakpoint
     31Creating "animation-frame" Event Breakpoint...
    2532Adding "animation-frame" Event Breakpoint...
    2633Removing "animation-frame" Event Breakpoint...
     
    3037
    3138-- Running test case: DOMDebugger.Event.AnimationFrame.RemoveDisabledBreakpoint
     39Creating "animation-frame" Event Breakpoint...
    3240Adding "animation-frame" Event Breakpoint...
    3341Disabling "animation-frame" Event Breakpoint...
     
    3745-- Running test teardown.
    3846
     47-- Running test case: DOMDebugger.Event.AnimationFrame.Options.Condition
     48Creating "animation-frame" Event Breakpoint...
     49Adding "animation-frame" Event Breakpoint...
     50
     51Setting condition to 'false'...
     52
     53Triggering breakpoint...
     54PASS: Should not pause.
     55
     56Triggering breakpoint...
     57PASS: Should not pause.
     58
     59Setting condition to 'true'...
     60
     61Triggering breakpoint...
     62PASS: Should pause.
     63
     64Triggering breakpoint...
     65PASS: Should pause.
     66-- Running test teardown.
     67
     68-- Running test case: DOMDebugger.Event.AnimationFrame.Options.IgnoreCount
     69Creating "animation-frame" Event Breakpoint...
     70Adding "animation-frame" Event Breakpoint...
     71
     72Setting ignoreCount to '2'...
     73
     74Triggering breakpoint...
     75PASS: Should not pause.
     76
     77Triggering breakpoint...
     78PASS: Should not pause.
     79
     80Triggering breakpoint...
     81PASS: Should pause.
     82
     83Triggering breakpoint...
     84PASS: Should pause.
     85-- Running test teardown.
     86
     87-- Running test case: DOMDebugger.Event.AnimationFrame.Options.Action.Log
     88Creating "animation-frame" Event Breakpoint...
     89Adding "animation-frame" Event Breakpoint...
     90
     91Adding log action...
     92
     93Triggering breakpoint...
     94PASS: Should execute breakpoint action.
     95PASS: Should pause.
     96
     97Editing log action...
     98
     99Triggering breakpoint...
     100PASS: Should execute breakpoint action.
     101PASS: Should pause.
     102
     103Editing log action...
     104Enabling auto-continue...
     105
     106Triggering breakpoint...
     107PASS: Should execute breakpoint action.
     108PASS: Should not pause.
     109
     110Editing log action...
     111
     112Triggering breakpoint...
     113PASS: Should execute breakpoint action.
     114PASS: Should not pause.
     115-- Running test teardown.
     116
     117-- Running test case: DOMDebugger.Event.AnimationFrame.Options.Actions.Evaluate
     118Creating "animation-frame" Event Breakpoint...
     119Adding "animation-frame" Event Breakpoint...
     120
     121Adding evaluate action...
     122
     123Triggering breakpoint...
     124PASS: Should execute breakpoint action.
     125PASS: Should pause.
     126
     127Editing evaluate action...
     128
     129Triggering breakpoint...
     130PASS: Should execute breakpoint action.
     131PASS: Should pause.
     132
     133Editing evaluate action...
     134Enabling auto-continue...
     135
     136Triggering breakpoint...
     137PASS: Should execute breakpoint action.
     138PASS: Should not pause.
     139
     140Editing evaluate action...
     141
     142Triggering breakpoint...
     143PASS: Should execute breakpoint action.
     144PASS: Should not pause.
     145-- Running test teardown.
     146
  • trunk/LayoutTests/inspector/dom-debugger/event-animation-frame-breakpoints.html

    r248201 r266074  
    4646            });
    4747
    48             InspectorTest.EventBreakpoint.addBreakpoint(WI.domDebuggerManager.allAnimationFramesBreakpoint)
     48            InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.AnimationFrame)
    4949            .then(InspectorTest.EventBreakpoint.awaitEvent("window", eventName))
    5050            .catch(reject);
     
    5959            InspectorTest.EventBreakpoint.failOnPause(resolve, reject, WI.DebuggerManager.PauseReason.AnimationFrame, eventName, "Should not pause for disabled breakpoint.");
    6060
    61             InspectorTest.EventBreakpoint.addBreakpoint(WI.domDebuggerManager.allAnimationFramesBreakpoint)
     61            InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.AnimationFrame)
    6262            .then(InspectorTest.EventBreakpoint.disableBreakpoint)
    6363            .then(InspectorTest.EventBreakpoint.awaitEvent("window", eventName))
     
    7373            InspectorTest.EventBreakpoint.failOnPause(resolve, reject, WI.DebuggerManager.PauseReason.AnimationFrame, eventName, "Should not pause for removed breakpoint.");
    7474
    75             InspectorTest.EventBreakpoint.addBreakpoint(WI.domDebuggerManager.allAnimationFramesBreakpoint)
     75            InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.AnimationFrame)
    7676            .then(InspectorTest.EventBreakpoint.removeBreakpoint)
    7777            .then(InspectorTest.EventBreakpoint.awaitEvent("window", eventName))
     
    8787            InspectorTest.EventBreakpoint.failOnPause(resolve, reject, WI.DebuggerManager.PauseReason.AnimationFrame, eventName, "Should not pause for removed disabled breakpoint.");
    8888
    89             InspectorTest.EventBreakpoint.addBreakpoint(WI.domDebuggerManager.allAnimationFramesBreakpoint)
     89            InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.AnimationFrame)
    9090            .then(InspectorTest.EventBreakpoint.disableBreakpoint)
    9191            .then(InspectorTest.EventBreakpoint.removeBreakpoint)
     
    9595        teardown: InspectorTest.EventBreakpoint.teardown,
    9696    });
     97
     98    InspectorTest.EventBreakpoint.addBreakpointOptionsTestCases(suite, WI.EventBreakpoint.Type.AnimationFrame, eventName);
    9799
    98100    suite.runTestCasesAndFinish();
  • trunk/LayoutTests/inspector/dom-debugger/event-interval-breakpoints-expected.txt

    r248201 r266074  
    1 Tests for Event Timer breakpoints.
     1CONSOLE MESSAGE: BREAKPOINT ACTION LOG 1
     2CONSOLE MESSAGE: BREAKPOINT ACTION LOG 2
     3CONSOLE MESSAGE: BREAKPOINT ACTION LOG 3
     4CONSOLE MESSAGE: BREAKPOINT ACTION LOG 4
     5Tests for Event Interval breakpoints.
    26
    37
    4 == Running test suite: DOMDebugger.Event.Timer
     8== Running test suite: DOMDebugger.Event.Interval
    59-- Running test case: DOMDebugger.Event.Interval.AddBreakpoint
     10Creating "interval" Event Breakpoint...
    611Adding "interval" Event Breakpoint...
    712Firing "setInterval" on window...
     
    1621
    1722-- Running test case: DOMDebugger.Event.Interval.AddDisabledBreakpoint
     23Creating "interval" Event Breakpoint...
    1824Adding "interval" Event Breakpoint...
    1925Disabling "interval" Event Breakpoint...
     
    2329
    2430-- Running test case: DOMDebugger.Event.Interval.RemoveBreakpoint
     31Creating "interval" Event Breakpoint...
    2532Adding "interval" Event Breakpoint...
    2633Removing "interval" Event Breakpoint...
     
    3037
    3138-- Running test case: DOMDebugger.Event.Interval.RemoveDisabledBreakpoint
     39Creating "interval" Event Breakpoint...
    3240Adding "interval" Event Breakpoint...
    3341Disabling "interval" Event Breakpoint...
     
    3846
    3947-- Running test case: DOMDebugger.Event.Interval.RepeatFireBreakpoint
     48Creating "interval" Event Breakpoint...
    4049Adding "interval" Event Breakpoint...
    4150Firing "setInterval" on window...
     
    5665-- Running test teardown.
    5766
     67-- Running test case: DOMDebugger.Event.Interval.Options.Condition
     68Creating "interval" Event Breakpoint...
     69Adding "interval" Event Breakpoint...
     70
     71Setting condition to 'false'...
     72
     73Triggering breakpoint...
     74PASS: Should not pause.
     75
     76Triggering breakpoint...
     77PASS: Should not pause.
     78
     79Setting condition to 'true'...
     80
     81Triggering breakpoint...
     82PASS: Should pause.
     83
     84Triggering breakpoint...
     85PASS: Should pause.
     86-- Running test teardown.
     87
     88-- Running test case: DOMDebugger.Event.Interval.Options.IgnoreCount
     89Creating "interval" Event Breakpoint...
     90Adding "interval" Event Breakpoint...
     91
     92Setting ignoreCount to '2'...
     93
     94Triggering breakpoint...
     95PASS: Should not pause.
     96
     97Triggering breakpoint...
     98PASS: Should not pause.
     99
     100Triggering breakpoint...
     101PASS: Should pause.
     102
     103Triggering breakpoint...
     104PASS: Should pause.
     105-- Running test teardown.
     106
     107-- Running test case: DOMDebugger.Event.Interval.Options.Action.Log
     108Creating "interval" Event Breakpoint...
     109Adding "interval" Event Breakpoint...
     110
     111Adding log action...
     112
     113Triggering breakpoint...
     114PASS: Should execute breakpoint action.
     115PASS: Should pause.
     116
     117Editing log action...
     118
     119Triggering breakpoint...
     120PASS: Should execute breakpoint action.
     121PASS: Should pause.
     122
     123Editing log action...
     124Enabling auto-continue...
     125
     126Triggering breakpoint...
     127PASS: Should execute breakpoint action.
     128PASS: Should not pause.
     129
     130Editing log action...
     131
     132Triggering breakpoint...
     133PASS: Should execute breakpoint action.
     134PASS: Should not pause.
     135-- Running test teardown.
     136
     137-- Running test case: DOMDebugger.Event.Interval.Options.Actions.Evaluate
     138Creating "interval" Event Breakpoint...
     139Adding "interval" Event Breakpoint...
     140
     141Adding evaluate action...
     142
     143Triggering breakpoint...
     144PASS: Should execute breakpoint action.
     145PASS: Should pause.
     146
     147Editing evaluate action...
     148
     149Triggering breakpoint...
     150PASS: Should execute breakpoint action.
     151PASS: Should pause.
     152
     153Editing evaluate action...
     154Enabling auto-continue...
     155
     156Triggering breakpoint...
     157PASS: Should execute breakpoint action.
     158PASS: Should not pause.
     159
     160Editing evaluate action...
     161
     162Triggering breakpoint...
     163PASS: Should execute breakpoint action.
     164PASS: Should not pause.
     165-- Running test teardown.
     166
  • trunk/LayoutTests/inspector/dom-debugger/event-interval-breakpoints.html

    r248201 r266074  
    1010
    1111function handleWindow_setInterval() {
     12    repeatClearInterval();
     13
    1214    TestPage.dispatchEventToFrontend("TestPage-setInterval");
    13 
    14     repeatClearInterval();
    1515}
    1616
     
    1919
    2020function trigger_setInterval() {
    21     intervalID = setInterval(handleWindow_setInterval, 100);
     21    intervalID = setInterval(handleWindow_setInterval, 10);
    2222}
    2323
    2424function repeatSetInterval() {
    25     intervalID = setInterval(handleRepeat, 100);
     25    intervalID = setInterval(handleRepeat, 10);
    2626}
    2727
     
    3434    const eventName = "setInterval";
    3535
    36     let suite = InspectorTest.createAsyncSuite("DOMDebugger.Event.Timer");
     36    let suite = InspectorTest.createAsyncSuite("DOMDebugger.Event.Interval");
    3737
    3838    suite.addTestCase({
     
    6262            });
    6363
    64             InspectorTest.EventBreakpoint.addBreakpoint(WI.domDebuggerManager.allIntervalsBreakpoint)
     64            InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.Interval)
    6565            .then(InspectorTest.EventBreakpoint.awaitEvent("window", eventName))
    6666            .catch(reject);
     
    7575            InspectorTest.EventBreakpoint.failOnPause(resolve, reject, WI.DebuggerManager.PauseReason.Interval, eventName, "Should not pause for disabled breakpoint.");
    7676
    77             InspectorTest.EventBreakpoint.addBreakpoint(WI.domDebuggerManager.allIntervalsBreakpoint)
     77            InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.Interval)
    7878            .then(InspectorTest.EventBreakpoint.disableBreakpoint)
    7979            .then(InspectorTest.EventBreakpoint.awaitEvent("window", eventName))
     
    8989            InspectorTest.EventBreakpoint.failOnPause(resolve, reject, WI.DebuggerManager.PauseReason.Interval, eventName, "Should not pause for removed breakpoint.");
    9090
    91             InspectorTest.EventBreakpoint.addBreakpoint(WI.domDebuggerManager.allIntervalsBreakpoint)
     91            InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.Interval)
    9292            .then(InspectorTest.EventBreakpoint.removeBreakpoint)
    9393            .then(InspectorTest.EventBreakpoint.awaitEvent("window", eventName))
     
    103103            InspectorTest.EventBreakpoint.failOnPause(resolve, reject, WI.DebuggerManager.PauseReason.Interval, eventName, "Should not pause for removed disabled breakpoint.");
    104104
    105             InspectorTest.EventBreakpoint.addBreakpoint(WI.domDebuggerManager.allIntervalsBreakpoint)
     105            InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.Interval)
    106106            .then(InspectorTest.EventBreakpoint.disableBreakpoint)
    107107            .then(InspectorTest.EventBreakpoint.removeBreakpoint)
     
    135135            });
    136136
    137             InspectorTest.EventBreakpoint.addBreakpoint(WI.domDebuggerManager.allIntervalsBreakpoint)
     137            InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.Interval)
    138138            .then(() => {
    139139                InspectorTest.log("Firing \"setInterval\" on window...");
     
    145145    });
    146146
     147    InspectorTest.EventBreakpoint.addBreakpointOptionsTestCases(suite, WI.EventBreakpoint.Type.Interval, eventName);
     148
    147149    suite.runTestCasesAndFinish();
    148150}
     
    150152</head>
    151153<body onload="runTest()">
    152     <p>Tests for Event Timer breakpoints.</p>
     154    <p>Tests for Event Interval breakpoints.</p>
    153155</body>
    154156</html>
  • trunk/LayoutTests/inspector/dom-debugger/event-listener-breakpoints-expected.txt

    r248201 r266074  
     1CONSOLE MESSAGE: BREAKPOINT ACTION LOG 1
     2CONSOLE MESSAGE: BREAKPOINT ACTION LOG 2
     3CONSOLE MESSAGE: BREAKPOINT ACTION LOG 3
     4CONSOLE MESSAGE: BREAKPOINT ACTION LOG 4
    15Tests for Event Listener breakpoints.
    26
     
    7680
    7781-- Running test case: DOMDebugger.Event.Listener.AllEventsBreakpoint
     82Creating "listener" Event Breakpoint...
    7883Adding "listener" Event Breakpoint...
    7984Firing "click" on body...
     
    122127-- Running test teardown.
    123128
     129-- Running test case: DOMDebugger.Event.Listener.Options.Condition
     130Creating "click" Event Breakpoint...
     131Adding "listener:click" Event Breakpoint...
     132
     133Setting condition to 'false'...
     134
     135Triggering breakpoint...
     136PASS: Should not pause.
     137
     138Triggering breakpoint...
     139PASS: Should not pause.
     140
     141Setting condition to 'true'...
     142
     143Triggering breakpoint...
     144PASS: Should pause.
     145
     146Triggering breakpoint...
     147PASS: Should pause.
     148-- Running test teardown.
     149
     150-- Running test case: DOMDebugger.Event.Listener.Options.IgnoreCount
     151Creating "click" Event Breakpoint...
     152Adding "listener:click" Event Breakpoint...
     153
     154Setting ignoreCount to '2'...
     155
     156Triggering breakpoint...
     157PASS: Should not pause.
     158
     159Triggering breakpoint...
     160PASS: Should not pause.
     161
     162Triggering breakpoint...
     163PASS: Should pause.
     164
     165Triggering breakpoint...
     166PASS: Should pause.
     167-- Running test teardown.
     168
     169-- Running test case: DOMDebugger.Event.Listener.Options.Action.Log
     170Creating "click" Event Breakpoint...
     171Adding "listener:click" Event Breakpoint...
     172
     173Adding log action...
     174
     175Triggering breakpoint...
     176PASS: Should execute breakpoint action.
     177PASS: Should pause.
     178
     179Editing log action...
     180
     181Triggering breakpoint...
     182PASS: Should execute breakpoint action.
     183PASS: Should pause.
     184
     185Editing log action...
     186Enabling auto-continue...
     187
     188Triggering breakpoint...
     189PASS: Should execute breakpoint action.
     190PASS: Should not pause.
     191
     192Editing log action...
     193
     194Triggering breakpoint...
     195PASS: Should execute breakpoint action.
     196PASS: Should not pause.
     197-- Running test teardown.
     198
     199-- Running test case: DOMDebugger.Event.Listener.Options.Actions.Evaluate
     200Creating "click" Event Breakpoint...
     201Adding "listener:click" Event Breakpoint...
     202
     203Adding evaluate action...
     204
     205Triggering breakpoint...
     206PASS: Should execute breakpoint action.
     207PASS: Should pause.
     208
     209Editing evaluate action...
     210
     211Triggering breakpoint...
     212PASS: Should execute breakpoint action.
     213PASS: Should pause.
     214
     215Editing evaluate action...
     216Enabling auto-continue...
     217
     218Triggering breakpoint...
     219PASS: Should execute breakpoint action.
     220PASS: Should not pause.
     221
     222Editing evaluate action...
     223
     224Triggering breakpoint...
     225PASS: Should execute breakpoint action.
     226PASS: Should not pause.
     227-- Running test teardown.
     228
  • trunk/LayoutTests/inspector/dom-debugger/event-listener-breakpoints.html

    r248201 r266074  
    5959                });
    6060
    61                 InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.Listener, eventName)
     61                InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.Listener, {eventName})
    6262                .then(InspectorTest.EventBreakpoint.awaitEvent("body", eventName))
    6363                .catch(reject);
     
    7272                InspectorTest.EventBreakpoint.failOnPause(resolve, reject, WI.DebuggerManager.PauseReason.Listener, eventName, "Should not pause for disabled breakpoint.");
    7373
    74                 InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.Listener, eventName)
     74                InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.Listener, {eventName})
    7575                .then(InspectorTest.EventBreakpoint.disableBreakpoint)
    7676                .then(InspectorTest.EventBreakpoint.awaitEvent("body", eventName))
     
    8686                InspectorTest.EventBreakpoint.failOnPause(resolve, reject, WI.DebuggerManager.PauseReason.Listener, eventName, "Should not pause for removed breakpoint.");
    8787
    88                 InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.Listener, eventName)
     88                InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.Listener, {eventName})
    8989                .then(InspectorTest.EventBreakpoint.removeBreakpoint)
    9090                .then(InspectorTest.EventBreakpoint.awaitEvent("body", eventName))
     
    100100                InspectorTest.EventBreakpoint.failOnPause(resolve, reject, WI.DebuggerManager.PauseReason.Listener, eventName, "Should not pause for removed disabled breakpoint.");
    101101
    102                 InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.Listener, eventName)
     102                InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.Listener, {eventName})
    103103                .then(InspectorTest.EventBreakpoint.disableBreakpoint)
    104104                .then(InspectorTest.EventBreakpoint.removeBreakpoint)
     
    129129            });
    130130
    131             InspectorTest.EventBreakpoint.addBreakpoint(WI.domDebuggerManager.allListenersBreakpoint)
     131            InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.Listener)
    132132            .then(() => {
    133133                InspectorTest.log("Firing \"click\" on body...");
     
    174174            });
    175175
    176             InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.Listener, "click")
     176            InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.Listener, {eventName: "click"})
    177177            .then(() => {
    178178                InspectorTest.log("Firing \"click\" on div#x...");
     
    212212            });
    213213
    214             InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.Listener, "click")
     214            InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.Listener, {eventName: "click"})
    215215            .then(() => {
    216216                InspectorTest.log("Firing \"click\" on div#x...");
     
    221221        teardown: InspectorTest.EventBreakpoint.teardown,
    222222    });
     223
     224    InspectorTest.EventBreakpoint.addBreakpointOptionsTestCases(suite, WI.EventBreakpoint.Type.Listener, "click");
    223225
    224226    suite.runTestCasesAndFinish();
  • trunk/LayoutTests/inspector/dom-debugger/event-timeout-breakpoints-expected.txt

    r248201 r266074  
     1CONSOLE MESSAGE: BREAKPOINT ACTION LOG 1
     2CONSOLE MESSAGE: BREAKPOINT ACTION LOG 2
     3CONSOLE MESSAGE: BREAKPOINT ACTION LOG 3
     4CONSOLE MESSAGE: BREAKPOINT ACTION LOG 4
    15Tests for Event Timer breakpoints.
    26
     
    48== Running test suite: DOMDebugger.Event.Timer
    59-- Running test case: DOMDebugger.Event.Timeout.AddBreakpoint
     10Creating "timeout" Event Breakpoint...
    611Adding "timeout" Event Breakpoint...
    712Firing "setTimeout" on window...
     
    1621
    1722-- Running test case: DOMDebugger.Event.Timeout.AddDisabledBreakpoint
     23Creating "timeout" Event Breakpoint...
    1824Adding "timeout" Event Breakpoint...
    1925Disabling "timeout" Event Breakpoint...
     
    2329
    2430-- Running test case: DOMDebugger.Event.Timeout.RemoveBreakpoint
     31Creating "timeout" Event Breakpoint...
    2532Adding "timeout" Event Breakpoint...
    2633Removing "timeout" Event Breakpoint...
     
    3037
    3138-- Running test case: DOMDebugger.Event.Timeout.RemoveDisabledBreakpoint
     39Creating "timeout" Event Breakpoint...
    3240Adding "timeout" Event Breakpoint...
    3341Disabling "timeout" Event Breakpoint...
     
    3745-- Running test teardown.
    3846
     47-- Running test case: DOMDebugger.Event.Timer.Options.Condition
     48Creating "timeout" Event Breakpoint...
     49Adding "timeout" Event Breakpoint...
     50
     51Setting condition to 'false'...
     52
     53Triggering breakpoint...
     54PASS: Should not pause.
     55
     56Triggering breakpoint...
     57PASS: Should not pause.
     58
     59Setting condition to 'true'...
     60
     61Triggering breakpoint...
     62PASS: Should pause.
     63
     64Triggering breakpoint...
     65PASS: Should pause.
     66-- Running test teardown.
     67
     68-- Running test case: DOMDebugger.Event.Timer.Options.IgnoreCount
     69Creating "timeout" Event Breakpoint...
     70Adding "timeout" Event Breakpoint...
     71
     72Setting ignoreCount to '2'...
     73
     74Triggering breakpoint...
     75PASS: Should not pause.
     76
     77Triggering breakpoint...
     78PASS: Should not pause.
     79
     80Triggering breakpoint...
     81PASS: Should pause.
     82
     83Triggering breakpoint...
     84PASS: Should pause.
     85-- Running test teardown.
     86
     87-- Running test case: DOMDebugger.Event.Timer.Options.Action.Log
     88Creating "timeout" Event Breakpoint...
     89Adding "timeout" Event Breakpoint...
     90
     91Adding log action...
     92
     93Triggering breakpoint...
     94PASS: Should execute breakpoint action.
     95PASS: Should pause.
     96
     97Editing log action...
     98
     99Triggering breakpoint...
     100PASS: Should execute breakpoint action.
     101PASS: Should pause.
     102
     103Editing log action...
     104Enabling auto-continue...
     105
     106Triggering breakpoint...
     107PASS: Should execute breakpoint action.
     108PASS: Should not pause.
     109
     110Editing log action...
     111
     112Triggering breakpoint...
     113PASS: Should execute breakpoint action.
     114PASS: Should not pause.
     115-- Running test teardown.
     116
     117-- Running test case: DOMDebugger.Event.Timer.Options.Actions.Evaluate
     118Creating "timeout" Event Breakpoint...
     119Adding "timeout" Event Breakpoint...
     120
     121Adding evaluate action...
     122
     123Triggering breakpoint...
     124PASS: Should execute breakpoint action.
     125PASS: Should pause.
     126
     127Editing evaluate action...
     128
     129Triggering breakpoint...
     130PASS: Should execute breakpoint action.
     131PASS: Should pause.
     132
     133Editing evaluate action...
     134Enabling auto-continue...
     135
     136Triggering breakpoint...
     137PASS: Should execute breakpoint action.
     138PASS: Should not pause.
     139
     140Editing evaluate action...
     141
     142Triggering breakpoint...
     143PASS: Should execute breakpoint action.
     144PASS: Should not pause.
     145-- Running test teardown.
     146
  • trunk/LayoutTests/inspector/dom-debugger/event-timeout-breakpoints.html

    r248201 r266074  
    1212
    1313function trigger_setTimeout() {
    14     setTimeout(handleWindow_setTimeout, 100);
     14    setTimeout(handleWindow_setTimeout, 10);
    1515}
    1616
     
    4646            });
    4747
    48             InspectorTest.EventBreakpoint.addBreakpoint(WI.domDebuggerManager.allTimeoutsBreakpoint)
     48            InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.Timeout)
    4949            .then(InspectorTest.EventBreakpoint.awaitEvent("window", eventName))
    5050            .catch(reject);
     
    5959            InspectorTest.EventBreakpoint.failOnPause(resolve, reject, WI.DebuggerManager.PauseReason.Timeout, eventName, "Should not pause for disabled breakpoint.");
    6060
    61             InspectorTest.EventBreakpoint.addBreakpoint(WI.domDebuggerManager.allTimeoutsBreakpoint)
     61            InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.Timeout)
    6262            .then(InspectorTest.EventBreakpoint.disableBreakpoint)
    6363            .then(InspectorTest.EventBreakpoint.awaitEvent("window", eventName))
     
    7373            InspectorTest.EventBreakpoint.failOnPause(resolve, reject, WI.DebuggerManager.PauseReason.Timeout, eventName, "Should not pause for removed breakpoint.");
    7474
    75             InspectorTest.EventBreakpoint.addBreakpoint(WI.domDebuggerManager.allTimeoutsBreakpoint)
     75            InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.Timeout)
    7676            .then(InspectorTest.EventBreakpoint.removeBreakpoint)
    7777            .then(InspectorTest.EventBreakpoint.awaitEvent("window", eventName))
     
    8787            InspectorTest.EventBreakpoint.failOnPause(resolve, reject, WI.DebuggerManager.PauseReason.Timeout, eventName, "Should not pause for removed disabled breakpoint.");
    8888
    89             InspectorTest.EventBreakpoint.addBreakpoint(WI.domDebuggerManager.allTimeoutsBreakpoint)
     89            InspectorTest.EventBreakpoint.createBreakpoint(WI.EventBreakpoint.Type.Timeout)
    9090            .then(InspectorTest.EventBreakpoint.disableBreakpoint)
    9191            .then(InspectorTest.EventBreakpoint.removeBreakpoint)
     
    9595        teardown: InspectorTest.EventBreakpoint.teardown,
    9696    });
     97
     98    InspectorTest.EventBreakpoint.addBreakpointOptionsTestCases(suite, WI.EventBreakpoint.Type.Timeout, eventName);
    9799
    98100    suite.runTestCasesAndFinish();
  • trunk/LayoutTests/inspector/dom-debugger/resources/event-breakpoint-utilities.js

    r248201 r266074  
    22    InspectorTest.EventBreakpoint = {};
    33
     4    InspectorTest.EventBreakpoint.addBreakpointOptionsTestCases = function(suite, type, eventName) {
     5        async function triggerBreakpoint() {
     6            InspectorTest.log("Triggering breakpoint...");
     7            return Promise.all([
     8                InspectorTest.awaitEvent("TestPage-" + eventName),
     9                InspectorTest.evaluateInPage(`trigger_${eventName}()`),
     10            ]);
     11        }
     12
     13        suite.addTestCase({
     14            name: suite.name + ".Options.Condition",
     15            description: "Check that the debugger will not pause unless the breakpoint has a truthy breakpoint condition.",
     16            async test() {
     17                let pauseCount = 0;
     18
     19                let listener = WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.Paused, (event) => {
     20                    ++pauseCount;
     21                    WI.debuggerManager.resume();
     22                });
     23
     24                let breakpoint = await InspectorTest.EventBreakpoint.createBreakpoint(type, {eventName});
     25
     26                InspectorTest.newline();
     27
     28                InspectorTest.log("Setting condition to 'false'...");
     29                breakpoint.condition = "false";
     30
     31                for (let i = 1; i <= 4; ++i) {
     32                    if (i === 3) {
     33                        InspectorTest.newline();
     34
     35                        InspectorTest.log("Setting condition to 'true'...");
     36                        breakpoint.condition = "true";
     37                    }
     38
     39                    InspectorTest.newline();
     40
     41                    await triggerBreakpoint();
     42
     43                    if (i <= 2)
     44                        InspectorTest.expectEqual(pauseCount, 0, "Should not pause.");
     45                    else
     46                        InspectorTest.expectEqual(pauseCount, i - 2, "Should pause.");
     47                }
     48
     49                WI.debuggerManager.removeEventListener(WI.DebuggerManager.Event.Paused, listener);
     50            },
     51            teardown: InspectorTest.EventBreakpoint.teardown,
     52        });
     53
     54        suite.addTestCase({
     55            name: suite.name + ".Options.IgnoreCount",
     56            description: "Check that the debugger will not pause unless the breakpoint is hit at least as many times as it's `ignoreCount`.",
     57            async test() {
     58                let pauseCount = 0;
     59
     60                let listener = WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.Paused, (event) => {
     61                    ++pauseCount;
     62                    WI.debuggerManager.resume();
     63                });
     64
     65                let breakpoint = await InspectorTest.EventBreakpoint.createBreakpoint(type, {eventName});
     66
     67                InspectorTest.newline();
     68
     69                InspectorTest.log("Setting ignoreCount to '2'...");
     70                breakpoint.ignoreCount = 2;
     71
     72                for (let i = 1; i <=4; ++i) {
     73                    InspectorTest.newline();
     74
     75                    await triggerBreakpoint();
     76
     77                    if (i <= 2)
     78                        InspectorTest.expectEqual(pauseCount, 0, "Should not pause.");
     79                    else
     80                        InspectorTest.expectEqual(pauseCount, i - 2, "Should pause.");
     81                }
     82
     83                WI.debuggerManager.removeEventListener(WI.DebuggerManager.Event.Paused, listener);
     84            },
     85            teardown: InspectorTest.EventBreakpoint.teardown,
     86        });
     87
     88        suite.addTestCase({
     89            name: suite.name + ".Options.Action.Log",
     90            description: "Check that log breakpoint actions execute when the breakpoint is hit.",
     91            async test() {
     92                let pauseCount = 0;
     93
     94                let listener = WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.Paused, (event) => {
     95                    ++pauseCount;
     96                    WI.debuggerManager.resume();
     97                });
     98
     99                let breakpoint = await InspectorTest.EventBreakpoint.createBreakpoint(type, {eventName});
     100
     101                InspectorTest.newline();
     102
     103                InspectorTest.log("Adding log action...");
     104                let action = breakpoint.createAction(WI.BreakpointAction.Type.Log, {data: "BREAKPOINT ACTION LOG 1"});
     105
     106                for (let i = 1; i <= 4; ++i) {
     107                    if (i > 1) {
     108                        InspectorTest.newline();
     109
     110                        InspectorTest.log("Editing log action...");
     111                        action.data = `BREAKPOINT ACTION LOG ${i}`;
     112
     113                        if (i === 3) {
     114                            InspectorTest.log("Enabling auto-continue...");
     115                            breakpoint.autoContinue = true;
     116                        }
     117                    }
     118
     119                    InspectorTest.newline();
     120
     121                    let [messageAddedEvent] = await Promise.all([
     122                        WI.consoleManager.awaitEvent(WI.ConsoleManager.Event.MessageAdded),
     123                        triggerBreakpoint(),
     124                    ]);
     125
     126                    InspectorTest.expectEqual(messageAddedEvent.data.message.messageText, action.data, "Should execute breakpoint action.");
     127
     128                    if (i <= 2)
     129                        InspectorTest.expectEqual(pauseCount, i, "Should pause.");
     130                    else
     131                        InspectorTest.expectEqual(pauseCount, 2, "Should not pause.");
     132                }
     133
     134                WI.debuggerManager.removeEventListener(WI.DebuggerManager.Event.Paused, listener);
     135            },
     136            teardown: InspectorTest.EventBreakpoint.teardown,
     137        });
     138
     139        suite.addTestCase({
     140            name: suite.name + ".Options.Actions.Evaluate",
     141            description: "Check that evaluate breakpoint actions execute when the breakpoint is hit.",
     142            async test() {
     143                let pauseCount = 0;
     144
     145                let listener = WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.Paused, (event) => {
     146                    ++pauseCount;
     147                    WI.debuggerManager.resume();
     148                });
     149
     150                let breakpoint = await InspectorTest.EventBreakpoint.createBreakpoint(type, {eventName});
     151
     152                InspectorTest.newline();
     153
     154                InspectorTest.log("Adding evaluate action...");
     155                let action = breakpoint.createAction(WI.BreakpointAction.Type.Evaluate, {data: "window.BREAKPOINT_ACTION_EVALUATE = 1;"});
     156
     157                for (let i = 1; i <= 4; ++i) {
     158                    if (i > 1) {
     159                        InspectorTest.newline();
     160
     161                        InspectorTest.log("Editing evaluate action...");
     162                        action.data = `window.BREAKPOINT_ACTION_EVALUATE = ${i};`;
     163
     164                        if (i === 3) {
     165                            InspectorTest.log("Enabling auto-continue...");
     166                            breakpoint.autoContinue = true;
     167                        }
     168                    }
     169
     170                    InspectorTest.newline();
     171
     172                    await triggerBreakpoint();
     173
     174                    let breakpointActionEvaluateResult = await InspectorTest.evaluateInPage(`window.BREAKPOINT_ACTION_EVALUATE`);
     175                    InspectorTest.expectEqual(breakpointActionEvaluateResult, i, "Should execute breakpoint action.");
     176
     177                    if (i <= 2)
     178                        InspectorTest.expectEqual(pauseCount, i, "Should pause.");
     179                    else
     180                        InspectorTest.expectEqual(pauseCount, 2, "Should not pause.");
     181                }
     182
     183                WI.debuggerManager.removeEventListener(WI.DebuggerManager.Event.Paused, listener);
     184            },
     185            teardown: InspectorTest.EventBreakpoint.teardown,
     186        });
     187    };
     188
    4189    InspectorTest.EventBreakpoint.teardown = function(resolve, reject) {
    5         WI.domDebuggerManager.removeEventBreakpoint(WI.domDebuggerManager.allAnimationFramesBreakpoint);
    6         WI.domDebuggerManager.removeEventBreakpoint(WI.domDebuggerManager.allIntervalsBreakpoint);
    7         WI.domDebuggerManager.removeEventBreakpoint(WI.domDebuggerManager.allListenersBreakpoint);
    8         WI.domDebuggerManager.removeEventBreakpoint(WI.domDebuggerManager.allTimeoutsBreakpoint);
     190        WI.domDebuggerManager.allAnimationFramesBreakpoint?.remove();
     191        WI.domDebuggerManager.allIntervalsBreakpoint?.remove();
     192        WI.domDebuggerManager.allListenersBreakpoint?.remove();
     193        WI.domDebuggerManager.allTimeoutsBreakpoint?.remove();
    9194
    10195        for (let breakpoint of WI.domDebuggerManager.listenerBreakpoints)
    11             WI.domDebuggerManager.removeEventBreakpoint(breakpoint);
     196            breakpoint.remove();
    12197
    13198        resolve();
     
    43228    };
    44229
    45     InspectorTest.EventBreakpoint.createBreakpoint = function(type, eventName) {
    46         InspectorTest.log(`Creating "${eventName}" Event Breakpoint...`);
     230    InspectorTest.EventBreakpoint.createBreakpoint = function(type, {eventName} = {}) {
     231        if (type !== WI.EventBreakpoint.Type.Listener)
     232            eventName = null;
     233
     234        InspectorTest.log(`Creating "${eventName || type}" Event Breakpoint...`);
    47235        return InspectorTest.EventBreakpoint.addBreakpoint(new WI.EventBreakpoint(type, {eventName}));
    48236    };
     
    75263            });
    76264
    77             WI.domDebuggerManager.removeEventBreakpoint(breakpoint);
     265            breakpoint.remove();
    78266        });
    79267    };
  • trunk/LayoutTests/inspector/dom/breakpoint-for-event-listener-expected.txt

    r249128 r266074  
     1CONSOLE MESSAGE: BREAKPOINT ACTION LOG 1
     2CONSOLE MESSAGE: BREAKPOINT ACTION LOG 2
     3CONSOLE MESSAGE: BREAKPOINT ACTION LOG 3
     4CONSOLE MESSAGE: BREAKPOINT ACTION LOG 4
    15Testing DOMAgent.setBreakpointForEventListener and DOMAgent.removeBreakpointForEventListener.
    26
     
    2024PASS: Should not pause before button1 event handler is run.
    2125
     26-- Running test case: DOM.setBreakpointForEventListener.Options.Condition
     27
     28Setting condition to 'false'...
     29
     30Triggering breakpoint...
     31PASS: Should not pause.
     32
     33Triggering breakpoint...
     34PASS: Should not pause.
     35
     36Setting condition to 'true'...
     37
     38Triggering breakpoint...
     39PASS: Should pause.
     40
     41Triggering breakpoint...
     42PASS: Should pause.
     43
     44-- Running test case: DOM.setBreakpointForEventListener.Options.IgnoreCount
     45
     46Setting ignoreCount to '2'...
     47
     48Triggering breakpoint...
     49PASS: Should not pause.
     50
     51Triggering breakpoint...
     52PASS: Should not pause.
     53
     54Triggering breakpoint...
     55PASS: Should pause.
     56
     57Triggering breakpoint...
     58PASS: Should pause.
     59
     60-- Running test case: DOM.setBreakpointForEventListener.Options.Action.Log
     61
     62Adding log action...
     63
     64Triggering breakpoint...
     65PASS: Should execute breakpoint action.
     66PASS: Should pause.
     67
     68Editing log action...
     69
     70Triggering breakpoint...
     71PASS: Should execute breakpoint action.
     72PASS: Should pause.
     73
     74Editing log action...
     75Enabling auto-continue...
     76
     77Triggering breakpoint...
     78PASS: Should execute breakpoint action.
     79PASS: Should not pause.
     80
     81Editing log action...
     82
     83Triggering breakpoint...
     84PASS: Should execute breakpoint action.
     85PASS: Should not pause.
     86
     87-- Running test case: DOM.setBreakpointForEventListener.Options.Actions.Evaluate
     88
     89Adding evaluate action...
     90
     91Triggering breakpoint...
     92PASS: Should execute breakpoint action.
     93PASS: Should pause.
     94
     95Editing evaluate action...
     96
     97Triggering breakpoint...
     98PASS: Should execute breakpoint action.
     99PASS: Should pause.
     100
     101Editing evaluate action...
     102Enabling auto-continue...
     103
     104Triggering breakpoint...
     105PASS: Should execute breakpoint action.
     106PASS: Should not pause.
     107
     108Editing evaluate action...
     109
     110Triggering breakpoint...
     111PASS: Should execute breakpoint action.
     112PASS: Should not pause.
     113
    22114-- Running test case: DOM.setBreakpointForEventListener.Invalid
    23115PASS: Should produce an error.
  • trunk/LayoutTests/inspector/dom/breakpoint-for-event-listener.html

    r253242 r266074  
    2424    let button2Node = null;
    2525
    26     function awaitGetClickEventListener(nodeId) {
    27         return DOMAgent.getEventListenersForNode(nodeId)
    28         .then(({listeners}) => listeners.find((eventListener) => eventListener.type === "click"));
     26    async function getClickEventListener(nodeId) {
     27        let {listeners} = await DOMAgent.getEventListenersForNode(nodeId);
     28        return listeners.find((eventListener) => eventListener.type === "click");
     29    }
     30
     31    async function setBreakpointForClickEventListener(node) {
     32        let clickEventListener = await getClickEventListener(node.id);
     33        InspectorTest.assert(!clickEventListener.hasBreakpoint, "Click event listener for button1 should not have a breakpoint.");
     34
     35        return new Promise((resolve, reject) => {
     36            WI.domDebuggerManager.singleFireEventListener(WI.DOMDebuggerManager.Event.EventBreakpointAdded, (event) => {
     37                resolve(event.data.breakpoint);
     38            });
     39
     40            WI.domManager.setBreakpointForEventListener(clickEventListener);
     41        });
    2942    }
    3043
     
    5063                InspectorTest.expectEqual(targetData.pauseData.eventName, "click", `Pause data eventName should be "click".`);
    5164
    52                 awaitGetClickEventListener(button1Node.id)
     65                getClickEventListener(button1Node.id)
    5366                .then((clickEventListener) => {
    5467                    InspectorTest.assert(targetData.pauseData.eventListenerId === clickEventListener.eventListenerId, `Pause data eventListenerId should be "${clickEventListener.eventListenerId}".`);
     
    7891            });
    7992
    80             awaitGetClickEventListener(button1Node.id)
     93            getClickEventListener(button1Node.id)
    8194            .then((clickEventListener) => {
    8295                InspectorTest.assert(!clickEventListener.hasBreakpoint, "Click event listener for button1 should not have a breakpoint.");
     
    112125                InspectorTest.assert(targetData.pauseData.eventName, "click", `Pause data eventName should be "click".`);
    113126
    114                 awaitGetClickEventListener(button1Node.id)
     127                getClickEventListener(button1Node.id)
    115128                .then((clickEventListener) => {
    116129                    InspectorTest.assert(targetData.pauseData.eventListenerId === clickEventListener.eventListenerId, `Pause data eventListenerId should be "${clickEventListener.eventListenerId}".`);
     
    140153            });
    141154
    142             awaitGetClickEventListener(button1Node.id)
     155            getClickEventListener(button1Node.id)
    143156            .then((clickEventListener) => {
    144157                InspectorTest.assert(clickEventListener.hasBreakpoint, "Click event listener for button1 should have a breakpoint.");
     
    153166            .catch(reject);
    154167        }
     168    });
     169
     170    suite.addTestCase({
     171        name: "DOM.setBreakpointForEventListener.Options.Condition",
     172        description: "Check that the debugger will not pause unless the breakpoint has a truthy breakpoint condition.",
     173        async test() {
     174            let pauseCount = 0;
     175
     176            let listener = WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.Paused, (event) => {
     177                ++pauseCount;
     178                WI.debuggerManager.resume();
     179            });
     180
     181            let breakpoint = await setBreakpointForClickEventListener(button1Node);
     182
     183            InspectorTest.newline();
     184
     185            InspectorTest.log("Setting condition to 'false'...");
     186            breakpoint.condition = "false";
     187
     188            for (let i = 1; i <= 4; ++i) {
     189                if (i === 3) {
     190                    InspectorTest.newline();
     191
     192                    InspectorTest.log("Setting condition to 'true'...");
     193                    breakpoint.condition = "true";
     194                }
     195
     196                InspectorTest.newline();
     197
     198                InspectorTest.log("Triggering breakpoint...");
     199                await Promise.all([
     200                    InspectorTest.awaitEvent("TestPageButton1Click"),
     201                    InspectorTest.evaluateInPage(`clickButton1()`),
     202                ]);
     203
     204                if (i <= 2)
     205                    InspectorTest.expectEqual(pauseCount, 0, "Should not pause.");
     206                else
     207                    InspectorTest.expectEqual(pauseCount, i - 2, "Should pause.");
     208            }
     209
     210            breakpoint.remove();
     211            WI.debuggerManager.removeEventListener(WI.DebuggerManager.Event.Paused, listener);
     212        },
     213    });
     214
     215    suite.addTestCase({
     216        name: "DOM.setBreakpointForEventListener.Options.IgnoreCount",
     217        description: "Check that the debugger will not pause unless the breakpoint is hit at least as many times as it's `ignoreCount`.",
     218        async test() {
     219            let pauseCount = 0;
     220
     221            let listener = WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.Paused, (event) => {
     222                ++pauseCount;
     223                WI.debuggerManager.resume();
     224            });
     225
     226            let breakpoint = await setBreakpointForClickEventListener(button1Node);
     227
     228            InspectorTest.newline();
     229
     230            InspectorTest.log("Setting ignoreCount to '2'...");
     231            breakpoint.ignoreCount = 2;
     232
     233            for (let i = 1; i <=4; ++i) {
     234                InspectorTest.newline();
     235
     236                InspectorTest.log("Triggering breakpoint...");
     237                await Promise.all([
     238                    InspectorTest.awaitEvent("TestPageButton1Click"),
     239                    InspectorTest.evaluateInPage(`clickButton1()`),
     240                ]);
     241
     242                if (i <= 2)
     243                    InspectorTest.expectEqual(pauseCount, 0, "Should not pause.");
     244                else
     245                    InspectorTest.expectEqual(pauseCount, i - 2, "Should pause.");
     246            }
     247
     248            breakpoint.remove();
     249            WI.debuggerManager.removeEventListener(WI.DebuggerManager.Event.Paused, listener);
     250        },
     251    });
     252
     253    suite.addTestCase({
     254        name: "DOM.setBreakpointForEventListener.Options.Action.Log",
     255        description: "Check that log breakpoint actions execute when the breakpoint is hit.",
     256        async test() {
     257            let pauseCount = 0;
     258
     259            let listener = WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.Paused, (event) => {
     260                ++pauseCount;
     261                WI.debuggerManager.resume();
     262            });
     263
     264            let breakpoint = await setBreakpointForClickEventListener(button1Node);
     265
     266            InspectorTest.newline();
     267
     268            InspectorTest.log("Adding log action...");
     269            let action = breakpoint.createAction(WI.BreakpointAction.Type.Log, {data: "BREAKPOINT ACTION LOG 1"});
     270
     271            for (let i = 1; i <= 4; ++i) {
     272                if (i > 1) {
     273                    InspectorTest.newline();
     274
     275                    InspectorTest.log("Editing log action...");
     276                    action.data = `BREAKPOINT ACTION LOG ${i}`;
     277
     278                    if (i === 3) {
     279                        InspectorTest.log("Enabling auto-continue...");
     280                        breakpoint.autoContinue = true;
     281                    }
     282                }
     283
     284                InspectorTest.newline();
     285
     286                InspectorTest.log("Triggering breakpoint...");
     287                let [messageAddedEvent] = await Promise.all([
     288                    WI.consoleManager.awaitEvent(WI.ConsoleManager.Event.MessageAdded),
     289                    InspectorTest.awaitEvent("TestPageButton1Click"),
     290                    InspectorTest.evaluateInPage(`clickButton1()`),
     291                ]);
     292
     293                InspectorTest.expectEqual(messageAddedEvent.data.message.messageText, action.data, "Should execute breakpoint action.");
     294
     295                if (i <= 2)
     296                    InspectorTest.expectEqual(pauseCount, i, "Should pause.");
     297                else
     298                    InspectorTest.expectEqual(pauseCount, 2, "Should not pause.");
     299            }
     300
     301            breakpoint.remove();
     302            WI.debuggerManager.removeEventListener(WI.DebuggerManager.Event.Paused, listener);
     303        },
     304    });
     305
     306    suite.addTestCase({
     307        name: "DOM.setBreakpointForEventListener.Options.Actions.Evaluate",
     308        description: "Check that evaluate breakpoint actions execute when the breakpoint is hit.",
     309        async test() {
     310            let pauseCount = 0;
     311
     312            let listener = WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.Paused, (event) => {
     313                ++pauseCount;
     314                WI.debuggerManager.resume();
     315            });
     316
     317            let breakpoint = await setBreakpointForClickEventListener(button1Node);
     318
     319            InspectorTest.newline();
     320
     321            InspectorTest.log("Adding evaluate action...");
     322            let action = breakpoint.createAction(WI.BreakpointAction.Type.Evaluate, {data: "window.BREAKPOINT_ACTION_EVALUATE = 1;"});
     323
     324            for (let i = 1; i <= 4; ++i) {
     325                if (i > 1) {
     326                    InspectorTest.newline();
     327
     328                    InspectorTest.log("Editing evaluate action...");
     329                    action.data = `window.BREAKPOINT_ACTION_EVALUATE = ${i};`;
     330
     331                    if (i === 3) {
     332                        InspectorTest.log("Enabling auto-continue...");
     333                        breakpoint.autoContinue = true;
     334                    }
     335                }
     336
     337                InspectorTest.newline();
     338
     339                InspectorTest.log("Triggering breakpoint...");
     340                await Promise.all([
     341                    InspectorTest.awaitEvent("TestPageButton1Click"),
     342                    InspectorTest.evaluateInPage(`clickButton1()`),
     343                ]);
     344
     345                let breakpointActionEvaluateResult = await InspectorTest.evaluateInPage(`window.BREAKPOINT_ACTION_EVALUATE`);
     346                InspectorTest.expectEqual(breakpointActionEvaluateResult, i, "Should execute breakpoint action.");
     347
     348                if (i <= 2)
     349                    InspectorTest.expectEqual(pauseCount, i, "Should pause.");
     350                else
     351                    InspectorTest.expectEqual(pauseCount, 2, "Should not pause.");
     352            }
     353
     354            breakpoint.remove();
     355            WI.debuggerManager.removeEventListener(WI.DebuggerManager.Event.Paused, listener);
     356        },
    155357    });
    156358
  • trunk/LayoutTests/inspector/worker/debugger-pause.html

    r251227 r266074  
    6464        test(resolve, reject) {
    6565            let location = workerTarget.mainResource.createSourceCodeLocation(8, 0);
    66             let breakpoint = new WI.Breakpoint(location);
     66            let breakpoint = new WI.JavaScriptBreakpoint(location);
    6767            WI.debuggerManager.addBreakpoint(breakpoint);
    6868            InspectorTest.evaluateInPage(`worker.postMessage("triggerBreakpoint")`);
  • trunk/LayoutTests/inspector/worker/debugger-shared-breakpoint.html

    r251227 r266074  
    9595            InspectorTest.assert(workerTarget1.mainResource instanceof WI.Script);
    9696            let location = workerTarget1.mainResource.createSourceCodeLocation(8, 0);
    97             breakpoint = new WI.Breakpoint(location);
     97            breakpoint = new WI.JavaScriptBreakpoint(location);
    9898            WI.debuggerManager.addBreakpoint(breakpoint);
    9999
  • trunk/Source/JavaScriptCore/CMakeLists.txt

    r266032 r266074  
    690690    inspector/PerGlobalObjectWrapperWorld.h
    691691    inspector/ScriptArguments.h
    692     inspector/ScriptBreakpoint.h
    693692    inspector/ScriptCallFrame.h
    694693    inspector/ScriptCallStack.h
    695694    inspector/ScriptCallStackFactory.h
    696     inspector/ScriptDebugListener.h
    697     inspector/ScriptDebugServer.h
    698695
    699696    inspector/agents/InspectorAgent.h
  • trunk/Source/JavaScriptCore/ChangeLog

    r266072 r266074  
     12020-08-24  Devin Rousso  <drousso@apple.com>
     2
     3        Web Inspector: allow event breakpoints to be configured
     4        https://bugs.webkit.org/show_bug.cgi?id=215362
     5        <rdar://problem/66932921>
     6
     7        Reviewed by Brian Burg.
     8
     9        This allows developers to do things like:
     10         - only pause when `window.event.type` is a certain value
     11         - ignore the first N pauses
     12         - evaluate JavaScript whenever an event listener is invoked without pausing
     13
     14        * inspector/protocol/DOM.json:
     15        Add an `options` paramater to `DOM.setBreakpointForEventListener` to allow configuration.
     16
     17        * inspector/protocol/DOMDebugger.json:
     18        Add an `options` paramater to `DOMDebugger.setEventBreakpoint` to allow configuration.
     19
     20        * debugger/Breakpoint.h:
     21        (JSC::Breakpoint::id const): Added.
     22        (JSC::Breakpoint::sourceID const): Added.
     23        (JSC::Breakpoint::lineNumber const): Added.
     24        (JSC::Breakpoint::columnNumber const): Added.
     25        (JSC::Breakpoint::condition const): Added.
     26        (JSC::Breakpoint::actions const): Added.
     27        (JSC::Breakpoint::isAutoContinue const): Added.
     28        (JSC::Breakpoint::resetHitCount): Added.
     29        (JSC::Breakpoint::isLinked const): Added.
     30        (JSC::Breakpoint::isResolved const): Added.
     31        (JSC::BreakpointsList::~BreakpointsList): Deleted.
     32        * debugger/Breakpoint.cpp: Added.
     33        (JSC::Breakpoint::Action::Action): Added.
     34        (JSC::Breakpoint::create): Added.
     35        (JSC::Breakpoint::Breakpoint): Added.
     36        (JSC::Breakpoint::link): Added.
     37        (JSC::Breakpoint::resolve): Added.
     38        (JSC::Breakpoint::shouldPause): Added.
     39        Unify `JSC::Breakpoint` and `Inspector::ScriptBreakpoint`.
     40
     41        * debugger/DebuggerPrimitives.h:
     42        * debugger/Debugger.h:
     43        * debugger/Debugger.cpp:
     44        (JSC::Debugger::Debugger):
     45        (JSC::Debugger::addObserver): Added.
     46        (JSC::Debugger::removeObserver): Added.
     47        (JSC::Debugger::canDispatchFunctionToObservers const): Added.
     48        (JSC::Debugger::dispatchFunctionToObservers): Added.
     49        (JSC::Debugger::sourceParsed): Added.
     50        (JSC::Debugger::toggleBreakpoint):
     51        (JSC::Debugger::applyBreakpoints):
     52        (JSC::Debugger::resolveBreakpoint):
     53        (JSC::Debugger::setBreakpoint):
     54        (JSC::Debugger::removeBreakpoint):
     55        (JSC::Debugger::didHitBreakpoint): Added.
     56        (JSC::Debugger::clearBreakpoints):
     57        (JSC::Debugger::evaluateBreakpointCondition): Added.
     58        (JSC::Debugger::evaluateBreakpointActions): Added.
     59        (JSC::Debugger::schedulePauseAtNextOpportunity): Added.
     60        (JSC::Debugger::cancelPauseAtNextOpportunity): Added.
     61        (JSC::Debugger::schedulePauseForSpecialBreakpoint): Added.
     62        (JSC::Debugger::cancelPauseForSpecialBreakpoint): Added.
     63        (JSC::Debugger::continueProgram):
     64        (JSC::Debugger::stepNextExpression):
     65        (JSC::Debugger::stepIntoStatement):
     66        (JSC::Debugger::stepOverStatement):
     67        (JSC::Debugger::stepOutOfFunction):
     68        (JSC::Debugger::pauseIfNeeded):
     69        (JSC::Debugger::handlePause): Added.
     70        (JSC::Debugger::exceptionOrCaughtValue): Added.
     71        (JSC::Debugger::atExpression):
     72        (JSC::Debugger::clearNextPauseState):
     73        (JSC::Debugger::willRunMicrotask): Added.
     74        (JSC::Debugger::didRunMicrotask): Added.
     75        (JSC::Debugger::hasBreakpoint): Deleted.
     76        (JSC::Debugger::setPauseOnNextStatement): Deleted.
     77        Unify `JSC::Debugger` and `Inspector::ScriptDebugServer` to simplify breakpoint logic.
     78        Introduce the concept of a "special breakpoint", which is essentially a `JSC::Breakpoint`
     79        that is expected to pause at the next opportunity but isn't tied to a particular location.
     80        As an example, whenever an event breakpoint is hit, instead of just pausing at the next
     81        opportunity, the newly managed `JSC::Breakpoint` is used as a "special breakpoint", allowing
     82        for it's configuration (ie.g. condition, ignore count, actions, auto-continue) to be used.
     83
     84        * inspector/agents/InspectorDebuggerAgent.h:
     85        * inspector/agents/InspectorDebuggerAgent.cpp:
     86        (Inspector::objectGroupForBreakpointAction):
     87        (Inspector::breakpointActionTypeForString): Added.
     88        (Inspector::parseBreakpointOptions): Added.
     89        (Inspector::InspectorDebuggerAgent::ProtocolBreakpoint::fromPayload): Added.
     90        (Inspector::InspectorDebuggerAgent::ProtocolBreakpoint::ProtocolBreakpoint): Added.
     91        (Inspector::InspectorDebuggerAgent::ProtocolBreakpoint::createDebuggerBreakpoint const): Added.
     92        (Inspector::InspectorDebuggerAgent::ProtocolBreakpoint::matchesScriptURL const): Added.
     93        (Inspector::InspectorDebuggerAgent::debuggerBreakpointFromPayload): Added.
     94        (Inspector::InspectorDebuggerAgent::enable):
     95        (Inspector::InspectorDebuggerAgent::disable):
     96        (Inspector::InspectorDebuggerAgent::buildBreakpointPauseReason):
     97        (Inspector::InspectorDebuggerAgent::handleConsoleAssert):
     98        (Inspector::InspectorDebuggerAgent::didScheduleAsyncCall):
     99        (Inspector::buildDebuggerLocation):
     100        (Inspector::InspectorDebuggerAgent::setBreakpointByUrl):
     101        (Inspector::InspectorDebuggerAgent::setBreakpoint):
     102        (Inspector::InspectorDebuggerAgent::didSetBreakpoint):
     103        (Inspector::InspectorDebuggerAgent::resolveBreakpoint):
     104        (Inspector::InspectorDebuggerAgent::removeBreakpoint):
     105        (Inspector::InspectorDebuggerAgent::continueToLocation):
     106        (Inspector::InspectorDebuggerAgent::schedulePauseAtNextOpportunity): Added.
     107        (Inspector::InspectorDebuggerAgent::cancelPauseAtNextOpportunity): Added.
     108        (Inspector::InspectorDebuggerAgent::schedulePauseForSpecialBreakpoint): Added.
     109        (Inspector::InspectorDebuggerAgent::cancelPauseForSpecialBreakpoint): Added.
     110        (Inspector::InspectorDebuggerAgent::pause):
     111        (Inspector::InspectorDebuggerAgent::resume):
     112        (Inspector::InspectorDebuggerAgent::didBecomeIdle):
     113        (Inspector::InspectorDebuggerAgent::sourceMapURLForScript):
     114        (Inspector::InspectorDebuggerAgent::didParseSource):
     115        (Inspector::InspectorDebuggerAgent::willRunMicrotask):
     116        (Inspector::InspectorDebuggerAgent::didRunMicrotask):
     117        (Inspector::InspectorDebuggerAgent::didPause):
     118        (Inspector::InspectorDebuggerAgent::breakpointActionSound):
     119        (Inspector::InspectorDebuggerAgent::breakpointActionProbe):
     120        (Inspector::InspectorDebuggerAgent::clearInspectorBreakpointState):
     121        (Inspector::InspectorDebuggerAgent::clearDebuggerBreakpointState):
     122        (Inspector::matches): Deleted.
     123        (Inspector::buildObjectForBreakpointCookie): Deleted.
     124        (Inspector::InspectorDebuggerAgent::breakpointActionsFromProtocol): Deleted.
     125        (Inspector::InspectorDebuggerAgent::schedulePauseOnNextStatement): Deleted.
     126        (Inspector::InspectorDebuggerAgent::cancelPauseOnNextStatement): Deleted.
     127        Create a private `ProtocolBreakpoint` class that holds the data sent by the frontend. This
     128        is necessary because breakpoints in the frontend have a potentially one-to-many relationship
     129        with breakpoints in the backend, as the same script can be loaded many times on a page. Each
     130        of those scripts is independent, however, and can execute differently, meaning that the same
     131        breakpoint for each script also needs a different state (e.g. ignore count). As such, the
     132        `ProtocolBreakpoint` is effectively a template that is actualized whenever a new script is
     133        parsed that matches the URL of the `ProtocolBreakpoint` to create a `JSC::Breakpoint` that
     134        is used by the `JSC::Debugger`. `ProtocolBreakpoint` also parses breakpoint configurations.
     135
     136        * inspector/InspectorEnvironment.h:
     137        * inspector/JSGlobalObjectScriptDebugServer.h:
     138        * inspector/JSGlobalObjectScriptDebugServer.cpp:
     139        (Inspector::JSGlobalObjectScriptDebugServer::JSGlobalObjectScriptDebugServer):
     140        (Inspector::JSGlobalObjectScriptDebugServer::attachDebugger):
     141        (Inspector::JSGlobalObjectScriptDebugServer::detachDebugger):
     142        (Inspector::JSGlobalObjectScriptDebugServer::runEventLoopWhilePaused):
     143        * inspector/agents/InspectorAuditAgent.h:
     144        * inspector/agents/InspectorAuditAgent.cpp:
     145        (Inspector::InspectorAuditAgent::run):
     146        * inspector/agents/InspectorRuntimeAgent.h:
     147        * inspector/agents/InspectorRuntimeAgent.cpp:
     148        (Inspector::setPauseOnExceptionsState):
     149        (Inspector::InspectorRuntimeAgent::evaluate):
     150        (Inspector::InspectorRuntimeAgent::callFunctionOn):
     151        (Inspector::InspectorRuntimeAgent::getPreview):
     152        (Inspector::InspectorRuntimeAgent::getProperties):
     153        (Inspector::InspectorRuntimeAgent::getDisplayableProperties):
     154        * inspector/agents/InspectorScriptProfilerAgent.cpp:
     155        * inspector/agents/JSGlobalObjectDebuggerAgent.h:
     156        Replace `Inspector::ScriptDebugServer` with `JSC::Debugger`.
     157
     158        * runtime/JSMicrotask.cpp:
     159        (JSC::JSMicrotask::run):
     160        Drive-by: r248894 mistakenly omitted the call to notify the debugger that the microtask ran.
     161
     162        * inspector/ScriptBreakpoint.h: Removed.
     163        * inspector/ScriptDebugListener.h: Removed.
     164        * inspector/ScriptDebugServer.h: Removed.
     165        * inspector/ScriptDebugServer.cpp: Removed.
     166        * CMakeLists.txt:
     167        * JavaScriptCore.xcodeproj/project.pbxproj:
     168        * Sources.txt:
     169
    11702020-08-24  Devin Rousso  <drousso@apple.com>
    2171
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r266032 r266074  
    13941394                A503FA1A188E0FB000110F14 /* JavaScriptCallFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = A503FA14188E0FAF00110F14 /* JavaScriptCallFrame.h */; };
    13951395                A503FA1E188E0FB000110F14 /* JSJavaScriptCallFramePrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = A503FA18188E0FB000110F14 /* JSJavaScriptCallFramePrototype.h */; };
    1396                 A503FA21188EFF6800110F14 /* ScriptBreakpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = A503FA1F188EFF6800110F14 /* ScriptBreakpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
    1397                 A503FA22188EFF6800110F14 /* ScriptDebugListener.h in Headers */ = {isa = PBXBuildFile; fileRef = A503FA20188EFF6800110F14 /* ScriptDebugListener.h */; settings = {ATTRIBUTES = (Private, ); }; };
    1398                 A503FA26188EFFFD00110F14 /* ScriptDebugServer.h in Headers */ = {isa = PBXBuildFile; fileRef = A503FA24188EFFFD00110F14 /* ScriptDebugServer.h */; settings = {ATTRIBUTES = (Private, ); }; };
    13991396                A503FA2A188F105900110F14 /* JSGlobalObjectScriptDebugServer.h in Headers */ = {isa = PBXBuildFile; fileRef = A503FA28188F105900110F14 /* JSGlobalObjectScriptDebugServer.h */; };
    14001397                A5098B041C16AA0200087797 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A5098B031C16AA0200087797 /* Security.framework */; };
     
    42534250                918E15BE2447B22700447A56 /* AggregateErrorPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AggregateErrorPrototype.cpp; sourceTree = "<group>"; };
    42544251                918E15BF2447B22700447A56 /* AggregateErrorConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AggregateErrorConstructor.h; sourceTree = "<group>"; };
     4252                91D1578C24E0BE35001F4CED /* Breakpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Breakpoint.cpp; sourceTree = "<group>"; };
    42554253                93052C320FB792190048FDC3 /* ParserArena.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParserArena.cpp; sourceTree = "<group>"; };
    42564254                93052C330FB792190048FDC3 /* ParserArena.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParserArena.h; sourceTree = "<group>"; };
     
    43914389                A503FA17188E0FB000110F14 /* JSJavaScriptCallFramePrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSJavaScriptCallFramePrototype.cpp; sourceTree = "<group>"; };
    43924390                A503FA18188E0FB000110F14 /* JSJavaScriptCallFramePrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSJavaScriptCallFramePrototype.h; sourceTree = "<group>"; };
    4393                 A503FA1F188EFF6800110F14 /* ScriptBreakpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptBreakpoint.h; sourceTree = "<group>"; };
    4394                 A503FA20188EFF6800110F14 /* ScriptDebugListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptDebugListener.h; sourceTree = "<group>"; };
    4395                 A503FA23188EFFFD00110F14 /* ScriptDebugServer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScriptDebugServer.cpp; sourceTree = "<group>"; };
    4396                 A503FA24188EFFFD00110F14 /* ScriptDebugServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptDebugServer.h; sourceTree = "<group>"; };
    43974391                A503FA27188F105900110F14 /* JSGlobalObjectScriptDebugServer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSGlobalObjectScriptDebugServer.cpp; sourceTree = "<group>"; };
    43984392                A503FA28188F105900110F14 /* JSGlobalObjectScriptDebugServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGlobalObjectScriptDebugServer.h; sourceTree = "<group>"; };
     
    65506544                        isa = PBXGroup;
    65516545                        children = (
     6546                                91D1578C24E0BE35001F4CED /* Breakpoint.cpp */,
    65526547                                FEA0861E182B7A0400F6D851 /* Breakpoint.h */,
    65536548                                F692A8580255597D01FF60F7 /* Debugger.cpp */,
     
    87108705                                A5FD0065189AFE9C00633231 /* ScriptArguments.cpp */,
    87118706                                A5FD0066189AFE9C00633231 /* ScriptArguments.h */,
    8712                                 A503FA1F188EFF6800110F14 /* ScriptBreakpoint.h */,
    87138707                                A5FD0069189B00A900633231 /* ScriptCallFrame.cpp */,
    87148708                                A5FD006A189B00A900633231 /* ScriptCallFrame.h */,
     
    87178711                                A5FD007B189B0B4C00633231 /* ScriptCallStackFactory.cpp */,
    87188712                                A5FD007C189B0B4C00633231 /* ScriptCallStackFactory.h */,
    8719                                 A503FA20188EFF6800110F14 /* ScriptDebugListener.h */,
    8720                                 A503FA23188EFFFD00110F14 /* ScriptDebugServer.cpp */,
    8721                                 A503FA24188EFFFD00110F14 /* ScriptDebugServer.h */,
    87228713                        );
    87238714                        path = inspector;
     
    1032810319                                33111B8B2397256500AA34CE /* Scribble.h in Headers */,
    1032910320                                A5FD0068189AFE9C00633231 /* ScriptArguments.h in Headers */,
    10330                                 A503FA21188EFF6800110F14 /* ScriptBreakpoint.h in Headers */,
    1033110321                                A5FD006E189B00AA00633231 /* ScriptCallFrame.h in Headers */,
    1033210322                                A5FD0070189B00AA00633231 /* ScriptCallStack.h in Headers */,
    1033310323                                A5FD007E189B0B4C00633231 /* ScriptCallStackFactory.h in Headers */,
    10334                                 A503FA22188EFF6800110F14 /* ScriptDebugListener.h in Headers */,
    10335                                 A503FA26188EFFFD00110F14 /* ScriptDebugServer.h in Headers */,
    1033610324                                147341CE1DC02D7900AA29BA /* ScriptExecutable.h in Headers */,
    1033710325                                CEAE7D7B889B477BA93ABA6C /* ScriptFetcher.h in Headers */,
  • trunk/Source/JavaScriptCore/Sources.txt

    r266032 r266074  
    301301bytecompiler/ProfileTypeBytecodeFlag.cpp
    302302
     303debugger/Breakpoint.cpp
    303304debugger/Debugger.cpp
    304305debugger/DebuggerCallFrame.cpp
     
    594595inspector/ScriptCallStack.cpp
    595596inspector/ScriptCallStackFactory.cpp
    596 inspector/ScriptDebugServer.cpp
    597597
    598598// Derived Sources
  • trunk/Source/JavaScriptCore/debugger/Breakpoint.h

    r250655 r266074  
    2727
    2828#include "DebuggerPrimitives.h"
    29 #include <wtf/DoublyLinkedList.h>
     29#include <wtf/FastMalloc.h>
     30#include <wtf/Noncopyable.h>
     31#include <wtf/Ref.h>
    3032#include <wtf/RefCounted.h>
     33#include <wtf/Vector.h>
    3134#include <wtf/text/WTFString.h>
    3235
    3336namespace JSC {
    3437
    35 struct Breakpoint : public DoublyLinkedListNode<Breakpoint> {
    36     Breakpoint()
    37     {
    38     }
     38class Debugger;
     39class JSGlobalObject;
    3940
    40     Breakpoint(SourceID sourceID, unsigned line, unsigned column, const String& condition, bool autoContinue, unsigned ignoreCount)
    41         : sourceID(sourceID)
    42         , line(line)
    43         , column(column)
    44         , condition(condition)
    45         , autoContinue(autoContinue)
    46         , ignoreCount(ignoreCount)
    47     {
    48     }
     41class Breakpoint : public RefCounted<Breakpoint> {
     42    WTF_MAKE_NONCOPYABLE(Breakpoint);
     43    WTF_MAKE_FAST_ALLOCATED;
     44public:
     45    struct Action {
     46        enum class Type : uint8_t {
     47            Log,
     48            Evaluate,
     49            Sound,
     50            Probe,
     51        };
    4952
    50     BreakpointID id { noBreakpointID };
    51     SourceID sourceID { noSourceID };
    52     unsigned line { 0 };
    53     unsigned column { 0 };
    54     String condition;
    55     bool autoContinue { false };
    56     unsigned ignoreCount { 0 };
    57     unsigned hitCount { 0 };
    58     bool resolved { false };
     53        Action(Type);
     54
     55        Type type;
     56        String data;
     57        BreakpointActionID id { noBreakpointActionID };
     58    };
     59
     60    using ActionsVector = Vector<Action>;
     61
     62    static Ref<Breakpoint> create(BreakpointID, const String& condition = nullString(), ActionsVector&& = { }, bool autoContinue = false, size_t ignoreCount = 0);
     63
     64    BreakpointID id() const { return m_id; }
     65
     66    SourceID sourceID() const { return m_sourceID; }
     67    unsigned lineNumber() const { return m_lineNumber; }
     68    unsigned columnNumber() const { return m_columnNumber; }
     69
     70    const String& condition() const { return m_condition; }
     71    const ActionsVector& actions() const { return m_actions; }
     72    bool isAutoContinue() const { return m_autoContinue; }
     73
     74    void resetHitCount() { m_hitCount = 0; }
     75
     76    // Associates this breakpoint with a position in a specific source code.
     77    bool link(SourceID, unsigned lineNumber, unsigned columnNumber);
     78    bool isLinked() const { return m_sourceID != noSourceID; }
     79
     80    // Adjust the previously associated position to the next pause opportunity.
     81    bool resolve(unsigned lineNumber, unsigned columnNumber);
     82    bool isResolved() const { return m_resolved; }
     83
     84    bool shouldPause(Debugger&, JSGlobalObject*);
    5985
    6086private:
    61     Breakpoint* m_prev;
    62     Breakpoint* m_next;
     87    Breakpoint(BreakpointID, String condition = nullString(), ActionsVector&& = { }, bool autoContinue = false, size_t ignoreCount = 0);
    6388
    64     friend class WTF::DoublyLinkedListNode<Breakpoint>;
     89    BreakpointID m_id { noBreakpointID };
     90
     91    SourceID m_sourceID { noSourceID };
     92
     93    // FIXME: <https://webkit.org/b/162771> Web Inspector: Adopt TextPosition in Inspector to avoid oneBasedInt/zeroBasedInt ambiguity
     94    unsigned m_lineNumber { 0 };
     95    unsigned m_columnNumber { 0 };
     96
     97    bool m_resolved { false };
     98
     99    String m_condition;
     100    ActionsVector m_actions;
     101    bool m_autoContinue { false };
     102    size_t m_ignoreCount { 0 };
     103    size_t m_hitCount { 0 };
    65104};
    66105
    67 class BreakpointsList : public DoublyLinkedList<Breakpoint>,
    68     public RefCounted<BreakpointsList> {
    69 public:
    70     ~BreakpointsList()
    71     {
    72         Breakpoint* breakpoint;
    73         while ((breakpoint = removeHead()))
    74             delete breakpoint;
    75         ASSERT(isEmpty());
    76     }
    77 };
     106using BreakpointsVector = Vector<Ref<JSC::Breakpoint>>;
    78107
    79108} // namespace JSC
  • trunk/Source/JavaScriptCore/debugger/Debugger.cpp

    r261895 r266074  
    2525#include "CodeBlock.h"
    2626#include "DebuggerCallFrame.h"
     27#include "DebuggerScope.h"
    2728#include "HeapIterationScope.h"
    2829#include "JSCInlines.h"
    2930#include "MarkedSpaceInlines.h"
    3031#include "VMEntryScope.h"
     32#include <wtf/HashMap.h>
     33#include <wtf/HashSet.h>
     34#include <wtf/RefPtr.h>
     35#include <wtf/Vector.h>
     36#include <wtf/text/TextPosition.h>
    3137
    3238namespace JSC {
     
    9096    , m_lastExecutedLine(UINT_MAX)
    9197    , m_lastExecutedSourceID(noSourceID)
    92     , m_topBreakpointID(noBreakpointID)
    9398    , m_pausingBreakpointID(noBreakpointID)
    9499{
     
    206211}
    207212
     213void Debugger::addObserver(Observer& observer)
     214{
     215    bool wasEmpty = m_observers.isEmpty();
     216
     217    m_observers.add(&observer);
     218
     219    if (wasEmpty)
     220        attachDebugger();
     221}
     222
     223void Debugger::removeObserver(Observer& observer, bool isBeingDestroyed)
     224{
     225    m_observers.remove(&observer);
     226
     227    if (m_observers.isEmpty())
     228        detachDebugger(isBeingDestroyed);
     229}
     230
     231bool Debugger::canDispatchFunctionToObservers() const
     232{
     233    return !m_dispatchingFunctionToObservers && !m_observers.isEmpty();
     234}
     235
     236void Debugger::dispatchFunctionToObservers(Function<void(Observer&)> func)
     237{
     238    if (!canDispatchFunctionToObservers())
     239        return;
     240
     241    SetForScope<bool> change(m_dispatchingFunctionToObservers, true);
     242
     243    for (auto* observer : copyToVector(m_observers))
     244        func(*observer);
     245}
     246
    208247void Debugger::setProfilingClient(ProfilingClient* client)
    209248{
     
    212251}
    213252
     253void Debugger::sourceParsed(JSGlobalObject* globalObject, SourceProvider* sourceProvider, int errorLine, const String& errorMessage)
     254{
     255    // Preemptively check whether we can dispatch so that we don't do any unnecessary allocations.
     256    if (!canDispatchFunctionToObservers())
     257        return;
     258
     259    if (errorLine != -1) {
     260        auto sourceURL = sourceProvider->sourceURL();
     261        auto data = sourceProvider->source().toString();
     262        auto firstLine = sourceProvider->startPosition().m_line.oneBasedInt();
     263        dispatchFunctionToObservers([&] (Observer& observer) {
     264            observer.failedToParseSource(sourceURL, data, firstLine, errorLine, errorMessage);
     265        });
     266        return;
     267    }
     268
     269    JSC::SourceID sourceID = sourceProvider->asID();
     270
     271    // FIXME: <https://webkit.org/b/162773> Web Inspector: Simplify Debugger::Script to use SourceProvider
     272    Debugger::Script script;
     273    script.sourceProvider = sourceProvider;
     274    script.url = sourceProvider->sourceURL();
     275    script.source = sourceProvider->source().toString();
     276    script.startLine = sourceProvider->startPosition().m_line.zeroBasedInt();
     277    script.startColumn = sourceProvider->startPosition().m_column.zeroBasedInt();
     278    script.isContentScript = isContentScript(globalObject);
     279    script.sourceURL = sourceProvider->sourceURLDirective();
     280    script.sourceMappingURL = sourceProvider->sourceMappingURLDirective();
     281
     282    int sourceLength = script.source.length();
     283    int lineCount = 1;
     284    int lastLineStart = 0;
     285    for (int i = 0; i < sourceLength; ++i) {
     286        if (script.source[i] == '\n') {
     287            lineCount += 1;
     288            lastLineStart = i + 1;
     289        }
     290    }
     291
     292    script.endLine = script.startLine + lineCount - 1;
     293    if (lineCount == 1)
     294        script.endColumn = script.startColumn + sourceLength;
     295    else
     296        script.endColumn = sourceLength - lastLineStart;
     297
     298    dispatchFunctionToObservers([&] (Observer& observer) {
     299        observer.didParseSource(sourceID, script);
     300    });
     301}
     302
    214303Seconds Debugger::willEvaluateScript()
    215304{
     
    224313void Debugger::toggleBreakpoint(CodeBlock* codeBlock, Breakpoint& breakpoint, BreakpointState enabledOrNot)
    225314{
    226     ASSERT(breakpoint.resolved);
     315    ASSERT(breakpoint.isResolved());
    227316
    228317    ScriptExecutable* executable = codeBlock->ownerExecutable();
    229318
    230319    SourceID sourceID = static_cast<SourceID>(executable->sourceID());
    231     if (breakpoint.sourceID != sourceID)
     320    if (breakpoint.sourceID() != sourceID)
    232321        return;
    233322
     
    239328    // Inspector breakpoint line and column values are zero-based but the executable
    240329    // and CodeBlock line and column values are one-based.
    241     unsigned line = breakpoint.line + 1;
     330    unsigned line = breakpoint.lineNumber() + 1;
    242331    Optional<unsigned> column;
    243     if (breakpoint.column)
    244         column = breakpoint.column + 1;
     332    if (breakpoint.columnNumber())
     333        column = breakpoint.columnNumber() + 1;
    245334
    246335    if (line < startLine || line > endLine)
     
    264353void Debugger::applyBreakpoints(CodeBlock* codeBlock)
    265354{
    266     BreakpointIDToBreakpointMap& breakpoints = m_breakpointIDToBreakpoint;
    267     for (auto* breakpoint : breakpoints.values())
    268         toggleBreakpoint(codeBlock, *breakpoint, BreakpointEnabled);
     355    for (auto& breakpoint : m_breakpoints)
     356        toggleBreakpoint(codeBlock, breakpoint, BreakpointEnabled);
    269357}
    270358
     
    315403}
    316404
    317 void Debugger::resolveBreakpoint(Breakpoint& breakpoint, SourceProvider* sourceProvider)
    318 {
    319     RELEASE_ASSERT(!breakpoint.resolved);
    320     ASSERT(breakpoint.sourceID != noSourceID);
     405bool Debugger::resolveBreakpoint(Breakpoint& breakpoint, SourceProvider* sourceProvider)
     406{
     407    RELEASE_ASSERT(!breakpoint.isResolved());
     408    ASSERT(breakpoint.isLinked());
    321409
    322410    // FIXME: <https://webkit.org/b/162771> Web Inspector: Adopt TextPosition in Inspector to avoid oneBasedInt/zeroBasedInt ambiguity
    323411    // Inspector breakpoint line and column values are zero-based but the executable
    324412    // and CodeBlock line values are one-based while column is zero-based.
    325     int line = breakpoint.line + 1;
    326     int column = breakpoint.column;
     413    int line = breakpoint.lineNumber() + 1;
     414    int column = breakpoint.columnNumber();
    327415
    328416    // Account for a <script>'s start position on the first line only.
    329417    int providerStartLine = sourceProvider->startPosition().m_line.oneBasedInt(); // One based to match the already adjusted line.
    330418    int providerStartColumn = sourceProvider->startPosition().m_column.zeroBasedInt(); // Zero based so column zero is zero.
    331     if (line == providerStartLine && breakpoint.column) {
     419    if (line == providerStartLine && breakpoint.columnNumber()) {
    332420        ASSERT(providerStartColumn <= column);
    333421        if (providerStartColumn)
     
    335423    }
    336424
    337     DebuggerParseData& parseData = debuggerParseData(breakpoint.sourceID, sourceProvider);
     425    DebuggerParseData& parseData = debuggerParseData(breakpoint.sourceID(), sourceProvider);
    338426    Optional<JSTextPosition> resolvedPosition = parseData.pausePositions.breakpointLocationForLineColumn(line, column);
    339427    if (!resolvedPosition)
    340         return;
     428        return false;
    341429
    342430    int resolvedLine = resolvedPosition->line;
     
    344432
    345433    // Re-account for a <script>'s start position on the first line only.
    346     if (resolvedLine == providerStartLine && breakpoint.column) {
     434    if (resolvedLine == providerStartLine && breakpoint.columnNumber()) {
    347435        if (providerStartColumn)
    348436            resolvedColumn += providerStartColumn;
    349437    }
    350438
    351     breakpoint.line = resolvedLine - 1;
    352     breakpoint.column = resolvedColumn;
    353     breakpoint.resolved = true;
    354 }
    355 
    356 BreakpointID Debugger::setBreakpoint(Breakpoint& breakpoint, bool& existing)
    357 {
    358     ASSERT(breakpoint.resolved);
    359     ASSERT(breakpoint.sourceID != noSourceID);
    360 
    361     SourceID sourceID = breakpoint.sourceID;
    362     unsigned line = breakpoint.line;
    363     unsigned column = breakpoint.column;
    364 
    365     SourceIDToBreakpointsMap::iterator it = m_sourceIDToBreakpoints.find(breakpoint.sourceID);
    366     if (it == m_sourceIDToBreakpoints.end())
    367         it = m_sourceIDToBreakpoints.set(sourceID, LineToBreakpointsMap()).iterator;
    368 
    369     LineToBreakpointsMap::iterator breaksIt = it->value.find(line);
    370     if (breaksIt == it->value.end())
    371         breaksIt = it->value.set(line, adoptRef(new BreakpointsList)).iterator;
    372 
    373     BreakpointsList& breakpoints = *breaksIt->value;
    374     for (Breakpoint* current = breakpoints.head(); current; current = current->next()) {
    375         if (current->column == column) {
     439    return breakpoint.resolve(resolvedLine - 1, resolvedColumn);
     440}
     441
     442bool Debugger::setBreakpoint(Breakpoint& breakpoint)
     443{
     444    ASSERT(breakpoint.isResolved());
     445
     446    auto& breakpointsForLine = m_breakpointsForSourceID.ensure(breakpoint.sourceID(), [] {
     447        return LineToBreakpointsMap();
     448    }).iterator->value;
     449
     450    auto& breakpoints = breakpointsForLine.ensure(breakpoint.lineNumber(), [] {
     451        return BreakpointsVector();
     452    }).iterator->value;
     453
     454    for (auto& existingBreakpoint : breakpoints) {
     455        if (existingBreakpoint->columnNumber() == breakpoint.columnNumber()) {
     456            ASSERT(existingBreakpoint->id() != breakpoint.id());
    376457            // Found existing breakpoint. Do not create a duplicate at this location.
    377             existing = true;
    378             return current->id;
     458            return false;
    379459        }
    380460    }
    381461
    382     existing = false;
    383     BreakpointID id = ++m_topBreakpointID;
    384     RELEASE_ASSERT(id != noBreakpointID);
    385 
    386     breakpoint.id = id;
    387 
    388     Breakpoint* newBreakpoint = new Breakpoint(breakpoint);
    389     breakpoints.append(newBreakpoint);
    390     m_breakpointIDToBreakpoint.set(id, newBreakpoint);
    391 
    392     toggleBreakpoint(*newBreakpoint, BreakpointEnabled);
    393 
    394     return id;
    395 }
    396 
    397 void Debugger::removeBreakpoint(BreakpointID id)
    398 {
    399     ASSERT(id != noBreakpointID);
    400 
    401     BreakpointIDToBreakpointMap::iterator idIt = m_breakpointIDToBreakpoint.find(id);
    402     ASSERT(idIt != m_breakpointIDToBreakpoint.end());
    403     Breakpoint* breakpoint = idIt->value;
    404 
    405     SourceID sourceID = breakpoint->sourceID;
    406     ASSERT(sourceID);
    407     SourceIDToBreakpointsMap::iterator it = m_sourceIDToBreakpoints.find(sourceID);
    408     ASSERT(it != m_sourceIDToBreakpoints.end());
    409     LineToBreakpointsMap::iterator breaksIt = it->value.find(breakpoint->line);
    410     ASSERT(breaksIt != it->value.end());
    411 
    412     toggleBreakpoint(*breakpoint, BreakpointDisabled);
    413 
    414     BreakpointsList& breakpoints = *breaksIt->value;
     462    breakpoints.append(makeRef(breakpoint));
     463
     464    m_breakpoints.add(makeRef(breakpoint));
     465
     466    toggleBreakpoint(breakpoint, BreakpointEnabled);
     467
     468    return true;
     469}
     470
     471bool Debugger::removeBreakpoint(Breakpoint& breakpoint)
     472{
     473    ASSERT(breakpoint.isResolved());
     474
     475    auto breakpointsForLineIterator = m_breakpointsForSourceID.find(breakpoint.sourceID());
     476    if (breakpointsForLineIterator == m_breakpointsForSourceID.end())
     477        return false;
     478
     479    auto breakpointsIterator = breakpointsForLineIterator->value.find(breakpoint.lineNumber());
     480    if (breakpointsIterator == breakpointsForLineIterator->value.end())
     481        return false;
     482
     483    toggleBreakpoint(breakpoint, BreakpointDisabled);
     484
     485    auto& breakpoints = breakpointsIterator->value;
     486
    415487#if ASSERT_ENABLED
    416488    bool found = false;
    417     for (Breakpoint* current = breakpoints.head(); current && !found; current = current->next()) {
    418         if (current->id == breakpoint->id)
     489    for (auto& existingBreakpoint : breakpoints) {
     490        if (existingBreakpoint->columnNumber() == breakpoint.columnNumber()) {
     491            ASSERT(existingBreakpoint->id() == breakpoint.id());
     492            ASSERT(!found);
    419493            found = true;
    420     }
    421     ASSERT(found);
     494        }
     495    }
    422496#endif // ASSERT_ENABLED
    423497
    424     m_breakpointIDToBreakpoint.remove(idIt);
    425     breakpoints.remove(breakpoint);
    426     delete breakpoint;
     498    auto removed = m_breakpoints.remove(breakpoint);
     499    removed |= !breakpoints.removeAllMatching([&] (const Ref<Breakpoint>& existingBreakpoint) {
     500        return &breakpoint == existingBreakpoint.ptr();
     501    });
    427502
    428503    if (breakpoints.isEmpty()) {
    429         it->value.remove(breaksIt);
    430         if (it->value.isEmpty())
    431             m_sourceIDToBreakpoints.remove(it);
    432     }
    433 }
    434 
    435 bool Debugger::hasBreakpoint(SourceID sourceID, const TextPosition& position, Breakpoint *hitBreakpoint)
     504        breakpointsForLineIterator->value.remove(breakpointsIterator);
     505        if (breakpointsForLineIterator->value.isEmpty())
     506            m_breakpointsForSourceID.remove(breakpointsForLineIterator);
     507    }
     508
     509    return removed;
     510}
     511
     512RefPtr<Breakpoint> Debugger::didHitBreakpoint(JSGlobalObject* globalObject, SourceID sourceID, const TextPosition& position)
    436513{
    437514    if (!m_breakpointsActivated)
    438         return false;
    439 
    440     SourceIDToBreakpointsMap::const_iterator it = m_sourceIDToBreakpoints.find(sourceID);
    441     if (it == m_sourceIDToBreakpoints.end())
    442         return false;
     515        return nullptr;
     516
     517    auto breakpointsForLineIterator = m_breakpointsForSourceID.find(sourceID);
     518    if (breakpointsForLineIterator == m_breakpointsForSourceID.end())
     519        return nullptr;
    443520
    444521    unsigned line = position.m_line.zeroBasedInt();
    445522    unsigned column = position.m_column.zeroBasedInt();
    446523   
    447     LineToBreakpointsMap::const_iterator breaksIt = it->value.find(line);
    448     if (breaksIt == it->value.end())
    449         return false;
    450 
    451     bool hit = false;
    452     const BreakpointsList& breakpoints = *breaksIt->value;
    453     Breakpoint* breakpoint;
    454     for (breakpoint = breakpoints.head(); breakpoint; breakpoint = breakpoint->next()) {
    455         unsigned breakLine = breakpoint->line;
    456         unsigned breakColumn = breakpoint->column;
     524    auto breakpointsIterator = breakpointsForLineIterator->value.find(line);
     525    if (breakpointsIterator == breakpointsForLineIterator->value.end())
     526        return nullptr;
     527
     528    for (auto& breakpoint : breakpointsIterator->value) {
     529        unsigned breakLine = breakpoint->lineNumber();
     530        unsigned breakColumn = breakpoint->columnNumber();
     531
    457532        // Since frontend truncates the indent, the first statement in a line must match the breakpoint (line,0).
    458533        ASSERT(this == m_currentCallFrame->codeBlock()->globalObject()->debugger());
    459         if ((line != m_lastExecutedLine && line == breakLine && !breakColumn)
    460             || (line == breakLine && column == breakColumn)) {
    461             hit = true;
     534        if ((line != m_lastExecutedLine && line == breakLine && !breakColumn) || (line == breakLine && column == breakColumn)) {
     535            if (breakpoint->shouldPause(*this, globalObject))
     536                return breakpoint.copyRef();
    462537            break;
    463538        }
    464539    }
    465     if (!hit)
    466         return false;
    467 
    468     if (hitBreakpoint)
    469         *hitBreakpoint = *breakpoint;
    470 
    471     breakpoint->hitCount++;
    472     if (breakpoint->ignoreCount >= breakpoint->hitCount)
    473         return false;
    474 
    475     if (breakpoint->condition.isEmpty())
    476         return true;
    477 
    478     // We cannot stop in the debugger while executing condition code,
    479     // so make it looks like the debugger is already paused.
    480     TemporaryPausedState pausedState(*this);
    481 
    482     NakedPtr<Exception> exception;
    483     DebuggerCallFrame& debuggerCallFrame = currentDebuggerCallFrame();
    484     JSObject* scopeExtensionObject = nullptr;
    485     JSValue result = debuggerCallFrame.evaluateWithScopeExtension(breakpoint->condition, scopeExtensionObject, exception);
    486 
    487     // We can lose the debugger while executing JavaScript.
    488     if (!m_currentCallFrame)
    489         return false;
    490 
    491     JSGlobalObject* globalObject = m_currentCallFrame->lexicalGlobalObject(m_vm);
    492     if (exception) {
    493         // An erroneous condition counts as "false".
    494         handleExceptionInBreakpointCondition(globalObject, exception);
    495         return false;
    496     }
    497 
    498     return result.toBoolean(globalObject);
     540
     541    return nullptr;
    499542}
    500543
     
    520563    m_vm.heap.completeAllJITPlans();
    521564
    522     m_topBreakpointID = noBreakpointID;
    523     m_breakpointIDToBreakpoint.clear();
    524     m_sourceIDToBreakpoints.clear();
     565    m_breakpointsForSourceID.clear();
     566    m_breakpoints.clear();
     567    m_specialBreakpoint = nullptr;
    525568
    526569    ClearCodeBlockDebuggerRequestsFunctor functor(this);
    527570    m_vm.heap.forEachCodeBlock(functor);
     571}
     572
     573bool Debugger::evaluateBreakpointCondition(Breakpoint& breakpoint, JSGlobalObject* globalObject)
     574{
     575    const String& condition = breakpoint.condition();
     576    if (condition.isEmpty())
     577        return true;
     578
     579    // We cannot stop in the debugger while executing condition code,
     580    // so make it looks like the debugger is already paused.
     581    TemporaryPausedState pausedState(*this);
     582
     583    NakedPtr<Exception> exception;
     584    DebuggerCallFrame& debuggerCallFrame = currentDebuggerCallFrame();
     585    JSObject* scopeExtensionObject = nullptr;
     586    JSValue result = debuggerCallFrame.evaluateWithScopeExtension(condition, scopeExtensionObject, exception);
     587
     588    // We can lose the debugger while executing JavaScript.
     589    if (!m_currentCallFrame)
     590        return false;
     591
     592    if (exception) {
     593        reportException(globalObject, exception);
     594        return false;
     595    }
     596
     597    return result.toBoolean(globalObject);
     598}
     599
     600void Debugger::evaluateBreakpointActions(Breakpoint& breakpoint, JSGlobalObject* globalObject)
     601{
     602    ASSERT(m_isPaused);
     603    ASSERT(isAttached(globalObject));
     604
     605    m_currentProbeBatchId++;
     606
     607    for (auto& action : breakpoint.actions()) {
     608        auto& debuggerCallFrame = currentDebuggerCallFrame();
     609
     610        switch (action.type) {
     611        case Breakpoint::Action::Type::Log:
     612            dispatchFunctionToObservers([&] (Observer& observer) {
     613                observer.breakpointActionLog(debuggerCallFrame.globalObject(), action.data);
     614            });
     615            break;
     616
     617        case Breakpoint::Action::Type::Evaluate: {
     618            NakedPtr<Exception> exception;
     619            JSObject* scopeExtensionObject = nullptr;
     620            debuggerCallFrame.evaluateWithScopeExtension(action.data, scopeExtensionObject, exception);
     621            if (exception)
     622                reportException(debuggerCallFrame.globalObject(), exception);
     623            break;
     624        }
     625
     626        case Breakpoint::Action::Type::Sound:
     627            dispatchFunctionToObservers([&] (Observer& observer) {
     628                observer.breakpointActionSound(action.id);
     629            });
     630            break;
     631
     632        case Breakpoint::Action::Type::Probe: {
     633            NakedPtr<Exception> exception;
     634            JSObject* scopeExtensionObject = nullptr;
     635            JSValue result = debuggerCallFrame.evaluateWithScopeExtension(action.data, scopeExtensionObject, exception);
     636            JSC::JSGlobalObject* debuggerGlobalObject = debuggerCallFrame.globalObject();
     637            if (exception)
     638                reportException(debuggerGlobalObject, exception);
     639
     640            dispatchFunctionToObservers([&] (Observer& observer) {
     641                observer.breakpointActionProbe(debuggerGlobalObject, action.id, m_currentProbeBatchId, m_nextProbeSampleId++, exception ? exception->value() : result);
     642            });
     643            break;
     644        }
     645        }
     646
     647        if (!isAttached(globalObject))
     648            return;
     649    }
    528650}
    529651
     
    572694}
    573695
    574 void Debugger::setPauseOnNextStatement(bool pause)
    575 {
    576     m_pauseAtNextOpportunity = pause;
    577     if (pause)
    578         setSteppingMode(SteppingModeEnabled);
     696void Debugger::schedulePauseAtNextOpportunity()
     697{
     698    m_pauseAtNextOpportunity = true;
     699
     700    setSteppingMode(SteppingModeEnabled);
     701}
     702
     703void Debugger::cancelPauseAtNextOpportunity()
     704{
     705    m_pauseAtNextOpportunity = false;
     706}
     707
     708bool Debugger::schedulePauseForSpecialBreakpoint(Breakpoint& breakpoint)
     709{
     710    if (m_specialBreakpoint)
     711        return false;
     712
     713    m_specialBreakpoint = makeRef(breakpoint);
     714    setSteppingMode(SteppingModeEnabled);
     715    return true;
     716}
     717
     718bool Debugger::cancelPauseForSpecialBreakpoint(Breakpoint& breakpoint)
     719{
     720    if (&breakpoint != m_specialBreakpoint)
     721        return false;
     722
     723    m_specialBreakpoint = nullptr;
     724    return true;
    579725}
    580726
     
    600746        return;
    601747
    602     notifyDoneProcessingDebuggerEvents();
     748    m_doneProcessingDebuggerEvents = true;
    603749}
    604750
     
    611757    m_pauseOnStepNext = true;
    612758    setSteppingMode(SteppingModeEnabled);
    613     notifyDoneProcessingDebuggerEvents();
     759    m_doneProcessingDebuggerEvents = true;
    614760}
    615761
     
    621767    m_pauseAtNextOpportunity = true;
    622768    setSteppingMode(SteppingModeEnabled);
    623     notifyDoneProcessingDebuggerEvents();
     769    m_doneProcessingDebuggerEvents = true;
    624770}
    625771
     
    631777    m_pauseOnCallFrame = m_currentCallFrame;
    632778    setSteppingMode(SteppingModeEnabled);
    633     notifyDoneProcessingDebuggerEvents();
     779    m_doneProcessingDebuggerEvents = true;
    634780}
    635781
     
    643789    m_pauseOnStepOut = true;
    644790    setSteppingMode(SteppingModeEnabled);
    645     notifyDoneProcessingDebuggerEvents();
     791    m_doneProcessingDebuggerEvents = true;
    646792}
    647793
     
    702848    bool didPauseForStep = pauseNow;
    703849
    704     Breakpoint breakpoint;
    705850    TextPosition position = DebuggerCallFrame::positionForCallFrame(vm, m_currentCallFrame);
    706     bool didHitBreakpoint = hasBreakpoint(sourceID, position, &breakpoint);
    707     pauseNow |= didHitBreakpoint;
     851
     852    auto breakpoint = didHitBreakpoint(globalObject, sourceID, position);
     853    if (breakpoint)
     854        pauseNow = true;
     855
     856    // Special breakpoints are only given one opportunity to pause.
     857    auto specialBreakpoint = WTFMove(m_specialBreakpoint);
     858    if (specialBreakpoint && specialBreakpoint->shouldPause(*this, globalObject))
     859        pauseNow = true;
     860
    708861    m_lastExecutedLine = position.m_line.zeroBasedInt();
    709862    if (!pauseNow)
     
    717870    TemporaryPausedState pausedState(*this);
    718871
    719     if (didHitBreakpoint) {
    720         handleBreakpointHit(globalObject, breakpoint);
     872    if (breakpoint || specialBreakpoint) {
    721873        // Note that the actions can potentially stop the debugger, so we need to check that
    722874        // we still have a current call frame when we get back.
    723         if (!m_currentCallFrame)
    724             return;
    725 
    726         if (breakpoint.autoContinue) {
     875
     876        bool autoContinue = false;
     877
     878        if (breakpoint) {
     879            evaluateBreakpointActions(*breakpoint, globalObject);
     880
     881            if (!m_currentCallFrame)
     882                return;
     883
     884            if (breakpoint->isAutoContinue())
     885                autoContinue = true;
     886        }
     887
     888        if (specialBreakpoint) {
     889            evaluateBreakpointActions(*specialBreakpoint, globalObject);
     890
     891            if (!m_currentCallFrame)
     892                return;
     893
     894            if (specialBreakpoint->isAutoContinue())
     895                autoContinue = true;
     896        }
     897
     898        if (autoContinue) {
    727899            if (!didPauseForStep)
    728900                return;
    729             didHitBreakpoint = false;
    730         } else
    731             m_pausingBreakpointID = breakpoint.id;
     901
     902            breakpoint = nullptr;
     903            specialBreakpoint = nullptr;
     904        } else if (breakpoint)
     905            m_pausingBreakpointID = breakpoint->id();
    732906    }
    733907
    734908    if (blackboxTypeIterator != m_blackboxedScripts.end() && blackboxTypeIterator->value == BlackboxType::Deferred) {
    735909        m_afterBlackboxedScript = true;
    736         setPauseOnNextStatement(true);
     910        schedulePauseAtNextOpportunity();
    737911        return;
    738912    }
     
    742916        if (afterBlackboxedScript)
    743917            reason = PausedAfterBlackboxedScript;
    744         else if (didHitBreakpoint)
     918        else if (breakpoint)
    745919            reason = PausedForBreakpoint;
    746920        PauseReasonDeclaration rauseReasonDeclaration(*this, reason);
     
    752926    m_pausingBreakpointID = noBreakpointID;
    753927
    754     if (!m_pauseAtNextOpportunity && !m_pauseOnCallFrame) {
     928    if (!m_pauseAtNextOpportunity && !m_pauseOnCallFrame && !m_specialBreakpoint) {
    755929        setSteppingMode(SteppingModeDisabled);
    756930        m_currentCallFrame = nullptr;
    757931    }
     932}
     933
     934void Debugger::handlePause(JSGlobalObject* globalObject, ReasonForPause)
     935{
     936    dispatchFunctionToObservers([&] (Observer& observer) {
     937        ASSERT(isPaused());
     938        observer.didPause(globalObject, currentDebuggerCallFrame(), exceptionOrCaughtValue(globalObject));
     939    });
     940
     941    didPause(globalObject);
     942
     943    m_doneProcessingDebuggerEvents = false;
     944    runEventLoopWhilePaused();
     945
     946    didContinue(globalObject);
     947
     948    dispatchFunctionToObservers([&] (Observer& observer) {
     949        observer.didContinue();
     950    });
     951}
     952
     953JSC::JSValue Debugger::exceptionOrCaughtValue(JSC::JSGlobalObject* globalObject)
     954{
     955    if (reasonForPause() == PausedForException)
     956        return currentException();
     957
     958    for (RefPtr<DebuggerCallFrame> frame = &currentDebuggerCallFrame(); frame; frame = frame->callerFrame()) {
     959        DebuggerScope& scope = *frame->scope();
     960        if (scope.isCatchScope())
     961            return scope.caughtValue(globalObject);
     962    }
     963
     964    return { };
    758965}
    759966
     
    8081015    }
    8091016
    810     // Only pause at the next expression with step-in, step-next, and step-out.
    811     bool shouldAttemptPause = m_pauseAtNextOpportunity || m_pauseOnStepNext || m_pauseOnStepOut;
     1017    // Only pause at the next expression for step-in, step-next, step-out, or special breakpoints.
     1018    bool shouldAttemptPause = m_pauseAtNextOpportunity || m_pauseOnStepNext || m_pauseOnStepOut || m_specialBreakpoint;
    8121019
    8131020    PauseReasonDeclaration reason(*this, PausedAtExpression);
     
    9181125    m_pauseOnStepOut = false;
    9191126    m_afterBlackboxedScript = false;
     1127    m_specialBreakpoint = nullptr;
    9201128}
    9211129
     
    9341142}
    9351143
     1144void Debugger::willRunMicrotask()
     1145{
     1146    dispatchFunctionToObservers([&] (Observer& observer) {
     1147        observer.willRunMicrotask();
     1148    });
     1149}
     1150
     1151void Debugger::didRunMicrotask()
     1152{
     1153    dispatchFunctionToObservers([&] (Observer& observer) {
     1154        observer.didRunMicrotask();
     1155    });
     1156}
     1157
    9361158DebuggerCallFrame& Debugger::currentDebuggerCallFrame()
    9371159{
  • trunk/Source/JavaScriptCore/debugger/Debugger.h

    r260113 r266074  
    2828#include "DebuggerPrimitives.h"
    2929#include "JSCJSValue.h"
    30 #include <wtf/HashMap.h>
    31 #include <wtf/HashSet.h>
    32 #include <wtf/RefPtr.h>
    33 #include <wtf/text/TextPosition.h>
     30#include <wtf/Forward.h>
    3431
    3532namespace JSC {
     
    4239class VM;
    4340
    44 class JS_EXPORT_PRIVATE Debugger {
     41class Debugger {
    4542    WTF_MAKE_FAST_ALLOCATED;
    4643public:
    47     Debugger(VM&);
    48     virtual ~Debugger();
     44    JS_EXPORT_PRIVATE Debugger(VM&);
     45    JS_EXPORT_PRIVATE virtual ~Debugger();
    4946
    5047    VM& vm() { return m_vm; }
    51 
    52     JSC::DebuggerCallFrame& currentDebuggerCallFrame();
    53     bool hasHandlerForExceptionCallback() const
    54     {
    55         ASSERT(m_reasonForPause == PausedForException);
    56         return m_hasHandlerForExceptionCallback;
    57     }
    58     JSValue currentException()
    59     {
    60         ASSERT(m_reasonForPause == PausedForException);
    61         return m_currentException;
    62     }
    6348
    6449    bool needsExceptionCallbacks() const { return m_breakpointsActivated && m_pauseOnExceptionsState != DontPauseOnExceptions; }
     
    6954        GlobalObjectIsDestructing
    7055    };
    71     void attach(JSGlobalObject*);
    72     void detach(JSGlobalObject*, ReasonForDetach);
    73     bool isAttached(JSGlobalObject*);
    74 
    75     void resolveBreakpoint(Breakpoint&, SourceProvider*);
    76     BreakpointID setBreakpoint(Breakpoint&, bool& existing);
    77     void removeBreakpoint(BreakpointID);
     56    JS_EXPORT_PRIVATE void attach(JSGlobalObject*);
     57    JS_EXPORT_PRIVATE void detach(JSGlobalObject*, ReasonForDetach);
     58    JS_EXPORT_PRIVATE bool isAttached(JSGlobalObject*);
     59
     60    bool resolveBreakpoint(Breakpoint&, SourceProvider*);
     61    bool setBreakpoint(Breakpoint&);
     62    bool removeBreakpoint(Breakpoint&);
    7863    void clearBreakpoints();
    7964
     
    8166    void deactivateBreakpoints() { setBreakpointsActivated(false); }
    8267    bool breakpointsActive() const { return m_breakpointsActivated; }
     68
     69    // Breakpoint "delegate" functionality.
     70    bool evaluateBreakpointCondition(Breakpoint&, JSGlobalObject*);
     71    void evaluateBreakpointActions(Breakpoint&, JSGlobalObject*);
    8372
    8473    enum PauseOnExceptionsState {
     
    8877    };
    8978    PauseOnExceptionsState pauseOnExceptionsState() const { return m_pauseOnExceptionsState; }
    90     void setPauseOnExceptionsState(PauseOnExceptionsState);
     79    JS_EXPORT_PRIVATE void setPauseOnExceptionsState(PauseOnExceptionsState);
    9180
    9281    void setPauseOnDebuggerStatements(bool enabled) { m_pauseOnDebuggerStatements = enabled; }
     
    10695    BreakpointID pausingBreakpointID() const { return m_pausingBreakpointID; }
    10796
    108     void setPauseOnNextStatement(bool);
     97    void schedulePauseAtNextOpportunity();
     98    void cancelPauseAtNextOpportunity();
     99    bool schedulePauseForSpecialBreakpoint(Breakpoint&);
     100    bool cancelPauseForSpecialBreakpoint(Breakpoint&);
    109101    void breakProgram();
    110102    void continueProgram();
     
    124116    void setSuppressAllPauses(bool suppress) { m_suppressAllPauses = suppress; }
    125117
    126     virtual void sourceParsed(JSGlobalObject*, SourceProvider*, int errorLineNumber, const WTF::String& errorMessage) = 0;
    127     virtual void willRunMicrotask() { }
    128     virtual void didRunMicrotask() { }
     118    JS_EXPORT_PRIVATE virtual void sourceParsed(JSGlobalObject*, SourceProvider*, int errorLineNumber, const WTF::String& errorMessage);
    129119
    130120    void exception(JSGlobalObject*, CallFrame*, JSValue exceptionValue, bool hasCatchHandler);
     
    138128    void didReachDebuggerStatement(CallFrame*);
    139129
    140     virtual void recompileAllJSFunctions();
     130    void willRunMicrotask();
     131    void didRunMicrotask();
    141132
    142133    void registerCodeBlock(CodeBlock*);
     134
     135    // FIXME: <https://webkit.org/b/162773> Web Inspector: Simplify Debugger::Script to use SourceProvider
     136    struct Script {
     137        String url;
     138        String source;
     139        String sourceURL;
     140        String sourceMappingURL;
     141        RefPtr<SourceProvider> sourceProvider;
     142        int startLine { 0 };
     143        int startColumn { 0 };
     144        int endLine { 0 };
     145        int endColumn { 0 };
     146        bool isContentScript { false };
     147    };
     148
     149    class Observer {
     150    public:
     151        virtual ~Observer() { }
     152
     153        virtual void didParseSource(SourceID, const Debugger::Script&) { }
     154        virtual void failedToParseSource(const String& /* url */, const String& /* data */, int /* firstLine */, int /* errorLine */, const String& /* errorMessage */) { }
     155
     156        virtual void willRunMicrotask() { }
     157        virtual void didRunMicrotask() { }
     158
     159        virtual void didPause(JSGlobalObject*, DebuggerCallFrame&, JSValue /* exceptionOrCaughtValue */) { }
     160        virtual void didContinue() { }
     161
     162        virtual void breakpointActionLog(JSGlobalObject*, const String& /* data */) { }
     163        virtual void breakpointActionSound(BreakpointActionID) { }
     164        virtual void breakpointActionProbe(JSGlobalObject*, BreakpointActionID, unsigned /* batchId */, unsigned /* sampleId */, JSValue /* result */) { }
     165    };
     166
     167    JS_EXPORT_PRIVATE void addObserver(Observer&);
     168    JS_EXPORT_PRIVATE void removeObserver(Observer&, bool isBeingDestroyed);
    143169
    144170    class ProfilingClient {
     
    157183
    158184protected:
    159     virtual void handleBreakpointHit(JSGlobalObject*, const Breakpoint&) { }
    160     virtual void handleExceptionInBreakpointCondition(JSGlobalObject*, Exception*) const { }
    161     virtual void handlePause(JSGlobalObject*, ReasonForPause) { }
    162     virtual void notifyDoneProcessingDebuggerEvents() { }
     185    JS_EXPORT_PRIVATE JSC::DebuggerCallFrame& currentDebuggerCallFrame();
     186
     187    bool hasHandlerForExceptionCallback() const
     188    {
     189        ASSERT(m_reasonForPause == PausedForException);
     190        return m_hasHandlerForExceptionCallback;
     191    }
     192
     193    JSValue currentException()
     194    {
     195        ASSERT(m_reasonForPause == PausedForException);
     196        return m_currentException;
     197    }
     198
     199    virtual void attachDebugger() { }
     200    virtual void detachDebugger(bool /* isBeingDestroyed */) { }
     201    JS_EXPORT_PRIVATE virtual void recompileAllJSFunctions();
     202
     203    virtual void didPause(JSGlobalObject*) { }
     204    JS_EXPORT_PRIVATE virtual void handlePause(JSGlobalObject*, ReasonForPause);
     205    virtual void didContinue(JSGlobalObject*) { }
     206    virtual void runEventLoopWhilePaused() { }
     207
     208    virtual bool isContentScript(JSGlobalObject*) const { return false; }
     209
     210    // NOTE: Currently all exceptions are reported at the API boundary through reportAPIException.
     211    // Until a time comes where an exception can be caused outside of the API (e.g. setTimeout
     212    // or some other async operation in a pure JSContext) we can ignore exceptions reported here.
     213    virtual void reportException(JSGlobalObject*, Exception*) const { }
     214
     215    bool doneProcessingDebuggerEvents() const { return m_doneProcessingDebuggerEvents; }
    163216
    164217private:
    165     typedef HashMap<BreakpointID, Breakpoint*> BreakpointIDToBreakpointMap;
    166 
    167     typedef HashMap<unsigned, RefPtr<BreakpointsList>, WTF::IntHash<int>, WTF::UnsignedWithZeroKeyHashTraits<int>> LineToBreakpointsMap;
    168     typedef HashMap<SourceID, LineToBreakpointsMap, WTF::IntHash<SourceID>, WTF::UnsignedWithZeroKeyHashTraits<SourceID>> SourceIDToBreakpointsMap;
     218    JSValue exceptionOrCaughtValue(JSGlobalObject*);
    169219
    170220    class ClearCodeBlockDebuggerRequestsFunctor;
     
    189239    };
    190240
    191     bool hasBreakpoint(SourceID, const TextPosition&, Breakpoint* hitBreakpoint);
     241    RefPtr<Breakpoint> didHitBreakpoint(JSGlobalObject*, SourceID, const TextPosition&);
    192242
    193243    DebuggerParseData& debuggerParseData(SourceID, SourceProvider*);
     
    216266        BreakpointEnabled
    217267    };
    218     void setBreakpointsActivated(bool);
     268    JS_EXPORT_PRIVATE void setBreakpointsActivated(bool);
    219269    void toggleBreakpoint(CodeBlock*, Breakpoint&, BreakpointState);
    220270    void applyBreakpoints(CodeBlock*);
     
    223273    void clearDebuggerRequests(JSGlobalObject*);
    224274    void clearParsedData();
     275
     276    bool canDispatchFunctionToObservers() const;
     277    void dispatchFunctionToObservers(Function<void(Observer&)>);
    225278
    226279    VM& m_vm;
     
    249302    bool m_afterBlackboxedScript { false };
    250303
    251     BreakpointID m_topBreakpointID;
     304    using LineToBreakpointsMap = HashMap<unsigned, BreakpointsVector, WTF::IntHash<int>, WTF::UnsignedWithZeroKeyHashTraits<int>>;
     305    HashMap<SourceID, LineToBreakpointsMap, WTF::IntHash<SourceID>, WTF::UnsignedWithZeroKeyHashTraits<SourceID>> m_breakpointsForSourceID;
     306    HashSet<Ref<Breakpoint>> m_breakpoints;
     307    RefPtr<Breakpoint> m_specialBreakpoint;
    252308    BreakpointID m_pausingBreakpointID;
    253     BreakpointIDToBreakpointMap m_breakpointIDToBreakpoint;
    254     SourceIDToBreakpointsMap m_sourceIDToBreakpoints;
     309
     310    unsigned m_nextProbeSampleId { 1 };
     311    unsigned m_currentProbeBatchId { 0 };
    255312
    256313    RefPtr<JSC::DebuggerCallFrame> m_currentDebuggerCallFrame;
    257314
     315    HashSet<Observer*> m_observers;
     316    bool m_dispatchingFunctionToObservers { false };
     317
    258318    ProfilingClient* m_profilingClient { nullptr };
     319
     320    bool m_doneProcessingDebuggerEvents { true };
    259321
    260322    friend class DebuggerPausedScope;
  • trunk/Source/JavaScriptCore/debugger/DebuggerPrimitives.h

    r250005 r266074  
    3030namespace JSC {
    3131
    32 typedef size_t SourceID;
    33 static constexpr SourceID noSourceID = 0;
     32using SourceID = size_t;
     33constexpr SourceID noSourceID = 0;
    3434
    35 typedef size_t BreakpointID;
    36 static constexpr BreakpointID noBreakpointID = 0;
     35using BreakpointID = size_t;
     36constexpr BreakpointID noBreakpointID = 0;
     37
     38using BreakpointActionID = int;
     39constexpr BreakpointActionID noBreakpointActionID = 0;
    3740
    3841} // namespace JSC
  • trunk/Source/JavaScriptCore/inspector/InspectorEnvironment.h

    r261233 r266074  
    3333
    3434namespace JSC {
     35class Debugger;
    3536class Exception;
    3637class SourceCode;
     
    4041namespace Inspector {
    4142
    42 class ScriptDebugServer;
    4343typedef JSC::JSValue (*InspectorFunctionCallHandler)(JSC::JSGlobalObject* globalObject, JSC::JSValue functionObject, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args, NakedPtr<JSC::Exception>& returnedException);
    4444typedef JSC::JSValue (*InspectorEvaluateHandler)(JSC::JSGlobalObject*, const JSC::SourceCode&, JSC::JSValue thisValue, NakedPtr<JSC::Exception>& returnedException);
     
    5353    virtual void frontendInitialized() = 0;
    5454    virtual WTF::Stopwatch& executionStopwatch() const = 0;
    55     virtual ScriptDebugServer& scriptDebugServer() = 0;
     55    virtual JSC::Debugger& scriptDebugServer() = 0;
    5656    virtual JSC::VM& vm() = 0;
    5757};
  • trunk/Source/JavaScriptCore/inspector/JSGlobalObjectScriptDebugServer.cpp

    r261755 r266074  
    3636
    3737JSGlobalObjectScriptDebugServer::JSGlobalObjectScriptDebugServer(JSGlobalObject& globalObject)
    38     : ScriptDebugServer(globalObject.vm())
     38    : Debugger(globalObject.vm())
    3939    , m_globalObject(globalObject)
    4040{
     
    4343void JSGlobalObjectScriptDebugServer::attachDebugger()
    4444{
     45    JSC::Debugger::attachDebugger();
     46
    4547    attach(&m_globalObject);
    4648}
     
    4850void JSGlobalObjectScriptDebugServer::detachDebugger(bool isBeingDestroyed)
    4951{
     52    JSC::Debugger::detachDebugger(isBeingDestroyed);
     53
    5054    detach(&m_globalObject, isBeingDestroyed ? Debugger::GlobalObjectIsDestructing : Debugger::TerminatingDebuggingSession);
    5155    if (!isBeingDestroyed)
     
    5559void JSGlobalObjectScriptDebugServer::runEventLoopWhilePaused()
    5660{
     61    JSC::Debugger::runEventLoopWhilePaused();
     62
    5763    // Drop all locks so another thread can work in the VM while we are nested.
    5864    JSC::JSLock::DropAllLocks dropAllLocks(&m_globalObject.vm());
    5965
    60     while (!m_doneProcessingDebuggerEvents) {
     66    while (!doneProcessingDebuggerEvents()) {
    6167        if (RunLoop::cycle(JSGlobalObjectScriptDebugServer::runLoopMode()) == RunLoop::CycleResult::Stop)
    6268            break;
  • trunk/Source/JavaScriptCore/inspector/JSGlobalObjectScriptDebugServer.h

    r261569 r266074  
    2626#pragma once
    2727
    28 #include "ScriptDebugServer.h"
     28#include "Debugger.h"
    2929#include <wtf/RunLoop.h>
    3030
    3131namespace Inspector {
    3232
    33 class JSGlobalObjectScriptDebugServer final : public ScriptDebugServer {
     33class JSGlobalObjectScriptDebugServer final : public JSC::Debugger {
    3434    WTF_MAKE_NONCOPYABLE(JSGlobalObjectScriptDebugServer);
    3535    WTF_MAKE_FAST_ALLOCATED;
     
    4343
    4444private:
     45    // JSC::Debugger
    4546    void attachDebugger() final;
    4647    void detachDebugger(bool isBeingDestroyed) final;
    47 
    48     void didPause(JSC::JSGlobalObject*) final { }
    49     void didContinue(JSC::JSGlobalObject*) final { }
    5048    void runEventLoopWhilePaused() final;
    51     bool isContentScript(JSC::JSGlobalObject*) const final { return false; }
    52 
    53     // NOTE: Currently all exceptions are reported at the API boundary through reportAPIException.
    54     // Until a time comes where an exception can be caused outside of the API (e.g. setTimeout
    55     // or some other async operation in a pure JSContext) we can ignore exceptions reported here.
    56     void reportException(JSC::JSGlobalObject*, JSC::Exception*) const final { }
    5749
    5850    JSC::JSGlobalObject& m_globalObject;
  • trunk/Source/JavaScriptCore/inspector/agents/InspectorAuditAgent.cpp

    r261755 r266074  
    2727#include "InspectorAuditAgent.h"
    2828
     29#include "Debugger.h"
    2930#include "InjectedScript.h"
    3031#include "JSLock.h"
    3132#include "ObjectConstructor.h"
    32 #include "ScriptDebugServer.h"
    3333#include <wtf/RefPtr.h>
    3434#include <wtf/Vector.h>
     
    106106    Optional<int> savedResultIndex;
    107107
    108     ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = m_scriptDebugServer.pauseOnExceptionsState();
     108    auto previousPauseOnExceptionsState = m_scriptDebugServer.pauseOnExceptionsState();
    109109
    110     m_scriptDebugServer.setPauseOnExceptionsState(ScriptDebugServer::DontPauseOnExceptions);
     110    m_scriptDebugServer.setPauseOnExceptionsState(Debugger::DontPauseOnExceptions);
    111111    muteConsole();
    112112
  • trunk/Source/JavaScriptCore/inspector/agents/InspectorAuditAgent.h

    r251425 r266074  
    3333#include <wtf/Noncopyable.h>
    3434
     35namespace JSC {
     36class Debugger;
     37}
     38
    3539namespace Inspector {
    3640
    3741class InjectedScript;
    3842class InjectedScriptManager;
    39 class ScriptDebugServer;
    4043typedef String ErrorString;
    4144
     
    7275    RefPtr<AuditBackendDispatcher> m_backendDispatcher;
    7376    InjectedScriptManager& m_injectedScriptManager;
    74     ScriptDebugServer& m_scriptDebugServer;
     77    JSC::Debugger& m_scriptDebugServer;
    7578
    7679    JSC::Strong<JSC::JSObject> m_injectedWebInspectorAuditValue;
  • trunk/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp

    r262786 r266074  
    3333#include "AsyncStackTrace.h"
    3434#include "ContentSearchUtilities.h"
     35#include "Debugger.h"
     36#include "DebuggerScope.h"
    3537#include "InjectedScript.h"
    3638#include "InjectedScriptManager.h"
     39#include "JSJavaScriptCallFrame.h"
     40#include "JavaScriptCallFrame.h"
    3741#include "RegularExpression.h"
    3842#include "ScriptCallStack.h"
    3943#include "ScriptCallStackFactory.h"
    40 #include "ScriptDebugServer.h"
     44#include <wtf/Function.h>
    4145#include <wtf/JSONValues.h>
    4246#include <wtf/Stopwatch.h>
     
    5155// have several object groups, and objects from several backend breakpoint action instances may
    5256// create objects in the same group.
    53 static String objectGroupForBreakpointAction(const ScriptBreakpointAction& action)
    54 {
    55     return makeString("breakpoint-action-", action.identifier);
     57static String objectGroupForBreakpointAction(JSC::BreakpointActionID id)
     58{
     59    return makeString("breakpoint-action-", id);
    5660}
    5761
     
    5963{
    6064    return sourceURL.startsWith("__InjectedScript_") && sourceURL.endsWith(".js");
     65}
     66
     67static Optional<JSC::Breakpoint::Action::Type> breakpointActionTypeForString(ErrorString& errorString, const String& typeString)
     68{
     69    auto type = Inspector::Protocol::InspectorHelpers::parseEnumValueFromString<Inspector::Protocol::Debugger::BreakpointAction::Type>(typeString);
     70    if (!type) {
     71        errorString = makeString("Unknown breakpoint action type: "_s, typeString);
     72        return WTF::nullopt;
     73    }
     74
     75    switch (*type) {
     76    case Inspector::Protocol::Debugger::BreakpointAction::Type::Log:
     77        return JSC::Breakpoint::Action::Type::Log;
     78
     79    case Inspector::Protocol::Debugger::BreakpointAction::Type::Evaluate:
     80        return JSC::Breakpoint::Action::Type::Evaluate;
     81
     82    case Inspector::Protocol::Debugger::BreakpointAction::Type::Sound:
     83        return JSC::Breakpoint::Action::Type::Sound;
     84
     85    case Inspector::Protocol::Debugger::BreakpointAction::Type::Probe:
     86        return JSC::Breakpoint::Action::Type::Probe;
     87    }
     88
     89    ASSERT_NOT_REACHED();
     90    return WTF::nullopt;
     91}
     92
     93template <typename T>
     94static T parseBreakpointOptions(ErrorString& errorString, const JSON::Object* optionsPayload, Function<T(const String&, JSC::Breakpoint::ActionsVector&&, bool, size_t)> callback)
     95{
     96    String condition;
     97    JSC::Breakpoint::ActionsVector actions;
     98    bool autoContinue = false;
     99    size_t ignoreCount = 0;
     100
     101    if (optionsPayload) {
     102        optionsPayload->getString("condition"_s, condition);
     103
     104        RefPtr<JSON::Array> actionsPayload;
     105        optionsPayload->getArray("actions"_s, actionsPayload);
     106        if (auto count = actionsPayload ? actionsPayload->length() : 0) {
     107            actions.reserveCapacity(count);
     108
     109            for (unsigned i = 0; i < count; ++i) {
     110                RefPtr<JSON::Object> actionObject;
     111                if (!actionsPayload->get(i)->asObject(actionObject)) {
     112                    errorString = "Unexpected non-object item in given actions"_s;
     113                    return { };
     114                }
     115
     116                String actionTypeString;
     117                if (!actionObject->getString("type"_s, actionTypeString)) {
     118                    errorString = "Missing type for item in given actions"_s;
     119                    return { };
     120                }
     121
     122                auto actionType = breakpointActionTypeForString(errorString, actionTypeString);
     123                if (!actionType)
     124                    return { };
     125
     126                JSC::Breakpoint::Action action(*actionType);
     127
     128                actionObject->getString("data"_s, action.data);
     129
     130                // Specifying an identifier is optional. They are used to correlate probe samples
     131                // in the frontend across multiple backend probe actions and segregate object groups.
     132                actionObject->getInteger("id"_s, action.id);
     133
     134                actions.append(WTFMove(action));
     135            }
     136        }
     137
     138        optionsPayload->getBoolean("autoContinue"_s, autoContinue);
     139        optionsPayload->getInteger("ignoreCount"_s, ignoreCount);
     140    }
     141
     142    return callback(condition, WTFMove(actions), autoContinue, ignoreCount);
     143}
     144
     145Optional<InspectorDebuggerAgent::ProtocolBreakpoint> InspectorDebuggerAgent::ProtocolBreakpoint::fromPayload(ErrorString& errorString, JSC::SourceID sourceID, unsigned lineNumber, unsigned columnNumber, const JSON::Object* optionsPayload)
     146{
     147    return parseBreakpointOptions<Optional<ProtocolBreakpoint>>(errorString, optionsPayload, [&] (const String& condition, JSC::Breakpoint::ActionsVector&& actions, bool autoContinue, size_t ignoreCount) -> Optional<ProtocolBreakpoint> {
     148        return ProtocolBreakpoint(sourceID, lineNumber, columnNumber, condition, WTFMove(actions), autoContinue, ignoreCount);
     149    });
     150}
     151
     152Optional<InspectorDebuggerAgent::ProtocolBreakpoint> InspectorDebuggerAgent::ProtocolBreakpoint::fromPayload(ErrorString& errorString, const String& url, bool isRegex, unsigned lineNumber, unsigned columnNumber, const JSON::Object* optionsPayload)
     153{
     154    return parseBreakpointOptions<Optional<ProtocolBreakpoint>>(errorString, optionsPayload, [&] (const String& condition, JSC::Breakpoint::ActionsVector&& actions, bool autoContinue, size_t ignoreCount) -> Optional<ProtocolBreakpoint> {
     155        return ProtocolBreakpoint(url, isRegex, lineNumber, columnNumber, condition, WTFMove(actions), autoContinue, ignoreCount);
     156    });
     157}
     158
     159InspectorDebuggerAgent::ProtocolBreakpoint::ProtocolBreakpoint() = default;
     160
     161InspectorDebuggerAgent::ProtocolBreakpoint::ProtocolBreakpoint(JSC::SourceID sourceID, unsigned lineNumber, unsigned columnNumber, const String& condition, JSC::Breakpoint::ActionsVector&& actions, bool autoContinue, size_t ignoreCount)
     162    : m_id(makeString(sourceID, ':', lineNumber, ':', columnNumber))
     163#if ASSERT_ENABLED
     164    , m_sourceID(sourceID)
     165#endif
     166    , m_lineNumber(lineNumber)
     167    , m_columnNumber(columnNumber)
     168    , m_condition(condition)
     169    , m_actions(WTFMove(actions))
     170    , m_autoContinue(autoContinue)
     171    , m_ignoreCount(ignoreCount)
     172{
     173}
     174
     175InspectorDebuggerAgent::ProtocolBreakpoint::ProtocolBreakpoint(const String& url, bool isRegex, unsigned lineNumber, unsigned columnNumber, const String& condition, JSC::Breakpoint::ActionsVector&& actions, bool autoContinue, size_t ignoreCount)
     176    : m_id(makeString(isRegex ? "/" : "", url, isRegex ? "/" : "", ':', lineNumber, ':', columnNumber))
     177    , m_url(url)
     178    , m_isRegex(isRegex)
     179    , m_lineNumber(lineNumber)
     180    , m_columnNumber(columnNumber)
     181    , m_condition(condition)
     182    , m_actions(WTFMove(actions))
     183    , m_autoContinue(autoContinue)
     184    , m_ignoreCount(ignoreCount)
     185{
     186}
     187
     188Ref<JSC::Breakpoint> InspectorDebuggerAgent::ProtocolBreakpoint::createDebuggerBreakpoint(JSC::BreakpointID debuggerBreakpointID, JSC::SourceID sourceID) const
     189{
     190    ASSERT(debuggerBreakpointID != JSC::noBreakpointID);
     191    ASSERT(sourceID != JSC::noSourceID);
     192    ASSERT(sourceID == m_sourceID || m_sourceID == JSC::noSourceID);
     193
     194    auto debuggerBreakpoint = JSC::Breakpoint::create(debuggerBreakpointID, m_condition, copyToVector(m_actions), m_autoContinue, m_ignoreCount);
     195    debuggerBreakpoint->link(sourceID, m_lineNumber, m_columnNumber);
     196    return debuggerBreakpoint;
     197}
     198
     199bool InspectorDebuggerAgent::ProtocolBreakpoint::matchesScriptURL(const String& scriptURL) const
     200{
     201    ASSERT(m_sourceID == JSC::noSourceID);
     202
     203    if (m_isRegex) {
     204        JSC::Yarr::RegularExpression regex(m_url);
     205        return regex.match(scriptURL) != -1;
     206    }
     207    return m_url == scriptURL;
     208}
     209
     210RefPtr<JSC::Breakpoint> InspectorDebuggerAgent::debuggerBreakpointFromPayload(ErrorString& errorString, const JSON::Object* optionsPayload)
     211{
     212    return parseBreakpointOptions<RefPtr<JSC::Breakpoint>>(errorString, optionsPayload, [] (const String& condition, JSC::Breakpoint::ActionsVector&& actions, bool autoContinue, size_t ignoreCount) {
     213        return JSC::Breakpoint::create(JSC::noBreakpointID, condition, WTFMove(actions), autoContinue, ignoreCount);
     214    });
    61215}
    62216
     
    88242    m_enabled = true;
    89243
    90     m_scriptDebugServer.addListener(this);
     244    m_scriptDebugServer.addObserver(*this);
    91245
    92246    for (auto* listener : copyToVector(m_listeners))
     
    109263        listener->debuggerWasDisabled();
    110264
    111     m_scriptDebugServer.removeListener(this, isBeingDestroyed);
     265    m_scriptDebugServer.removeObserver(*this, isBeingDestroyed);
    112266
    113267    clearInspectorBreakpointState();
     
    115269    if (!isBeingDestroyed)
    116270        m_scriptDebugServer.deactivateBreakpoints();
    117 
    118     ASSERT(m_javaScriptBreakpoints.isEmpty());
    119271
    120272    clearAsyncStackTraceData();
     
    207359}
    208360
    209 RefPtr<JSON::Object> InspectorDebuggerAgent::buildBreakpointPauseReason(JSC::BreakpointID debuggerBreakpointIdentifier)
    210 {
    211     ASSERT(debuggerBreakpointIdentifier != JSC::noBreakpointID);
    212     auto it = m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier.find(debuggerBreakpointIdentifier);
    213     if (it == m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier.end())
    214         return nullptr;
    215 
    216     auto reason = Protocol::Debugger::BreakpointPauseReason::create()
    217         .setBreakpointId(it->value)
    218         .release();
    219     return reason->openAccessors();
     361RefPtr<JSON::Object> InspectorDebuggerAgent::buildBreakpointPauseReason(JSC::BreakpointID debuggerBreakpointID)
     362{
     363    ASSERT(debuggerBreakpointID != JSC::noBreakpointID);
     364
     365    for (auto& [protocolBreakpointID, debuggerBreakpoints] : m_debuggerBreakpointsForProtocolBreakpointID) {
     366        for (auto& debuggerBreakpoint : debuggerBreakpoints) {
     367            if (debuggerBreakpoint->id() == debuggerBreakpointID) {
     368                auto reason = Protocol::Debugger::BreakpointPauseReason::create()
     369                    .setBreakpointId(protocolBreakpointID)
     370                    .release();
     371                return reason->openAccessors();
     372            }
     373        }
     374    }
     375
     376    return nullptr;
    220377}
    221378
     
    235392void InspectorDebuggerAgent::handleConsoleAssert(const String& message)
    236393{
    237     if (!m_scriptDebugServer.breakpointsActive())
     394    if (!breakpointsActive())
    238395        return;
    239396
     
    252409        return;
    253410
    254     if (!m_scriptDebugServer.breakpointsActive())
     411    if (!breakpointsActive())
    255412        return;
    256413
     
    334491}
    335492
    336 static Ref<JSON::Object> buildObjectForBreakpointCookie(const String& url, int lineNumber, int columnNumber, const String& condition, RefPtr<JSON::Array>& actions, bool isRegex, bool autoContinue, unsigned ignoreCount)
    337 {
    338     Ref<JSON::Object> breakpointObject = JSON::Object::create();
    339     breakpointObject->setString("url"_s, url);
    340     breakpointObject->setInteger("lineNumber"_s, lineNumber);
    341     breakpointObject->setInteger("columnNumber"_s, columnNumber);
    342     breakpointObject->setString("condition"_s, condition);
    343     breakpointObject->setBoolean("isRegex"_s, isRegex);
    344     breakpointObject->setBoolean("autoContinue"_s, autoContinue);
    345     breakpointObject->setInteger("ignoreCount"_s, ignoreCount);
    346 
    347     if (actions)
    348         breakpointObject->setArray("actions"_s, actions);
    349 
    350     return breakpointObject;
    351 }
    352 
    353 static bool matches(const String& url, const String& pattern, bool isRegex)
    354 {
    355     if (isRegex) {
    356         JSC::Yarr::RegularExpression regex(pattern);
    357         return regex.match(url) != -1;
    358     }
    359     return url == pattern;
    360 }
    361 
    362 static bool breakpointActionTypeForString(const String& typeString, ScriptBreakpointActionType* output)
    363 {
    364     if (typeString == Protocol::InspectorHelpers::getEnumConstantValue(Protocol::Debugger::BreakpointAction::Type::Log)) {
    365         *output = ScriptBreakpointActionTypeLog;
    366         return true;
    367     }
    368     if (typeString == Protocol::InspectorHelpers::getEnumConstantValue(Protocol::Debugger::BreakpointAction::Type::Evaluate)) {
    369         *output = ScriptBreakpointActionTypeEvaluate;
    370         return true;
    371     }
    372     if (typeString == Protocol::InspectorHelpers::getEnumConstantValue(Protocol::Debugger::BreakpointAction::Type::Sound)) {
    373         *output = ScriptBreakpointActionTypeSound;
    374         return true;
    375     }
    376     if (typeString == Protocol::InspectorHelpers::getEnumConstantValue(Protocol::Debugger::BreakpointAction::Type::Probe)) {
    377         *output = ScriptBreakpointActionTypeProbe;
    378         return true;
    379     }
    380 
    381     return false;
    382 }
    383 
    384 bool InspectorDebuggerAgent::breakpointActionsFromProtocol(ErrorString& errorString, RefPtr<JSON::Array>& actions, BreakpointActions* result)
    385 {
    386     if (!actions)
    387         return true;
    388 
    389     unsigned actionsLength = actions->length();
    390     if (!actionsLength)
    391         return true;
    392 
    393     result->reserveCapacity(actionsLength);
    394     for (unsigned i = 0; i < actionsLength; ++i) {
    395         RefPtr<JSON::Value> value = actions->get(i);
    396         RefPtr<JSON::Object> object;
    397         if (!value->asObject(object)) {
    398             errorString = "Unexpected non-object item in given actions"_s;
    399             return false;
    400         }
    401 
    402         String typeString;
    403         if (!object->getString("type"_s, typeString)) {
    404             errorString = "Missing type for item in given actions"_s;
    405             return false;
    406         }
    407 
    408         ScriptBreakpointActionType type;
    409         if (!breakpointActionTypeForString(typeString, &type)) {
    410             errorString = "Non-string type for item in given actions"_s;
    411             return false;
    412         }
    413 
    414         // Specifying an identifier is optional. They are used to correlate probe samples
    415         // in the frontend across multiple backend probe actions and segregate object groups.
    416         int identifier = 0;
    417         object->getInteger("id"_s, identifier);
    418 
    419         String data;
    420         object->getString("data"_s, data);
    421 
    422         result->append(ScriptBreakpointAction(type, identifier, data));
    423     }
    424 
    425     return true;
    426 }
    427 
    428 static RefPtr<Protocol::Debugger::Location> buildDebuggerLocation(const JSC::Breakpoint& breakpoint)
    429 {
    430     ASSERT(breakpoint.resolved);
     493static RefPtr<Protocol::Debugger::Location> buildDebuggerLocation(const JSC::Breakpoint& debuggerBreakpoint)
     494{
     495    ASSERT(debuggerBreakpoint.isResolved());
    431496
    432497    auto location = Protocol::Debugger::Location::create()
    433         .setScriptId(String::number(breakpoint.sourceID))
    434         .setLineNumber(breakpoint.line)
     498        .setScriptId(String::number(debuggerBreakpoint.sourceID()))
     499        .setLineNumber(debuggerBreakpoint.lineNumber())
    435500        .release();
    436     location->setColumnNumber(breakpoint.column);
     501    location->setColumnNumber(debuggerBreakpoint.columnNumber());
    437502
    438503    return location;
     
    460525}
    461526
    462 void InspectorDebuggerAgent::setBreakpointByUrl(ErrorString& errorString, int lineNumber, const String* optionalURL, const String* optionalURLRegex, const int* optionalColumnNumber, const JSON::Object* options, Protocol::Debugger::BreakpointId* outBreakpointIdentifier, RefPtr<JSON::ArrayOf<Protocol::Debugger::Location>>& locations)
    463 {
    464     locations = JSON::ArrayOf<Protocol::Debugger::Location>::create();
     527void InspectorDebuggerAgent::setBreakpointByUrl(ErrorString& errorString, int lineNumber, const String* optionalURL, const String* optionalURLRegex, const int* optionalColumnNumber, const JSON::Object* optionsPayload, Protocol::Debugger::BreakpointId* outBreakpointId, RefPtr<JSON::ArrayOf<Protocol::Debugger::Location>>& outLocations)
     528{
    465529    if (!optionalURL == !optionalURLRegex) {
    466530        errorString = "Either url or urlRegex must be specified"_s;
     
    468532    }
    469533
    470     String url = optionalURL ? *optionalURL : *optionalURLRegex;
    471     int columnNumber = optionalColumnNumber ? *optionalColumnNumber : 0;
    472     bool isRegex = optionalURLRegex;
    473 
    474     String breakpointIdentifier = makeString(isRegex ? "/" : "", url, isRegex ? "/:" : ":", lineNumber, ':', columnNumber);
    475     if (m_javaScriptBreakpoints.contains(breakpointIdentifier)) {
     534    auto protocolBreakpoint = ProtocolBreakpoint::fromPayload(errorString, optionalURL ? *optionalURL : *optionalURLRegex, !!optionalURLRegex, lineNumber, optionalColumnNumber ? *optionalColumnNumber : 0, optionsPayload);
     535    if (!protocolBreakpoint)
     536        return;
     537
     538    if (m_protocolBreakpointForProtocolBreakpointID.contains(protocolBreakpoint->id())) {
    476539        errorString = "Breakpoint for given location already exists."_s;
    477540        return;
    478541    }
    479542
    480     String condition = emptyString();
    481     bool autoContinue = false;
    482     unsigned ignoreCount = 0;
    483     RefPtr<JSON::Array> actions;
    484     if (options) {
    485         options->getString("condition"_s, condition);
    486         options->getBoolean("autoContinue"_s, autoContinue);
    487         options->getArray("actions"_s, actions);
    488         options->getInteger("ignoreCount"_s, ignoreCount);
    489     }
    490 
    491     BreakpointActions breakpointActions;
    492     if (!breakpointActionsFromProtocol(errorString, actions, &breakpointActions))
    493         return;
    494 
    495     m_javaScriptBreakpoints.set(breakpointIdentifier, buildObjectForBreakpointCookie(url, lineNumber, columnNumber, condition, actions, isRegex, autoContinue, ignoreCount));
    496 
    497     for (auto& entry : m_scripts) {
    498         Script& script = entry.value;
     543    m_protocolBreakpointForProtocolBreakpointID.set(protocolBreakpoint->id(), *protocolBreakpoint);
     544
     545    outLocations = JSON::ArrayOf<Protocol::Debugger::Location>::create();
     546
     547    for (auto& [sourceID, script] : m_scripts) {
    499548        String scriptURLForBreakpoints = !script.sourceURL.isEmpty() ? script.sourceURL : script.url;
    500         if (!matches(scriptURLForBreakpoints, url, isRegex))
     549        if (!protocolBreakpoint->matchesScriptURL(scriptURLForBreakpoints))
    501550            continue;
    502551
    503         JSC::SourceID sourceID = entry.key;
    504         JSC::Breakpoint breakpoint(sourceID, lineNumber, columnNumber, condition, autoContinue, ignoreCount);
    505         resolveBreakpoint(script, breakpoint);
    506         if (!breakpoint.resolved)
     552        auto debuggerBreakpoint = protocolBreakpoint->createDebuggerBreakpoint(m_nextDebuggerBreakpointID++, sourceID);
     553
     554        if (!resolveBreakpoint(script, debuggerBreakpoint))
    507555            continue;
    508556
    509         bool existing;
    510         setBreakpoint(breakpoint, existing);
    511         if (existing)
     557        if (!setBreakpoint(debuggerBreakpoint))
    512558            continue;
    513559
    514         ScriptBreakpoint scriptBreakpoint(breakpoint.line, breakpoint.column, condition, breakpointActions, autoContinue, ignoreCount);
    515         didSetBreakpoint(breakpoint, breakpointIdentifier, scriptBreakpoint);
    516 
    517         locations->addItem(buildDebuggerLocation(breakpoint));
    518     }
    519 
    520     *outBreakpointIdentifier = breakpointIdentifier;
    521 }
    522 
    523 void InspectorDebuggerAgent::setBreakpoint(ErrorString& errorString, const JSON::Object& location, const JSON::Object* options, Protocol::Debugger::BreakpointId* outBreakpointIdentifier, RefPtr<Protocol::Debugger::Location>& actualLocation)
     560        didSetBreakpoint(*protocolBreakpoint, debuggerBreakpoint);
     561
     562        outLocations->addItem(buildDebuggerLocation(debuggerBreakpoint));
     563    }
     564
     565    *outBreakpointId = protocolBreakpoint->id();
     566}
     567
     568void InspectorDebuggerAgent::setBreakpoint(ErrorString& errorString, const JSON::Object& location, const JSON::Object* optionsPayload, Protocol::Debugger::BreakpointId* outBreakpointId, RefPtr<Protocol::Debugger::Location>& outActualLocation)
    524569{
    525570    JSC::SourceID sourceID;
     
    529574        return;
    530575
    531     String condition = emptyString();
    532     bool autoContinue = false;
    533     unsigned ignoreCount = 0;
    534     RefPtr<JSON::Array> actions;
    535     if (options) {
    536         options->getString("condition"_s, condition);
    537         options->getBoolean("autoContinue"_s, autoContinue);
    538         options->getArray("actions"_s, actions);
    539         options->getInteger("ignoreCount"_s, ignoreCount);
    540     }
    541 
    542     BreakpointActions breakpointActions;
    543     if (!breakpointActionsFromProtocol(errorString, actions, &breakpointActions))
    544         return;
    545 
    546576    auto scriptIterator = m_scripts.find(sourceID);
    547577    if (scriptIterator == m_scripts.end()) {
     
    550580    }
    551581
    552     Script& script = scriptIterator->value;
    553     JSC::Breakpoint breakpoint(sourceID, lineNumber, columnNumber, condition, autoContinue, ignoreCount);
    554     resolveBreakpoint(script, breakpoint);
    555     if (!breakpoint.resolved) {
     582    auto protocolBreakpoint = ProtocolBreakpoint::fromPayload(errorString, sourceID, lineNumber, columnNumber, optionsPayload);
     583    if (!protocolBreakpoint)
     584        return;
     585
     586    // Don't save `protocolBreakpoint` in `m_protocolBreakpointForProtocolBreakpointID` because it
     587    // was set specifically for the given `sourceID`, which is unique, meaning that it will never
     588    // be used inside `InspectorDebuggerAgent::didParseSource`.
     589
     590    auto debuggerBreakpoint = protocolBreakpoint->createDebuggerBreakpoint(m_nextDebuggerBreakpointID++, sourceID);
     591
     592    if (!resolveBreakpoint(scriptIterator->value, debuggerBreakpoint)) {
    556593        errorString = "Could not resolve breakpoint"_s;
    557594        return;
    558595    }
    559596
    560     bool existing;
    561     setBreakpoint(breakpoint, existing);
    562     if (existing) {
     597    if (!setBreakpoint(debuggerBreakpoint)) {
    563598        errorString = "Breakpoint for given location already exists"_s;
    564599        return;
    565600    }
    566601
    567     String breakpointIdentifier = makeString(sourceID, ':', breakpoint.line, ':', breakpoint.column);
    568     ScriptBreakpoint scriptBreakpoint(breakpoint.line, breakpoint.column, condition, breakpointActions, autoContinue, ignoreCount);
    569     didSetBreakpoint(breakpoint, breakpointIdentifier, scriptBreakpoint);
    570 
    571     actualLocation = buildDebuggerLocation(breakpoint);
    572     *outBreakpointIdentifier = breakpointIdentifier;
    573 }
    574 
    575 void InspectorDebuggerAgent::didSetBreakpoint(const JSC::Breakpoint& breakpoint, const String& breakpointIdentifier, const ScriptBreakpoint& scriptBreakpoint)
    576 {
    577     JSC::BreakpointID id = breakpoint.id;
    578     m_scriptDebugServer.setBreakpointActions(id, scriptBreakpoint);
    579 
    580     auto debugServerBreakpointIDsIterator = m_breakpointIdentifierToDebugServerBreakpointIDs.find(breakpointIdentifier);
    581     if (debugServerBreakpointIDsIterator == m_breakpointIdentifierToDebugServerBreakpointIDs.end())
    582         debugServerBreakpointIDsIterator = m_breakpointIdentifierToDebugServerBreakpointIDs.set(breakpointIdentifier, Vector<JSC::BreakpointID>()).iterator;
    583     debugServerBreakpointIDsIterator->value.append(id);
    584 
    585     m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier.set(id, breakpointIdentifier);
    586 }
    587 
    588 void InspectorDebuggerAgent::resolveBreakpoint(const Script& script, JSC::Breakpoint& breakpoint)
    589 {
    590     if (breakpoint.line < static_cast<unsigned>(script.startLine) || static_cast<unsigned>(script.endLine) < breakpoint.line)
    591         return;
    592 
    593     m_scriptDebugServer.resolveBreakpoint(breakpoint, script.sourceProvider.get());
    594 }
    595 
    596 void InspectorDebuggerAgent::setBreakpoint(JSC::Breakpoint& breakpoint, bool& existing)
     602    didSetBreakpoint(*protocolBreakpoint, debuggerBreakpoint);
     603
     604    outActualLocation = buildDebuggerLocation(debuggerBreakpoint);
     605    *outBreakpointId = protocolBreakpoint->id();
     606}
     607
     608void InspectorDebuggerAgent::didSetBreakpoint(ProtocolBreakpoint& protocolBreakpoint, JSC::Breakpoint& debuggerBreakpoint)
     609{
     610    auto& debuggerBreakpoints = m_debuggerBreakpointsForProtocolBreakpointID.ensure(protocolBreakpoint.id(), [] {
     611        return JSC::BreakpointsVector();
     612    }).iterator->value;
     613
     614    debuggerBreakpoints.append(debuggerBreakpoint);
     615}
     616
     617bool InspectorDebuggerAgent::resolveBreakpoint(const JSC::Debugger::Script& script, JSC::Breakpoint& debuggerBreakpoint)
     618{
     619    if (debuggerBreakpoint.lineNumber() < static_cast<unsigned>(script.startLine) || static_cast<unsigned>(script.endLine) < debuggerBreakpoint.lineNumber())
     620        return false;
     621
     622    return m_scriptDebugServer.resolveBreakpoint(debuggerBreakpoint, script.sourceProvider.get());
     623}
     624
     625bool InspectorDebuggerAgent::setBreakpoint(JSC::Breakpoint& debuggerBreakpoint)
    597626{
    598627    JSC::JSLockHolder locker(m_scriptDebugServer.vm());
    599     m_scriptDebugServer.setBreakpoint(breakpoint, existing);
    600 }
    601 
    602 void InspectorDebuggerAgent::removeBreakpoint(ErrorString&, const String& breakpointIdentifier)
    603 {
    604     m_javaScriptBreakpoints.remove(breakpointIdentifier);
    605 
    606     for (JSC::BreakpointID breakpointID : m_breakpointIdentifierToDebugServerBreakpointIDs.take(breakpointIdentifier)) {
    607         m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier.remove(breakpointID);
    608 
    609         const BreakpointActions& breakpointActions = m_scriptDebugServer.getActionsForBreakpoint(breakpointID);
    610         for (auto& action : breakpointActions)
    611             m_injectedScriptManager.releaseObjectGroup(objectGroupForBreakpointAction(action));
     628    return m_scriptDebugServer.setBreakpoint(debuggerBreakpoint);
     629}
     630
     631void InspectorDebuggerAgent::removeBreakpoint(ErrorString&, const Inspector::Protocol::Debugger::BreakpointId& protocolBreakpointID)
     632{
     633    m_protocolBreakpointForProtocolBreakpointID.remove(protocolBreakpointID);
     634
     635    for (auto& debuggerBreakpoint : m_debuggerBreakpointsForProtocolBreakpointID.take(protocolBreakpointID)) {
     636        for (const auto& action : debuggerBreakpoint->actions())
     637            m_injectedScriptManager.releaseObjectGroup(objectGroupForBreakpointAction(action.id));
    612638
    613639        JSC::JSLockHolder locker(m_scriptDebugServer.vm());
    614         m_scriptDebugServer.removeBreakpointActions(breakpointID);
    615         m_scriptDebugServer.removeBreakpoint(breakpointID);
     640        m_scriptDebugServer.removeBreakpoint(debuggerBreakpoint);
    616641    }
    617642}
     
    634659        return;
    635660
    636     if (m_continueToLocationBreakpointID != JSC::noBreakpointID) {
    637         m_scriptDebugServer.removeBreakpoint(m_continueToLocationBreakpointID);
    638         m_continueToLocationBreakpointID = JSC::noBreakpointID;
     661    if (m_continueToLocationDebuggerBreakpoint) {
     662        m_scriptDebugServer.removeBreakpoint(*m_continueToLocationDebuggerBreakpoint);
     663        m_continueToLocationDebuggerBreakpoint = nullptr;
    639664    }
    640665
     
    653678    }
    654679
    655     String condition;
    656     bool autoContinue = false;
    657     unsigned ignoreCount = 0;
    658     JSC::Breakpoint breakpoint(sourceID, lineNumber, columnNumber, condition, autoContinue, ignoreCount);
    659     Script& script = scriptIterator->value;
    660     resolveBreakpoint(script, breakpoint);
    661     if (!breakpoint.resolved) {
     680    auto protocolBreakpoint = ProtocolBreakpoint::fromPayload(errorString, sourceID, lineNumber, columnNumber);
     681    if (!protocolBreakpoint)
     682        return;
     683
     684    // Don't save `protocolBreakpoint` in `m_protocolBreakpointForProtocolBreakpointID` because it
     685    // is a temporary breakpoint that will be removed as soon as `location` is reached.
     686
     687    auto debuggerBreakpoint = protocolBreakpoint->createDebuggerBreakpoint(m_nextDebuggerBreakpointID++, sourceID);
     688
     689    if (!resolveBreakpoint(scriptIterator->value, debuggerBreakpoint)) {
    662690        m_scriptDebugServer.continueProgram();
    663691        m_frontendDispatcher->resumed();
     
    666694    }
    667695
    668     bool existing;
    669     setBreakpoint(breakpoint, existing);
    670     if (existing) {
     696    if (!setBreakpoint(debuggerBreakpoint)) {
    671697        // There is an existing breakpoint at this location. Instead of
    672698        // acting like a series of steps, just resume and we will either
     
    677703    }
    678704
    679     m_continueToLocationBreakpointID = breakpoint.id;
     705    m_continueToLocationDebuggerBreakpoint = WTFMove(debuggerBreakpoint);
    680706
    681707    // Treat this as a series of steps until reaching the new breakpoint.
     
    720746}
    721747
    722 void InspectorDebuggerAgent::schedulePauseOnNextStatement(DebuggerFrontendDispatcher::Reason reason, RefPtr<JSON::Object>&& data)
     748void InspectorDebuggerAgent::schedulePauseAtNextOpportunity(DebuggerFrontendDispatcher::Reason reason, RefPtr<JSON::Object>&& data)
    723749{
    724750    if (m_javaScriptPauseScheduled)
     
    730756
    731757    JSC::JSLockHolder locker(m_scriptDebugServer.vm());
    732     m_scriptDebugServer.setPauseOnNextStatement(true);
    733 }
    734 
    735 void InspectorDebuggerAgent::cancelPauseOnNextStatement()
     758    m_scriptDebugServer.schedulePauseAtNextOpportunity();
     759}
     760
     761void InspectorDebuggerAgent::cancelPauseAtNextOpportunity()
    736762{
    737763    if (!m_javaScriptPauseScheduled)
     
    741767
    742768    clearPauseDetails();
    743     m_scriptDebugServer.setPauseOnNextStatement(false);
     769    m_scriptDebugServer.cancelPauseAtNextOpportunity();
    744770    m_enablePauseWhenIdle = false;
    745771}
    746772
     773bool InspectorDebuggerAgent::schedulePauseForSpecialBreakpoint(JSC::Breakpoint& breakpoint, DebuggerFrontendDispatcher::Reason reason, RefPtr<JSON::Object>&& data)
     774{
     775    JSC::JSLockHolder locker(m_scriptDebugServer.vm());
     776
     777    if (!m_scriptDebugServer.schedulePauseForSpecialBreakpoint(breakpoint))
     778        return false;
     779
     780    updatePauseReasonAndData(reason, WTFMove(data));
     781    return true;
     782}
     783
     784bool InspectorDebuggerAgent::cancelPauseForSpecialBreakpoint(JSC::Breakpoint& breakpoint)
     785{
     786    if (!m_scriptDebugServer.cancelPauseForSpecialBreakpoint(breakpoint))
     787        return false;
     788
     789    clearPauseDetails();
     790    return true;
     791}
     792
    747793void InspectorDebuggerAgent::pause(ErrorString&)
    748794{
    749     schedulePauseOnNextStatement(DebuggerFrontendDispatcher::Reason::PauseOnNextStatement, nullptr);
     795    schedulePauseAtNextOpportunity(DebuggerFrontendDispatcher::Reason::PauseOnNextStatement);
    750796}
    751797
     
    757803    }
    758804
    759     cancelPauseOnNextStatement();
     805    cancelPauseAtNextOpportunity();
    760806    m_scriptDebugServer.continueProgram();
    761807    m_conditionToDispatchResumed = ShouldDispatchResumed::WhenContinued;
     
    823869
    824870    if (m_conditionToDispatchResumed == ShouldDispatchResumed::WhenIdle) {
    825         cancelPauseOnNextStatement();
     871        cancelPauseAtNextOpportunity();
    826872        m_scriptDebugServer.continueProgram();
    827873        m_frontendDispatcher->resumed();
     
    9591005}
    9601006
    961 String InspectorDebuggerAgent::sourceMapURLForScript(const Script& script)
     1007String InspectorDebuggerAgent::sourceMapURLForScript(const JSC::Debugger::Script& script)
    9621008{
    9631009    return script.sourceMappingURL;
     
    9791025}
    9801026
    981 void InspectorDebuggerAgent::didParseSource(JSC::SourceID sourceID, const Script& script)
     1027void InspectorDebuggerAgent::didParseSource(JSC::SourceID sourceID, const JSC::Debugger::Script& script)
    9821028{
    9831029    String scriptIDStr = String::number(sourceID);
     
    10051051        return;
    10061052
    1007     for (auto& entry : m_javaScriptBreakpoints) {
    1008         RefPtr<JSON::Object> breakpointObject = entry.value;
    1009 
    1010         bool isRegex;
    1011         String url;
    1012         breakpointObject->getBoolean("isRegex"_s, isRegex);
    1013         breakpointObject->getString("url"_s, url);
    1014         if (!matches(scriptURLForBreakpoints, url, isRegex))
     1053    for (auto& protocolBreakpoint : m_protocolBreakpointForProtocolBreakpointID.values()) {
     1054        if (!protocolBreakpoint.matchesScriptURL(scriptURLForBreakpoints))
    10151055            continue;
    10161056
    1017         ScriptBreakpoint scriptBreakpoint;
    1018         breakpointObject->getInteger("lineNumber"_s, scriptBreakpoint.lineNumber);
    1019         breakpointObject->getInteger("columnNumber"_s, scriptBreakpoint.columnNumber);
    1020         breakpointObject->getString("condition"_s, scriptBreakpoint.condition);
    1021         breakpointObject->getBoolean("autoContinue"_s, scriptBreakpoint.autoContinue);
    1022         breakpointObject->getInteger("ignoreCount"_s, scriptBreakpoint.ignoreCount);
    1023         ErrorString errorString;
    1024         RefPtr<JSON::Array> actions;
    1025         breakpointObject->getArray("actions"_s, actions);
    1026         if (!breakpointActionsFromProtocol(errorString, actions, &scriptBreakpoint.actions)) {
    1027             ASSERT_NOT_REACHED();
     1057        auto debuggerBreakpoint = protocolBreakpoint.createDebuggerBreakpoint(m_nextDebuggerBreakpointID++, sourceID);
     1058
     1059        if (!resolveBreakpoint(script, debuggerBreakpoint))
    10281060            continue;
    1029         }
    1030 
    1031         JSC::Breakpoint breakpoint(sourceID, scriptBreakpoint.lineNumber, scriptBreakpoint.columnNumber, scriptBreakpoint.condition, scriptBreakpoint.autoContinue, scriptBreakpoint.ignoreCount);
    1032         resolveBreakpoint(script, breakpoint);
    1033         if (!breakpoint.resolved)
     1061
     1062        if (!setBreakpoint(debuggerBreakpoint))
    10341063            continue;
    10351064
    1036         bool existing;
    1037         setBreakpoint(breakpoint, existing);
    1038         if (existing)
    1039             continue;
    1040 
    1041         String breakpointIdentifier = entry.key;
    1042         didSetBreakpoint(breakpoint, breakpointIdentifier, scriptBreakpoint);
    1043 
    1044         m_frontendDispatcher->breakpointResolved(breakpointIdentifier, buildDebuggerLocation(breakpoint));
     1065        didSetBreakpoint(protocolBreakpoint, debuggerBreakpoint);
     1066
     1067        m_frontendDispatcher->breakpointResolved(protocolBreakpoint.id(), buildDebuggerLocation(debuggerBreakpoint));
    10451068    }
    10461069}
     
    10531076void InspectorDebuggerAgent::willRunMicrotask()
    10541077{
    1055     if (!m_scriptDebugServer.breakpointsActive())
     1078    if (!breakpointsActive())
    10561079        return;
    10571080
    10581081    if (m_pauseOnMicrotasks)
    1059         schedulePauseOnNextStatement(DebuggerFrontendDispatcher::Reason::Microtask, nullptr);
     1082        schedulePauseAtNextOpportunity(DebuggerFrontendDispatcher::Reason::Microtask);
    10601083}
    10611084
    10621085void InspectorDebuggerAgent::didRunMicrotask()
    10631086{
    1064     if (!m_scriptDebugServer.breakpointsActive())
     1087    if (!breakpointsActive())
    10651088        return;
    10661089
    10671090    if (m_pauseOnMicrotasks)
    1068         cancelPauseOnNextStatement();
    1069 }
    1070 
    1071 void InspectorDebuggerAgent::didPause(JSC::JSGlobalObject* globalObject, JSC::JSValue callFrames, JSC::JSValue exceptionOrCaughtValue)
     1091        cancelPauseAtNextOpportunity();
     1092}
     1093
     1094void InspectorDebuggerAgent::didPause(JSC::JSGlobalObject* globalObject, JSC::DebuggerCallFrame& debuggerCallFrame, JSC::JSValue exceptionOrCaughtValue)
    10721095{
    10731096    ASSERT(!m_pausedGlobalObject);
    10741097    m_pausedGlobalObject = globalObject;
    1075     m_currentCallStack = { globalObject->vm(), callFrames };
    1076 
    1077     InjectedScript injectedScript = m_injectedScriptManager.injectedScriptFor(globalObject);
     1098
     1099    auto* debuggerGlobalObject = debuggerCallFrame.scope()->globalObject();
     1100    m_currentCallStack = { m_pausedGlobalObject->vm(), toJS(debuggerGlobalObject, debuggerGlobalObject, JavaScriptCallFrame::create(debuggerCallFrame).ptr()) };
     1101
     1102    InjectedScript injectedScript = m_injectedScriptManager.injectedScriptFor(m_pausedGlobalObject);
    10781103
    10791104    // If a high level pause pause reason is not already set, try to infer a reason from the debugger.
     
    10821107        case JSC::Debugger::PausedForBreakpoint: {
    10831108            auto debuggerBreakpointId = m_scriptDebugServer.pausingBreakpointID();
    1084             if (debuggerBreakpointId != m_continueToLocationBreakpointID)
     1109            if (!m_continueToLocationDebuggerBreakpoint || debuggerBreakpointId != m_continueToLocationDebuggerBreakpoint->id())
    10851110                updatePauseReasonAndData(DebuggerFrontendDispatcher::Reason::Breakpoint, buildBreakpointPauseReason(debuggerBreakpointId));
    10861111            break;
     
    11201145        RefPtr<JSON::Object> data;
    11211146        if (auto debuggerBreakpointId = m_scriptDebugServer.pausingBreakpointID()) {
    1122             ASSERT(debuggerBreakpointId != m_continueToLocationBreakpointID);
     1147            ASSERT(!m_continueToLocationDebuggerBreakpoint || debuggerBreakpointId != m_continueToLocationDebuggerBreakpoint->id());
    11231148            data = JSON::Object::create();
    11241149            data->setString("originalReason"_s, Protocol::InspectorHelpers::getEnumConstantValue(DebuggerFrontendDispatcher::Reason::Breakpoint));
     
    11521177    m_javaScriptPauseScheduled = false;
    11531178
    1154     if (m_continueToLocationBreakpointID != JSC::noBreakpointID) {
    1155         m_scriptDebugServer.removeBreakpoint(m_continueToLocationBreakpointID);
    1156         m_continueToLocationBreakpointID = JSC::noBreakpointID;
     1179    if (m_continueToLocationDebuggerBreakpoint) {
     1180        m_scriptDebugServer.removeBreakpoint(*m_continueToLocationDebuggerBreakpoint);
     1181        m_continueToLocationDebuggerBreakpoint = nullptr;
    11571182    }
    11581183
     
    11641189}
    11651190
    1166 void InspectorDebuggerAgent::breakpointActionSound(int breakpointActionIdentifier)
    1167 {
    1168     m_frontendDispatcher->playBreakpointActionSound(breakpointActionIdentifier);
    1169 }
    1170 
    1171 void InspectorDebuggerAgent::breakpointActionProbe(JSC::JSGlobalObject* globalObject, const ScriptBreakpointAction& action, unsigned batchId, unsigned sampleId, JSC::JSValue sample)
     1191void InspectorDebuggerAgent::breakpointActionSound(JSC::BreakpointActionID id)
     1192{
     1193    m_frontendDispatcher->playBreakpointActionSound(id);
     1194}
     1195
     1196void InspectorDebuggerAgent::breakpointActionProbe(JSC::JSGlobalObject* globalObject, JSC::BreakpointActionID actionID, unsigned batchId, unsigned sampleId, JSC::JSValue sample)
    11721197{
    11731198    InjectedScript injectedScript = m_injectedScriptManager.injectedScriptFor(globalObject);
    1174     auto payload = injectedScript.wrapObject(sample, objectGroupForBreakpointAction(action), true);
     1199    auto payload = injectedScript.wrapObject(sample, objectGroupForBreakpointAction(actionID), true);
    11751200    auto result = Protocol::Debugger::ProbeSample::create()
    1176         .setProbeId(action.identifier)
     1201        .setProbeId(actionID)
    11771202        .setBatchId(batchId)
    11781203        .setSampleId(sampleId)
     
    12101235{
    12111236    ErrorString ignored;
    1212     for (const String& identifier : copyToVector(m_breakpointIdentifierToDebugServerBreakpointIDs.keys()))
    1213         removeBreakpoint(ignored, identifier);
    1214 
    1215     m_javaScriptBreakpoints.clear();
     1237    for (auto& protocolBreakpointID : copyToVector(m_debuggerBreakpointsForProtocolBreakpointID.keys()))
     1238        removeBreakpoint(ignored, protocolBreakpointID);
     1239
     1240    m_protocolBreakpointForProtocolBreakpointID.clear();
     1241
     1242    if (m_continueToLocationDebuggerBreakpoint) {
     1243        m_scriptDebugServer.removeBreakpoint(*m_continueToLocationDebuggerBreakpoint);
     1244        m_continueToLocationDebuggerBreakpoint = nullptr;
     1245    }
    12161246
    12171247    clearDebuggerBreakpointState();
     
    12221252    {
    12231253        JSC::JSLockHolder holder(m_scriptDebugServer.vm());
    1224         m_scriptDebugServer.clearBreakpointActions();
    12251254        m_scriptDebugServer.clearBreakpoints();
    12261255        m_scriptDebugServer.clearBlackbox();
     
    12301259    m_currentCallStack = { };
    12311260    m_scripts.clear();
    1232     m_breakpointIdentifierToDebugServerBreakpointIDs.clear();
    1233     m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier.clear();
    1234     m_continueToLocationBreakpointID = JSC::noBreakpointID;
     1261    m_protocolBreakpointForProtocolBreakpointID.clear();
     1262    m_debuggerBreakpointsForProtocolBreakpointID.clear();
     1263    m_nextDebuggerBreakpointID = JSC::noBreakpointID + 1;
     1264    m_continueToLocationDebuggerBreakpoint = nullptr;
    12351265    clearPauseDetails();
    12361266    m_javaScriptPauseScheduled = false;
  • trunk/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.h

    r262786 r266074  
    3030#pragma once
    3131
     32#include "Breakpoint.h"
    3233#include "Debugger.h"
     34#include "DebuggerPrimitives.h"
    3335#include "InspectorAgentBase.h"
    3436#include "InspectorBackendDispatchers.h"
    3537#include "InspectorFrontendDispatchers.h"
    36 #include "ScriptBreakpoint.h"
    37 #include "ScriptDebugListener.h"
    3838#include <wtf/Forward.h>
    3939#include <wtf/HashMap.h>
    4040#include <wtf/HashSet.h>
    4141#include <wtf/Noncopyable.h>
     42#include <wtf/Optional.h>
     43#include <wtf/RefPtr.h>
    4244#include <wtf/Vector.h>
    4345
     
    4749class InjectedScript;
    4850class InjectedScriptManager;
    49 class ScriptDebugServer;
    5051typedef String ErrorString;
    5152
    52 class JS_EXPORT_PRIVATE InspectorDebuggerAgent : public InspectorAgentBase, public DebuggerBackendDispatcherHandler, public ScriptDebugListener {
     53class JS_EXPORT_PRIVATE InspectorDebuggerAgent : public InspectorAgentBase, public DebuggerBackendDispatcherHandler, public JSC::Debugger::Observer {
    5354    WTF_MAKE_NONCOPYABLE(InspectorDebuggerAgent);
    5455    WTF_MAKE_FAST_ALLOCATED;
    5556public:
    5657    ~InspectorDebuggerAgent() override;
     58
     59    static RefPtr<JSC::Breakpoint> debuggerBreakpointFromPayload(ErrorString&, const JSON::Object* optionsPayload);
    5760
    5861    static const char* const backtraceObjectGroup;
     
    6972    void setBreakpointsActive(ErrorString&, bool active) final;
    7073    void setBreakpointByUrl(ErrorString&, int lineNumber, const String* optionalURL, const String* optionalURLRegex, const int* optionalColumnNumber, const JSON::Object* options, Protocol::Debugger::BreakpointId*, RefPtr<JSON::ArrayOf<Protocol::Debugger::Location>>& locations) final;
    71     void setBreakpoint(ErrorString&, const JSON::Object& location, const JSON::Object* options, Protocol::Debugger::BreakpointId*, RefPtr<Protocol::Debugger::Location>& actualLocation) final;
     74    void setBreakpoint(ErrorString&, const JSON::Object& location, const JSON::Object* options, Protocol::Debugger::BreakpointId* outBreakpointId, RefPtr<Protocol::Debugger::Location>& outActualLocation) final;
    7275    void removeBreakpoint(ErrorString&, const String& breakpointIdentifier) final;
    7376    void continueUntilNextRunLoop(ErrorString&) final;
     
    9093    void setShouldBlackboxURL(ErrorString&, const String& url, bool shouldBlackbox, const bool* caseSensitive, const bool* isRegex) final;
    9194
    92     // ScriptDebugListener
    93     void didParseSource(JSC::SourceID, const Script&) final;
     95    // JSC::Debugger::Observer
     96    void didParseSource(JSC::SourceID, const JSC::Debugger::Script&) final;
    9497    void failedToParseSource(const String& url, const String& data, int firstLine, int errorLine, const String& errorMessage) final;
    9598    void willRunMicrotask() final;
    9699    void didRunMicrotask() final;
    97     void didPause(JSC::JSGlobalObject*, JSC::JSValue callFrames, JSC::JSValue exceptionOrCaughtValue) final;
     100    void didPause(JSC::JSGlobalObject*, JSC::DebuggerCallFrame&, JSC::JSValue exceptionOrCaughtValue) final;
    98101    void didContinue() final;
    99     void breakpointActionSound(int breakpointActionIdentifier) final;
    100     void breakpointActionProbe(JSC::JSGlobalObject*, const ScriptBreakpointAction&, unsigned batchId, unsigned sampleId, JSC::JSValue sample) final;
     102    void breakpointActionSound(JSC::BreakpointActionID) final;
     103    void breakpointActionProbe(JSC::JSGlobalObject*, JSC::BreakpointActionID, unsigned batchId, unsigned sampleId, JSC::JSValue sample) final;
    101104
    102105    bool isPaused() const;
     
    119122    void didDispatchAsyncCall();
    120123
    121     void schedulePauseOnNextStatement(DebuggerFrontendDispatcher::Reason, RefPtr<JSON::Object>&& data);
    122     void cancelPauseOnNextStatement();
     124    void schedulePauseAtNextOpportunity(DebuggerFrontendDispatcher::Reason, RefPtr<JSON::Object>&& data = nullptr);
     125    void cancelPauseAtNextOpportunity();
    123126    bool pauseOnNextStatementEnabled() const { return m_javaScriptPauseScheduled; }
     127
     128    bool schedulePauseForSpecialBreakpoint(JSC::Breakpoint&, DebuggerFrontendDispatcher::Reason, RefPtr<JSON::Object>&& data = nullptr);
     129    bool cancelPauseForSpecialBreakpoint(JSC::Breakpoint&);
    124130
    125131    void breakProgram(DebuggerFrontendDispatcher::Reason, RefPtr<JSON::Object>&& data);
     
    143149    virtual InjectedScript injectedScriptForEval(ErrorString&, const int* executionContextId) = 0;
    144150
    145     ScriptDebugServer& scriptDebugServer() { return m_scriptDebugServer; }
     151    JSC::Debugger& scriptDebugServer() { return m_scriptDebugServer; }
    146152
    147153    virtual void muteConsole() = 0;
    148154    virtual void unmuteConsole() = 0;
    149155
    150     virtual String sourceMapURLForScript(const Script&);
     156    virtual String sourceMapURLForScript(const JSC::Debugger::Script&);
    151157
    152158    void didClearGlobalObject();
     
    158164    Ref<JSON::ArrayOf<Protocol::Debugger::CallFrame>> currentCallFrames(const InjectedScript&);
    159165
    160     void resolveBreakpoint(const Script&, JSC::Breakpoint&);
    161     void setBreakpoint(JSC::Breakpoint&, bool& existing);
    162     void didSetBreakpoint(const JSC::Breakpoint&, const String&, const ScriptBreakpoint&);
     166    class ProtocolBreakpoint {
     167        WTF_MAKE_FAST_ALLOCATED;
     168    public:
     169        static Optional<ProtocolBreakpoint> fromPayload(ErrorString&, JSC::SourceID, unsigned lineNumber, unsigned columnNumber, const JSON::Object* optionsPayload = nullptr);
     170        static Optional<ProtocolBreakpoint> fromPayload(ErrorString&, const String& url, bool isRegex, unsigned lineNumber, unsigned columnNumber, const JSON::Object* optionsPayload = nullptr);
     171
     172        ProtocolBreakpoint();
     173        ProtocolBreakpoint(JSC::SourceID, unsigned lineNumber, unsigned columnNumber, const String& condition = nullString(), JSC::Breakpoint::ActionsVector&& actions = { }, bool autoContinue = false, size_t ignoreCount = 0);
     174        ProtocolBreakpoint(const String& url, bool isRegex, unsigned lineNumber, unsigned columnNumber, const String& condition = nullString(), JSC::Breakpoint::ActionsVector&& actions = { }, bool autoContinue = false, size_t ignoreCount = 0);
     175
     176        Ref<JSC::Breakpoint> createDebuggerBreakpoint(JSC::BreakpointID, JSC::SourceID) const;
     177
     178        const Inspector::Protocol::Debugger::BreakpointId& id() const { return m_id; }
     179
     180        bool matchesScriptURL(const String&) const;
     181
     182    private:
     183        Inspector::Protocol::Debugger::BreakpointId m_id;
     184
     185#if ASSERT_ENABLED
     186        JSC::SourceID m_sourceID { JSC::noSourceID };
     187#endif
     188        String m_url;
     189        bool m_isRegex { false };
     190
     191        // FIXME: <https://webkit.org/b/162771> Web Inspector: Adopt TextPosition in Inspector to avoid oneBasedInt/zeroBasedInt ambiguity
     192        unsigned m_lineNumber { 0 };
     193        unsigned m_columnNumber { 0 };
     194
     195        String m_condition;
     196        JSC::Breakpoint::ActionsVector m_actions;
     197        bool m_autoContinue { false };
     198        size_t m_ignoreCount { 0 };
     199    };
     200
     201    bool resolveBreakpoint(const JSC::Debugger::Script&, JSC::Breakpoint&);
     202    bool setBreakpoint(JSC::Breakpoint&);
     203    void didSetBreakpoint(ProtocolBreakpoint&, JSC::Breakpoint&);
    163204
    164205    bool assertPaused(ErrorString&);
     
    179220    RefPtr<JSON::Object> buildExceptionPauseReason(JSC::JSValue exception, const InjectedScript&);
    180221
    181     bool breakpointActionsFromProtocol(ErrorString&, RefPtr<JSON::Array>& actions, BreakpointActions* result);
    182 
    183222    typedef std::pair<unsigned, int> AsyncCallIdentifier;
    184223    static AsyncCallIdentifier asyncCallIdentifier(AsyncCallType, int callbackId);
     
    187226    RefPtr<DebuggerBackendDispatcher> m_backendDispatcher;
    188227
    189     ScriptDebugServer& m_scriptDebugServer;
     228    JSC::Debugger& m_scriptDebugServer;
    190229    InjectedScriptManager& m_injectedScriptManager;
    191     HashMap<JSC::SourceID, Script> m_scripts;
     230    HashMap<JSC::SourceID, JSC::Debugger::Script> m_scripts;
    192231
    193232    struct BlackboxConfig {
     
    210249    JSC::Strong<JSC::Unknown> m_currentCallStack;
    211250
    212     HashMap<String, Vector<JSC::BreakpointID>> m_breakpointIdentifierToDebugServerBreakpointIDs;
    213     HashMap<String, RefPtr<JSON::Object>> m_javaScriptBreakpoints;
    214     HashMap<JSC::BreakpointID, String> m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier;
    215     JSC::BreakpointID m_continueToLocationBreakpointID { JSC::noBreakpointID };
     251    HashMap<Inspector::Protocol::Debugger::BreakpointId, ProtocolBreakpoint> m_protocolBreakpointForProtocolBreakpointID;
     252    HashMap<Inspector::Protocol::Debugger::BreakpointId, JSC::BreakpointsVector> m_debuggerBreakpointsForProtocolBreakpointID;
     253    JSC::BreakpointID m_nextDebuggerBreakpointID { JSC::noBreakpointID + 1 };
     254
     255    RefPtr<JSC::Breakpoint> m_continueToLocationDebuggerBreakpoint;
     256
    216257    ShouldDispatchResumed m_conditionToDispatchResumed { ShouldDispatchResumed::No };
    217258
  • trunk/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp

    r265142 r266074  
    3535#include "Completion.h"
    3636#include "ControlFlowProfiler.h"
     37#include "Debugger.h"
    3738#include "InjectedScript.h"
    3839#include "InjectedScriptHost.h"
     
    4041#include "JSLock.h"
    4142#include "ParserError.h"
    42 #include "ScriptDebugServer.h"
    4343#include "SourceCode.h"
    4444#include "TypeProfiler.h"
     
    7474}
    7575
    76 static ScriptDebugServer::PauseOnExceptionsState setPauseOnExceptionsState(ScriptDebugServer& scriptDebugServer, ScriptDebugServer::PauseOnExceptionsState newState)
     76static JSC::Debugger::PauseOnExceptionsState setPauseOnExceptionsState(JSC::Debugger& scriptDebugServer, JSC::Debugger::PauseOnExceptionsState newState)
    7777{
    7878    auto presentState = scriptDebugServer.pauseOnExceptionsState();
     
    124124        return;
    125125
    126     ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = ScriptDebugServer::DontPauseOnExceptions;
     126    auto previousPauseOnExceptionsState = JSC::Debugger::DontPauseOnExceptions;
    127127    if (asBool(doNotPauseOnExceptionsAndMuteConsole))
    128         previousPauseOnExceptionsState = setPauseOnExceptionsState(m_scriptDebugServer, ScriptDebugServer::DontPauseOnExceptions);
     128        previousPauseOnExceptionsState = setPauseOnExceptionsState(m_scriptDebugServer, JSC::Debugger::DontPauseOnExceptions);
    129129    if (asBool(doNotPauseOnExceptionsAndMuteConsole))
    130130        muteConsole();
     
    166166        arguments = optionalArguments->toJSONString();
    167167
    168     ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = ScriptDebugServer::DontPauseOnExceptions;
     168    auto previousPauseOnExceptionsState = JSC::Debugger::DontPauseOnExceptions;
    169169    if (asBool(doNotPauseOnExceptionsAndMuteConsole))
    170         previousPauseOnExceptionsState = setPauseOnExceptionsState(m_scriptDebugServer, ScriptDebugServer::DontPauseOnExceptions);
     170        previousPauseOnExceptionsState = setPauseOnExceptionsState(m_scriptDebugServer, JSC::Debugger::DontPauseOnExceptions);
    171171    if (asBool(doNotPauseOnExceptionsAndMuteConsole))
    172172        muteConsole();
     
    188188    }
    189189
    190     ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = setPauseOnExceptionsState(m_scriptDebugServer, ScriptDebugServer::DontPauseOnExceptions);
     190    auto previousPauseOnExceptionsState = setPauseOnExceptionsState(m_scriptDebugServer, JSC::Debugger::DontPauseOnExceptions);
    191191    muteConsole();
    192192
     
    217217    }
    218218
    219     ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = setPauseOnExceptionsState(m_scriptDebugServer, ScriptDebugServer::DontPauseOnExceptions);
     219    auto previousPauseOnExceptionsState = setPauseOnExceptionsState(m_scriptDebugServer, JSC::Debugger::DontPauseOnExceptions);
    220220    muteConsole();
    221221
     
    250250    }
    251251
    252     ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = setPauseOnExceptionsState(m_scriptDebugServer, ScriptDebugServer::DontPauseOnExceptions);
     252    auto previousPauseOnExceptionsState = setPauseOnExceptionsState(m_scriptDebugServer, JSC::Debugger::DontPauseOnExceptions);
    253253    muteConsole();
    254254
  • trunk/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.h

    r251620 r266074  
    3838
    3939namespace JSC {
     40class Debugger;
    4041class VM;
    4142}
     
    4546class InjectedScript;
    4647class InjectedScriptManager;
    47 class ScriptDebugServer;
    4848typedef String ErrorString;
    4949
     
    9595
    9696    InjectedScriptManager& m_injectedScriptManager;
    97     ScriptDebugServer& m_scriptDebugServer;
     97    JSC::Debugger& m_scriptDebugServer;
    9898    JSC::VM& m_vm;
    9999    bool m_enabled {false};
  • trunk/Source/JavaScriptCore/inspector/agents/InspectorScriptProfilerAgent.cpp

    r261895 r266074  
    2727#include "InspectorScriptProfilerAgent.h"
    2828
     29#include "Debugger.h"
    2930#include "DeferGC.h"
    3031#include "HeapInlines.h"
    3132#include "InspectorEnvironment.h"
    3233#include "SamplingProfiler.h"
    33 #include "ScriptDebugServer.h"
    3434#include <wtf/Stopwatch.h>
    3535
  • trunk/Source/JavaScriptCore/inspector/agents/JSGlobalObjectDebuggerAgent.h

    r261569 r266074  
    3939    ~JSGlobalObjectDebuggerAgent() final;
    4040
    41     // ScriptDebugListener
    42     void breakpointActionLog(JSC::JSGlobalObject*, const String&) final;
     41    // JSC::Debugger::Observer
     42    void breakpointActionLog(JSC::JSGlobalObject*, const String& data) final;
    4343
    4444private:
  • trunk/Source/JavaScriptCore/inspector/protocol/DOM.json

    r262302 r266074  
    317317            "targetTypes": ["page"],
    318318            "parameters": [
    319                 { "name": "eventListenerId", "$ref": "EventListenerId" }
     319                { "name": "eventListenerId", "$ref": "EventListenerId" },
     320                { "name": "options", "$ref": "Debugger.BreakpointOptions", "optional": true, "description": "Options to apply to this breakpoint to modify its behavior." }
    320321            ]
    321322        },
  • trunk/Source/JavaScriptCore/inspector/protocol/DOMDebugger.json

    r251227 r266074  
    4040            "parameters": [
    4141                { "name": "breakpointType", "$ref": "EventBreakpointType" },
    42                 { "name": "eventName", "type": "string", "optional": true, "description": "The name of the specific event to stop on." }
     42                { "name": "eventName", "type": "string", "optional": true, "description": "The name of the specific event to stop on." },
     43                { "name": "options", "$ref": "Debugger.BreakpointOptions", "optional": true, "description": "Options to apply to this breakpoint to modify its behavior." }
    4344            ]
    4445        },
  • trunk/Source/JavaScriptCore/runtime/JSMicrotask.cpp

    r261755 r266074  
    9292    profiledCall(globalObject, ProfilingReason::Microtask, m_job.get(), handlerCallData, jsUndefined(), handlerArguments);
    9393    scope.clearException();
     94
     95    if (UNLIKELY(globalObject->hasDebugger()))
     96        globalObject->debugger()->didRunMicrotask();
    9497}
    9598
  • trunk/Source/WebCore/ChangeLog

    r266063 r266074  
     12020-08-24  Devin Rousso  <drousso@apple.com>
     2
     3        Web Inspector: allow event breakpoints to be configured
     4        https://bugs.webkit.org/show_bug.cgi?id=215362
     5        <rdar://problem/66932921>
     6
     7        Reviewed by Brian Burg.
     8
     9        This allows developers to do things like:
     10         - only pause when `window.event.type` is a certain value
     11         - ignore the first N pauses
     12         - evaluate JavaScript whenever an event listener is invoked without pausing
     13
     14        Tests: inspector/dom/breakpoint-for-event-listener.html
     15               inspector/dom-debugger/event-animation-frame-breakpoints.html
     16               inspector/dom-debugger/event-interval-breakpoints.html
     17               inspector/dom-debugger/event-listener-breakpoints.html
     18               inspector/dom-debugger/event-timeout-breakpoints.html
     19
     20        * inspector/agents/InspectorDOMAgent.h:
     21        * inspector/agents/InspectorDOMAgent.cpp:
     22        (WebCore::InspectorDOMAgent::getEventListenersForNode):
     23        (WebCore::InspectorDOMAgent::setBreakpointForEventListener):
     24        (WebCore::InspectorDOMAgent::removeBreakpointForEventListener):
     25        (WebCore::InspectorDOMAgent::buildObjectForEventListener):
     26        (WebCore::InspectorDOMAgent::breakpointForEventListener):
     27        (WebCore::InspectorDOMAgent::hasBreakpointForEventListener): Deleted.
     28        * inspector/agents/InspectorDOMDebuggerAgent.h:
     29        * inspector/agents/InspectorDOMDebuggerAgent.cpp:
     30        (WebCore::InspectorDOMDebuggerAgent::disable):
     31        (WebCore::InspectorDOMDebuggerAgent::mainFrameNavigated):
     32        (WebCore::InspectorDOMDebuggerAgent::setEventBreakpoint):
     33        (WebCore::InspectorDOMDebuggerAgent::removeEventBreakpoint):
     34        (WebCore::InspectorDOMDebuggerAgent::willHandleEvent):
     35        (WebCore::InspectorDOMDebuggerAgent::didHandleEvent):
     36        (WebCore::InspectorDOMDebuggerAgent::willFireTimer):
     37        (WebCore::InspectorDOMDebuggerAgent::didFireTimer):
     38        * inspector/agents/page/PageDOMDebuggerAgent.h:
     39        * inspector/agents/page/PageDOMDebuggerAgent.cpp:
     40        (WebCore::PageDOMDebuggerAgent::disable):
     41        (WebCore::PageDOMDebuggerAgent::mainFrameNavigated):
     42        (WebCore::PageDOMDebuggerAgent::willFireAnimationFrame):
     43        (WebCore::PageDOMDebuggerAgent::didFireAnimationFrame):
     44        (WebCore::PageDOMDebuggerAgent::setAnimationFrameBreakpoint):
     45        * inspector/agents/worker/WorkerDOMDebuggerAgent.h:
     46        * inspector/agents/worker/WorkerDOMDebuggerAgent.cpp:
     47        (WebCore::WorkerDOMDebuggerAgent::setAnimationFrameBreakpoint):
     48        Keep a `JSC::Breakpoint` for each event breakpoint instead of a simple `bool`, allowing for
     49        configuration when the breakpoint is first set. When any of these breakpoints are hit, pass
     50        it to the `JSC::Debugger` as a "special breakpoint", which behaves the same as "pause ASAP"
     51        but also supports a condition, an ignore count, actions, and auto-continue. Reset the hit
     52        count for any of these "special breakpoints" that persist across Web Inspector sessions
     53        when the main frame navigates.
     54
     55        * inspector/PageScriptDebugServer.h:
     56        * inspector/PageScriptDebugServer.cpp:
     57        (WebCore::PageScriptDebugServer::PageScriptDebugServer):
     58        (WebCore::PageScriptDebugServer::attachDebugger):
     59        (WebCore::PageScriptDebugServer::detachDebugger):
     60        (WebCore::PageScriptDebugServer::didPause):
     61        (WebCore::PageScriptDebugServer::didContinue):
     62        (WebCore::PageScriptDebugServer::runEventLoopWhilePaused):
     63        (WebCore::PageScriptDebugServer::runEventLoopWhilePausedInternal):
     64        (WebCore::PageScriptDebugServer::isContentScript const):
     65        (WebCore::PageScriptDebugServer::reportException const):
     66        * inspector/WorkerScriptDebugServer.h:
     67        * inspector/WorkerScriptDebugServer.cpp:
     68        (WebCore::WorkerScriptDebugServer::WorkerScriptDebugServer):
     69        (WebCore::WorkerScriptDebugServer::attachDebugger):
     70        (WebCore::WorkerScriptDebugServer::detachDebugger):
     71        (WebCore::WorkerScriptDebugServer::runEventLoopWhilePaused):
     72        (WebCore::WorkerScriptDebugServer::reportException const):
     73        * inspector/agents/page/PageDebuggerAgent.h:
     74        * inspector/agents/page/PageDebuggerAgent.cpp:
     75        (WebCore::PageDebuggerAgent::sourceMapURLForScript):
     76        Replace `Inspector::ScriptDebugServer` with `JSC::Debugger`.
     77
     78        * inspector/TimelineRecordFactory.h:
     79        * inspector/TimelineRecordFactory.cpp:
     80        (WebCore::TimelineRecordFactory::createProbeSampleData):
     81        * inspector/agents/InspectorTimelineAgent.h:
     82        * inspector/agents/InspectorTimelineAgent.cpp:
     83        (WebCore::InspectorTimelineAgent::internalStart):
     84        (WebCore::InspectorTimelineAgent::internalStop):
     85        (WebCore::InspectorTimelineAgent::breakpointActionProbe):
     86        Replace `Inspector::ScriptBreakpoint` with `JSC::Breakpoint`.
     87
     88        * inspector/InspectorInstrumentation.h:
     89        (WebCore::InspectorInstrumentation::didHandleEvent):
     90        (WebCore::InspectorInstrumentation::didFireTimer):
     91        * inspector/InspectorInstrumentation.cpp:
     92        (WebCore::InspectorInstrumentation::didHandleEventImpl):
     93        (WebCore::InspectorInstrumentation::didFireTimerImpl):
     94        (WebCore::InspectorInstrumentation::didCommitLoadImpl):
     95        (WebCore::InspectorInstrumentation::didFireAnimationFrameImpl):
     96
     97        * dom/EventTarget.cpp:
     98        (WebCore::EventTarget::innerInvokeEventListeners):
     99        * page/DOMTimer.cpp:
     100        (WebCore::DOMTimer::fired):
     101        When notifying Web Inspector that activity did occur, include all information previously
     102        included when notifying Web Inspector that that activity was about to occur so that Web
     103        Inspector can know whether a pause for the "special breakpoint" for that activity is still
     104        scheduled and if so cancel it.
     105
    11062020-08-24  Aditya Keerthi  <akeerthi@apple.com>
    2107
  • trunk/Source/WebCore/dom/EventTarget.cpp

    r265623 r266074  
    331331        InspectorInstrumentation::willHandleEvent(context, event, *registeredListener);
    332332        registeredListener->callback().handleEvent(context, event);
    333         InspectorInstrumentation::didHandleEvent(context);
     333        InspectorInstrumentation::didHandleEvent(context, event, *registeredListener);
    334334
    335335        if (registeredListener->isPassive())
  • trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp

    r263119 r266074  
    419419}
    420420
    421 void InspectorInstrumentation::didHandleEventImpl(InstrumentingAgents& instrumentingAgents)
     421void InspectorInstrumentation::didHandleEventImpl(InstrumentingAgents& instrumentingAgents, Event& event, const RegisteredEventListener& listener)
    422422{
    423423    if (auto* webDebuggerAgent = instrumentingAgents.enabledWebDebuggerAgent())
     
    425425
    426426    if (auto* domDebuggerAgent = instrumentingAgents.enabledDOMDebuggerAgent())
    427         domDebuggerAgent->didHandleEvent();
     427        domDebuggerAgent->didHandleEvent(event, listener);
    428428}
    429429
     
    474474}
    475475
    476 void InspectorInstrumentation::didFireTimerImpl(InstrumentingAgents& instrumentingAgents)
     476void InspectorInstrumentation::didFireTimerImpl(InstrumentingAgents& instrumentingAgents, int /* timerId */, bool oneShot)
    477477{
    478478    if (auto* webDebuggerAgent = instrumentingAgents.enabledWebDebuggerAgent())
    479479        webDebuggerAgent->didDispatchAsyncCall();
     480    if (auto* domDebuggerAgent = instrumentingAgents.enabledDOMDebuggerAgent())
     481        domDebuggerAgent->didFireTimer(oneShot);
    480482    if (auto* timelineAgent = instrumentingAgents.trackingTimelineAgent())
    481483        timelineAgent->didFireTimer();
     
    716718        if (auto* pageDebuggerAgent = instrumentingAgents.enabledPageDebuggerAgent())
    717719            pageDebuggerAgent->mainFrameNavigated();
     720
     721        if (auto* domDebuggerAgent = instrumentingAgents.enabledDOMDebuggerAgent())
     722            domDebuggerAgent->mainFrameNavigated();
    718723
    719724        if (auto* enabledPageHeapAgent = instrumentingAgents.enabledPageHeapAgent())
     
    12631268    if (auto* webDebuggerAgent = instrumentingAgents.enabledWebDebuggerAgent())
    12641269        webDebuggerAgent->didDispatchAsyncCall();
     1270    if (auto* pageDOMDebuggerAgent = instrumentingAgents.enabledPageDOMDebuggerAgent())
     1271        pageDOMDebuggerAgent->didFireAnimationFrame();
    12651272    if (auto* timelineAgent = instrumentingAgents.trackingTimelineAgent())
    12661273        timelineAgent->didFireAnimationFrame();
  • trunk/Source/WebCore/inspector/InspectorInstrumentation.h

    r263119 r266074  
    172172    static void didDispatchEvent(Document&, const Event&);
    173173    static void willHandleEvent(ScriptExecutionContext&, Event&, const RegisteredEventListener&);
    174     static void didHandleEvent(ScriptExecutionContext&);
     174    static void didHandleEvent(ScriptExecutionContext&, Event&, const RegisteredEventListener&);
    175175    static void willDispatchEventOnWindow(Frame*, const Event&, DOMWindow&);
    176176    static void didDispatchEventOnWindow(Frame*, const Event&);
     
    179179    static void didEvaluateScript(Frame&);
    180180    static void willFireTimer(ScriptExecutionContext&, int timerId, bool oneShot);
    181     static void didFireTimer(ScriptExecutionContext&);
     181    static void didFireTimer(ScriptExecutionContext&, int timerId, bool oneShot);
    182182    static void didInvalidateLayout(Frame&);
    183183    static void willLayout(Frame&);
     
    395395    static void willDispatchEventImpl(InstrumentingAgents&, Document&, const Event&);
    396396    static void willHandleEventImpl(InstrumentingAgents&, Event&, const RegisteredEventListener&);
    397     static void didHandleEventImpl(InstrumentingAgents&);
     397    static void didHandleEventImpl(InstrumentingAgents&, Event&, const RegisteredEventListener&);
    398398    static void didDispatchEventImpl(InstrumentingAgents&, const Event&);
    399399    static void willDispatchEventOnWindowImpl(InstrumentingAgents&, const Event&, DOMWindow&);
     
    403403    static void didEvaluateScriptImpl(InstrumentingAgents&, Frame&);
    404404    static void willFireTimerImpl(InstrumentingAgents&, int timerId, bool oneShot, ScriptExecutionContext&);
    405     static void didFireTimerImpl(InstrumentingAgents&);
     405    static void didFireTimerImpl(InstrumentingAgents&, int timerId, bool oneShot);
    406406    static void didInvalidateLayoutImpl(InstrumentingAgents&, Frame&);
    407407    static void willLayoutImpl(InstrumentingAgents&, Frame&);
     
    893893}
    894894
    895 inline void InspectorInstrumentation::didHandleEvent(ScriptExecutionContext& context)
     895inline void InspectorInstrumentation::didHandleEvent(ScriptExecutionContext& context, Event& event, const RegisteredEventListener& listener)
    896896{
    897897    FAST_RETURN_IF_NO_FRONTENDS(void());
    898898    if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
    899         return didHandleEventImpl(*instrumentingAgents);
     899        return didHandleEventImpl(*instrumentingAgents, event, listener);
    900900}
    901901
     
    947947}
    948948
    949 inline void InspectorInstrumentation::didFireTimer(ScriptExecutionContext& context)
     949inline void InspectorInstrumentation::didFireTimer(ScriptExecutionContext& context, int timerId, bool oneShot)
    950950{
    951951    FAST_RETURN_IF_NO_FRONTENDS(void());
    952952    if (auto* instrumentingAgents = instrumentingAgentsForContext(context))
    953         didFireTimerImpl(*instrumentingAgents);
     953        didFireTimerImpl(*instrumentingAgents, timerId, oneShot);
    954954}
    955955
  • trunk/Source/WebCore/inspector/PageScriptDebugServer.cpp

    r263432 r266074  
    5555
    5656PageScriptDebugServer::PageScriptDebugServer(Page& page)
    57     : ScriptDebugServer(WebCore::commonVM())
     57    : Debugger(WebCore::commonVM())
    5858    , m_page(page)
    5959{
     
    6262void PageScriptDebugServer::attachDebugger()
    6363{
     64    JSC::Debugger::attachDebugger();
     65
    6466    m_page.setDebugger(this);
    6567}
     
    6769void PageScriptDebugServer::detachDebugger(bool isBeingDestroyed)
    6870{
     71    JSC::Debugger::detachDebugger(isBeingDestroyed);
     72
    6973    m_page.setDebugger(nullptr);
    7074    if (!isBeingDestroyed)
     
    7882}
    7983
    80 void PageScriptDebugServer::didPause(JSGlobalObject*)
     84void PageScriptDebugServer::didPause(JSGlobalObject* globalObject)
    8185{
     86    JSC::Debugger::didPause(globalObject);
     87
    8288    setJavaScriptPaused(m_page.group(), true);
    8389}
    8490
    85 void PageScriptDebugServer::didContinue(JSGlobalObject*)
     91void PageScriptDebugServer::didContinue(JSGlobalObject* globalObject)
    8692{
     93    JSC::Debugger::didContinue(globalObject);
     94
    8795    setJavaScriptPaused(m_page.group(), false);
    8896}
     
    9098void PageScriptDebugServer::runEventLoopWhilePaused()
    9199{
     100    JSC::Debugger::runEventLoopWhilePaused();
     101
    92102#if PLATFORM(IOS_FAMILY)
    93103    // On iOS, running an EventLoop causes us to run a nested WebRunLoop.
     
    116126    m_page.incrementNestedRunLoopCount();
    117127
    118     while (!m_doneProcessingDebuggerEvents) {
     128    while (!doneProcessingDebuggerEvents()) {
    119129        if (!platformShouldContinueRunningEventLoopWhilePaused())
    120130            break;
     
    126136bool PageScriptDebugServer::isContentScript(JSGlobalObject* state) const
    127137{
    128     return &currentWorld(*state) != &mainThreadNormalWorld();
     138    return &currentWorld(*state) != &mainThreadNormalWorld() || JSC::Debugger::isContentScript(state);
    129139}
    130140
    131141void PageScriptDebugServer::reportException(JSGlobalObject* state, JSC::Exception* exception) const
    132142{
     143    JSC::Debugger::reportException(state, exception);
     144
    133145    WebCore::reportException(state, exception);
    134146}
  • trunk/Source/WebCore/inspector/PageScriptDebugServer.h

    r259931 r266074  
    2727#pragma once
    2828
    29 #include <JavaScriptCore/ScriptDebugServer.h>
     29#include <JavaScriptCore/Debugger.h>
    3030
    3131namespace WebCore {
     
    3535class PageGroup;
    3636
    37 class PageScriptDebugServer final : public Inspector::ScriptDebugServer {
     37class PageScriptDebugServer final : public JSC::Debugger {
    3838    WTF_MAKE_NONCOPYABLE(PageScriptDebugServer);
    3939    WTF_MAKE_FAST_ALLOCATED;
     
    4545
    4646private:
    47     void attachDebugger() override;
    48     void detachDebugger(bool isBeingDestroyed) override;
    49 
    50     void didPause(JSC::JSGlobalObject*) override;
    51     void didContinue(JSC::JSGlobalObject*) override;
    52     void runEventLoopWhilePaused() override;
    53     bool isContentScript(JSC::JSGlobalObject*) const override;
    54     void reportException(JSC::JSGlobalObject*, JSC::Exception*) const override;
     47    // JSC::Debugger
     48    void attachDebugger() final;
     49    void detachDebugger(bool isBeingDestroyed) final;
     50    void didPause(JSC::JSGlobalObject*) final;
     51    void didContinue(JSC::JSGlobalObject*) final;
     52    void runEventLoopWhilePaused() final;
     53    bool isContentScript(JSC::JSGlobalObject*) const final;
     54    void reportException(JSC::JSGlobalObject*, JSC::Exception*) const final;
    5555
    5656    void runEventLoopWhilePausedInternal();
  • trunk/Source/WebCore/inspector/TimelineRecordFactory.cpp

    r240323 r266074  
    3737#include "JSExecState.h"
    3838#include <JavaScriptCore/InspectorProtocolObjects.h>
    39 #include <JavaScriptCore/ScriptBreakpoint.h>
    4039#include <JavaScriptCore/ScriptCallStack.h>
    4140#include <JavaScriptCore/ScriptCallStackFactory.h>
     
    7473}
    7574
    76 Ref<JSON::Object> TimelineRecordFactory::createProbeSampleData(const ScriptBreakpointAction& action, unsigned sampleId)
     75Ref<JSON::Object> TimelineRecordFactory::createProbeSampleData(JSC::BreakpointActionID actionID, unsigned sampleId)
    7776{
    7877    Ref<JSON::Object> data = JSON::Object::create();
    79     data->setInteger("probeId"_s, action.identifier);
     78    data->setInteger("probeId"_s, actionID);
    8079    data->setInteger("sampleId"_s, sampleId);
    8180    return data;
  • trunk/Source/WebCore/inspector/TimelineRecordFactory.h

    r240323 r266074  
    3232#pragma once
    3333
     34#include <JavaScriptCore/DebuggerPrimitives.h>
    3435#include <wtf/Forward.h>
    3536#include <wtf/JSONValues.h>
    3637#include <wtf/Seconds.h>
    3738#include <wtf/text/WTFString.h>
    38 
    39 namespace Inspector {
    40 struct ScriptBreakpointAction;
    41 }
    4239
    4340namespace WebCore {
     
    5249    static Ref<JSON::Object> createFunctionCallData(const String& scriptName, int scriptLine, int scriptColumn);
    5350    static Ref<JSON::Object> createConsoleProfileData(const String& title);
    54     static Ref<JSON::Object> createProbeSampleData(const Inspector::ScriptBreakpointAction&, unsigned sampleId);
     51    static Ref<JSON::Object> createProbeSampleData(JSC::BreakpointActionID, unsigned sampleId);
    5552    static Ref<JSON::Object> createEventDispatchData(const Event&);
    5653    static Ref<JSON::Object> createGenericTimerData(int timerId);
  • trunk/Source/WebCore/inspector/WorkerScriptDebugServer.cpp

    r251425 r266074  
    4545
    4646WorkerScriptDebugServer::WorkerScriptDebugServer(WorkerGlobalScope& context)
    47     : ScriptDebugServer(context.script()->vm())
     47    : Debugger(context.script()->vm())
    4848    , m_workerGlobalScope(context)
    4949{
     
    5252void WorkerScriptDebugServer::attachDebugger()
    5353{
     54    JSC::Debugger::attachDebugger();
     55
    5456    m_workerGlobalScope.script()->attachDebugger(this);
    5557}
     
    5759void WorkerScriptDebugServer::detachDebugger(bool isBeingDestroyed)
    5860{
     61    JSC::Debugger::detachDebugger(isBeingDestroyed);
     62
    5963    if (m_workerGlobalScope.script())
    6064        m_workerGlobalScope.script()->detachDebugger(this);
     
    7175void WorkerScriptDebugServer::runEventLoopWhilePaused()
    7276{
     77    JSC::Debugger::runEventLoopWhilePaused();
     78
    7379    TimerBase::fireTimersInNestedEventLoop();
    7480
     
    7682    do {
    7783        result = m_workerGlobalScope.thread().runLoop().runInDebuggerMode(m_workerGlobalScope);
    78     } while (result != MessageQueueTerminated && !m_doneProcessingDebuggerEvents);
     84    } while (result != MessageQueueTerminated && !doneProcessingDebuggerEvents());
    7985}
    8086
    8187void WorkerScriptDebugServer::reportException(JSC::JSGlobalObject* exec, JSC::Exception* exception) const
    8288{
     89    JSC::Debugger::reportException(exec, exception);
     90
    8391    WebCore::reportException(exec, exception);
    8492}
  • trunk/Source/WebCore/inspector/WorkerScriptDebugServer.h

    r251425 r266074  
    3232#pragma once
    3333
    34 #include <JavaScriptCore/ScriptDebugServer.h>
     34#include <JavaScriptCore/Debugger.h>
    3535
    3636namespace WebCore {
     
    3838class WorkerGlobalScope;
    3939
    40 class WorkerScriptDebugServer final : public Inspector::ScriptDebugServer {
     40class WorkerScriptDebugServer final : public JSC::Debugger {
    4141    WTF_MAKE_NONCOPYABLE(WorkerScriptDebugServer);
    4242    WTF_MAKE_FAST_ALLOCATED;
     
    4545    ~WorkerScriptDebugServer() override = default;
    4646
    47     void recompileAllJSFunctions() override;
    4847
    4948private:
    50     void attachDebugger() override;
    51     void detachDebugger(bool isBeingDestroyed) override;
    52 
    53     void didPause(JSC::JSGlobalObject*) override { }
    54     void didContinue(JSC::JSGlobalObject*) override { }
    55     void runEventLoopWhilePaused() override;
    56     bool isContentScript(JSC::JSGlobalObject*) const override { return false; }
    57     void reportException(JSC::JSGlobalObject*, JSC::Exception*) const override;
     49    // JSC::Debugger
     50    void attachDebugger() final;
     51    void detachDebugger(bool isBeingDestroyed) final;
     52    void recompileAllJSFunctions() final;
     53    void runEventLoopWhilePaused() final;
     54    void reportException(JSC::JSGlobalObject*, JSC::Exception*) const final;
    5855
    5956    WorkerGlobalScope& m_workerGlobalScope;
  • trunk/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp

    r264585 r266074  
    113113#include <JavaScriptCore/InjectedScript.h>
    114114#include <JavaScriptCore/InjectedScriptManager.h>
     115#include <JavaScriptCore/InspectorDebuggerAgent.h>
    115116#include <JavaScriptCore/JSCInlines.h>
    116117#include <pal/crypto/CryptoDigest.h>
     
    932933        int identifier = 0;
    933934        bool disabled = false;
    934         bool hasBreakpoint = false;
     935        RefPtr<JSC::Breakpoint> breakpoint;
    935936
    936937        for (auto& inspectorEventListener : m_eventListenerEntries.values()) {
     
    938939                identifier = inspectorEventListener.identifier;
    939940                disabled = inspectorEventListener.disabled;
    940                 hasBreakpoint = inspectorEventListener.hasBreakpoint;
     941                breakpoint = inspectorEventListener.breakpoint;
    941942                break;
    942943            }
     
    948949            identifier = inspectorEventListener.identifier;
    949950            disabled = inspectorEventListener.disabled;
    950             hasBreakpoint = inspectorEventListener.hasBreakpoint;
     951            breakpoint = inspectorEventListener.breakpoint;
    951952
    952953            m_eventListenerEntries.add(identifier, inspectorEventListener);
    953954        }
    954955
    955         listenersArray->addItem(buildObjectForEventListener(listener, identifier, *info.eventTarget, info.eventType, disabled, hasBreakpoint));
     956        listenersArray->addItem(buildObjectForEventListener(listener, identifier, *info.eventTarget, info.eventType, disabled, breakpoint));
    956957    };
    957958
     
    989990}
    990991
    991 void InspectorDOMAgent::setBreakpointForEventListener(ErrorString& errorString, int eventListenerId)
     992void InspectorDOMAgent::setBreakpointForEventListener(ErrorString& errorString, int eventListenerId, const JSON::Object* optionsPayload)
    992993{
    993994    auto it = m_eventListenerEntries.find(eventListenerId);
     
    997998    }
    998999
    999     it->value.hasBreakpoint = true;
     1000    if (it->value.breakpoint) {
     1001        errorString = "Breakpoint for given eventListenerId already exists"_s;
     1002        return;
     1003    }
     1004
     1005    it->value.breakpoint = InspectorDebuggerAgent::debuggerBreakpointFromPayload(errorString, optionsPayload);
    10001006}
    10011007
     
    10081014    }
    10091015
    1010     it->value.hasBreakpoint = false;
     1016    if (!it->value.breakpoint)
     1017        errorString = "Breakpoint for given eventListenerId missing"_s;
     1018
     1019    it->value.breakpoint = nullptr;
    10111020}
    10121021
     
    17521761}
    17531762
    1754 Ref<Inspector::Protocol::DOM::EventListener> InspectorDOMAgent::buildObjectForEventListener(const RegisteredEventListener& registeredEventListener, int identifier, EventTarget& eventTarget, const AtomString& eventType, bool disabled, bool hasBreakpoint)
     1763Ref<Inspector::Protocol::DOM::EventListener> InspectorDOMAgent::buildObjectForEventListener(const RegisteredEventListener& registeredEventListener, int identifier, EventTarget& eventTarget, const AtomString& eventType, bool disabled, const RefPtr<JSC::Breakpoint>& breakpoint)
    17551764{
    17561765    Ref<EventListener> eventListener = registeredEventListener.callback();
     
    18401849    if (disabled)
    18411850        value->setDisabled(disabled);
    1842     if (hasBreakpoint)
    1843         value->setHasBreakpoint(hasBreakpoint);
     1851    if (breakpoint)
     1852        value->setHasBreakpoint(breakpoint);
    18441853    return value;
    18451854}
     
    25492558}
    25502559
    2551 bool InspectorDOMAgent::hasBreakpointForEventListener(EventTarget& target, const AtomString& eventType, EventListener& listener, bool capture)
     2560RefPtr<JSC::Breakpoint> InspectorDOMAgent::breakpointForEventListener(EventTarget& target, const AtomString& eventType, EventListener& listener, bool capture)
    25522561{
    25532562    for (auto& inspectorEventListener : m_eventListenerEntries.values()) {
    25542563        if (inspectorEventListener.matches(target, eventType, listener, capture))
    2555             return inspectorEventListener.hasBreakpoint;
    2556     }
    2557     return false;
     2564            return inspectorEventListener.breakpoint;
     2565    }
     2566    return nullptr;
    25582567}
    25592568
  • trunk/Source/WebCore/inspector/agents/InspectorDOMAgent.h

    r262302 r266074  
    3333#include "InspectorWebAgentBase.h"
    3434#include "Timer.h"
     35#include <JavaScriptCore/Breakpoint.h>
    3536#include <JavaScriptCore/InspectorBackendDispatchers.h>
    3637#include <JavaScriptCore/InspectorFrontendDispatchers.h>
     
    126127    void getEventListenersForNode(ErrorString&, int nodeId, RefPtr<JSON::ArrayOf<Inspector::Protocol::DOM::EventListener>>& listenersArray) override;
    127128    void setEventListenerDisabled(ErrorString&, int eventListenerId, bool disabled) override;
    128     void setBreakpointForEventListener(ErrorString&, int eventListenerId) override;
     129    void setBreakpointForEventListener(ErrorString&, int eventListenerId, const JSON::Object* options) final;
    129130    void removeBreakpointForEventListener(ErrorString&, int eventListenerId) override;
    130131    void getAccessibilityPropertiesForNode(ErrorString&, int nodeId, RefPtr<Inspector::Protocol::DOM::AccessibilityProperties>& axProperties) override;
     
    206207    Document* assertDocument(ErrorString&, int nodeId);
    207208
    208     bool hasBreakpointForEventListener(EventTarget&, const AtomString& eventType, EventListener&, bool capture);
     209    RefPtr<JSC::Breakpoint> breakpointForEventListener(EventTarget&, const AtomString& eventType, EventListener&, bool capture);
    209210    int idForEventListener(EventTarget&, const AtomString& eventType, EventListener&, bool capture);
    210211
     
    232233    Ref<JSON::ArrayOf<Inspector::Protocol::DOM::Node>> buildArrayForContainerChildren(Node* container, int depth, NodeToIdMap* nodesMap);
    233234    RefPtr<JSON::ArrayOf<Inspector::Protocol::DOM::Node>> buildArrayForPseudoElements(const Element&, NodeToIdMap* nodesMap);
    234     Ref<Inspector::Protocol::DOM::EventListener> buildObjectForEventListener(const RegisteredEventListener&, int identifier, EventTarget&, const AtomString& eventType, bool disabled, bool hasBreakpoint);
     235    Ref<Inspector::Protocol::DOM::EventListener> buildObjectForEventListener(const RegisteredEventListener&, int identifier, EventTarget&, const AtomString& eventType, bool disabled, const RefPtr<JSC::Breakpoint>&);
    235236    RefPtr<Inspector::Protocol::DOM::AccessibilityProperties> buildObjectForAccessibilityProperties(Node*);
    236237    void processAccessibilityChildren(AXCoreObject&, JSON::ArrayOf<int>&);
     
    291292        bool useCapture { false };
    292293        bool disabled { false };
    293         bool hasBreakpoint { false };
     294        RefPtr<JSC::Breakpoint> breakpoint;
    294295
    295296        InspectorEventListener() { }
  • trunk/Source/WebCore/inspector/agents/InspectorDOMDebuggerAgent.cpp

    r262673 r266074  
    7777
    7878    m_listenerBreakpoints.clear();
     79    m_pauseOnAllIntervalsBreakpoint = nullptr;
     80    m_pauseOnAllListenersBreakpoint = nullptr;
     81    m_pauseOnAllTimeoutsBreakpoint = nullptr;
     82
    7983    m_urlBreakpoints.clear();
    80     m_pauseOnAllIntervalsEnabled = false;
    81     m_pauseOnAllListenersEnabled = false;
    82     m_pauseOnAllTimeoutsEnabled = false;
    8384    m_pauseOnAllURLsEnabled = false;
    8485}
     
    112113}
    113114
    114 void InspectorDOMDebuggerAgent::setEventBreakpoint(ErrorString& errorString, const String& breakpointTypeString, const String* eventName)
     115void InspectorDOMDebuggerAgent::mainFrameNavigated()
     116{
     117    for (auto& breakpoint : m_listenerBreakpoints.values())
     118        breakpoint->resetHitCount();
     119
     120    if (m_pauseOnAllIntervalsBreakpoint)
     121        m_pauseOnAllIntervalsBreakpoint->resetHitCount();
     122
     123    if (m_pauseOnAllListenersBreakpoint)
     124        m_pauseOnAllListenersBreakpoint->resetHitCount();
     125
     126    if (m_pauseOnAllTimeoutsBreakpoint)
     127        m_pauseOnAllTimeoutsBreakpoint->resetHitCount();
     128}
     129
     130void InspectorDOMDebuggerAgent::setEventBreakpoint(ErrorString& errorString, const String& breakpointTypeString, const String* eventName, const JSON::Object* optionsPayload)
    115131{
    116132    if (breakpointTypeString.isEmpty()) {
     
    125141    }
    126142
     143    auto breakpoint = InspectorDebuggerAgent::debuggerBreakpointFromPayload(errorString, optionsPayload);
     144    if (!breakpoint)
     145        return;
     146
    127147    if (eventName && !eventName->isEmpty()) {
    128148        if (breakpointType.value() == Inspector::Protocol::DOMDebugger::EventBreakpointType::Listener) {
    129             if (!m_listenerBreakpoints.add(*eventName))
     149            if (!m_listenerBreakpoints.add(*eventName, breakpoint.releaseNonNull()))
    130150                errorString = "Breakpoint with eventName already exists"_s;
    131151            return;
     
    138158    switch (breakpointType.value()) {
    139159    case Inspector::Protocol::DOMDebugger::EventBreakpointType::AnimationFrame:
    140         setAnimationFrameBreakpoint(errorString, true);
     160        setAnimationFrameBreakpoint(errorString, WTFMove(breakpoint));
    141161        break;
    142162
    143163    case Inspector::Protocol::DOMDebugger::EventBreakpointType::Interval:
    144         if (m_pauseOnAllIntervalsEnabled)
     164        if (!m_pauseOnAllIntervalsBreakpoint)
     165            m_pauseOnAllIntervalsBreakpoint = WTFMove(breakpoint);
     166        else
    145167            errorString = "Breakpoint for Interval already exists"_s;
    146         m_pauseOnAllIntervalsEnabled = true;
    147168        break;
    148169
    149170    case Inspector::Protocol::DOMDebugger::EventBreakpointType::Listener:
    150         if (m_pauseOnAllListenersEnabled)
     171        if (!m_pauseOnAllListenersBreakpoint)
     172            m_pauseOnAllListenersBreakpoint = WTFMove(breakpoint);
     173        else
    151174            errorString = "Breakpoint for Listener already exists"_s;
    152         m_pauseOnAllListenersEnabled = true;
    153175        break;
    154176
    155177    case Inspector::Protocol::DOMDebugger::EventBreakpointType::Timeout:
    156         if (m_pauseOnAllTimeoutsEnabled)
     178        if (!m_pauseOnAllTimeoutsBreakpoint)
     179            m_pauseOnAllTimeoutsBreakpoint = WTFMove(breakpoint);
     180        else
    157181            errorString = "Breakpoint for Timeout already exists"_s;
    158         m_pauseOnAllTimeoutsEnabled = true;
    159182        break;
    160183    }
     
    187210    switch (breakpointType.value()) {
    188211    case Inspector::Protocol::DOMDebugger::EventBreakpointType::AnimationFrame:
    189         setAnimationFrameBreakpoint(errorString, false);
     212        setAnimationFrameBreakpoint(errorString, nullptr);
    190213        break;
    191214
    192215    case Inspector::Protocol::DOMDebugger::EventBreakpointType::Interval:
    193         if (!m_pauseOnAllIntervalsEnabled)
     216        if (!m_pauseOnAllIntervalsBreakpoint)
    194217            errorString = "Breakpoint for Intervals missing"_s;
    195         m_pauseOnAllIntervalsEnabled = false;
     218        m_pauseOnAllIntervalsBreakpoint = nullptr;
    196219        break;
    197220
    198221    case Inspector::Protocol::DOMDebugger::EventBreakpointType::Listener:
    199         if (!m_pauseOnAllListenersEnabled)
     222        if (!m_pauseOnAllListenersBreakpoint)
    200223            errorString = "Breakpoint for Listeners missing"_s;
    201         m_pauseOnAllListenersEnabled = false;
     224        m_pauseOnAllListenersBreakpoint = nullptr;
    202225        break;
    203226
    204227    case Inspector::Protocol::DOMDebugger::EventBreakpointType::Timeout:
    205         if (!m_pauseOnAllTimeoutsEnabled)
     228        if (!m_pauseOnAllTimeoutsBreakpoint)
    206229            errorString = "Breakpoint for Timeouts missing"_s;
    207         m_pauseOnAllTimeoutsEnabled = false;
     230        m_pauseOnAllTimeoutsBreakpoint = nullptr;
    208231        break;
    209232    }
     
    212235void InspectorDOMDebuggerAgent::willHandleEvent(Event& event, const RegisteredEventListener& registeredEventListener)
    213236{
    214     if (!m_debuggerAgent->breakpointsActive())
    215         return;
    216 
    217237    auto state = event.target()->scriptExecutionContext()->execState();
    218238    auto injectedScript = m_injectedScriptManager.injectedScriptFor(state);
     
    220240        return;
    221241
     242    // Set Web Inspector console command line `$event` getter.
    222243    {
    223244        JSC::JSLockHolder lock(state);
     
    226247    }
    227248
     249    if (!m_debuggerAgent->breakpointsActive())
     250        return;
     251
    228252    auto* domAgent = m_instrumentingAgents.persistentDOMAgent();
    229253
    230     bool shouldPause = m_debuggerAgent->pauseOnNextStatementEnabled() || m_pauseOnAllListenersEnabled || m_listenerBreakpoints.contains(event.type());
    231     if (!shouldPause && domAgent)
    232         shouldPause = domAgent->hasBreakpointForEventListener(*event.currentTarget(), event.type(), registeredEventListener.callback(), registeredEventListener.useCapture());
    233     if (!shouldPause)
     254    auto breakpoint = m_pauseOnAllListenersBreakpoint;
     255    if (!breakpoint) {
     256        auto it = m_listenerBreakpoints.find(event.type());
     257        if (it != m_listenerBreakpoints.end())
     258            breakpoint = it->value.copyRef();
     259    }
     260    if (!breakpoint && domAgent)
     261        breakpoint = domAgent->breakpointForEventListener(*event.currentTarget(), event.type(), registeredEventListener.callback(), registeredEventListener.useCapture());
     262    if (!breakpoint)
    234263        return;
    235264
     
    242271    }
    243272
    244     m_debuggerAgent->schedulePauseOnNextStatement(Inspector::DebuggerFrontendDispatcher::Reason::Listener, WTFMove(eventData));
    245 }
    246 
    247 void InspectorDOMDebuggerAgent::didHandleEvent()
    248 {
    249     m_injectedScriptManager.clearEventValue();
     273    m_debuggerAgent->schedulePauseForSpecialBreakpoint(*breakpoint, Inspector::DebuggerFrontendDispatcher::Reason::Listener, WTFMove(eventData));
     274}
     275
     276void InspectorDOMDebuggerAgent::didHandleEvent(Event& event, const RegisteredEventListener& registeredEventListener)
     277{
     278    auto state = event.target()->scriptExecutionContext()->execState();
     279    auto injectedScript = m_injectedScriptManager.injectedScriptFor(state);
     280    if (injectedScript.hasNoValue())
     281        return;
     282
     283    // Clear Web Inspector console command line `$event` getter.
     284    {
     285        JSC::JSLockHolder lock(state);
     286
     287        injectedScript.clearEventValue();
     288    }
     289
     290    if (!m_debuggerAgent->breakpointsActive())
     291        return;
     292
     293    auto breakpoint = m_pauseOnAllListenersBreakpoint;
     294    if (!breakpoint)
     295        breakpoint = m_listenerBreakpoints.get(event.type());
     296    if (!breakpoint) {
     297        if (auto* domAgent = m_instrumentingAgents.persistentDOMAgent())
     298            breakpoint = domAgent->breakpointForEventListener(*event.currentTarget(), event.type(), registeredEventListener.callback(), registeredEventListener.useCapture());
     299    }
     300    if (!breakpoint)
     301        return;
     302
     303    m_debuggerAgent->cancelPauseForSpecialBreakpoint(*breakpoint);
    250304}
    251305
     
    255309        return;
    256310
    257     bool shouldPause = m_debuggerAgent->pauseOnNextStatementEnabled() || (oneShot ? m_pauseOnAllTimeoutsEnabled : m_pauseOnAllIntervalsEnabled);
    258     if (!shouldPause)
     311    auto breakpoint = oneShot ? m_pauseOnAllTimeoutsBreakpoint : m_pauseOnAllIntervalsBreakpoint;
     312    if (!breakpoint)
    259313        return;
    260314
    261315    auto breakReason = oneShot ? Inspector::DebuggerFrontendDispatcher::Reason::Timeout : Inspector::DebuggerFrontendDispatcher::Reason::Interval;
    262     m_debuggerAgent->schedulePauseOnNextStatement(breakReason, nullptr);
     316    m_debuggerAgent->schedulePauseForSpecialBreakpoint(*breakpoint, breakReason);
     317}
     318
     319void InspectorDOMDebuggerAgent::didFireTimer(bool oneShot)
     320{
     321    if (!m_debuggerAgent->breakpointsActive())
     322        return;
     323
     324    auto breakpoint = oneShot ? m_pauseOnAllTimeoutsBreakpoint : m_pauseOnAllIntervalsBreakpoint;
     325    if (!breakpoint)
     326        return;
     327
     328    m_debuggerAgent->cancelPauseForSpecialBreakpoint(*breakpoint);
    263329}
    264330
  • trunk/Source/WebCore/inspector/agents/InspectorDOMDebuggerAgent.h

    r250996 r266074  
    3333
    3434#include "InspectorWebAgentBase.h"
     35#include <JavaScriptCore/Breakpoint.h>
    3536#include <JavaScriptCore/InspectorBackendDispatchers.h>
    3637#include <JavaScriptCore/InspectorDebuggerAgent.h>
    3738#include <wtf/HashMap.h>
     39#include <wtf/HashSet.h>
    3840#include <wtf/JSONValues.h>
     41#include <wtf/RefPtr.h>
    3942#include <wtf/text/WTFString.h>
    4043
     
    6568    void setURLBreakpoint(ErrorString&, const String& url, const bool* optionalIsRegex) final;
    6669    void removeURLBreakpoint(ErrorString&, const String& url) final;
    67     void setEventBreakpoint(ErrorString&, const String& breakpointType, const String* eventName) final;
     70    void setEventBreakpoint(ErrorString&, const String& breakpointType, const String* eventName, const JSON::Object* options) final;
    6871    void removeEventBreakpoint(ErrorString&, const String& breakpointType, const String* eventName) final;
    6972
     
    7376
    7477    // InspectorInstrumentation
     78    virtual void mainFrameNavigated();
    7579    void willSendXMLHttpRequest(const String& url);
    7680    void willFetch(const String& url);
    7781    void willHandleEvent(Event&, const RegisteredEventListener&);
    78     void didHandleEvent();
     82    void didHandleEvent(Event&, const RegisteredEventListener&);
    7983    void willFireTimer(bool oneShot);
     84    void didFireTimer(bool oneShot);
    8085
    8186protected:
     
    8489    virtual void disable();
    8590
    86     virtual void setAnimationFrameBreakpoint(ErrorString&, bool enabled) = 0;
     91    virtual void setAnimationFrameBreakpoint(ErrorString&, RefPtr<JSC::Breakpoint>&&) = 0;
    8792
    8893    Inspector::InspectorDebuggerAgent* m_debuggerAgent { nullptr };
     
    95100    Inspector::InjectedScriptManager& m_injectedScriptManager;
    96101
    97     HashSet<String> m_listenerBreakpoints;
     102    HashMap<String, Ref<JSC::Breakpoint>> m_listenerBreakpoints;
     103    RefPtr<JSC::Breakpoint> m_pauseOnAllIntervalsBreakpoint;
     104    RefPtr<JSC::Breakpoint> m_pauseOnAllListenersBreakpoint;
     105    RefPtr<JSC::Breakpoint> m_pauseOnAllTimeoutsBreakpoint;
    98106
    99107    enum class URLBreakpointType { RegularExpression, Text };
    100108    HashMap<String, URLBreakpointType> m_urlBreakpoints;
    101 
    102     bool m_pauseOnAllIntervalsEnabled { false };
    103     bool m_pauseOnAllListenersEnabled { false };
    104     bool m_pauseOnAllTimeoutsEnabled { false };
    105109    bool m_pauseOnAllURLsEnabled { false };
    106110};
  • trunk/Source/WebCore/inspector/agents/InspectorTimelineAgent.cpp

    r262673 r266074  
    5252#include "WebConsoleAgent.h"
    5353#include "WebDebuggerAgent.h"
     54#include <JavaScriptCore/Breakpoint.h>
    5455#include <JavaScriptCore/ConsoleMessage.h>
    5556#include <JavaScriptCore/InspectorScriptProfilerAgent.h>
    56 #include <JavaScriptCore/ScriptBreakpoint.h>
    5757#include <wtf/Stopwatch.h>
    5858
     
    188188    m_instrumentingAgents.setTrackingTimelineAgent(this);
    189189
    190     m_environment.scriptDebugServer().addListener(this);
     190    m_environment.scriptDebugServer().addObserver(*this);
    191191
    192192    m_tracking = true;
     
    242242    m_instrumentingAgents.setTrackingTimelineAgent(nullptr);
    243243
    244     m_environment.scriptDebugServer().removeListener(this, true);
     244    m_environment.scriptDebugServer().removeObserver(*this, true);
    245245
    246246#if PLATFORM(COCOA)
     
    670670}
    671671
    672 // ScriptDebugListener
    673 
    674 void InspectorTimelineAgent::breakpointActionProbe(JSC::JSGlobalObject* lexicalGlobalObject, const Inspector::ScriptBreakpointAction& action, unsigned /*batchId*/, unsigned sampleId, JSC::JSValue)
    675 {
    676     appendRecord(TimelineRecordFactory::createProbeSampleData(action, sampleId), TimelineRecordType::ProbeSample, false, frameFromExecState(lexicalGlobalObject));
     672void InspectorTimelineAgent::breakpointActionProbe(JSC::JSGlobalObject* lexicalGlobalObject, JSC::BreakpointActionID actionID, unsigned /*batchId*/, unsigned sampleId, JSC::JSValue)
     673{
     674    appendRecord(TimelineRecordFactory::createProbeSampleData(actionID, sampleId), TimelineRecordType::ProbeSample, false, frameFromExecState(lexicalGlobalObject));
    677675}
    678676
  • trunk/Source/WebCore/inspector/agents/InspectorTimelineAgent.h

    r251959 r266074  
    3535#include "InspectorWebAgentBase.h"
    3636#include "LayoutRect.h"
     37#include <JavaScriptCore/Debugger.h>
     38#include <JavaScriptCore/DebuggerPrimitives.h>
    3739#include <JavaScriptCore/InspectorBackendDispatchers.h>
    3840#include <JavaScriptCore/InspectorFrontendDispatchers.h>
    39 #include <JavaScriptCore/ScriptDebugListener.h>
    4041#include <wtf/JSONValues.h>
    4142#include <wtf/Vector.h>
     
    8283};
    8384
    84 class InspectorTimelineAgent final : public InspectorAgentBase , public Inspector::TimelineBackendDispatcherHandler , public Inspector::ScriptDebugListener {
     85class InspectorTimelineAgent final : public InspectorAgentBase , public Inspector::TimelineBackendDispatcherHandler , public JSC::Debugger::Observer {
    8586    WTF_MAKE_NONCOPYABLE(InspectorTimelineAgent);
    8687    WTF_MAKE_FAST_ALLOCATED;
     
    101102    void setInstruments(ErrorString&, const JSON::Array&) override;
    102103
    103     // ScriptDebugListener
    104     void didParseSource(JSC::SourceID, const Script&) override { }
    105     void failedToParseSource(const String&, const String&, int, int, const String&) override { }
    106     void willRunMicrotask() override { }
    107     void didRunMicrotask() override { }
    108     void didPause(JSC::JSGlobalObject*, JSC::JSValue, JSC::JSValue) override { }
    109     void didContinue() override { }
    110     void breakpointActionLog(JSC::JSGlobalObject*, const String&) override { }
    111     void breakpointActionSound(int) override { }
    112     void breakpointActionProbe(JSC::JSGlobalObject*, const Inspector::ScriptBreakpointAction&, unsigned batchId, unsigned sampleId, JSC::JSValue result) override;
     104    // JSC::Debugger::Observer
     105    void breakpointActionProbe(JSC::JSGlobalObject*, JSC::BreakpointActionID, unsigned batchId, unsigned sampleId, JSC::JSValue result) final;
    113106
    114107    // InspectorInstrumentation
  • trunk/Source/WebCore/inspector/agents/page/PageDOMDebuggerAgent.cpp

    r262673 r266074  
    9595
    9696    m_domBreakpoints.clear();
    97     m_pauseOnAllAnimationFramesEnabled = false;
     97
     98    m_pauseOnAllAnimationFramesBreakpoint = nullptr;
    9899
    99100    InspectorDOMDebuggerAgent::disable();
     
    151152            updateSubtreeBreakpoints(child, rootBit, false);
    152153    }
     154}
     155
     156void PageDOMDebuggerAgent::mainFrameNavigated()
     157{
     158    InspectorDOMDebuggerAgent::mainFrameNavigated();
     159
     160    if (m_pauseOnAllAnimationFramesBreakpoint)
     161        m_pauseOnAllAnimationFramesBreakpoint->resetHitCount();
    153162}
    154163
     
    253262        return;
    254263
    255     bool shouldPause = m_debuggerAgent->pauseOnNextStatementEnabled() || m_pauseOnAllAnimationFramesEnabled;
    256     if (!shouldPause)
    257         return;
    258 
    259     m_debuggerAgent->schedulePauseOnNextStatement(Inspector::DebuggerFrontendDispatcher::Reason::AnimationFrame, nullptr);
     264    auto breakpoint = m_pauseOnAllAnimationFramesBreakpoint;
     265    if (!breakpoint)
     266        return;
     267
     268    m_debuggerAgent->schedulePauseForSpecialBreakpoint(*breakpoint, Inspector::DebuggerFrontendDispatcher::Reason::AnimationFrame);
     269}
     270
     271void PageDOMDebuggerAgent::didFireAnimationFrame()
     272{
     273    if (!m_debuggerAgent->breakpointsActive())
     274        return;
     275
     276    auto breakpoint = m_pauseOnAllAnimationFramesBreakpoint;
     277    if (!breakpoint)
     278        return;
     279
     280    m_debuggerAgent->cancelPauseForSpecialBreakpoint(*breakpoint);
    260281}
    261282
     
    272293}
    273294
    274 void PageDOMDebuggerAgent::setAnimationFrameBreakpoint(ErrorString& errorString, bool enabled)
    275 {
    276     if (m_pauseOnAllAnimationFramesEnabled == enabled)
    277         errorString = m_pauseOnAllAnimationFramesEnabled ? "Breakpoint for AnimationFrame already exists"_s : "Breakpoint for AnimationFrame missing"_s;
    278 
    279     m_pauseOnAllAnimationFramesEnabled = enabled;
     295void PageDOMDebuggerAgent::setAnimationFrameBreakpoint(ErrorString& errorString, RefPtr<JSC::Breakpoint>&& breakpoint)
     296{
     297    if (!m_pauseOnAllAnimationFramesBreakpoint == !breakpoint) {
     298        errorString = m_pauseOnAllAnimationFramesBreakpoint ? "Breakpoint for AnimationFrame already exists"_s : "Breakpoint for AnimationFrame missing"_s;
     299        return;
     300    }
     301
     302    m_pauseOnAllAnimationFramesBreakpoint = WTFMove(breakpoint);
    280303}
    281304
  • trunk/Source/WebCore/inspector/agents/page/PageDOMDebuggerAgent.h

    r251871 r266074  
    2727
    2828#include "InspectorDOMDebuggerAgent.h"
     29#include <JavaScriptCore/Breakpoint.h>
     30#include <wtf/RefPtr.h>
    2931
    3032namespace WebCore {
     
    4850
    4951    // InspectorInstrumentation
     52    void mainFrameNavigated() final;
    5053    void frameDocumentUpdated(Frame&);
    5154    void willInsertDOMNode(Node& parent);
     
    5659    void willInvalidateStyleAttr(Element&);
    5760    void willFireAnimationFrame();
     61    void didFireAnimationFrame();
    5862
    5963private:
     
    6165    void disable() override;
    6266
    63     void setAnimationFrameBreakpoint(ErrorString&, bool enabled) override;
     67    void setAnimationFrameBreakpoint(ErrorString&, RefPtr<JSC::Breakpoint>&&) override;
    6468
    6569    void descriptionForDOMEvent(Node&, int breakpointType, bool insertion, JSON::Object& description);
     
    6973
    7074    HashMap<Node*, uint32_t> m_domBreakpoints;
    71     bool m_pauseOnAllAnimationFramesEnabled { false };
     75
     76    RefPtr<JSC::Breakpoint> m_pauseOnAllAnimationFramesBreakpoint;
    7277};
    7378
  • trunk/Source/WebCore/inspector/agents/page/PageDebuggerAgent.cpp

    r262673 r266074  
    9191}
    9292
    93 String PageDebuggerAgent::sourceMapURLForScript(const Script& script)
     93String PageDebuggerAgent::sourceMapURLForScript(const JSC::Debugger::Script& script)
    9494{
    9595    static NeverDestroyed<String> sourceMapHTTPHeader(MAKE_STATIC_STRING_IMPL("SourceMap"));
  • trunk/Source/WebCore/inspector/agents/page/PageDebuggerAgent.h

    r255191 r266074  
    5252    void evaluateOnCallFrame(ErrorString&, const String& callFrameId, const String& expression, const String* objectGroup, const bool* includeCommandLineAPI, const bool* doNotPauseOnExceptionsAndMuteConsole, const bool* returnByValue, const bool* generatePreview, const bool* saveResult, const bool* emulateUserGesture, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result, Optional<bool>& wasThrown, Optional<int>& savedResultIndex) override;
    5353
    54     // ScriptDebugListener
    55     void breakpointActionLog(JSC::JSGlobalObject*, const String&) override;
     54    // JSC::Debugger::Observer
     55    void breakpointActionLog(JSC::JSGlobalObject*, const String& data) final;
    5656
    5757    // InspectorInstrumentation
     
    6868    void disable(bool isBeingDestroyed) override;
    6969
    70     String sourceMapURLForScript(const Script&) override;
     70    String sourceMapURLForScript(const JSC::Debugger::Script&) override;
    7171
    7272    void muteConsole() override;
  • trunk/Source/WebCore/inspector/agents/worker/WorkerDOMDebuggerAgent.cpp

    r249305 r266074  
    4848}
    4949
    50 void WorkerDOMDebuggerAgent::setAnimationFrameBreakpoint(ErrorString& errorString, bool /* enabled */)
     50void WorkerDOMDebuggerAgent::setAnimationFrameBreakpoint(ErrorString& errorString, RefPtr<JSC::Breakpoint>&&)
    5151{
    5252    errorString = "Not supported"_s;
  • trunk/Source/WebCore/inspector/agents/worker/WorkerDOMDebuggerAgent.h

    r250996 r266074  
    2727
    2828#include "InspectorDOMDebuggerAgent.h"
     29#include <JavaScriptCore/Breakpoint.h>
     30#include <wtf/RefPtr.h>
    2931
    3032namespace WebCore {
     
    4244
    4345private:
    44     void setAnimationFrameBreakpoint(ErrorString&, bool enabled) override;
     46    void setAnimationFrameBreakpoint(ErrorString&, RefPtr<JSC::Breakpoint>&&) override;
    4547};
    4648
  • trunk/Source/WebCore/inspector/agents/worker/WorkerDebuggerAgent.h

    r251425 r266074  
    3939    ~WorkerDebuggerAgent() override;
    4040
    41     // ScriptDebugListener
    42     void breakpointActionLog(JSC::JSGlobalObject*, const String&) override;
     41    // JSC::Debugger::Observer
     42    void breakpointActionLog(JSC::JSGlobalObject*, const String& data) final;
    4343
    4444private:
  • trunk/Source/WebCore/page/DOMTimer.cpp

    r264853 r266074  
    285285    Ref<DOMTimer> protectedThis(*this);
    286286
     287    bool oneShot = !repeatInterval();
     288
    287289    ASSERT(scriptExecutionContext());
    288290    ScriptExecutionContext& context = *scriptExecutionContext();
     
    292294        auto& document = downcast<Document>(context);
    293295        if (auto* holdingTank = document.domTimerHoldingTankIfExists(); holdingTank && holdingTank->contains(*this)) {
    294             if (!repeatInterval())
     296            if (oneShot)
    295297                startOneShot(0_s);
    296298            return;
     
    310312    m_userGestureTokenToForward = nullptr;
    311313
    312     InspectorInstrumentation::willFireTimer(context, m_timeoutId, !repeatInterval());
     314    InspectorInstrumentation::willFireTimer(context, m_timeoutId, oneShot);
    313315
    314316    // Simple case for non-one-shot timers.
     
    321323        m_action->execute(context);
    322324
    323         InspectorInstrumentation::didFireTimer(context);
     325        InspectorInstrumentation::didFireTimer(context, m_timeoutId, oneShot);
    324326
    325327        updateThrottlingStateIfNecessary(fireState);
     
    339341    m_action->execute(context);
    340342
    341     InspectorInstrumentation::didFireTimer(context);
     343    InspectorInstrumentation::didFireTimer(context, m_timeoutId, oneShot);
    342344
    343345    // Check if we should throttle nested single-shot timers.
  • trunk/Source/WebInspectorUI/ChangeLog

    r266072 r266074  
     12020-08-24  Devin Rousso  <drousso@apple.com>
     2
     3        Web Inspector: allow event breakpoints to be configured
     4        https://bugs.webkit.org/show_bug.cgi?id=215362
     5        <rdar://problem/66932921>
     6
     7        Reviewed by Brian Burg.
     8
     9        This allows developers to do things like:
     10         - only pause when `window.event.type` is a certain value
     11         - ignore the first N pauses
     12         - evaluate JavaScript whenever an event listener is invoked without pausing
     13
     14        * UserInterface/Models/Breakpoint.js:
     15        (WI.Breakpoint):
     16        (WI.Breakpoint.prototype.toJSON):
     17        (WI.Breakpoint.prototype.get special): Added.
     18        (WI.Breakpoint.prototype.get removable): Added.
     19        (WI.Breakpoint.prototype.get editable): Added.
     20        (WI.Breakpoint.prototype.set condition):
     21        (WI.Breakpoint.prototype.get ignoreCount):
     22        (WI.Breakpoint.prototype.set ignoreCount):
     23        (WI.Breakpoint.prototype.get autoContinue):
     24        (WI.Breakpoint.prototype.set autoContinue):
     25        (WI.Breakpoint.prototype.get actions):
     26        (WI.Breakpoint.prototype.get probeActions):
     27        (WI.Breakpoint.prototype.cycleToNextMode):
     28        (WI.Breakpoint.prototype.createAction):
     29        (WI.Breakpoint.prototype.recreateAction):
     30        (WI.Breakpoint.prototype.removeAction):
     31        (WI.Breakpoint.prototype.clearActions):
     32        (WI.Breakpoint.prototype.remove): Added.
     33        (WI.Breakpoint.prototype.optionsToProtocol): Added.
     34        (WI.Breakpoint.prototype.breakpointActionDidChange):
     35        (WI.Breakpoint.fromJSON): Deleted.
     36        (WI.Breakpoint.prototype.get sourceCodeLocation): Deleted.
     37        (WI.Breakpoint.prototype.get contentIdentifier): Deleted.
     38        (WI.Breakpoint.prototype.get scriptIdentifier): Deleted.
     39        (WI.Breakpoint.prototype.get target): Deleted.
     40        (WI.Breakpoint.prototype.get identifier): Deleted.
     41        (WI.Breakpoint.prototype.set identifier): Deleted.
     42        (WI.Breakpoint.prototype.get resolved): Deleted.
     43        (WI.Breakpoint.prototype.set resolved): Deleted.
     44        (WI.Breakpoint.prototype.saveIdentityToCookie): Deleted.
     45        (WI.Breakpoint.prototype._isSpecial): Deleted.
     46        (WI.Breakpoint.prototype._sourceCodeLocationLocationChanged): Deleted.
     47        (WI.Breakpoint.prototype._sourceCodeLocationDisplayLocationChanged): Deleted.
     48        * UserInterface/Models/DOMBreakpoint.js:
     49        (WI.DOMBreakpoint):
     50        (WI.DOMBreakpoint.fromJSON): Added.
     51        (WI.DOMBreakpoint.prototype.remove): Added.
     52        (WI.DOMBreakpoint.prototype.toJSON):
     53        (WI.DOMBreakpoint.deserialize): Deleted.
     54        (WI.DOMBreakpoint.prototype.get disabled): Deleted.
     55        (WI.DOMBreakpoint.prototype.set disabled): Deleted.
     56        * UserInterface/Models/EventBreakpoint.js:
     57        (WI.EventBreakpoint):
     58        (WI.EventBreakpoint.fromJSON): Added.
     59        (WI.EventBreakpoint.prototype.get special): Added.
     60        (WI.EventBreakpoint.prototype.get editable): Added.
     61        (WI.EventBreakpoint.prototype.remove): Added.
     62        (WI.EventBreakpoint.prototype.saveIdentityToCookie):
     63        (WI.EventBreakpoint.prototype.toJSON):
     64        (WI.EventBreakpoint.deserialize): Deleted.
     65        (WI.EventBreakpoint.prototype.get disabled): Deleted.
     66        (WI.EventBreakpoint.prototype.set disabled): Deleted.
     67        * UserInterface/Models/JavaScriptBreakpoint.js: Copied from UserInterface/Models/Breakpoint.js.
     68        (WI.JavaScriptBreakpoint):
     69        (WI.JavaScriptBreakpoint.fromJSON):
     70        (WI.JavaScriptBreakpoint.prototype.toJSON):
     71        (WI.JavaScriptBreakpoint.prototype.get sourceCodeLocation):
     72        (WI.JavaScriptBreakpoint.prototype.get contentIdentifier):
     73        (WI.JavaScriptBreakpoint.prototype.get scriptIdentifier):
     74        (WI.JavaScriptBreakpoint.prototype.get target):
     75        (WI.JavaScriptBreakpoint.prototype.get special): Added.
     76        (WI.JavaScriptBreakpoint.prototype.get removable): Added.
     77        (WI.JavaScriptBreakpoint.prototype.get editable): Added.
     78        (WI.JavaScriptBreakpoint.prototype.get identifier):
     79        (WI.JavaScriptBreakpoint.prototype.set identifier):
     80        (WI.JavaScriptBreakpoint.prototype.get resolved):
     81        (WI.JavaScriptBreakpoint.prototype.set resolved):
     82        (WI.JavaScriptBreakpoint.prototype.remove): Added.
     83        (WI.JavaScriptBreakpoint.prototype.saveIdentityToCookie):
     84        (WI.JavaScriptBreakpoint.prototype._isSpecial):
     85        (WI.JavaScriptBreakpoint.prototype._sourceCodeLocationLocationChanged):
     86        (WI.JavaScriptBreakpoint.prototype._sourceCodeLocationDisplayLocationChanged):
     87        * UserInterface/Models/URLBreakpoint.js:
     88        (WI.URLBreakpoint):
     89        (WI.URLBreakpoint.fromJSON): Added.
     90        (WI.URLBreakpoint.prototype.get special): Added.
     91        (WI.URLBreakpoint.prototype.remove): Added.
     92        (WI.URLBreakpoint.prototype.toJSON):
     93        (WI.URLBreakpoint.deserialize): Deleted.
     94        (WI.URLBreakpoint.prototype.get disabled): Deleted.
     95        (WI.URLBreakpoint.prototype.set disabled): Deleted.
     96        Rename `WI.Breakpoint` to `WI.JavaScriptBreakpoint` and use `WI.Breakpoint` as a new common
     97        base class for all breakpoint types, allowing more logic to be shared (e.g. disabled state).
     98        Additionally, breakpoints are now able to
     99         - determine whether or not they're
     100            - special
     101            - removable
     102            - editable (i.e. configurable)
     103         - remove themselves
     104        without the caller needing to know what manager to consult with.
     105
     106        * UserInterface/Controllers/DOMManager.js:
     107        (WI.DOMManager):
     108        (WI.DOMManager.supportsEventListenerBreakpointConfiguration): Added.
     109        (WI.DOMManager.prototype.setBreakpointForEventListener):
     110        (WI.DOMManager.prototype.removeBreakpointForEventListener):
     111        (WI.DOMManager.prototype._setEventBreakpoint): Added.
     112        (WI.DOMManager.prototype._removeEventBreakpoint): Added.
     113        (WI.DOMManager.prototype._handleEventBreakpointEditablePropertyChanged): Added.
     114        (WI.DOMManager.prototype._handleEventBreakpointActionsChanged): Added.
     115        (WI.DOMManager.prototype._updateEventBreakpoint): Deleted.
     116        Keep track of configuration changes for specific listener breakpoints.
     117
     118        * UserInterface/Controllers/DOMDebuggerManager.js:
     119        (WI.DOMDebuggerManager):
     120        (WI.DOMDebuggerManager.prototype.initializeTarget):
     121        (WI.DOMDebuggerManager.prototype.addDOMBreakpoint):
     122        (WI.DOMDebuggerManager.prototype.removeDOMBreakpoint):
     123        (WI.DOMDebuggerManager.prototype.addEventBreakpoint):
     124        (WI.DOMDebuggerManager.prototype.removeEventBreakpoint):
     125        (WI.DOMDebuggerManager.prototype.addURLBreakpoint):
     126        (WI.DOMDebuggerManager.prototype.removeURLBreakpoint):
     127        (WI.DOMDebuggerManager.prototype._commandArgumentsForEventBreakpoint): Added.
     128        (WI.DOMDebuggerManager.prototype._setEventBreakpoint): Added.
     129        (WI.DOMDebuggerManager.prototype._removeEventBreakpoint): Added.
     130        (WI.DOMDebuggerManager.prototype._handleEventBreakpointDisabledStateChanged): Added.
     131        (WI.DOMDebuggerManager.prototype._handleEventBreakpointEditablePropertyChanged): Added.
     132        (WI.DOMDebuggerManager.prototype._handleEventBreakpointActionsChanged): Added.
     133        (WI.DOMDebuggerManager.prototype.isBreakpointSpecial): Deleted.
     134        (WI.DOMDebuggerManager.prototype._updateEventBreakpoint): Deleted.
     135        Keep track of configuration changes for special event breakpoints.
     136        Store special event breakpoints inside `WI.objectStores.eventBreakpoints`.
     137
     138        * UserInterface/Controllers/DebuggerManager.js:
     139        (WI.DebuggerManager):
     140        (WI.DebuggerManager.prototype.addBreakpoint):
     141        (WI.DebuggerManager.prototype.removeBreakpoint):
     142        (WI.DebuggerManager.prototype.addProbesForBreakpoint): Added.
     143        (WI.DebuggerManager.prototype.removeProbesForBreakpoint): Added.
     144        (WI.DebuggerManager.prototype.updateProbesForBreakpoint): Added.
     145        (WI.DebuggerManager.prototype._setBreakpoint):
     146        (WI.DebuggerManager.prototype._breakpointEditablePropertyDidChange):
     147        (WI.DebuggerManager.prototype._handleBreakpointActionsDidChange):
     148        (WI.DebuggerManager.prototype.isBreakpointRemovable): Deleted.
     149        (WI.DebuggerManager.prototype.isBreakpointSpecial): Deleted.
     150        (WI.DebuggerManager.prototype.isBreakpointEditable): Deleted.
     151        (WI.DebuggerManager.prototype._debuggerBreakpointActionType): Deleted.
     152        (WI.DebuggerManager.prototype._debuggerBreakpointOptions): Deleted.
     153        (WI.DebuggerManager.prototype._addProbesForBreakpoint): Deleted.
     154        (WI.DebuggerManager.prototype._removeProbesForBreakpoint): Deleted.
     155        (WI.DebuggerManager.prototype._updateProbesForBreakpoint): Deleted.
     156        Replace `WI.Breakpoint` with `WI.JavaScriptBreakpoint`.
     157        Probes now support `WI.EventBreakpoint` in addition to `WI.JavaScriptBreakpoint`.
     158
     159        * UserInterface/Controllers/BreakpointPopoverController.js:
     160        (WI.BreakpointPopoverController.prototype.appendContextMenuItems):
     161        (WI.BreakpointPopoverController.prototype._createPopoverContent):
     162        Allow any breakpoint instead of only `WI.JavaScriptBreakpoint`.
     163        Drive-by: the existing `ignoreCount` value wasn't being used to populate the `<input>`.
     164
     165        * UserInterface/Views/BreakpointTreeElement.js:
     166        (WI.BreakpointTreeElement.prototype.ondelete):
     167        (WI.BreakpointTreeElement.prototype.get listenerSet): Added.
     168        (WI.BreakpointTreeElement.prototype.updateStatus): Added.
     169        (WI.BreakpointTreeElement.prototype.updateTitles): Added.
     170        (WI.BreakpointTreeElement.prototype.get breakpoint): Deleted.
     171        (WI.BreakpointTreeElement.prototype.get filterableData): Deleted.
     172        (WI.BreakpointTreeElement.prototype._updateTitles): Deleted.
     173        (WI.BreakpointTreeElement.prototype._updateStatus): Deleted.
     174        (WI.BreakpointTreeElement.prototype._breakpointLocationDidChange): Deleted.
     175        * UserInterface/Views/BreakpointTreeElement.css:
     176        (.item.breakpoint .status > .status-image):
     177        (.item.breakpoint.paused .icon): Added.
     178        (@media (prefers-color-scheme: dark) .item.breakpoint.paused .icon): Added.
     179        (.item.breakpoint .status > .status-image.resolved): Deleted.
     180        (body:not(.window-inactive, .window-docked-inactive) .tree-outline:focus-within .item.breakpoint.selected .status > .status-image.resolved): Deleted.
     181        (.item.breakpoint .subtitle.formatted-location): Deleted.
     182        (.breakpoint-debugger-statement-icon .icon): Deleted.
     183        (.breakpoint-exception-icon .icon): Deleted.
     184        (.breakpoint-assertion-icon .icon): Deleted.
     185        (.breakpoint-microtask-icon .icon): Deleted.
     186        (.breakpoint-paused-icon .icon): Deleted.
     187        (.breakpoint-generic-line-icon .icon): Deleted.
     188        (.breakpoint-generic-line-icon .icon > span): Deleted.
     189        (.data-updated.breakpoint-generic-line-icon .icon > span): Deleted.
     190        (@media (prefers-color-scheme: dark) .breakpoint-debugger-statement-icon .icon): Deleted.
     191        (@media (prefers-color-scheme: dark) .breakpoint-exception-icon .icon): Deleted.
     192        (@media (prefers-color-scheme: dark) .breakpoint-assertion-icon .icon): Deleted.
     193        (@media (prefers-color-scheme: dark) .breakpoint-microtask-icon .icon): Deleted.
     194        (@media (prefers-color-scheme: dark) .breakpoint-paused-icon .icon): Deleted.
     195        (@media (prefers-color-scheme: dark) .breakpoint-generic-line-icon .icon): Deleted.
     196        * UserInterface/Views/DOMBreakpointTreeElement.js:
     197        (WI.DOMBreakpointTreeElement):
     198        (WI.DOMBreakpointTreeElement.prototype.onattach): Deleted.
     199        (WI.DOMBreakpointTreeElement.prototype.ondetach): Deleted.
     200        (WI.DOMBreakpointTreeElement.prototype.ondelete): Deleted.
     201        (WI.DOMBreakpointTreeElement.prototype.onenter): Deleted.
     202        (WI.DOMBreakpointTreeElement.prototype.onspace): Deleted.
     203        (WI.DOMBreakpointTreeElement.prototype.populateContextMenu): Deleted.
     204        (WI.DOMBreakpointTreeElement.prototype._statusImageElementClicked): Deleted.
     205        (WI.DOMBreakpointTreeElement.prototype._statusImageElementFocused): Deleted.
     206        (WI.DOMBreakpointTreeElement.prototype._statusImageElementMouseDown): Deleted.
     207        (WI.DOMBreakpointTreeElement.prototype._toggleBreakpoint): Deleted.
     208        (WI.DOMBreakpointTreeElement.prototype._updateStatus): Deleted.
     209        * UserInterface/Views/DOMBreakpointTreeElement.css:
     210        (.item.breakpoint.dom.subtree-modified:not(.paused) .icon): Added.
     211        (.item.breakpoint.dom.attribute-modified:not(.paused) .icon): Added.
     212        (.item.breakpoint.dom.node-removed:not(.paused) .icon): Added.
     213        (@media (prefers-color-scheme: dark) .item.breakpoint.dom.subtree-modified:not(.paused) .icon): Added.
     214        (@media (prefers-color-scheme: dark) .item.breakpoint.dom.attribute-modified:not(.paused) .icon): Added.
     215        (@media (prefers-color-scheme: dark) .item.breakpoint.dom.node-removed:not(.paused) .icon): Added.
     216        (.breakpoint.dom.breakpoint-for-subtree-modified:not(.breakpoint-paused-icon) .icon): Deleted.
     217        (.breakpoint.dom.breakpoint-for-attribute-modified:not(.breakpoint-paused-icon) .icon): Deleted.
     218        (.breakpoint.dom.breakpoint-for-node-removed:not(.breakpoint-paused-icon) .icon): Deleted.
     219        (@media (prefers-color-scheme: dark) .breakpoint.dom.breakpoint-for-subtree-modified:not(.breakpoint-paused-icon) .icon): Deleted.
     220        (@media (prefers-color-scheme: dark) .breakpoint.dom.breakpoint-for-attribute-modified:not(.breakpoint-paused-icon) .icon): Deleted.
     221        (@media (prefers-color-scheme: dark) .breakpoint.dom.breakpoint-for-node-removed:not(.breakpoint-paused-icon) .icon): Deleted.
     222        * UserInterface/Views/EventBreakpointTreeElement.js:
     223        (WI.EventBreakpointTreeElement):
     224        (WI.EventBreakpointTreeElement.prototype.onattach): Deleted.
     225        (WI.EventBreakpointTreeElement.prototype.ondetach): Deleted.
     226        (WI.EventBreakpointTreeElement.prototype.ondelete): Deleted.
     227        (WI.EventBreakpointTreeElement.prototype.onenter): Deleted.
     228        (WI.EventBreakpointTreeElement.prototype.onspace): Deleted.
     229        (WI.EventBreakpointTreeElement.prototype.populateContextMenu): Deleted.
     230        (WI.EventBreakpointTreeElement.prototype._statusImageElementClicked): Deleted.
     231        (WI.EventBreakpointTreeElement.prototype._statusImageElementFocused): Deleted.
     232        (WI.EventBreakpointTreeElement.prototype._statusImageElementMouseDown): Deleted.
     233        (WI.EventBreakpointTreeElement.prototype._toggleBreakpoint): Deleted.
     234        (WI.EventBreakpointTreeElement.prototype._updateStatus): Deleted.
     235        * UserInterface/Views/EventBreakpointTreeElement.css:
     236        (.item.breakpoint.event.animation-frame:not(.paused) .icon): Added.
     237        (.item.breakpoint.event.interval:not(.paused) .icon): Added.
     238        (.item.breakpoint.event.listener:not(.paused) .icon): Added.
     239        (.item.breakpoint.event.timeout:not(.paused) .icon): Added.
     240        (@media(prefers-color-scheme: dark) .item.breakpoint.event.animation-frame:not(.paused) .icon): Added.
     241        (@media(prefers-color-scheme: dark) .item.breakpoint.event.interval:not(.paused) .icon): Added.
     242        (@media(prefers-color-scheme: dark) .item.breakpoint.event.listener:not(.paused) .icon): Added.
     243        (@media(prefers-color-scheme: dark) .item.breakpoint.event.timeout:not(.paused) .icon): Added.
     244        (.breakpoint.event.breakpoint-for-animation-frame:not(.breakpoint-paused-icon) .icon): Deleted.
     245        (.breakpoint.event.breakpoint-for-interval:not(.breakpoint-paused-icon) .icon): Deleted.
     246        (.breakpoint.event.breakpoint-for-listener:not(.breakpoint-paused-icon) .icon): Deleted.
     247        (.breakpoint.event.breakpoint-for-timeout:not(.breakpoint-paused-icon) .icon): Deleted.
     248        (@media(prefers-color-scheme: dark) .breakpoint.event.breakpoint-for-animation-frame:not(.breakpoint-paused-icon) .icon): Deleted.
     249        (@media(prefers-color-scheme: dark) .breakpoint.event.breakpoint-for-interval:not(.breakpoint-paused-icon) .icon): Deleted.
     250        (@media(prefers-color-scheme: dark) .breakpoint.event.breakpoint-for-listener:not(.breakpoint-paused-icon) .icon): Deleted.
     251        (@media(prefers-color-scheme: dark) .breakpoint.event.breakpoint-for-timeout:not(.breakpoint-paused-icon) .icon): Deleted.
     252        * UserInterface/Views/JavaScriptBreakpointTreeElement.js: Copied from Source/WebInspectorUI/UserInterface/Views/BreakpointTreeElement.js.
     253        (WI.JavaScriptBreakpointTreeElement):
     254        (WI.JavaScriptBreakpointTreeElement.prototype.get filterableData):
     255        (WI.JavaScriptBreakpointTreeElement.prototype.updateStatus): Added.
     256        (WI.JavaScriptBreakpointTreeElement.prototype.updateTitles): Added.
     257        (WI.JavaScriptBreakpointTreeElement.prototype._breakpointLocationDidChange):
     258        * UserInterface/Views/JavaScriptBreakpointTreeElement.css: Copied from Source/WebInspectorUI/UserInterface/Views/BreakpointTreeElement.css.
     259        (.item.breakpoint.javascript .status > .status-image): Added.
     260        (.item.breakpoint.javascript .status > .status-image.resolved): Added.
     261        (body:not(.window-inactive, .window-docked-inactive) .tree-outline:focus-within .item.breakpoint.javascript.selected .status > .status-image.resolved): Added.
     262        (.item.breakpoint.javascript .subtitle.formatted-location): Added.
     263        (.item.breakpoint.javascript.line .icon): Added.
     264        (.item.breakpoint.javascript.line .icon > span): Added.
     265        (.data-updated.item.breakpoint.javascript.line .icon > span): Added.
     266        (.item.breakpoint.javascript.debugger-statement .icon): Added.
     267        (.item.breakpoint.javascript.exception .icon): Added.
     268        (.item.breakpoint.javascript.assertion .icon): Added.
     269        (.item.breakpoint.javascript.microtask .icon): Added.
     270        (@media (prefers-color-scheme: dark) .item.breakpoint.javascript.line .icon): Added.
     271        (@media (prefers-color-scheme: dark) .item.breakpoint.javascript.debugger-statement .icon): Added.
     272        (@media (prefers-color-scheme: dark) .item.breakpoint.javascript.exception .icon): Added.
     273        (@media (prefers-color-scheme: dark) .item.breakpoint.javascript.assertion .icon): Added.
     274        (@media (prefers-color-scheme: dark) .item.breakpoint.javascript.microtask .icon): Added.
     275        * UserInterface/Views/URLBreakpointTreeElement.js:
     276        (WI.URLBreakpointTreeElement):
     277        (WI.URLBreakpointTreeElement.prototype.onattach): Deleted.
     278        (WI.URLBreakpointTreeElement.prototype.ondetach): Deleted.
     279        (WI.URLBreakpointTreeElement.prototype.ondelete): Deleted.
     280        (WI.URLBreakpointTreeElement.prototype.onenter): Deleted.
     281        (WI.URLBreakpointTreeElement.prototype.onspace): Deleted.
     282        (WI.URLBreakpointTreeElement.prototype.populateContextMenu): Deleted.
     283        (WI.URLBreakpointTreeElement.prototype._statusImageElementClicked): Deleted.
     284        (WI.URLBreakpointTreeElement.prototype._statusImageElementFocused): Deleted.
     285        (WI.URLBreakpointTreeElement.prototype._statusImageElementMouseDown): Deleted.
     286        (WI.URLBreakpointTreeElement.prototype._toggleBreakpoint): Deleted.
     287        (WI.URLBreakpointTreeElement.prototype._updateStatus): Deleted.
     288        * UserInterface/Views/URLBreakpointTreeElement.css:
     289        (.item.breakpoint.url .subtitle): Added.
     290        (.item.breakpoint.url:not(.paused) .icon): Added.
     291        (@media (prefers-color-scheme: dark) .item.breakpoint.url:not(.paused) .icon): Added.
     292        (.breakpoint.url .subtitle): Deleted.
     293        (.breakpoint.url:not(.breakpoint-paused-icon) .icon): Deleted.
     294        (@media (prefers-color-scheme: dark) .breakpoint.url:not(.breakpoint-paused-icon) .icon): Deleted.
     295        Rename `WI.BreakpointTreeElement` to `WI.JavaScriptBreakpointTreeElement` and use
     296        `WI.BreakpointTreeElement` as a new common base class for all breakpoint tree elements,
     297        allowing more logic and styles to be shared (e.g. disabled state).
     298
     299        * UserInterface/Views/SourcesNavigationSidebarPanel.js:
     300        (WI.SourcesNavigationSidebarPanel):
     301        (WI.SourcesNavigationSidebarPanel.prototype.closed):
     302        (WI.SourcesNavigationSidebarPanel.prototype._insertDebuggerTreeElement):
     303        (WI.SourcesNavigationSidebarPanel.prototype._compareJavaScriptBreakpointTreeElements): Added.
     304        (WI.SourcesNavigationSidebarPanel.prototype._addBreakpoint):
     305        (WI.SourcesNavigationSidebarPanel.prototype._removeAllBreakpoints):
     306        (WI.SourcesNavigationSidebarPanel.prototype._breakpointsBeneathTreeElement):
     307        (WI.SourcesNavigationSidebarPanel.prototype._addIssue):
     308        (WI.SourcesNavigationSidebarPanel.prototype._updatePauseReasonSection):
     309        (WI.SourcesNavigationSidebarPanel.prototype._handleTreeSelectionDidChange):
     310        (WI.SourcesNavigationSidebarPanel.prototype._handleBreakpointElementAddedOrRemoved):
     311        (WI.SourcesNavigationSidebarPanel.prototype._populateCreateBreakpointContextMenu.addToggleForSpecialEventBreakpoint):
     312        (WI.SourcesNavigationSidebarPanel.prototype._populateCreateBreakpointContextMenu):
     313        (WI.SourcesNavigationSidebarPanel.prototype._handleDebuggerObjectDisplayLocationDidChange):
     314        (WI.SourcesNavigationSidebarPanel.prototype._compareBreakpointTreeElements): Deleted.
     315
     316        * UserInterface/Models/ProbeSet.js:
     317        (WI.ProbeSet):
     318        (WI.ProbeSet.prototype.createProbe):
     319        (WI.ProbeSet.prototype.willRemove):
     320        * UserInterface/Controllers/TimelineManager.js:
     321        (WI.TimelineManager.prototype._processRecord):
     322        * UserInterface/Views/ProbeSetDetailsSection.js:
     323        (WI.ProbeSetDetailsSection):
     324        * UserInterface/Views/ProbeDetailsSidebarPanel.js:
     325        (WI.ProbeDetailsSidebarPanel.prototype.inspect):
     326        * UserInterface/Views/SourceCodeTextEditor.js:
     327        (WI.SourceCodeTextEditor):
     328        (WI.SourceCodeTextEditor.prototype.close):
     329        (WI.SourceCodeTextEditor.prototype.textEditorBreakpointAdded):
     330        * UserInterface/Views/TextResourceContentView.js:
     331        (WI.TextResourceContentView.prototype.get supplementalRepresentedObjects):
     332        (WI.TextResourceContentView.prototype._probeSetsChanged):
     333        Probes now support `WI.EventBreakpoint` in addition to `WI.JavaScriptBreakpoint`.
     334
     335        * UserInterface/Views/ContentView.js:
     336        (WI.ContentView.createFromRepresentedObject):
     337        (WI.ContentView.resolvedRepresentedObjectForRepresentedObject):
     338        (WI.ContentView.isViewable):
     339        * UserInterface/Views/ContextMenuUtilities.js:
     340        (WI.appendContextMenuItemsForSourceCode):
     341        Replace `WI.Breakpoint` with `WI.JavaScriptBreakpoint`.
     342
     343        * UserInterface/Views/DOMTreeContentView.js:
     344        (WI.DOMTreeContentView):
     345        Replace `WI.DOMBreakpoint` with `WI.Breakpoint`.
     346
     347        * UserInterface/Views/EventListenerSectionGroup.js:
     348        (WI.EventListenerSectionGroup):
     349        * UserInterface/Views/EventListenerSectionGroup.css:
     350        (.event-listener-section > .content input[type="checkbox"] + .go-to-arrow): Added.
     351        (.event-listener-section > .content input[type="checkbox"]:not(:checked) + .go-to-arrow): Added.
     352        Add a go-to arrow next to the Breakpoint checkbox that reveals the `WI.EventBreakpoint` in
     353        the Sources Tab.
     354
     355        * UserInterface/Views/BreakpointActionView.js:
     356        (WI.BreakpointActionView.prototype._appendActionButtonClicked):
     357        Drive-by: minor code cleanup.
     358
     359        * UserInterface/Views/CallFrameTreeElement.js:
     360        (WI.CallFrameTreeElement.prototype.populateContextMenu):
     361        Drive-by: include source code location context menu items.
     362
     363        * UserInterface/Base/Setting.js:
     364        * UserInterface/Main.html:
     365        * UserInterface/Test.html:
     366
    13672020-08-24  Devin Rousso  <drousso@apple.com>
    2368
  • trunk/Source/WebInspectorUI/UserInterface/Base/Setting.js

    r259929 r266074  
    198198    selectedNetworkDetailContentViewIdentifier: new WI.Setting("network-detail-content-view-identifier", "preview"),
    199199    sourceMapsEnabled: new WI.Setting("source-maps-enabled", true),
    200     showAllAnimationFramesBreakpoint: new WI.Setting("show-all-animation-frames-breakpoint", false),
    201     showAllIntervalsBreakpoint: new WI.Setting("show-all-inteverals-breakpoint", false),
    202     showAllListenersBreakpoint: new WI.Setting("show-all-listeners-breakpoint", false),
    203200    showAllMicrotasksBreakpoint: new WI.Setting("show-all-microtasks-breakpoint", false),
    204201    showAllRequestsBreakpoint: new WI.Setting("show-all-requests-breakpoint", false),
    205     showAllTimeoutsBreakpoint: new WI.Setting("show-all-timeouts-breakpoint", false),
    206202    showAssertionFailuresBreakpoint: new WI.Setting("show-assertion-failures-breakpoint", true),
    207203    showCanvasPath: new WI.Setting("show-canvas-path", false),
  • trunk/Source/WebInspectorUI/UserInterface/Controllers/BreakpointPopoverController.js

    r261109 r266074  
    4141        console.assert(document.body.contains(breakpointDisplayElement), "Breakpoint popover display element must be in the DOM.");
    4242
    43         const editBreakpoint = () => {
    44             console.assert(!this._popover, "Breakpoint popover already exists.");
    45             if (this._popover)
    46                 return;
    47 
    48             this._createPopoverContent(breakpoint);
    49             this._popover = new WI.Popover(this);
    50             this._popover.content = this._popoverContentElement;
    51 
    52             let bounds = WI.Rect.rectFromClientRect(breakpointDisplayElement.getBoundingClientRect());
    53             bounds.origin.x -= 1; // Move the anchor left one pixel so it looks more centered.
    54             this._popover.present(bounds.pad(2), [WI.RectEdge.MAX_Y]);
    55         };
    56 
    57         const removeBreakpoint = () => {
    58             WI.debuggerManager.removeBreakpoint(breakpoint);
    59         };
    60 
    61         const toggleBreakpoint = () => {
    62             breakpoint.disabled = !breakpoint.disabled;
    63         };
    64 
    65         const toggleAutoContinue = () => {
    66             breakpoint.autoContinue = !breakpoint.autoContinue;
    67         };
    68 
    69         const revealOriginalSourceCodeLocation = () => {
    70             const options = {
    71                 ignoreNetworkTab: true,
    72                 ignoreSearchTab: true,
    73             };
    74             WI.showOriginalOrFormattedSourceCodeLocation(breakpoint.sourceCodeLocation, options);
    75         };
    76 
    77         if (WI.debuggerManager.isBreakpointEditable(breakpoint))
    78             contextMenu.appendItem(WI.UIString("Edit Breakpoint\u2026"), editBreakpoint);
    79 
    80         if (breakpoint.autoContinue && !breakpoint.disabled) {
    81             contextMenu.appendItem(WI.UIString("Disable Breakpoint"), toggleBreakpoint);
    82             contextMenu.appendItem(WI.UIString("Cancel Automatic Continue"), toggleAutoContinue);
    83         } else if (!breakpoint.disabled)
    84             contextMenu.appendItem(WI.UIString("Disable Breakpoint"), toggleBreakpoint);
    85         else
    86             contextMenu.appendItem(WI.UIString("Enable Breakpoint"), toggleBreakpoint);
    87 
    88         if (!breakpoint.autoContinue && !breakpoint.disabled && breakpoint.actions.length)
    89             contextMenu.appendItem(WI.UIString("Set to Automatically Continue"), toggleAutoContinue);
    90 
    91         if (WI.debuggerManager.isBreakpointRemovable(breakpoint))
    92             contextMenu.appendItem(WI.UIString("Delete Breakpoint"), removeBreakpoint);
    93 
    94         if (breakpoint._sourceCodeLocation.hasMappedLocation()) {
     43        if (breakpoint.editable) {
     44            contextMenu.appendItem(WI.UIString("Edit Breakpoint\u2026"), () => {
     45                console.assert(!this._popover, "Breakpoint popover already exists.");
     46                if (this._popover)
     47                    return;
     48
     49                this._createPopoverContent(breakpoint);
     50                this._popover = new WI.Popover(this);
     51                this._popover.content = this._popoverContentElement;
     52
     53                let bounds = WI.Rect.rectFromClientRect(breakpointDisplayElement.getBoundingClientRect());
     54                bounds.origin.x -= 1; // Move the anchor left one pixel so it looks more centered.
     55                this._popover.present(bounds.pad(2), [WI.RectEdge.MAX_Y]);
     56            });
     57        }
     58
     59        if (!breakpoint.disabled) {
     60            contextMenu.appendItem(WI.UIString("Disable Breakpoint"), () => {
     61                breakpoint.disabled = !breakpoint.disabled;
     62            });
     63
     64            if (breakpoint.editable && breakpoint.autoContinue) {
     65                contextMenu.appendItem(WI.UIString("Cancel Automatic Continue"), () => {
     66                    breakpoint.autoContinue = !breakpoint.autoContinue;
     67                });
     68            }
     69        } else {
     70            contextMenu.appendItem(WI.UIString("Enable Breakpoint"), () => {
     71                breakpoint.disabled = !breakpoint.disabled;
     72            });
     73        }
     74
     75        if (breakpoint.editable && !breakpoint.autoContinue && !breakpoint.disabled && breakpoint.actions.length) {
     76            contextMenu.appendItem(WI.UIString("Set to Automatically Continue"), () => {
     77                breakpoint.autoContinue = !breakpoint.autoContinue;
     78            });
     79        }
     80
     81        if (breakpoint.removable) {
     82            contextMenu.appendItem(WI.UIString("Delete Breakpoint"), () => {
     83                breakpoint.remove();
     84            });
     85        }
     86
     87        if (breakpoint instanceof WI.JavaScriptBreakpoint && breakpoint.sourceCodeLocation.hasMappedLocation()) {
    9588            contextMenu.appendSeparator();
    96             contextMenu.appendItem(WI.UIString("Reveal in Original Resource"), revealOriginalSourceCodeLocation);
     89            contextMenu.appendItem(WI.UIString("Reveal in Original Resource"), () => {
     90                const options = {
     91                    ignoreNetworkTab: true,
     92                    ignoreSearchTab: true,
     93                };
     94                WI.showOriginalOrFormattedSourceCodeLocation(breakpoint.sourceCodeLocation, options);
     95            });
    9796        }
    9897    }
     
    125124        checkboxLabel.className = "toggle";
    126125        checkboxLabel.appendChild(checkboxElement);
    127         checkboxLabel.append(this._breakpoint.sourceCodeLocation.displayLocationString());
     126        if (this._breakpoint instanceof WI.JavaScriptBreakpoint)
     127            checkboxLabel.append(this._breakpoint.sourceCodeLocation.displayLocationString());
     128        else if (this._breakpoint instanceof WI.EventBreakpoint) {
     129            let displayName;
     130            if (breakpoint === WI.domDebuggerManager.allAnimationFramesBreakpoint)
     131                displayName = WI.UIString("All Animation Frames");
     132            else if (breakpoint === WI.domDebuggerManager.allIntervalsBreakpoint)
     133                displayName = WI.UIString("All Intervals");
     134            else if (breakpoint === WI.domDebuggerManager.allListenersBreakpoint)
     135                displayName = WI.UIString("All Events");
     136            else if (breakpoint === WI.domDebuggerManager.allTimeoutsBreakpoint)
     137                displayName = WI.UIString("All Timeouts");
     138            else
     139                displayName = breakpoint.eventName;
     140            checkboxLabel.appendChild(document.createTextNode(displayName));
     141        }
    128142
    129143        let table = document.createElement("table");
     
    177191        this._ignoreCountInput.type = "number";
    178192        this._ignoreCountInput.min = 0;
    179         this._ignoreCountInput.value = 0;
     193        this._ignoreCountInput.value = breakpoint.ignoreCount;
    180194        this._ignoreCountInput.addEventListener("change", this._popoverIgnoreInputChanged.bind(this));
    181195
  • trunk/Source/WebInspectorUI/UserInterface/Controllers/DOMDebuggerManager.js

    r261340 r266074  
    3434
    3535        this._listenerBreakpoints = [];
     36        this._allAnimationFramesBreakpoint = null;
     37        this._allIntervalsBreakpoint = null;
     38        this._allListenersBreakpoint = null;
     39        this._allTimeoutsBreakpoint = null;
     40
    3641        this._urlBreakpoints = [];
    37 
    38         this._allAnimationFramesBreakpointEnabledSetting = new WI.Setting("break-on-all-animation-frames", false);
    39         this._allAnimationFramesBreakpoint = new WI.EventBreakpoint(WI.EventBreakpoint.Type.AnimationFrame, {
    40             disabled: !this._allAnimationFramesBreakpointEnabledSetting.value,
    41         });
    42 
    43         this._allIntervalsBreakpointEnabledSetting = new WI.Setting("break-on-all-intervals", false);
    44         this._allIntervalsBreakpoint = new WI.EventBreakpoint(WI.EventBreakpoint.Type.Interval, {
    45             disabled: !this._allIntervalsBreakpointEnabledSetting.value,
    46         });
    47 
    48         this._allListenersBreakpointEnabledSetting = new WI.Setting("break-on-all-listeners", false);
    49         this._allListenersBreakpoint = new WI.EventBreakpoint(WI.EventBreakpoint.Type.Listener, {
    50             disabled: !this._allListenersBreakpointEnabledSetting.value,
    51         });
    52 
    53         this._allTimeoutsBreakpointEnabledSetting = new WI.Setting("break-on-all-timeouts", false);
    54         this._allTimeoutsBreakpoint = new WI.EventBreakpoint(WI.EventBreakpoint.Type.Timeout, {
    55             disabled: !this._allTimeoutsBreakpointEnabledSetting.value,
    56         });
    5742
    5843        this._allRequestsBreakpointEnabledSetting = new WI.Setting("break-on-all-requests", false);
     
    6146        });
    6247
    63         WI.DOMBreakpoint.addEventListener(WI.DOMBreakpoint.Event.DisabledStateChanged, this._handleDOMBreakpointDisabledStateChanged, this);
    64         WI.EventBreakpoint.addEventListener(WI.EventBreakpoint.Event.DisabledStateChanged, this._handleEventBreakpointDisabledStateChanged, this);
    65         WI.URLBreakpoint.addEventListener(WI.URLBreakpoint.Event.DisabledStateChanged, this._handleURLBreakpointDisabledStateChanged, this);
     48        WI.DOMBreakpoint.addEventListener(WI.Breakpoint.Event.DisabledStateDidChange, this._handleDOMBreakpointDisabledStateChanged, this);
     49
     50        WI.EventBreakpoint.addEventListener(WI.Breakpoint.Event.DisabledStateDidChange, this._handleEventBreakpointDisabledStateChanged, this);
     51        WI.EventBreakpoint.addEventListener(WI.Breakpoint.Event.ConditionDidChange, this._handleEventBreakpointEditablePropertyChanged, this);
     52        WI.EventBreakpoint.addEventListener(WI.Breakpoint.Event.IgnoreCountDidChange, this._handleEventBreakpointEditablePropertyChanged, this);
     53        WI.EventBreakpoint.addEventListener(WI.Breakpoint.Event.AutoContinueDidChange, this._handleEventBreakpointEditablePropertyChanged, this);
     54        WI.EventBreakpoint.addEventListener(WI.Breakpoint.Event.ActionsDidChange, this._handleEventBreakpointActionsChanged, this);
     55
     56        WI.URLBreakpoint.addEventListener(WI.Breakpoint.Event.DisabledStateDidChange, this._handleURLBreakpointDisabledStateChanged, this);
    6657
    6758        WI.domManager.addEventListener(WI.DOMManager.Event.NodeRemoved, this._nodeRemoved, this);
     
    7970                    if (existingSerializedBreakpoints) {
    8071                        for (let existingSerializedBreakpoint of existingSerializedBreakpoints)
    81                             await objectStore.putObject(constructor.deserialize(existingSerializedBreakpoint));
     72                            await objectStore.putObject(constructor.fromJSON(existingSerializedBreakpoint));
    8273                    }
    8374                }
     
    8778                this._restoringBreakpoints = true;
    8879                for (let serializedBreakpoint of serializedBreakpoints) {
    89                     let breakpoint = constructor.deserialize(serializedBreakpoint);
     80                    let breakpoint = constructor.fromJSON(serializedBreakpoint);
    9081
    9182                    const key = null;
     
    10697        if (DOMDebuggerManager.supportsEventBreakpoints() || DOMDebuggerManager.supportsEventListenerBreakpoints()) {
    10798            loadBreakpoints(WI.EventBreakpoint, WI.objectStores.eventBreakpoints, ["event-breakpoints"], (breakpoint) => {
    108                 // Migrate `requestAnimationFrame`, `setTimeout`, and `setInterval` global breakpoints.
    109                 switch (breakpoint.type) {
    110                 case WI.EventBreakpoint.Type.AnimationFrame:
    111                     this._allAnimationFramesBreakpoint.disabled = breakpoint.disabled;
    112                     if (!WI.settings.showAllAnimationFramesBreakpoint.value) {
    113                         WI.settings.showAllAnimationFramesBreakpoint.value = true;
    114                         this.addEventBreakpoint(this._allAnimationFramesBreakpoint);
    115                     }
    116                     WI.objectStores.eventBreakpoints.deleteObject(breakpoint);
    117                     return;
    118 
    119                 case WI.EventBreakpoint.Type.Timer:
    120                     switch (breakpoint.eventName) {
    121                     case "setTimeout":
    122                         this._allTimeoutsBreakpoint.disabled = breakpoint.disabled;
    123                         if (!WI.settings.showAllTimeoutsBreakpoint.value) {
    124                             WI.settings.showAllTimeoutsBreakpoint.value = true;
    125                             this.addEventBreakpoint(this._allTimeoutsBreakpoint);
    126                         }
    127                         break;
    128 
    129                     case "setInterval":
    130                         this._allIntervalsBreakpoint.disabled = breakpoint.disabled;
    131                         if (!WI.settings.showAllIntervalsBreakpoint.value) {
    132                             WI.settings.showAllIntervalsBreakpoint.value = true;
    133                             this.addEventBreakpoint(this._allIntervalsBreakpoint);
    134                         }
    135                         break;
    136                     }
    137 
    138                     WI.objectStores.eventBreakpoints.deleteObject(breakpoint);
    139                     return;
    140                 }
    141 
    14299                this.addEventBreakpoint(breakpoint);
    143100            });
     101
     102            let loadLegacyGlobalEventBreakpoint = (type, shownSettingsKey, enabledSettingsKey) => {
     103                if (!WI.Setting.migrateValue(shownSettingsKey))
     104                    return;
     105
     106                return new WI.EventBreakpoint(type, {
     107                    disabled: !WI.Setting.migrateValue(enabledSettingsKey),
     108                });
     109            };
     110            this._allAnimationFramesBreakpoint ??= loadLegacyGlobalEventBreakpoint(WI.EventBreakpoint.Type.AnimationFrame, "show-all-animation-frames-breakpoint", "break-on-all-animation-frames");
     111            this._allIntervalsBreakpoint ??= loadLegacyGlobalEventBreakpoint(WI.EventBreakpoint.Type.Interval, "show-all-inteverals-breakpoint", "break-on-all-intervals");
     112            this._allListenersBreakpoint ??= loadLegacyGlobalEventBreakpoint(WI.EventBreakpoint.Type.Listener, "show-all-listeners-breakpoint", "break-on-all-listeners");
     113            this._allTimeoutsBreakpoint ??= loadLegacyGlobalEventBreakpoint(WI.EventBreakpoint.Type.Timeout, "show-all-timeouts-breakpoint", "break-on-all-timeouts");
    144114        }
    145115
     
    161131                this._speculativelyResolveDOMBreakpointsForURL(target.mainResource.url);
    162132
    163             if (!this._allAnimationFramesBreakpoint.disabled)
    164                 this._updateEventBreakpoint(this._allAnimationFramesBreakpoint, target);
    165 
    166             if (!this._allIntervalsBreakpoint.disabled)
    167                 this._updateEventBreakpoint(this._allIntervalsBreakpoint, target);
    168 
    169             if (!this._allListenersBreakpoint.disabled)
    170                 this._updateEventBreakpoint(this._allListenersBreakpoint, target);
    171 
    172             if (!this._allTimeoutsBreakpoint.disabled)
    173                 this._updateEventBreakpoint(this._allTimeoutsBreakpoint, target);
     133            if (this._allAnimationFramesBreakpoint && !this._allAnimationFramesBreakpoint.disabled)
     134                this._setEventBreakpoint(this._allAnimationFramesBreakpoint, target);
     135
     136            if (this._allIntervalsBreakpoint && !this._allIntervalsBreakpoint.disabled)
     137                this._setEventBreakpoint(this._allIntervalsBreakpoint, target);
     138
     139            if (this._allListenersBreakpoint && !this._allListenersBreakpoint.disabled)
     140                this._setEventBreakpoint(this._allListenersBreakpoint, target);
     141
     142            if (this._allTimeoutsBreakpoint && !this._allTimeoutsBreakpoint.disabled)
     143                this._setEventBreakpoint(this._allTimeoutsBreakpoint, target);
    174144
    175145            if (!this._allRequestsBreakpoint.disabled)
     
    178148            for (let breakpoint of this._listenerBreakpoints) {
    179149                if (!breakpoint.disabled)
    180                     this._updateEventBreakpoint(breakpoint, target);
     150                    this._setEventBreakpoint(breakpoint, target);
    181151            }
    182152
     
    270240    get listenerBreakpoints() { return this._listenerBreakpoints; }
    271241    get urlBreakpoints() { return this._urlBreakpoints; }
    272 
    273     isBreakpointSpecial(breakpoint)
    274     {
    275         return breakpoint === this._allAnimationFramesBreakpoint
    276             || breakpoint === this._allIntervalsBreakpoint
    277             || breakpoint === this._allListenersBreakpoint
    278             || breakpoint === this._allTimeoutsBreakpoint
    279             || breakpoint === this._allRequestsBreakpoint;
    280     }
    281242
    282243    domBreakpointsForNode(node)
     
    320281            return;
    321282
    322         if (this.isBreakpointSpecial(breakpoint)) {
     283        if (breakpoint.special) {
    323284            this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.DOMBreakpointAdded, {breakpoint});
    324285            return;
     
    342303            return;
    343304
    344         if (this.isBreakpointSpecial(breakpoint)) {
     305        if (breakpoint.special) {
    345306            breakpoint.disabled = true;
    346307            this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.DOMBreakpointRemoved, {breakpoint});
     
    384345            return false;
    385346
    386         if (this.isBreakpointSpecial(breakpoint)) {
    387             this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.EventBreakpointAdded, {breakpoint});
    388             return true;
    389         }
    390 
    391         console.assert(breakpoint.type === WI.EventBreakpoint.Type.Listener, breakpoint);
    392         console.assert(breakpoint.eventName, breakpoint);
    393 
    394         if (this._listenerBreakpoints.find((existing) => existing.eventName === breakpoint.eventName))
    395             return false;
    396 
    397         this._listenerBreakpoints.push(breakpoint);
     347        console.assert(!breakpoint.special, breakpoint);
     348
     349        switch (breakpoint.type) {
     350        case WI.EventBreakpoint.Type.AnimationFrame:
     351            console.assert(!this._allAnimationFramesBreakpoint, this._allAnimationFramesBreakpoint, breakpoint);
     352            this._allAnimationFramesBreakpoint = breakpoint;
     353            break;
     354
     355        case WI.EventBreakpoint.Type.Interval:
     356            console.assert(!this._allIntervalsBreakpoint, this._allIntervalsBreakpoint, breakpoint);
     357            this._allIntervalsBreakpoint = breakpoint;
     358            break;
     359
     360        case WI.EventBreakpoint.Type.Listener:
     361            if (breakpoint.eventName) {
     362                if (this._listenerBreakpoints.find((existing) => existing.eventName === breakpoint.eventName))
     363                    return false;
     364
     365                this._listenerBreakpoints.push(breakpoint);
     366            } else {
     367                console.assert(!this._allListenersBreakpoint, this._allListenersBreakpoint, breakpoint);
     368                this._allListenersBreakpoint = breakpoint;
     369            }
     370            break;
     371
     372        case WI.EventBreakpoint.Type.Timeout:
     373            console.assert(!this._allTimeoutsBreakpoint, this._allTimeoutsBreakpoint, breakpoint);
     374            this._allTimeoutsBreakpoint = breakpoint;
     375            break;
     376        }
     377
     378        WI.debuggerManager.addProbesForBreakpoint(breakpoint);
    398379
    399380        this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.EventBreakpointAdded, {breakpoint});
     
    401382        if (!breakpoint.disabled) {
    402383            for (let target of WI.targets)
    403                 this._updateEventBreakpoint(breakpoint, target);
     384                this._setEventBreakpoint(breakpoint, target);
    404385        }
    405386
     
    416397            return;
    417398
    418         if (this.isBreakpointSpecial(breakpoint)) {
    419             breakpoint.disabled = true;
    420             this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.EventBreakpointRemoved, {breakpoint});
    421             return;
    422         }
    423 
    424         console.assert(breakpoint.type === WI.EventBreakpoint.Type.Listener, breakpoint);
    425         console.assert(breakpoint.eventName, breakpoint);
    426 
    427         console.assert(this._listenerBreakpoints.includes(breakpoint), breakpoint);
    428         if (!this._listenerBreakpoints.includes(breakpoint))
    429             return;
    430 
    431         this._listenerBreakpoints.remove(breakpoint);
     399        // Disable the breakpoint first, so removing actions doesn't re-add the breakpoint.
     400        breakpoint.disabled = true;
     401        breakpoint.clearActions();
     402
     403        switch (breakpoint.type) {
     404        case WI.EventBreakpoint.Type.AnimationFrame:
     405            console.assert(this._allAnimationFramesBreakpoint, this._allAnimationFramesBreakpoint);
     406            this._allAnimationFramesBreakpoint = null;
     407            break;
     408
     409        case WI.EventBreakpoint.Type.Interval:
     410            console.assert(this._allIntervalsBreakpoint, this._allIntervalsBreakpoint);
     411            this._allIntervalsBreakpoint = null;
     412            break;
     413
     414        case WI.EventBreakpoint.Type.Listener:
     415            if (breakpoint.eventName) {
     416                console.assert(this._listenerBreakpoints.includes(breakpoint), breakpoint);
     417                if (!this._listenerBreakpoints.includes(breakpoint))
     418                    return;
     419
     420                this._listenerBreakpoints.remove(breakpoint);
     421            } else {
     422                console.assert(this._allListenersBreakpoint, this._allListenersBreakpoint);
     423                this._allListenersBreakpoint = null;
     424            }
     425            break;
     426
     427        case WI.EventBreakpoint.Type.Timeout:
     428            console.assert(this._allTimeoutsBreakpoint, this._allTimeoutsBreakpoint);
     429            this._allTimeoutsBreakpoint = null;
     430            break;
     431        }
    432432
    433433        if (!this._restoringBreakpoints)
    434434            WI.objectStores.eventBreakpoints.deleteObject(breakpoint);
    435435
     436        WI.debuggerManager.removeProbesForBreakpoint(breakpoint);
     437
    436438        this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.EventBreakpointRemoved, {breakpoint});
    437 
    438         if (breakpoint.disabled)
    439             return;
    440 
    441         for (let target of WI.targets) {
    442             // COMPATIBILITY (iOS 12): DOMDebugger.removeEventBreakpoint did not exist.
    443             if (target.hasCommand("DOMDebugger.removeEventBreakpoint"))
    444                 target.DOMDebuggerAgent.removeEventBreakpoint(breakpoint.type, breakpoint.eventName);
    445             else if (target.hasCommand("DOMDebugger.removeEventListenerBreakpoint")) {
    446                 console.assert(breakpoint.type === WI.EventBreakpoint.Type.Listener);
    447                 target.DOMDebuggerAgent.removeEventListenerBreakpoint(breakpoint.eventName);
    448             }
    449         }
    450439    }
    451440
     
    461450            return false;
    462451
    463         if (this.isBreakpointSpecial(breakpoint)) {
     452        if (breakpoint.special) {
    464453            this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.URLBreakpointAdded, {breakpoint});
    465454            return true;
     
    494483            return;
    495484
    496         if (this.isBreakpointSpecial(breakpoint)) {
     485        if (breakpoint.special) {
    497486            breakpoint.disabled = true;
    498487            this.dispatchEventToListeners(WI.DOMDebuggerManager.Event.URLBreakpointRemoved, {breakpoint});
     
    633622    }
    634623
    635     _updateEventBreakpoint(breakpoint, target)
    636     {
    637         // Worker targets do not support `requestAnimationFrame` breakpoints.
    638         if (breakpoint === this._allAnimationFramesBreakpoint && target.type === WI.TargetType.Worker)
    639             return;
    640 
    641         // COMPATIBILITY (iOS 12): DOMDebugger.removeEventBreakpoint did not exist.
    642         if (target.hasCommand("DOMDebugger.setEventListenerBreakpoint") && target.hasCommand("DOMDebugger.removeEventListenerBreakpoint")) {
    643             console.assert(breakpoint.type === WI.EventBreakpoint.Type.Listener);
    644             if (breakpoint.disabled)
    645                 target.DOMDebuggerAgent.removeEventListenerBreakpoint(breakpoint.eventName);
    646             else {
    647                 if (!this._restoringBreakpoints && !WI.debuggerManager.breakpointsDisabledTemporarily)
    648                     WI.debuggerManager.breakpointsEnabled = true;
    649 
    650                 target.DOMDebuggerAgent.setEventListenerBreakpoint(breakpoint.eventName);
    651             }
    652             return;
    653         }
    654 
    655         if (!target.hasCommand("DOMDebugger.setEventBreakpoint") || !target.hasCommand("DOMDebugger.removeEventBreakpoint"))
    656             return;
    657 
     624    _commandArgumentsForEventBreakpoint(breakpoint)
     625    {
    658626        let commandArguments = {};
    659627
     
    697665        }
    698666
    699         const callback = null;
    700 
    701         if (breakpoint.disabled)
    702             target.DOMDebuggerAgent.removeEventBreakpoint.invoke(commandArguments, callback);
    703         else {
     667        return commandArguments;
     668    }
     669
     670    _setEventBreakpoint(breakpoint, target)
     671    {
     672        console.assert(!breakpoint.disabled, breakpoint);
     673
     674        // Worker targets do not support `requestAnimationFrame` breakpoints.
     675        if (breakpoint === this._allAnimationFramesBreakpoint && target.type === WI.TargetType.Worker)
     676            return;
     677
     678        // COMPATIBILITY (iOS 12): DOMDebugger.setEventBreakpoint did not exist.
     679        if (target.hasCommand("DOMDebugger.setEventListenerBreakpoint")) {
     680            console.assert(breakpoint.type === WI.EventBreakpoint.Type.Listener);
     681
    704682            if (!this._restoringBreakpoints && !WI.debuggerManager.breakpointsDisabledTemporarily)
    705683                WI.debuggerManager.breakpointsEnabled = true;
    706684
    707             target.DOMDebuggerAgent.setEventBreakpoint.invoke(commandArguments, callback);
    708         }
     685            target.DOMDebuggerAgent.setEventListenerBreakpoint(breakpoint.eventName);
     686            return;
     687        }
     688
     689        if (!target.hasCommand("DOMDebugger.setEventBreakpoint"))
     690            return;
     691
     692        let commandArguments = this._commandArgumentsForEventBreakpoint(breakpoint);
     693
     694        if (!this._restoringBreakpoints && !WI.debuggerManager.breakpointsDisabledTemporarily)
     695            WI.debuggerManager.breakpointsEnabled = true;
     696
     697        commandArguments.options = breakpoint.optionsToProtocol();
     698
     699        target.DOMDebuggerAgent.setEventBreakpoint.invoke(commandArguments);
     700    }
     701
     702    _removeEventBreakpoint(breakpoint, target)
     703    {
     704        // Worker targets do not support `requestAnimationFrame` breakpoints.
     705        if (breakpoint === this._allAnimationFramesBreakpoint && target.type === WI.TargetType.Worker)
     706            return;
     707
     708        // COMPATIBILITY (iOS 12): DOMDebugger.removeEventBreakpoint did not exist.
     709        if (target.hasCommand("DOMDebugger.removeEventListenerBreakpoint")) {
     710            console.assert(breakpoint.type === WI.EventBreakpoint.Type.Listener);
     711            target.DOMDebuggerAgent.removeEventListenerBreakpoint(breakpoint.eventName);
     712            return;
     713        }
     714
     715        if (!target.hasCommand("DOMDebugger.removeEventBreakpoint"))
     716            return;
     717
     718        let commandArguments = this._commandArgumentsForEventBreakpoint(breakpoint);
     719
     720        target.DOMDebuggerAgent.removeEventBreakpoint.invoke(commandArguments);
    709721    }
    710722
     
    758770            return;
    759771
    760         for (let target of WI.targets)
    761             this._updateEventBreakpoint(breakpoint, target);
    762 
    763         switch (breakpoint) {
    764         case this._allAnimationFramesBreakpoint:
    765             this._allAnimationFramesBreakpointEnabledSetting.value = !breakpoint.disabled;
    766             return;
    767 
    768         case this._allIntervalsBreakpoint:
    769             this._allIntervalsBreakpointEnabledSetting.value = !breakpoint.disabled;
    770             return;
    771 
    772         case this._allListenersBreakpoint:
    773             this._allListenersBreakpointEnabledSetting.value = !breakpoint.disabled;
    774             return;
    775 
    776         case this._allTimeoutsBreakpoint:
    777             this._allTimeoutsBreakpointEnabledSetting.value = !breakpoint.disabled;
    778             return;
     772        for (let target of WI.targets) {
     773            if (breakpoint.disabled)
     774                this._removeEventBreakpoint(breakpoint, target);
     775            else
     776                this._setEventBreakpoint(breakpoint, target);
    779777        }
    780778
    781779        if (!this._restoringBreakpoints)
    782780            WI.objectStores.eventBreakpoints.putObject(breakpoint);
     781    }
     782
     783    _handleEventBreakpointEditablePropertyChanged(event)
     784    {
     785        let breakpoint = event.target;
     786
     787        // Specific event listener breakpoints are handled by `DOMManager`.
     788        if (breakpoint.eventListener)
     789            return;
     790
     791        if (!this._restoringBreakpoints)
     792            WI.objectStores.eventBreakpoints.putObject(breakpoint);
     793
     794        if (breakpoint.disabled)
     795            return;
     796
     797        for (let target of WI.targets) {
     798            // Clear the old breakpoint from the backend before setting the new one.
     799            this._removeEventBreakpoint(breakpoint, target)
     800            this._setEventBreakpoint(breakpoint, target);
     801        }
     802    }
     803
     804    _handleEventBreakpointActionsChanged(event)
     805    {
     806        let breakpoint = event.target;
     807
     808        // Specific event listener breakpoints are handled by `DOMManager`.
     809        if (breakpoint.eventListener)
     810            return;
     811
     812        this._handleEventBreakpointEditablePropertyChanged(event);
     813
     814        WI.debuggerManager.updateProbesForBreakpoint(breakpoint);
    783815    }
    784816
  • trunk/Source/WebInspectorUI/UserInterface/Controllers/DOMManager.js

    r262302 r266074  
    5151        this._pendingDocumentRequestCallbacks = null;
    5252
    53         WI.EventBreakpoint.addEventListener(WI.EventBreakpoint.Event.DisabledStateChanged, this._handleEventBreakpointDisabledStateChanged, this);
     53        WI.EventBreakpoint.addEventListener(WI.Breakpoint.Event.DisabledStateDidChange, this._handleEventBreakpointDisabledStateChanged, this);
     54        WI.EventBreakpoint.addEventListener(WI.Breakpoint.Event.ConditionDidChange, this._handleEventBreakpointEditablePropertyChanged, this);
     55        WI.EventBreakpoint.addEventListener(WI.Breakpoint.Event.IgnoreCountDidChange, this._handleEventBreakpointEditablePropertyChanged, this);
     56        WI.EventBreakpoint.addEventListener(WI.Breakpoint.Event.AutoContinueDidChange, this._handleEventBreakpointEditablePropertyChanged, this);
     57        WI.EventBreakpoint.addEventListener(WI.Breakpoint.Event.ActionsDidChange, this._handleEventBreakpointActionsChanged, this);
    5458
    5559        WI.Frame.addEventListener(WI.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this);
     
    125129        return InspectorBackend.hasCommand("DOM.setBreakpointForEventListener")
    126130            && InspectorBackend.hasCommand("DOM.removeBreakpointForEventListener");
     131    }
     132
     133    static supportsEventListenerBreakpointConfiguration()
     134    {
     135        // COMPATIBILITY (iOS 14): DOM.setBreakpointForEventListener did not have an "options" parameter yet.
     136        return InspectorBackend.hasCommand("DOM.setBreakpointForEventListener", "options");
    127137    }
    128138
     
    665675        for (let target of WI.targets) {
    666676            if (target.hasDomain("DOM"))
    667                 this._updateEventBreakpoint(breakpoint, target);
    668         }
     677                this._setEventBreakpoint(breakpoint, target);
     678        }
     679
     680        WI.debuggerManager.addProbesForBreakpoint(breakpoint);
    669681
    670682        WI.domDebuggerManager.dispatchEventToListeners(WI.DOMDebuggerManager.Event.EventBreakpointAdded, {breakpoint});
     
    680692                target.DOMAgent.removeBreakpointForEventListener(eventListener.eventListenerId);
    681693        }
     694
     695        // Disable the breakpoint first, so removing actions doesn't re-add the breakpoint.
     696        breakpoint.disabled = true;
     697        breakpoint.clearActions();
     698
     699        WI.debuggerManager.removeProbesForBreakpoint(breakpoint);
    682700
    683701        WI.domDebuggerManager.dispatchEventToListeners(WI.DOMDebuggerManager.Event.EventBreakpointRemoved, {breakpoint});
     
    700718    // Private
    701719
    702     _updateEventBreakpoint(breakpoint, target)
    703     {
     720    _setEventBreakpoint(breakpoint, target)
     721    {
     722        console.assert(!breakpoint.disabled, breakpoint);
     723
    704724        let eventListener = breakpoint.eventListener;
    705725        console.assert(eventListener);
    706726
    707         if (breakpoint.disabled)
    708             target.DOMAgent.removeBreakpointForEventListener(eventListener.eventListenerId);
    709         else {
    710727            if (!WI.debuggerManager.breakpointsDisabledTemporarily)
    711728                WI.debuggerManager.breakpointsEnabled = true;
    712729
    713             target.DOMAgent.setBreakpointForEventListener(eventListener.eventListenerId);
    714         }
     730        target.DOMAgent.setBreakpointForEventListener.invoke({
     731            eventListenerId: eventListener.eventListenerId,
     732            options: breakpoint.optionsToProtocol(),
     733        });
     734    }
     735
     736    _removeEventBreakpoint(breakpoint, target)
     737    {
     738        let eventListener = breakpoint.eventListener;
     739        console.assert(eventListener);
     740
     741        target.DOMAgent.removeBreakpointForEventListener(eventListener.eventListenerId);
    715742    }
    716743
     
    724751
    725752        for (let target of WI.targets) {
    726             if (target.hasDomain("DOM"))
    727                 this._updateEventBreakpoint(breakpoint, target);
    728         }
     753            if (!target.hasDomain("DOM"))
     754                continue;
     755
     756            if (breakpoint.disabled)
     757                this._removeEventBreakpoint(breakpoint, target);
     758            else
     759                this._setEventBreakpoint(breakpoint, target);
     760        }
     761    }
     762
     763    _handleEventBreakpointEditablePropertyChanged(event)
     764    {
     765        let breakpoint = event.target;
     766
     767        // Non-specific event listener breakpoints are handled by `DOMDebuggerManager`.
     768        if (!breakpoint.eventListener)
     769            return;
     770
     771        if (breakpoint.disabled)
     772            return;
     773
     774        for (let target of WI.targets) {
     775            // Clear the old breakpoint from the backend before setting the new one.
     776            this._removeEventBreakpoint(breakpoint, target);
     777            this._setEventBreakpoint(breakpoint, target);
     778        }
     779    }
     780
     781    _handleEventBreakpointActionsChanged(event)
     782    {
     783        let breakpoint = event.target;
     784
     785        // Non-specific event listener breakpoints are handled by `DOMDebuggerManager`.
     786        if (!breakpoint.eventListener)
     787            return;
     788
     789        this._handleEventBreakpointEditablePropertyChanged(event);
     790
     791        WI.debuggerManager.updateProbesForBreakpoint(breakpoint);
    729792    }
    730793
  • trunk/Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js

    r261109 r266074  
    3030        super();
    3131
    32         WI.Breakpoint.addEventListener(WI.Breakpoint.Event.DisplayLocationDidChange, this._breakpointDisplayLocationDidChange, this);
    33         WI.Breakpoint.addEventListener(WI.Breakpoint.Event.DisabledStateDidChange, this._breakpointDisabledStateDidChange, this);
    34         WI.Breakpoint.addEventListener(WI.Breakpoint.Event.ConditionDidChange, this._breakpointEditablePropertyDidChange, this);
    35         WI.Breakpoint.addEventListener(WI.Breakpoint.Event.IgnoreCountDidChange, this._breakpointEditablePropertyDidChange, this);
    36         WI.Breakpoint.addEventListener(WI.Breakpoint.Event.AutoContinueDidChange, this._breakpointEditablePropertyDidChange, this);
    37         WI.Breakpoint.addEventListener(WI.Breakpoint.Event.ActionsDidChange, this._handleBreakpointActionsDidChange, this);
     32        WI.JavaScriptBreakpoint.addEventListener(WI.Breakpoint.Event.DisabledStateDidChange, this._breakpointDisabledStateDidChange, this);
     33        WI.JavaScriptBreakpoint.addEventListener(WI.Breakpoint.Event.ConditionDidChange, this._breakpointEditablePropertyDidChange, this);
     34        WI.JavaScriptBreakpoint.addEventListener(WI.Breakpoint.Event.IgnoreCountDidChange, this._breakpointEditablePropertyDidChange, this);
     35        WI.JavaScriptBreakpoint.addEventListener(WI.Breakpoint.Event.AutoContinueDidChange, this._breakpointEditablePropertyDidChange, this);
     36        WI.JavaScriptBreakpoint.addEventListener(WI.Breakpoint.Event.ActionsDidChange, this._handleBreakpointActionsDidChange, this);
     37        WI.JavaScriptBreakpoint.addEventListener(WI.JavaScriptBreakpoint.Event.DisplayLocationDidChange, this._breakpointDisplayLocationDidChange, this);
    3838
    3939        WI.timelineManager.addEventListener(WI.TimelineManager.Event.CapturingStateChanged, this._handleTimelineCapturingStateChanged, this);
     
    5757
    5858        this._debuggerStatementsBreakpointEnabledSetting = new WI.Setting("break-on-debugger-statements", true);
    59         this._debuggerStatementsBreakpoint = new WI.Breakpoint(specialBreakpointLocation, {
     59        this._debuggerStatementsBreakpoint = new WI.JavaScriptBreakpoint(specialBreakpointLocation, {
    6060            disabled: !this._debuggerStatementsBreakpointEnabledSetting.value,
    6161        });
     
    6363
    6464        this._allExceptionsBreakpointEnabledSetting = new WI.Setting("break-on-all-exceptions", false);
    65         this._allExceptionsBreakpoint = new WI.Breakpoint(specialBreakpointLocation, {
     65        this._allExceptionsBreakpoint = new WI.JavaScriptBreakpoint(specialBreakpointLocation, {
    6666            disabled: !this._allExceptionsBreakpointEnabledSetting.value,
    6767        });
     
    6969
    7070        this._uncaughtExceptionsBreakpointEnabledSetting = new WI.Setting("break-on-uncaught-exceptions", false);
    71         this._uncaughtExceptionsBreakpoint = new WI.Breakpoint(specialBreakpointLocation, {
     71        this._uncaughtExceptionsBreakpoint = new WI.JavaScriptBreakpoint(specialBreakpointLocation, {
    7272            disabled: !this._uncaughtExceptionsBreakpointEnabledSetting.value,
    7373        });
     
    7575
    7676        this._assertionFailuresBreakpointEnabledSetting = new WI.Setting("break-on-assertion-failures", false);
    77         this._assertionFailuresBreakpoint = new WI.Breakpoint(specialBreakpointLocation, {
     77        this._assertionFailuresBreakpoint = new WI.JavaScriptBreakpoint(specialBreakpointLocation, {
    7878            disabled: !this._assertionFailuresBreakpointEnabledSetting.value,
    7979        });
     
    8181
    8282        this._allMicrotasksBreakpointEnabledSetting = new WI.Setting("break-on-all-microtasks", false);
    83         this._allMicrotasksBreakpoint = new WI.Breakpoint(specialBreakpointLocation, {
     83        this._allMicrotasksBreakpoint = new WI.JavaScriptBreakpoint(specialBreakpointLocation, {
    8484            disabled: !this._allMicrotasksBreakpointEnabledSetting.value,
    8585        });
     
    127127            if (existingSerializedBreakpoints) {
    128128                for (let existingSerializedBreakpoint of existingSerializedBreakpoints)
    129                     await WI.objectStores.breakpoints.putObject(WI.Breakpoint.fromJSON(existingSerializedBreakpoint));
     129                    await WI.objectStores.breakpoints.putObject(WI.JavaScriptBreakpoint.fromJSON(existingSerializedBreakpoint));
    130130            }
    131131
     
    134134            this._restoringBreakpoints = true;
    135135            for (let serializedBreakpoint of serializedBreakpoints) {
    136                 let breakpoint = WI.Breakpoint.fromJSON(serializedBreakpoint);
     136                let breakpoint = WI.JavaScriptBreakpoint.fromJSON(serializedBreakpoint);
    137137
    138138                const key = null;
     
    343343    }
    344344
    345     isBreakpointRemovable(breakpoint)
    346     {
    347         return breakpoint !== this._debuggerStatementsBreakpoint
    348             && breakpoint !== this._allExceptionsBreakpoint
    349             && breakpoint !== this._uncaughtExceptionsBreakpoint;
    350     }
    351 
    352     isBreakpointSpecial(breakpoint)
    353     {
    354         return !this.isBreakpointRemovable(breakpoint)
    355             || breakpoint === this._assertionFailuresBreakpoint
    356             || breakpoint === this._allMicrotasksBreakpoint;
    357     }
    358 
    359     isBreakpointEditable(breakpoint)
    360     {
    361         return !this.isBreakpointSpecial(breakpoint);
    362     }
    363 
    364345    get breakpointsEnabled()
    365346    {
     
    660641    addBreakpoint(breakpoint)
    661642    {
    662         console.assert(breakpoint instanceof WI.Breakpoint);
     643        console.assert(breakpoint instanceof WI.JavaScriptBreakpoint);
    663644        if (!breakpoint)
    664645            return;
    665646
    666         if (this.isBreakpointSpecial(breakpoint)) {
     647        if (breakpoint.special) {
    667648            this.dispatchEventToListeners(WI.DebuggerManager.Event.BreakpointAdded, {breakpoint});
    668649            return;
     
    683664            WI.objectStores.breakpoints.putObject(breakpoint);
    684665
    685         this._addProbesForBreakpoint(breakpoint);
     666        this.addProbesForBreakpoint(breakpoint);
    686667
    687668        this.dispatchEventToListeners(WI.DebuggerManager.Event.BreakpointAdded, {breakpoint});
     
    690671    removeBreakpoint(breakpoint)
    691672    {
    692         console.assert(breakpoint instanceof WI.Breakpoint);
     673        console.assert(breakpoint instanceof WI.JavaScriptBreakpoint);
    693674        if (!breakpoint)
    694675            return;
    695676
    696         console.assert(this.isBreakpointRemovable(breakpoint));
    697         if (!this.isBreakpointRemovable(breakpoint))
    698             return;
    699 
    700         if (this.isBreakpointSpecial(breakpoint)) {
     677        console.assert(breakpoint.removable);
     678        if (!breakpoint.removable)
     679            return;
     680
     681        if (breakpoint.special) {
    701682            breakpoint.disabled = true;
    702683            this.dispatchEventToListeners(WI.DebuggerManager.Event.BreakpointRemoved, {breakpoint});
     
    722703            WI.objectStores.breakpoints.deleteObject(breakpoint);
    723704
    724         this._removeProbesForBreakpoint(breakpoint);
     705        this.removeProbesForBreakpoint(breakpoint);
    725706
    726707        this.dispatchEventToListeners(WI.DebuggerManager.Event.BreakpointRemoved, {breakpoint});
     
    730711    {
    731712        return this._nextBreakpointActionIdentifier++;
     713    }
     714
     715    addProbesForBreakpoint(breakpoint)
     716    {
     717        if (this._knownProbeIdentifiersForBreakpoint.has(breakpoint))
     718            return;
     719
     720        this._knownProbeIdentifiersForBreakpoint.set(breakpoint, new Set);
     721
     722        this.updateProbesForBreakpoint(breakpoint);
     723    }
     724
     725    removeProbesForBreakpoint(breakpoint)
     726    {
     727        console.assert(this._knownProbeIdentifiersForBreakpoint.has(breakpoint));
     728
     729        this.updateProbesForBreakpoint(breakpoint);
     730        this._knownProbeIdentifiersForBreakpoint.delete(breakpoint);
     731    }
     732
     733    updateProbesForBreakpoint(breakpoint)
     734    {
     735        let knownProbeIdentifiers = this._knownProbeIdentifiersForBreakpoint.get(breakpoint);
     736        if (!knownProbeIdentifiers) {
     737            // Sometimes actions change before the added breakpoint is fully dispatched.
     738            this.addProbesForBreakpoint(breakpoint);
     739            return;
     740        }
     741
     742        let seenProbeIdentifiers = new Set;
     743
     744        for (let probeAction of breakpoint.probeActions) {
     745            let probeIdentifier = probeAction.id;
     746            console.assert(probeIdentifier, "Probe added without breakpoint action identifier: ", breakpoint);
     747
     748            seenProbeIdentifiers.add(probeIdentifier);
     749            if (!knownProbeIdentifiers.has(probeIdentifier)) {
     750                // New probe; find or create relevant probe set.
     751                knownProbeIdentifiers.add(probeIdentifier);
     752                let probeSet = this._probeSetForBreakpoint(breakpoint);
     753                let newProbe = new WI.Probe(probeIdentifier, breakpoint, probeAction.data);
     754                this._probesByIdentifier.set(probeIdentifier, newProbe);
     755                probeSet.addProbe(newProbe);
     756                break;
     757            }
     758
     759            let probe = this._probesByIdentifier.get(probeIdentifier);
     760            console.assert(probe, "Probe known but couldn't be found by identifier: ", probeIdentifier);
     761            // Update probe expression; if it differed, change events will fire.
     762            probe.expression = probeAction.data;
     763        }
     764
     765        // Look for missing probes based on what we saw last.
     766        for (let probeIdentifier of knownProbeIdentifiers) {
     767            if (seenProbeIdentifiers.has(probeIdentifier))
     768                break;
     769
     770            // The probe has gone missing, remove it.
     771            let probeSet = this._probeSetForBreakpoint(breakpoint);
     772            let probe = this._probesByIdentifier.get(probeIdentifier);
     773            this._probesByIdentifier.delete(probeIdentifier);
     774            knownProbeIdentifiers.delete(probeIdentifier);
     775            probeSet.removeProbe(probe);
     776
     777            // Remove the probe set if it has become empty.
     778            if (!probeSet.probes.length) {
     779                this._probeSetsByBreakpoint.delete(probeSet.breakpoint);
     780                probeSet.willRemove();
     781                this.dispatchEventToListeners(WI.DebuggerManager.Event.ProbeSetRemoved, {probeSet});
     782            }
     783        }
    732784    }
    733785
     
    9981050    }
    9991051
    1000     _debuggerBreakpointActionType(type)
    1001     {
    1002         switch (type) {
    1003         case WI.BreakpointAction.Type.Log:
    1004             return InspectorBackend.Enum.Debugger.BreakpointActionType.Log;
    1005         case WI.BreakpointAction.Type.Evaluate:
    1006             return InspectorBackend.Enum.Debugger.BreakpointActionType.Evaluate;
    1007         case WI.BreakpointAction.Type.Sound:
    1008             return InspectorBackend.Enum.Debugger.BreakpointActionType.Sound;
    1009         case WI.BreakpointAction.Type.Probe:
    1010             return InspectorBackend.Enum.Debugger.BreakpointActionType.Probe;
    1011         default:
    1012             console.assert(false);
    1013             return InspectorBackend.Enum.Debugger.BreakpointActionType.Log;
    1014         }
    1015     }
    1016 
    1017     _debuggerBreakpointOptions(breakpoint)
    1018     {
    1019         let actions = breakpoint.actions;
    1020         actions = actions.map((action) => action.toProtocol());
    1021         actions = actions.filter((action) => {
    1022             if (action.type !== WI.BreakpointAction.Type.Log)
    1023                 return true;
    1024 
    1025             if (!/\$\{.*?\}/.test(action.data))
    1026                 return true;
    1027 
    1028             let lexer = new WI.BreakpointLogMessageLexer;
    1029             let tokens = lexer.tokenize(action.data);
    1030             if (!tokens)
    1031                 return false;
    1032 
    1033             let templateLiteral = tokens.reduce((text, token) => {
    1034                 if (token.type === WI.BreakpointLogMessageLexer.TokenType.PlainText)
    1035                     return text + token.data.escapeCharacters("`\\");
    1036                 if (token.type === WI.BreakpointLogMessageLexer.TokenType.Expression)
    1037                     return text + "${" + token.data + "}";
    1038                 return text;
    1039             }, "");
    1040 
    1041             action.data = "console.log(`" + templateLiteral + "`)";
    1042             action.type = WI.BreakpointAction.Type.Evaluate;
    1043             return true;
    1044         });
    1045 
    1046         return {
    1047             condition: breakpoint.condition,
    1048             ignoreCount: breakpoint.ignoreCount,
    1049             autoContinue: breakpoint.autoContinue,
    1050             actions,
    1051         };
    1052     }
    1053 
    10541052    _setBreakpoint(breakpoint, specificTarget)
    10551053    {
     
    10881086        if (!specificTarget)
    10891087            breakpoint.resolved = false;
    1090 
    1091         // Convert BreakpointAction types to DebuggerAgent protocol types.
    1092         // NOTE: Breakpoint.options returns new objects each time, so it is safe to modify.
    1093         let options = this._debuggerBreakpointOptions(breakpoint);
    1094         for (let action of options.actions)
    1095             action.type = this._debuggerBreakpointActionType(action.type);
    10961088
    10971089        if (breakpoint.contentIdentifier) {
     
    11031095                    urlRegex: undefined,
    11041096                    columnNumber: breakpoint.sourceCodeLocation.columnNumber,
    1105                     options
     1097                    options: breakpoint.optionsToProtocol(),
    11061098                }, didSetBreakpoint.bind(this, target));
    11071099            }
     
    11101102            target.DebuggerAgent.setBreakpoint.invoke({
    11111103                location: {scriptId: breakpoint.scriptIdentifier, lineNumber: breakpoint.sourceCodeLocation.lineNumber, columnNumber: breakpoint.sourceCodeLocation.columnNumber},
    1112                 options
     1104                options: breakpoint.optionsToProtocol(),
    11131105            }, didSetBreakpoint.bind(this, target));
    11141106        } else
     
    12341226            return;
    12351227
    1236         console.assert(this.isBreakpointEditable(breakpoint));
    1237         if (!this.isBreakpointEditable(breakpoint))
     1228        console.assert(breakpoint.editable);
     1229        if (!breakpoint.editable)
    12381230            return;
    12391231
     
    12511243        this._breakpointEditablePropertyDidChange(event);
    12521244
    1253         this._updateProbesForBreakpoint(event.target);
     1245        this.updateProbesForBreakpoint(event.target);
    12541246    }
    12551247
     
    14121404
    14131405        this._ignoreBreakpointDisplayLocationDidChangeEvent = false;
    1414     }
    1415 
    1416     _addProbesForBreakpoint(breakpoint)
    1417     {
    1418         if (this._knownProbeIdentifiersForBreakpoint.has(breakpoint))
    1419             return;
    1420 
    1421         this._knownProbeIdentifiersForBreakpoint.set(breakpoint, new Set);
    1422 
    1423         this._updateProbesForBreakpoint(breakpoint);
    1424     }
    1425 
    1426     _removeProbesForBreakpoint(breakpoint)
    1427     {
    1428         console.assert(this._knownProbeIdentifiersForBreakpoint.has(breakpoint));
    1429 
    1430         this._updateProbesForBreakpoint(breakpoint);
    1431         this._knownProbeIdentifiersForBreakpoint.delete(breakpoint);
    1432     }
    1433 
    1434     _updateProbesForBreakpoint(breakpoint)
    1435     {
    1436         let knownProbeIdentifiers = this._knownProbeIdentifiersForBreakpoint.get(breakpoint);
    1437         if (!knownProbeIdentifiers) {
    1438             // Sometimes actions change before the added breakpoint is fully dispatched.
    1439             this._addProbesForBreakpoint(breakpoint);
    1440             return;
    1441         }
    1442 
    1443         let seenProbeIdentifiers = new Set;
    1444 
    1445         for (let probeAction of breakpoint.probeActions) {
    1446             let probeIdentifier = probeAction.id;
    1447             console.assert(probeIdentifier, "Probe added without breakpoint action identifier: ", breakpoint);
    1448 
    1449             seenProbeIdentifiers.add(probeIdentifier);
    1450             if (!knownProbeIdentifiers.has(probeIdentifier)) {
    1451                 // New probe; find or create relevant probe set.
    1452                 knownProbeIdentifiers.add(probeIdentifier);
    1453                 let probeSet = this._probeSetForBreakpoint(breakpoint);
    1454                 let newProbe = new WI.Probe(probeIdentifier, breakpoint, probeAction.data);
    1455                 this._probesByIdentifier.set(probeIdentifier, newProbe);
    1456                 probeSet.addProbe(newProbe);
    1457                 break;
    1458             }
    1459 
    1460             let probe = this._probesByIdentifier.get(probeIdentifier);
    1461             console.assert(probe, "Probe known but couldn't be found by identifier: ", probeIdentifier);
    1462             // Update probe expression; if it differed, change events will fire.
    1463             probe.expression = probeAction.data;
    1464         }
    1465 
    1466         // Look for missing probes based on what we saw last.
    1467         for (let probeIdentifier of knownProbeIdentifiers) {
    1468             if (seenProbeIdentifiers.has(probeIdentifier))
    1469                 break;
    1470 
    1471             // The probe has gone missing, remove it.
    1472             let probeSet = this._probeSetForBreakpoint(breakpoint);
    1473             let probe = this._probesByIdentifier.get(probeIdentifier);
    1474             this._probesByIdentifier.delete(probeIdentifier);
    1475             knownProbeIdentifiers.delete(probeIdentifier);
    1476             probeSet.removeProbe(probe);
    1477 
    1478             // Remove the probe set if it has become empty.
    1479             if (!probeSet.probes.length) {
    1480                 this._probeSetsByBreakpoint.delete(probeSet.breakpoint);
    1481                 probeSet.willRemove();
    1482                 this.dispatchEventToListeners(WI.DebuggerManager.Event.ProbeSetRemoved, {probeSet});
    1483             }
    1484         }
    14851406    }
    14861407
  • trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js

    r266072 r266074  
    955955            break;
    956956
    957         case InspectorBackend.Enum.Timeline.EventType.ProbeSample:
     957        case InspectorBackend.Enum.Timeline.EventType.ProbeSample: {
     958            let probe = WI.debuggerManager.probeForIdentifier(recordPayload.data.probeId);
     959            if (probe.breakpoint instanceof WI.JavaScriptBreakpoint)
     960                sourceCodeLocation = probe.breakpoint.sourceCodeLocation;
     961
    958962            // Pass the startTime as the endTime since this record type has no duration.
    959             sourceCodeLocation = WI.debuggerManager.probeForIdentifier(recordPayload.data.probeId).breakpoint.sourceCodeLocation;
    960963            return new WI.ScriptTimelineRecord(WI.ScriptTimelineRecord.EventType.ProbeSampleRecorded, startTime, startTime, callFrames, sourceCodeLocation, recordPayload.data.probeId);
     964        }
    961965
    962966        case InspectorBackend.Enum.Timeline.EventType.TimerInstall:
  • trunk/Source/WebInspectorUI/UserInterface/Main.html

    r261498 r266074  
    128128    <link rel="stylesheet" href="Views/InputPopover.css">
    129129    <link rel="stylesheet" href="Views/IssueTreeElement.css">
     130    <link rel="stylesheet" href="Views/JavaScriptBreakpointTreeElement.css">
    130131    <link rel="stylesheet" href="Views/LayerDetailsSidebarPanel.css">
    131132    <link rel="stylesheet" href="Views/LayerTreeDetailsSidebarPanel.css">
     
    350351    <script src="Protocol/WorkerObserver.js"></script>
    351352
     353    <script src="Models/Breakpoint.js"></script>
    352354    <script src="Models/BreakpointAction.js"></script>
    353355    <script src="Models/Collection.js"></script>
     
    370372    <script src="Models/BackForwardEntry.js"></script>
    371373    <script src="Models/BoxShadow.js"></script>
    372     <script src="Models/Breakpoint.js"></script>
    373374    <script src="Models/CPUInstrument.js"></script>
    374375    <script src="Models/CPUTimeline.js"></script>
     
    417418    <script src="Models/IndexedDatabaseObjectStoreIndex.js"></script>
    418419    <script src="Models/IssueMessage.js"></script>
     420    <script src="Models/JavaScriptBreakpoint.js"></script>
    419421    <script src="Models/KeyboardShortcut.js"></script>
    420422    <script src="Models/Layer.js"></script>
     
    717719    <script src="Views/InputPopover.js"></script>
    718720    <script src="Views/IssueTreeElement.js"></script>
     721    <script src="Views/JavaScriptBreakpointTreeElement.js"></script>
    719722    <script src="Views/LayerDetailsSidebarPanel.js"></script>
    720723    <script src="Views/LayerTreeDataGridNode.js"></script>
  • trunk/Source/WebInspectorUI/UserInterface/Models/Breakpoint.js

    r243727 r266074  
    2626WI.Breakpoint = class Breakpoint extends WI.Object
    2727{
    28     constructor(sourceCodeLocation, {contentIdentifier, disabled, condition, ignoreCount, autoContinue} = {})
    29     {
    30         console.assert(sourceCodeLocation instanceof WI.SourceCodeLocation);
    31         console.assert(!contentIdentifier || typeof contentIdentifier === "string");
    32         console.assert(!disabled || typeof disabled === "boolean");
    33         console.assert(!condition || typeof condition === "string");
    34         console.assert(!ignoreCount || !isNaN(ignoreCount));
    35         console.assert(!autoContinue || typeof autoContinue === "boolean");
     28    constructor({disabled, condition, ignoreCount, autoContinue} = {})
     29    {
     30        console.assert(!disabled || typeof disabled === "boolean", disabled);
     31        console.assert(!condition || typeof condition === "string", condition);
     32        console.assert(!ignoreCount || !isNaN(ignoreCount), ignoreCount);
     33        console.assert(!autoContinue || typeof autoContinue === "boolean", autoContinue);
    3634
    3735        super();
    3836
    39         this._id = null;
    40         this._sourceCodeLocation = sourceCodeLocation;
    41 
    42         let sourceCode = this._sourceCodeLocation.sourceCode;
    43         if (sourceCode) {
    44             this._contentIdentifier = sourceCode.contentIdentifier;
    45             console.assert(!contentIdentifier || contentIdentifier === this._contentIdentifier, "The content identifier from the source code should match the given value.");
    46         } else
    47             this._contentIdentifier = contentIdentifier || null;
    48         console.assert(this._contentIdentifier || this._isSpecial(), "There should always be a content identifier for a breakpoint.");
    49 
    50         this._scriptIdentifier = sourceCode instanceof WI.Script ? sourceCode.id : null;
    51         this._target = sourceCode instanceof WI.Script ? sourceCode.target : null;
     37        // This class should not be instantiated directly. Create a concrete subclass instead.
     38        console.assert(this.constructor !== WI.Breakpoint && this instanceof WI.Breakpoint);
     39
    5240        this._disabled = disabled || false;
    5341        this._condition = condition || "";
     
    5543        this._autoContinue = autoContinue || false;
    5644        this._actions = [];
    57         this._resolved = false;
    58 
    59         this._sourceCodeLocation.addEventListener(WI.SourceCodeLocation.Event.LocationChanged, this._sourceCodeLocationLocationChanged, this);
    60         this._sourceCodeLocation.addEventListener(WI.SourceCodeLocation.Event.DisplayLocationChanged, this._sourceCodeLocationDisplayLocationChanged, this);
    6145    }
    6246
    6347    // Import / Export
    6448
    65     static fromJSON(json)
    66     {
    67         const sourceCode = null;
    68         let breakpoint = new Breakpoint(new WI.SourceCodeLocation(sourceCode, json.lineNumber || 0, json.columnNumber || 0), {
    69             // The 'url' fallback is for transitioning from older frontends and should be removed.
    70             contentIdentifier: json.contentIdentifier || json.url,
    71             disabled: json.disabled,
    72             condition: json.condition,
    73             ignoreCount: json.ignoreCount,
    74             autoContinue: json.autoContinue,
    75         });
    76         breakpoint._actions = json.actions.map((actionJSON) => WI.BreakpointAction.fromJSON(actionJSON, breakpoint));
    77         return breakpoint;
    78     }
    79 
    8049    toJSON(key)
    8150    {
    82         // The id, scriptIdentifier, target, and resolved state are tied to the current session, so don't include them for serialization.
    83         let json = {
    84             contentIdentifier: this._contentIdentifier,
    85             lineNumber: this._sourceCodeLocation.lineNumber,
    86             columnNumber: this._sourceCodeLocation.columnNumber,
    87             disabled: this._disabled,
    88             condition: this._condition,
    89             ignoreCount: this._ignoreCount,
    90             actions: this._actions.map((action) => action.toJSON()),
    91             autoContinue: this._autoContinue,
    92         };
    93         if (key === WI.ObjectStore.toJSONSymbol)
    94             json[WI.objectStores.breakpoints.keyPath] = this._contentIdentifier + ":" + this._sourceCodeLocation.lineNumber + ":" + this._sourceCodeLocation.columnNumber;
     51        let json = {};
     52        if (this._disabled)
     53            json.disabled = this._disabled;
     54        if (this.editable) {
     55            if (this._condition)
     56                json.condition = this._condition;
     57            if (this._ignoreCount)
     58                json.ignoreCount = this._ignoreCount;
     59            if (this._actions.length)
     60                json.actions = this._actions.map((action) => action.toJSON());
     61            if (this._autoContinue)
     62                json.autoContinue = this._autoContinue;
     63        }
    9564        return json;
    9665    }
     
    9867    // Public
    9968
    100     get sourceCodeLocation() { return this._sourceCodeLocation; }
    101     get contentIdentifier() { return this._contentIdentifier; }
    102     get scriptIdentifier() { return this._scriptIdentifier; }
    103     get target() { return this._target; }
    104 
    105     get identifier()
    106     {
    107         return this._id;
    108     }
    109 
    110     set identifier(id)
    111     {
    112         this._id = id || null;
    113     }
    114 
    115     get resolved()
    116     {
    117         return this._resolved;
    118     }
    119 
    120     set resolved(resolved)
    121     {
    122         if (this._resolved === resolved)
    123             return;
    124 
    125         console.assert(!resolved || this._sourceCodeLocation.sourceCode || this._isSpecial(), "Breakpoints must have a SourceCode to be resolved.", this);
    126 
    127         this._resolved = resolved || false;
    128 
    129         this.dispatchEventToListeners(WI.Breakpoint.Event.ResolvedStateDidChange);
     69    get special()
     70    {
     71        // Overridden by subclasses if needed.
     72        return false;
     73    }
     74
     75    get removable()
     76    {
     77        // Overridden by subclasses if needed.
     78        return true;
     79    }
     80
     81    get editable()
     82    {
     83        // Overridden by subclasses if needed.
     84        return false;
    13085    }
    13186
     
    152107    set condition(condition)
    153108    {
     109        console.assert(this.editable, this);
     110        console.assert(typeof condition === "string");
     111
    154112        if (this._condition === condition)
    155113            return;
     
    162120    get ignoreCount()
    163121    {
     122        console.assert(this.editable, this);
     123
    164124        return this._ignoreCount;
    165125    }
     
    167127    set ignoreCount(ignoreCount)
    168128    {
     129        console.assert(this.editable, this);
     130
    169131        console.assert(ignoreCount >= 0, "Ignore count cannot be negative.");
    170132        if (ignoreCount < 0)
     
    181143    get autoContinue()
    182144    {
     145        console.assert(this.editable, this);
     146
    183147        return this._autoContinue;
    184148    }
     
    186150    set autoContinue(cont)
    187151    {
     152        console.assert(this.editable, this);
     153
    188154        if (this._autoContinue === cont)
    189155            return;
     
    196162    get actions()
    197163    {
     164        console.assert(this.editable, this);
     165
    198166        return this._actions;
    199167    }
     
    201169    get probeActions()
    202170    {
     171        console.assert(this.editable, this);
     172
    203173        return this._actions.filter(function(action) {
    204174            return action.type === WI.BreakpointAction.Type.Probe;
     
    209179    {
    210180        if (this.disabled) {
    211             // When cycling, clear auto-continue when going from disabled to enabled.
    212             this.autoContinue = false;
     181            if (this.editable) {
     182                // When cycling, clear auto-continue when going from disabled to enabled.
     183                this.autoContinue = false;
     184            }
     185
    213186            this.disabled = false;
    214187            return;
    215188        }
    216189
    217         if (this.autoContinue) {
    218             this.disabled = true;
    219             return;
    220         }
    221 
    222         if (this.actions.length) {
    223             this.autoContinue = true;
    224             return;
     190        if (this.editable) {
     191            if (this.autoContinue) {
     192                this.disabled = true;
     193                return;
     194            }
     195
     196            if (this.actions.length) {
     197                this.autoContinue = true;
     198                return;
     199            }
    225200        }
    226201
     
    228203    }
    229204
    230     createAction(type, precedingAction, data)
    231     {
     205    createAction(type, {data, precedingAction} = {})
     206    {
     207        console.assert(this.editable, this);
     208
    232209        var newAction = new WI.BreakpointAction(this, type, data || null);
    233210
     
    250227    recreateAction(type, actionToReplace)
    251228    {
     229        console.assert(this.editable, this);
     230
    252231        let index = this._actions.indexOf(actionToReplace);
    253232        console.assert(index !== -1);
     
    266245    removeAction(action)
    267246    {
     247        console.assert(this.editable, this);
     248
    268249        var index = this._actions.indexOf(action);
    269250        console.assert(index !== -1);
     
    281262    clearActions(type)
    282263    {
     264        console.assert(this.editable, this);
     265
    283266        if (!type)
    284267            this._actions = [];
     
    289272    }
    290273
    291     saveIdentityToCookie(cookie)
    292     {
    293         cookie["breakpoint-content-identifier"] = this._contentIdentifier;
    294         cookie["breakpoint-line-number"] = this._sourceCodeLocation.lineNumber;
    295         cookie["breakpoint-column-number"] = this._sourceCodeLocation.columnNumber;
     274    remove()
     275    {
     276        console.assert(this.removable, this);
     277
     278        // Overridden by subclasses if needed.
     279    }
     280
     281    optionsToProtocol()
     282    {
     283        console.assert(this.editable, this);
     284
     285        let payload = {};
     286
     287        if (this._condition)
     288            payload.condition = this._condition;
     289
     290        if (this._actions.length) {
     291            payload.actions = this._actions.map((action) => action.toProtocol()).filter((action) => {
     292                if (action.type !== WI.BreakpointAction.Type.Log)
     293                    return true;
     294
     295                if (!/\$\{.*?\}/.test(action.data))
     296                    return true;
     297
     298                let lexer = new WI.BreakpointLogMessageLexer;
     299                let tokens = lexer.tokenize(action.data);
     300                if (!tokens)
     301                    return false;
     302
     303                let templateLiteral = tokens.reduce((text, token) => {
     304                    if (token.type === WI.BreakpointLogMessageLexer.TokenType.PlainText)
     305                        return text + token.data.escapeCharacters("`\\");
     306                    if (token.type === WI.BreakpointLogMessageLexer.TokenType.Expression)
     307                        return text + "${" + token.data + "}";
     308                    return text;
     309                }, "");
     310
     311                action.data = "console.log(`" + templateLiteral + "`)";
     312                action.type = WI.BreakpointAction.Type.Evaluate;
     313                return true;
     314            });
     315        }
     316
     317        if (this._autoContinue)
     318            payload.autoContinue = this._autoContinue;
     319
     320        if (this._ignoreCount)
     321            payload.ignoreCount = this._ignoreCount;
     322
     323        return !isEmptyObject(payload) ? payload : undefined;
    296324    }
    297325
     
    300328    breakpointActionDidChange(action)
    301329    {
     330        console.assert(this.editable, this);
     331
    302332        var index = this._actions.indexOf(action);
    303333        console.assert(index !== -1);
     
    307337        this.dispatchEventToListeners(WI.Breakpoint.Event.ActionsDidChange);
    308338    }
    309 
    310     // Private
    311 
    312     _isSpecial()
    313     {
    314         return this._sourceCodeLocation.isEqual(new WI.SourceCodeLocation(null, Infinity, Infinity));
    315     }
    316 
    317     _sourceCodeLocationLocationChanged(event)
    318     {
    319         this.dispatchEventToListeners(WI.Breakpoint.Event.LocationDidChange, event.data);
    320     }
    321 
    322     _sourceCodeLocationDisplayLocationChanged(event)
    323     {
    324         this.dispatchEventToListeners(WI.Breakpoint.Event.DisplayLocationDidChange, event.data);
    325     }
    326339};
    327340
     
    330343WI.Breakpoint.Event = {
    331344    DisabledStateDidChange: "breakpoint-disabled-state-did-change",
    332     ResolvedStateDidChange: "breakpoint-resolved-state-did-change",
    333345    ConditionDidChange: "breakpoint-condition-did-change",
    334346    IgnoreCountDidChange: "breakpoint-ignore-count-did-change",
    335347    ActionsDidChange: "breakpoint-actions-did-change",
    336348    AutoContinueDidChange: "breakpoint-auto-continue-did-change",
    337     LocationDidChange: "breakpoint-location-did-change",
    338     DisplayLocationDidChange: "breakpoint-display-location-did-change",
    339349};
  • trunk/Source/WebInspectorUI/UserInterface/Models/BreakpointAction.js

    r243727 r266074  
    2828    constructor(breakpoint, type, data)
    2929    {
    30         console.assert(breakpoint instanceof WI.Breakpoint);
    31         console.assert(Object.values(WI.BreakpointAction.Type).includes(type));
     30        console.assert(breakpoint instanceof WI.Breakpoint, breakpoint);
     31        console.assert(Object.values(WI.BreakpointAction.Type).includes(type), type);
     32        console.assert(!data || typeof data === "string", data);
    3233
    3334        this._breakpoint = breakpoint;
  • trunk/Source/WebInspectorUI/UserInterface/Models/DOMBreakpoint.js

    r244279 r266074  
    2424 */
    2525
    26 WI.DOMBreakpoint = class DOMBreakpoint extends WI.Object
     26WI.DOMBreakpoint = class DOMBreakpoint extends WI.Breakpoint
    2727{
    2828    constructor(domNodeOrInfo, type, {disabled} = {})
     
    3131        console.assert(Object.values(WI.DOMBreakpoint.Type).includes(type), type);
    3232
    33         super();
     33        super({disabled});
    3434
    3535        if (domNodeOrInfo instanceof WI.DOMNode) {
     
    4545
    4646        this._type = type;
    47         this._disabled = disabled || false;
    4847    }
    4948
    5049    // Static
    5150
    52     static deserialize(serializedInfo)
     51    static fromJSON(json)
    5352    {
    54         return new WI.DOMBreakpoint(serializedInfo, serializedInfo.type, {
    55             disabled: !!serializedInfo.disabled,
     53        return new WI.DOMBreakpoint(json, json.type, {
     54            disabled: json.disabled,
    5655        });
    5756    }
     
    6261    get url() { return this._url; }
    6362    get path() { return this._path; }
    64 
    65     get disabled()
    66     {
    67         return this._disabled;
    68     }
    69 
    70     set disabled(disabled)
    71     {
    72         if (this._disabled === disabled)
    73             return;
    74 
    75         this._disabled = disabled;
    76 
    77         this.dispatchEventToListeners(WI.DOMBreakpoint.Event.DisabledStateChanged);
    78     }
    7963
    8064    get domNodeIdentifier()
     
    9781    }
    9882
     83    remove()
     84    {
     85        super.remove();
     86
     87        WI.domDebuggerManager.removeDOMBreakpoint(this);
     88    }
     89
    9990    saveIdentityToCookie(cookie)
    10091    {
     
    10697    toJSON(key)
    10798    {
    108         let json = {
    109             url: this._url,
    110             path: this._path,
    111             type: this._type,
    112         };
    113         if (this._disabled)
    114             json.disabled = true;
     99        let json = super.toJSON(key);
     100        json.url = this._url;
     101        json.path = this._path;
     102        json.type = this._type;
    115103        if (key === WI.ObjectStore.toJSONSymbol)
    116104            json[WI.objectStores.domBreakpoints.keyPath] = this._url + ":" + this._path + ":" + this._type;
     
    127115WI.DOMBreakpoint.Event = {
    128116    DOMNodeChanged: "dom-breakpoint-dom-node-changed",
    129     DisabledStateChanged: "dom-breakpoint-disabled-state-changed",
    130117};
  • trunk/Source/WebInspectorUI/UserInterface/Models/EventBreakpoint.js

    r248201 r266074  
    2424 */
    2525
    26 WI.EventBreakpoint = class EventBreakpoint extends WI.Object
     26WI.EventBreakpoint = class EventBreakpoint extends WI.Breakpoint
    2727{
    28     constructor(type, {eventName, eventListener, disabled} = {})
     28    constructor(type, {eventName, eventListener, disabled, actions, condition, ignoreCount, autoContinue} = {})
    2929    {
    30         super();
     30        // COMPATIBILITY (iOS 13): DOMDebugger.EventBreakpointTypes.Timer was removed.
     31        if (type === "timer") {
     32            switch (eventName) {
     33            case "setInterval":
     34                type = WI.EventBreakpoint.Type.Interval;
     35                break;
     36
     37            case "setTimeout":
     38                type = WI.EventBreakpoint.Type.Timeout;
     39                break;
     40            }
     41        }
    3142
    3243        console.assert(Object.values(WI.EventBreakpoint.Type).includes(type), type);
     44        console.assert(!eventName || type === WI.EventBreakpoint.Type.Listener, eventName);
     45        console.assert(!eventListener || type === WI.EventBreakpoint.Type.Listener, eventListener);
     46
     47        super({disabled, condition, actions, ignoreCount, autoContinue});
    3348
    3449        this._type = type;
    3550        this._eventName = eventName || null;
    3651        this._eventListener = eventListener || null;
    37         this._disabled = disabled || false;
    3852    }
    3953
    4054    // Static
    4155
    42     static deserialize(serializedInfo)
     56    static fromJSON(json)
    4357    {
    44         return new WI.EventBreakpoint(serializedInfo.type, {
    45             eventName: serializedInfo.eventName,
    46             disabled: !!serializedInfo.disabled,
     58        let breakpoint = new WI.EventBreakpoint(json.type, {
     59            eventName: json.eventName,
     60            disabled: json.disabled,
     61            condition: json.condition,
     62            ignoreCount: json.ignoreCount,
     63            autoContinue: json.autoContinue,
    4764        });
     65        breakpoint._actions = json.actions?.map((actionJSON) => WI.BreakpointAction.fromJSON(actionJSON, breakpoint)) || [];
     66        return breakpoint;
    4867    }
    4968
     
    5473    get eventListener() { return this._eventListener; }
    5574
    56     get disabled()
     75    get special()
    5776    {
    58         return this._disabled;
     77        switch (this) {
     78        case WI.domDebuggerManager.allAnimationFramesBreakpoint:
     79        case WI.domDebuggerManager.allIntervalsBreakpoint:
     80        case WI.domDebuggerManager.allListenersBreakpoint:
     81        case WI.domDebuggerManager.allTimeoutsBreakpoint:
     82            return true;
     83        }
     84
     85        return super.special;
    5986    }
    6087
    61     set disabled(disabled)
     88    get editable()
    6289    {
    63         if (this._disabled === disabled)
    64             return;
     90        // COMPATIBILITY (iOS 14): DOM.setBreakpointForEventListener did not have an "options" parameter yet.
     91        // COMPATIBILITY (iOS 14): DOMDebugger.setEventBreakpoint did not have an "options" parameter yet.
     92        return (this._eventListener ? InspectorBackend.hasCommand("DOM.setBreakpointForEventListener", "options") : InspectorBackend.hasCommand("DOMDebugger.setEventBreakpoint", "options")) || super.editable;
     93    }
    6594
    66         this._disabled = disabled;
     95    remove()
     96    {
     97        super.remove();
    6798
    68         this.dispatchEventToListeners(WI.EventBreakpoint.Event.DisabledStateChanged);
     99        if (this._eventListener)
     100            WI.domManager.removeBreakpointForEventListener(this._eventListener);
     101        else
     102            WI.domDebuggerManager.removeEventBreakpoint(this);
    69103    }
    70104
     
    76110        if (this._eventListener)
    77111            cookie["event-breakpoint-event-listener"] = this._eventListener.eventListenerId;
    78         if (this._disabled)
    79             cookie["event-breakpoint-disabled"] = this._disabled;
    80112    }
    81113
    82114    toJSON(key)
    83115    {
    84         let json = {
    85             type: this._type,
    86         };
     116        let json = super.toJSON(key);
     117        json.type = this._type;
    87118        if (this._eventName)
    88119            json.eventName = this._eventName;
    89         if (this._disabled)
    90             json.disabled = true;
    91120        if (key === WI.ObjectStore.toJSONSymbol)
    92121            json[WI.objectStores.eventBreakpoints.keyPath] = this._type + (this._eventName ? ":" + this._eventName : "");
     
    100129    Listener: "listener",
    101130    Timeout: "timeout",
    102 
    103     // COMPATIBILITY (iOS 13): DOMDebugger.EventBreakpointTypes.Timer was removed.
    104     Timer: "timer",
    105131};
    106 
    107 WI.EventBreakpoint.Event = {
    108     DisabledStateChanged: "event-breakpoint-disabled-state-changed",
    109 };
  • trunk/Source/WebInspectorUI/UserInterface/Models/ProbeSet.js

    r220119 r266074  
    4343        WI.Frame.addEventListener(WI.Frame.Event.MainResourceDidChange, this._mainResourceChanged, this);
    4444        WI.Probe.addEventListener(WI.Probe.Event.SampleAdded, this._sampleCollected, this);
    45         WI.Breakpoint.addEventListener(WI.Breakpoint.Event.ResolvedStateDidChange, this._breakpointResolvedStateDidChange, this);
     45        WI.JavaScriptBreakpoint.addEventListener(WI.JavaScriptBreakpoint.Event.ResolvedStateDidChange, this._breakpointResolvedStateDidChange, this);
    4646    }
    4747
     
    6969    createProbe(expression)
    7070    {
    71         this.breakpoint.createAction(WI.BreakpointAction.Type.Probe, null, expression);
     71        this.breakpoint.createAction(WI.BreakpointAction.Type.Probe, {data: expression});
    7272    }
    7373
     
    102102        WI.Frame.removeEventListener(WI.Frame.Event.MainResourceDidChange, this._mainResourceChanged, this);
    103103        WI.Probe.removeEventListener(WI.Probe.Event.SampleAdded, this._sampleCollected, this);
    104         WI.Breakpoint.removeEventListener(WI.Breakpoint.Event.ResolvedStateDidChange, this._breakpointResolvedStateDidChange, this);
     104        WI.JavaScriptBreakpoint.removeEventListener(WI.JavaScriptBreakpoint.Event.ResolvedStateDidChange, this._breakpointResolvedStateDidChange, this);
    105105    }
    106106
  • trunk/Source/WebInspectorUI/UserInterface/Models/URLBreakpoint.js

    r244279 r266074  
    2424 */
    2525
    26 WI.URLBreakpoint = class URLBreakpoint extends WI.Object
     26WI.URLBreakpoint = class URLBreakpoint extends WI.Breakpoint
    2727{
    2828    constructor(type, url, {disabled} = {})
     
    3131        console.assert(typeof url === "string", url);
    3232
    33         super();
     33        super({disabled});
    3434
    3535        this._type = type;
    3636        this._url = url;
    37         this._disabled = disabled || false;
    3837    }
    3938
    4039    // Static
    4140
    42     static deserialize(serializedInfo)
     41    static fromJSON(json)
    4342    {
    44         return new WI.URLBreakpoint(serializedInfo.type, serializedInfo.url, {
    45             disabled: !!serializedInfo.disabled,
     43        return new WI.URLBreakpoint(json.type, json.url, {
     44            disabled: json.disabled,
    4645        });
    4746    }
     
    5251    get url() { return this._url; }
    5352
    54     get disabled()
     53    get special()
    5554    {
    56         return this._disabled;
     55        return this === WI.domDebuggerManager.allRequestsBreakpoint || super.special;
    5756    }
    5857
    59     set disabled(disabled)
     58    remove()
    6059    {
    61         if (this._disabled === disabled)
    62             return;
     60        super.remove();
    6361
    64         this._disabled = disabled;
    65 
    66         this.dispatchEventToListeners(WI.URLBreakpoint.Event.DisabledStateChanged);
     62        WI.domDebuggerManager.removeURLBreakpoint(this);
    6763    }
    6864
     
    7571    toJSON(key)
    7672    {
    77         let json = {
    78             type: this._type,
    79             url: this._url,
    80         };
    81         if (this._disabled)
    82             json.disabled = true;
     73        let json = super.toJSON(key);
     74        json.type = this._type;
     75        json.url = this._url;
    8376        if (key === WI.ObjectStore.toJSONSymbol)
    8477            json[WI.objectStores.urlBreakpoints.keyPath] = this._type + ":" + this._url;
     
    8780};
    8881
    89 WI.URLBreakpoint.Event = {
    90     DisabledStateChanged: "url-breakpoint-disabled-state-changed",
    91 };
    92 
    9382WI.URLBreakpoint.Type = {
    9483    Text: "text",
  • trunk/Source/WebInspectorUI/UserInterface/Test.html

    r259170 r266074  
    109109    <script src="Protocol/WorkerObserver.js"></script>
    110110
     111    <script src="Models/Breakpoint.js"></script>
    111112    <script src="Models/BreakpointAction.js"></script>
    112113    <script src="Models/Collection.js"></script>
     
    127128    <script src="Models/AnimationCollection.js"></script>
    128129    <script src="Models/BoxShadow.js"></script>
    129     <script src="Models/Breakpoint.js"></script>
    130130    <script src="Models/CPUInstrument.js"></script>
    131131    <script src="Models/CPUTimeline.js"></script>
     
    170170    <script src="Models/IndexedDatabaseObjectStoreIndex.js"></script>
    171171    <script src="Models/IssueMessage.js"></script>
     172    <script src="Models/JavaScriptBreakpoint.js"></script>
    172173    <script src="Models/Layer.js"></script>
    173174    <script src="Models/LayoutInstrument.js"></script>
  • trunk/Source/WebInspectorUI/UserInterface/Views/BreakpointActionView.js

    r253402 r266074  
    116116    _appendActionButtonClicked(event)
    117117    {
    118         var newAction = this._action.breakpoint.createAction(this._action.type, this._action);
     118        var newAction = this._action.breakpoint.createAction(this._action.type, {precedingAction: this._action});
    119119        this._delegate.breakpointActionViewAppendActionView(this, newAction);
    120120    }
  • trunk/Source/WebInspectorUI/UserInterface/Views/BreakpointTreeElement.css

    r258809 r266074  
    3535    fill: var(--breakpoint-color);
    3636    stroke: hsla(0, 0%, 10%, 0.3);
    37     filter: grayscale();
    38 }
    39 
    40 .item.breakpoint .status > .status-image.resolved {
    41     filter: none;
    42 }
    43 
    44 body:not(.window-inactive, .window-docked-inactive) .tree-outline:focus-within .item.breakpoint.selected .status > .status-image.resolved {
    45     stroke: var(--selected-foreground-color);
    4637}
    4738
     
    6051}
    6152
    62 .item.breakpoint .subtitle.formatted-location {
    63     font-style: italic;
    64 }
    65 
    66 .breakpoint-debugger-statement-icon .icon {
    67     content: url(../Images/TypeIcons.svg#DebuggerStatement-light);
    68 }
    69 
    70 .breakpoint-exception-icon .icon {
    71     content: url(../Images/TypeIcons.svg#Exception-light);
    72 }
    73 
    74 .breakpoint-assertion-icon .icon {
    75     content: url(../Images/TypeIcons.svg#Assertion-light);
    76 }
    77 
    78 .breakpoint-microtask-icon .icon {
    79     content: url(../Images/TypeIcons.svg#Microtask-light);
    80 }
    81 
    82 .breakpoint-paused-icon .icon {
     53.item.breakpoint.paused .icon {
    8354    content: url(../Images/TypeIcons.svg#PausedBreakpoint-light);
    8455}
    8556
    86 /* When animating a layer on top of a tree element's icon, move the main
    87 icon to the icon element's background so animations are layered on top. */
    88 .breakpoint-generic-line-icon .icon {
    89     background-image: url(../Images/TypeIcons.svg#ResultLine-light);
    90     content: '';
    91 }
    92 
    93 .breakpoint-generic-line-icon .icon > span {
    94     position: absolute;
    95     top: 0;
    96     right: 0;
    97     bottom: 0;
    98     left: 0;
    99 
    100     border-radius: 50%;
    101     transform: scale(0);
    102     transition: none;
    103     background-color: hsl(216, 30%, 42%);
    104 }
    105 
    106 .data-updated.breakpoint-generic-line-icon .icon > span {
    107     border-radius: 0;
    108     transform: scale(0.85);
    109     transition: all .4s ease-out;
    110     background-color: hsla(216, 30%, 42%, 0.1);
    111 }
    112 
    11357@media (prefers-color-scheme: dark) {
    114     .breakpoint-debugger-statement-icon .icon {
    115         content: url(../Images/TypeIcons.svg#DebuggerStatement-dark);
    116     }
    117    
    118     .breakpoint-exception-icon .icon {
    119         content: url(../Images/TypeIcons.svg#Exception-dark);
    120     }
    121 
    122     .breakpoint-assertion-icon .icon {
    123         content: url(../Images/TypeIcons.svg#Assertion-dark);
    124     }
    125 
    126     .breakpoint-microtask-icon .icon {
    127         content: url(../Images/TypeIcons.svg#Microtask-dark);
    128     }
    129 
    130     .breakpoint-paused-icon .icon {
     58    .item.breakpoint.paused .icon {
    13159        content: url(../Images/TypeIcons.svg#PausedBreakpoint-dark);
    13260    }
    133 
    134     .breakpoint-generic-line-icon .icon {
    135         background-image: url(../Images/TypeIcons.svg#ResultLine-dark);
    136     }
    137    
    13861}
  • trunk/Source/WebInspectorUI/UserInterface/Views/BreakpointTreeElement.js

    r249291 r266074  
    2626WI.BreakpointTreeElement = class BreakpointTreeElement extends WI.GeneralTreeElement
    2727{
    28     constructor(breakpoint, {className, title} = {})
     28    constructor(breakpoint, {classNames, title, subtitle} = {})
    2929    {
    3030        console.assert(breakpoint instanceof WI.Breakpoint);
    3131
    32         if (!className)
    33             className = WI.BreakpointTreeElement.GenericLineIconStyleClassName;
    34 
    35         const subtitle = null;
    36         super(["breakpoint", className], title, subtitle, breakpoint);
     32        if (!Array.isArray(classNames))
     33            classNames = [];
     34        classNames.push("breakpoint");
     35
     36        super(classNames, title, subtitle, breakpoint);
     37
     38        // This class should not be instantiated directly. Create a concrete subclass instead.
     39        console.assert(this.constructor !== WI.BreakpointTreeElement && this instanceof WI.BreakpointTreeElement);
    3740
    3841        this._breakpoint = breakpoint;
     
    4043
    4144        this._listenerSet = new WI.EventListenerSet(this, "BreakpointTreeElement listeners");
    42         if (!title)
    43             this._listenerSet.register(breakpoint, WI.Breakpoint.Event.LocationDidChange, this._breakpointLocationDidChange);
    44         this._listenerSet.register(breakpoint, WI.Breakpoint.Event.DisabledStateDidChange, this._updateStatus);
    45         this._listenerSet.register(breakpoint, WI.Breakpoint.Event.AutoContinueDidChange, this._updateStatus);
    46         this._listenerSet.register(breakpoint, WI.Breakpoint.Event.ResolvedStateDidChange, this._updateStatus);
    47         this._listenerSet.register(WI.debuggerManager, WI.DebuggerManager.Event.BreakpointsEnabledDidChange, this._updateStatus);
     45        this._listenerSet.register(breakpoint, WI.Breakpoint.Event.DisabledStateDidChange, this.updateStatus);
     46        this._listenerSet.register(breakpoint, WI.Breakpoint.Event.AutoContinueDidChange, this.updateStatus);
     47        this._listenerSet.register(WI.debuggerManager, WI.DebuggerManager.Event.BreakpointsEnabledDidChange, this.updateStatus);
    4848        this._listenerSet.register(WI.debuggerManager, WI.DebuggerManager.Event.ProbeSetAdded, this._probeSetAdded);
    4949        this._listenerSet.register(WI.debuggerManager, WI.DebuggerManager.Event.ProbeSetRemoved, this._probeSetRemoved);
     
    5656
    5757        if (!title)
    58             this._updateTitles();
    59         this._updateStatus();
     58            this.updateTitles();
     59        this.updateStatus();
    6060
    6161        this._iconAnimationLayerElement = document.createElement("span");
     
    6969    {
    7070        return this._breakpoint;
    71     }
    72 
    73     get filterableData()
    74     {
    75         return {text: [this.breakpoint.contentIdentifier]};
    7671    }
    7772
     
    8378        this.__deletedViaDeleteKeyboardShortcut = true;
    8479
    85         if (WI.debuggerManager.isBreakpointRemovable(this._breakpoint)) {
    86             WI.debuggerManager.removeBreakpoint(this._breakpoint);
     80        if (this._breakpoint.removable) {
     81            this._breakpoint.remove();
    8782            return true;
    8883        }
     
    135130    }
    136131
    137     // Private
    138 
    139     _updateTitles()
    140     {
    141         var sourceCodeLocation = this._breakpoint.sourceCodeLocation;
    142 
    143         var displayLineNumber = sourceCodeLocation.displayLineNumber;
    144         var displayColumnNumber = sourceCodeLocation.displayColumnNumber;
    145         if (displayColumnNumber > 0)
    146             this.mainTitle = WI.UIString("Line %d:%d").format(displayLineNumber + 1, displayColumnNumber + 1); // The user visible line and column numbers are 1-based.
    147         else
    148             this.mainTitle = WI.UIString("Line %d").format(displayLineNumber + 1); // The user visible line number is 1-based.
    149 
    150         if (sourceCodeLocation.hasMappedLocation()) {
    151             this.subtitle = sourceCodeLocation.formattedLocationString();
    152 
    153             if (sourceCodeLocation.hasFormattedLocation())
    154                 this.subtitleElement.classList.add(WI.BreakpointTreeElement.FormattedLocationStyleClassName);
    155             else
    156                 this.subtitleElement.classList.remove(WI.BreakpointTreeElement.FormattedLocationStyleClassName);
    157 
    158             this.tooltip = this.mainTitle + " \u2014 " + WI.UIString("originally %s").format(sourceCodeLocation.originalLocationString());
    159         }
    160     }
    161 
    162     _updateStatus()
     132    // Protected
     133
     134    get listenerSet() { return this._listenerSet; }
     135
     136    updateStatus()
    163137    {
    164138        if (!this.status)
     
    166140
    167141        this.status.classList.toggle(WI.BreakpointTreeElement.StatusImageDisabledStyleClassName, this._breakpoint.disabled);
    168         this.status.classList.toggle(WI.BreakpointTreeElement.StatusImageAutoContinueStyleClassName, this._breakpoint.autoContinue);
    169         this.status.classList.toggle(WI.BreakpointTreeElement.StatusImageResolvedStyleClassName, this._breakpoint.resolved && WI.debuggerManager.breakpointsEnabled);
    170     }
     142        if (this._breakpoint.editable)
     143            this.status.classList.toggle(WI.BreakpointTreeElement.StatusImageAutoContinueStyleClassName, this._breakpoint.autoContinue);
     144    }
     145
     146    updateTitles()
     147    {
     148        // Overridden by subclasses if needed.
     149    }
     150
     151    // Private
    171152
    172153    _addProbeSet(probeSet)
     
    231212    }
    232213
    233     _breakpointLocationDidChange(event)
    234     {
    235         console.assert(event.target === this._breakpoint);
    236 
    237         // The Breakpoint has a new display SourceCode. The sidebar will remove us, and ondetach() will clear listeners.
    238         if (event.data.oldDisplaySourceCode === this._breakpoint.displaySourceCode)
    239             return;
    240 
    241         this._updateTitles();
    242     }
    243 
    244214    _statusImageElementMouseDown(event)
    245215    {
     
    254224};
    255225
    256 WI.BreakpointTreeElement.GenericLineIconStyleClassName = "breakpoint-generic-line-icon";
    257226WI.BreakpointTreeElement.StatusImageElementStyleClassName = "status-image";
    258 WI.BreakpointTreeElement.StatusImageResolvedStyleClassName = "resolved";
    259227WI.BreakpointTreeElement.StatusImageAutoContinueStyleClassName = "auto-continue";
    260228WI.BreakpointTreeElement.StatusImageDisabledStyleClassName = "disabled";
    261 WI.BreakpointTreeElement.FormattedLocationStyleClassName = "formatted-location";
    262229WI.BreakpointTreeElement.ProbeDataUpdatedStyleClassName = "data-updated";
    263230
  • trunk/Source/WebInspectorUI/UserInterface/Views/CallFrameTreeElement.js

    r259738 r266074  
    108108    }
    109109
     110    populateContextMenu(contextMenu, event)
     111    {
     112        if (this._callFrame.sourceCodeLocation)
     113            WI.appendContextMenuItemsForSourceCode(contextMenu, this._callFrame.sourceCodeLocation);
     114
     115        super.populateContextMenu(contextMenu, event);
     116    }
     117
    110118    // Private
    111119
  • trunk/Source/WebInspectorUI/UserInterface/Views/ContentView.js

    r255396 r266074  
    9494        }
    9595
    96         if (representedObject instanceof WI.Breakpoint || representedObject instanceof WI.IssueMessage) {
     96        if (representedObject instanceof WI.JavaScriptBreakpoint || representedObject instanceof WI.IssueMessage) {
    9797            if (representedObject.sourceCodeLocation)
    9898                return WI.ContentView.createFromRepresentedObject(representedObject.sourceCodeLocation.displaySourceCode, extraArguments);
     
    235235            return representedObject.mainResource;
    236236
    237         if (representedObject instanceof WI.Breakpoint || representedObject instanceof WI.IssueMessage) {
     237        if (representedObject instanceof WI.JavaScriptBreakpoint || representedObject instanceof WI.IssueMessage) {
    238238            if (representedObject.sourceCodeLocation)
    239239                return representedObject.sourceCodeLocation.displaySourceCode;
     
    280280        if (representedObject instanceof WI.Timeline)
    281281            return true;
    282         if (representedObject instanceof WI.Breakpoint || representedObject instanceof WI.IssueMessage)
     282        if (representedObject instanceof WI.JavaScriptBreakpoint || representedObject instanceof WI.IssueMessage)
    283283            return representedObject.sourceCodeLocation;
    284284        if (representedObject instanceof WI.LocalResourceOverride)
  • trunk/Source/WebInspectorUI/UserInterface/Views/ContextMenuUtilities.js

    r264669 r266074  
    119119        } else {
    120120            contextMenu.appendItem(WI.UIString("Add Breakpoint"), () => {
    121                 WI.debuggerManager.addBreakpoint(new WI.Breakpoint(location));
     121                WI.debuggerManager.addBreakpoint(new WI.JavaScriptBreakpoint(location));
    122122            });
    123123        }
  • trunk/Source/WebInspectorUI/UserInterface/Views/DOMBreakpointTreeElement.css

    r256774 r266074  
    2424 */
    2525
    26 .breakpoint.dom.breakpoint-for-subtree-modified:not(.breakpoint-paused-icon) .icon {
     26.item.breakpoint.dom.subtree-modified:not(.paused) .icon {
    2727    content: url(../Images/TypeIcons.svg#DOMBreakpointSubtreeModified-light);
    2828}
    2929
    30 .breakpoint.dom.breakpoint-for-attribute-modified:not(.breakpoint-paused-icon) .icon {
     30.item.breakpoint.dom.attribute-modified:not(.paused) .icon {
    3131    content: url(../Images/TypeIcons.svg#DOMBreakpointAttributeModified-light);
    3232}
    3333
    34 .breakpoint.dom.breakpoint-for-node-removed:not(.breakpoint-paused-icon) .icon {
     34.item.breakpoint.dom.node-removed:not(.paused) .icon {
    3535    content: url(../Images/TypeIcons.svg#DOMBreakpointNodeRemoved-light);
    3636}
    3737
    3838@media (prefers-color-scheme: dark) {
    39     .breakpoint.dom.breakpoint-for-subtree-modified:not(.breakpoint-paused-icon) .icon {
     39    .item.breakpoint.dom.subtree-modified:not(.paused) .icon {
    4040        content: url(../Images/TypeIcons.svg#DOMBreakpointSubtreeModified-dark);
    4141    }
    4242
    43     .breakpoint.dom.breakpoint-for-attribute-modified:not(.breakpoint-paused-icon) .icon {
     43    .item.breakpoint.dom.attribute-modified:not(.paused) .icon {
    4444        content: url(../Images/TypeIcons.svg#DOMBreakpointAttributeModified-dark);
    4545    }
    4646
    47     .breakpoint.dom.breakpoint-for-node-removed:not(.breakpoint-paused-icon) .icon {
     47    .item.breakpoint.dom.node-removed:not(.paused) .icon {
    4848        content: url(../Images/TypeIcons.svg#DOMBreakpointNodeRemoved-dark);
    4949    }
  • trunk/Source/WebInspectorUI/UserInterface/Views/DOMBreakpointTreeElement.js

    r249291 r266074  
    2424 */
    2525
    26 WI.DOMBreakpointTreeElement = class DOMBreakpointTreeElement extends WI.GeneralTreeElement
     26WI.DOMBreakpointTreeElement = class DOMBreakpointTreeElement extends WI.BreakpointTreeElement
    2727{
    28     constructor(breakpoint, {className, title} = {})
     28    constructor(breakpoint, {classNames, title} = {})
    2929    {
    3030        console.assert(breakpoint instanceof WI.DOMBreakpoint);
    3131
    32         let classNames = ["breakpoint", "dom", `breakpoint-for-${breakpoint.type}`];
    33         if (className)
    34             classNames.push(className);
     32        if (!Array.isArray(classNames))
     33            classNames = [];
     34        classNames.push("dom", breakpoint.type);
    3535
    3636        if (!title)
    3737            title = WI.DOMBreakpointTreeElement.displayNameForType(breakpoint.type);
    3838
    39         const subtitle = null;
    40         super(classNames, title, subtitle, breakpoint);
    41 
    42         this.status = WI.ImageUtilities.useSVGSymbol("Images/Breakpoint.svg");
    43         this.status.className = WI.BreakpointTreeElement.StatusImageElementStyleClassName;
    44 
    45         this.tooltipHandledSeparately = true;
     39        super(breakpoint, {classNames, title});
    4640    }
    4741
     
    6256        }
    6357    }
    64 
    65     // Protected
    66 
    67     onattach()
    68     {
    69         super.onattach();
    70 
    71         this.representedObject.addEventListener(WI.DOMBreakpoint.Event.DisabledStateChanged, this._updateStatus, this);
    72         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.BreakpointsEnabledDidChange, this._updateStatus, this);
    73 
    74         this._boundStatusImageElementClicked = this._statusImageElementClicked.bind(this);
    75         this._boundStatusImageElementFocused = this._statusImageElementFocused.bind(this);
    76         this._boundStatusImageElementMouseDown = this._statusImageElementMouseDown.bind(this);
    77 
    78         this.status.addEventListener("click", this._boundStatusImageElementClicked);
    79         this.status.addEventListener("focus", this._boundStatusImageElementFocused);
    80         this.status.addEventListener("mousedown", this._boundStatusImageElementMouseDown);
    81 
    82         this._updateStatus();
    83     }
    84 
    85     ondetach()
    86     {
    87         super.ondetach();
    88 
    89         this.representedObject.removeEventListener(null, null, this);
    90         WI.debuggerManager.removeEventListener(null, null, this);
    91 
    92         this.status.removeEventListener("click", this._boundStatusImageElementClicked);
    93         this.status.removeEventListener("focus", this._boundStatusImageElementFocused);
    94         this.status.removeEventListener("mousedown", this._boundStatusImageElementMouseDown);
    95 
    96         this._boundStatusImageElementClicked = null;
    97         this._boundStatusImageElementFocused = null;
    98         this._boundStatusImageElementMouseDown = null;
    99     }
    100 
    101     ondelete()
    102     {
    103         // We set this flag so that TreeOutlines that will remove this
    104         // BreakpointTreeElement will know whether it was deleted from
    105         // within the TreeOutline or from outside it (e.g. TextEditor).
    106         this.__deletedViaDeleteKeyboardShortcut = true;
    107 
    108         WI.domDebuggerManager.removeDOMBreakpoint(this.representedObject);
    109 
    110         return true;
    111     }
    112 
    113     onenter()
    114     {
    115         this._toggleBreakpoint();
    116         return true;
    117     }
    118 
    119     onspace()
    120     {
    121         this._toggleBreakpoint();
    122         return true;
    123     }
    124 
    125     populateContextMenu(contextMenu, event)
    126     {
    127         let breakpoint = this.representedObject;
    128         let label = breakpoint.disabled ? WI.UIString("Enable Breakpoint") : WI.UIString("Disable Breakpoint");
    129         contextMenu.appendItem(label, this._toggleBreakpoint.bind(this));
    130 
    131         contextMenu.appendItem(WI.UIString("Delete Breakpoint"), function() {
    132             WI.domDebuggerManager.removeDOMBreakpoint(breakpoint);
    133         });
    134     }
    135 
    136     // Private
    137 
    138     _statusImageElementClicked(event)
    139     {
    140         this._toggleBreakpoint();
    141     }
    142 
    143     _statusImageElementFocused(event)
    144     {
    145         // Prevent tree outline focus.
    146         event.stopPropagation();
    147     }
    148 
    149     _statusImageElementMouseDown(event)
    150     {
    151         // Prevent tree element selection.
    152         event.stopPropagation();
    153     }
    154 
    155     _toggleBreakpoint()
    156     {
    157         this.representedObject.disabled = !this.representedObject.disabled;
    158     }
    159 
    160     _updateStatus()
    161     {
    162         if (!this.status)
    163             return;
    164 
    165         this.status.classList.toggle(WI.BreakpointTreeElement.StatusImageDisabledStyleClassName, this.representedObject.disabled);
    166         this.status.classList.toggle(WI.BreakpointTreeElement.StatusImageResolvedStyleClassName, WI.debuggerManager.breakpointsEnabled);
    167     }
    16858};
  • trunk/Source/WebInspectorUI/UserInterface/Views/DOMTreeContentView.js

    r262302 r266074  
    9696            WI.domDebuggerManager.addEventListener(WI.DOMDebuggerManager.Event.DOMBreakpointRemoved, this._domBreakpointAddedOrRemoved, this);
    9797
    98             WI.DOMBreakpoint.addEventListener(WI.DOMBreakpoint.Event.DisabledStateChanged, this._handleDOMBreakpointDisabledStateChanged, this);
     98            WI.DOMBreakpoint.addEventListener(WI.Breakpoint.Event.DisabledStateDidChange, this._handleDOMBreakpointDisabledStateChanged, this);
    9999            WI.DOMBreakpoint.addEventListener(WI.DOMBreakpoint.Event.DOMNodeChanged, this._handleDOMBreakpointDOMNodeChanged, this);
    100100
  • trunk/Source/WebInspectorUI/UserInterface/Views/EventBreakpointTreeElement.css

    r257757 r266074  
    2424 */
    2525
    26 .breakpoint.event.breakpoint-for-animation-frame:not(.breakpoint-paused-icon) .icon {
     26.item.breakpoint.event.animation-frame:not(.paused) .icon {
    2727    content: url(../Images/TypeIcons.svg#EventBreakpointAnimationFrame-light);
    2828}
    2929
    30 .breakpoint.event.breakpoint-for-interval:not(.breakpoint-paused-icon) .icon {
     30.item.breakpoint.event.interval:not(.paused) .icon {
    3131    content: url(../Images/TypeIcons.svg#EventBreakpointInterval-light);
    3232}
    3333
    34 .breakpoint.event.breakpoint-for-listener:not(.breakpoint-paused-icon) .icon {
     34.item.breakpoint.event.listener:not(.paused) .icon {
    3535    content: url(../Images/TypeIcons.svg#EventBreakpointListener-light);
    3636}
    3737
    38 .breakpoint.event.breakpoint-for-timeout:not(.breakpoint-paused-icon) .icon {
     38.item.breakpoint.event.timeout:not(.paused) .icon {
    3939    content: url(../Images/TypeIcons.svg#EventBreakpointTimeout-light);
    4040}
    4141
    4242@media(prefers-color-scheme: dark) {
    43     .breakpoint.event.breakpoint-for-animation-frame:not(.breakpoint-paused-icon) .icon {
     43    .item.breakpoint.event.animation-frame:not(.paused) .icon {
    4444        content: url(../Images/TypeIcons.svg#EventBreakpointAnimationFrame-dark);
    4545    }
    46    
    47     .breakpoint.event.breakpoint-for-interval:not(.breakpoint-paused-icon) .icon {
     46
     47    .item.breakpoint.event.interval:not(.paused) .icon {
    4848        content: url(../Images/TypeIcons.svg#EventBreakpointInterval-dark);
    4949    }
    50    
    51     .breakpoint.event.breakpoint-for-listener:not(.breakpoint-paused-icon) .icon {
     50
     51    .item.breakpoint.event.listener:not(.paused) .icon {
    5252        content: url(../Images/TypeIcons.svg#EventBreakpointListener-dark);
    5353    }
    54    
    55     .breakpoint.event.breakpoint-for-timeout:not(.breakpoint-paused-icon) .icon {
     54
     55    .item.breakpoint.event.timeout:not(.paused) .icon {
    5656        content: url(../Images/TypeIcons.svg#EventBreakpointTimeout-dark);
    57     }   
     57    }
    5858}
  • trunk/Source/WebInspectorUI/UserInterface/Views/EventBreakpointTreeElement.js

    r249291 r266074  
    2424 */
    2525
    26 WI.EventBreakpointTreeElement = class EventBreakpointTreeElement extends WI.GeneralTreeElement
     26WI.EventBreakpointTreeElement = class EventBreakpointTreeElement extends WI.BreakpointTreeElement
    2727{
    28     constructor(breakpoint, {className, title} = {})
     28    constructor(breakpoint, {classNames, title} = {})
    2929    {
    3030        console.assert(breakpoint instanceof WI.EventBreakpoint);
    3131
    32         let classNames = ["breakpoint", "event", `breakpoint-for-${breakpoint.type}`];
    33         if (className)
    34             classNames.push(className);
     32        if (!Array.isArray(classNames))
     33            classNames = [];
     34        classNames.push("event", breakpoint.type);
    3535
    3636        if (!title)
    3737            title = breakpoint.eventName;
    3838
    39         const subtitle = null;
    40         super(classNames, title, subtitle, breakpoint);
    41 
    42         this.status = WI.ImageUtilities.useSVGSymbol("Images/Breakpoint.svg");
    43         this.status.className = WI.BreakpointTreeElement.StatusImageElementStyleClassName;
    44 
    45         this.tooltipHandledSeparately = true;
    46     }
    47 
    48     // Protected
    49 
    50     onattach()
    51     {
    52         super.onattach();
    53 
    54         this.representedObject.addEventListener(WI.EventBreakpoint.Event.DisabledStateChanged, this._updateStatus, this);
    55         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.BreakpointsEnabledDidChange, this._updateStatus, this);
    56 
    57         this._boundStatusImageElementClicked = this._statusImageElementClicked.bind(this);
    58         this._boundStatusImageElementFocused = this._statusImageElementFocused.bind(this);
    59         this._boundStatusImageElementMouseDown = this._statusImageElementMouseDown.bind(this);
    60 
    61         this.status.addEventListener("click", this._boundStatusImageElementClicked);
    62         this.status.addEventListener("focus", this._boundStatusImageElementFocused);
    63         this.status.addEventListener("mousedown", this._boundStatusImageElementMouseDown);
    64 
    65         this._updateStatus();
    66     }
    67 
    68     ondetach()
    69     {
    70         super.ondetach();
    71 
    72         this.representedObject.removeEventListener(null, null, this);
    73         WI.debuggerManager.removeEventListener(null, null, this);
    74 
    75         this.status.removeEventListener("click", this._boundStatusImageElementClicked);
    76         this.status.removeEventListener("focus", this._boundStatusImageElementFocused);
    77         this.status.removeEventListener("mousedown", this._boundStatusImageElementMouseDown);
    78 
    79         this._boundStatusImageElementClicked = null;
    80         this._boundStatusImageElementFocused = null;
    81         this._boundStatusImageElementMouseDown = null;
    82     }
    83 
    84     ondelete()
    85     {
    86         // We set this flag so that TreeOutlines that will remove this
    87         // BreakpointTreeElement will know whether it was deleted from
    88         // within the TreeOutline or from outside it (e.g. TextEditor).
    89         this.__deletedViaDeleteKeyboardShortcut = true;
    90 
    91         if (this.representedObject.eventListener)
    92             WI.domManager.removeBreakpointForEventListener(this.representedObject.eventListener);
    93         else
    94             WI.domDebuggerManager.removeEventBreakpoint(this.representedObject);
    95 
    96         return true;
    97     }
    98 
    99     onenter()
    100     {
    101         this._toggleBreakpoint();
    102         return true;
    103     }
    104 
    105     onspace()
    106     {
    107         this._toggleBreakpoint();
    108         return true;
    109     }
    110 
    111     populateContextMenu(contextMenu, event)
    112     {
    113         let breakpoint = this.representedObject;
    114 
    115         let label = breakpoint.disabled ? WI.UIString("Enable Breakpoint") : WI.UIString("Disable Breakpoint");
    116         contextMenu.appendItem(label, this._toggleBreakpoint.bind(this));
    117 
    118         contextMenu.appendItem(WI.UIString("Delete Breakpoint"), () => {
    119             if (breakpoint.eventListener)
    120                 WI.domManager.removeBreakpointForEventListener(breakpoint.eventListener);
    121             else
    122                 WI.domDebuggerManager.removeEventBreakpoint(breakpoint);
    123         });
    124     }
    125 
    126     // Private
    127 
    128     _statusImageElementClicked(event)
    129     {
    130         this._toggleBreakpoint();
    131     }
    132 
    133     _statusImageElementFocused(event)
    134     {
    135         // Prevent tree outline focus.
    136         event.stopPropagation();
    137     }
    138 
    139     _statusImageElementMouseDown(event)
    140     {
    141         // Prevent tree element selection.
    142         event.stopPropagation();
    143     }
    144 
    145     _toggleBreakpoint()
    146     {
    147         this.representedObject.disabled = !this.representedObject.disabled;
    148     }
    149 
    150     _updateStatus()
    151     {
    152         if (!this.status)
    153             return;
    154 
    155         this.status.classList.toggle(WI.BreakpointTreeElement.StatusImageDisabledStyleClassName, this.representedObject.disabled);
    156         this.status.classList.toggle(WI.BreakpointTreeElement.StatusImageResolvedStyleClassName, WI.debuggerManager.breakpointsEnabled);
     39        super(breakpoint, {classNames, title});
    15740    }
    15841};
  • trunk/Source/WebInspectorUI/UserInterface/Views/EventListenerSectionGroup.css

    r224002 r266074  
    3535    margin: 0;
    3636}
     37
     38.event-listener-section > .content input[type="checkbox"] + .go-to-arrow {
     39    vertical-align: -2px;
     40}
     41
     42.event-listener-section > .content input[type="checkbox"]:not(:checked) + .go-to-arrow {
     43    display: none;
     44}
  • trunk/Source/WebInspectorUI/UserInterface/Views/EventListenerSectionGroup.js

    r248765 r266074  
    7373
    7474            if (WI.DOMManager.supportsEventListenerBreakpoints()) {
    75                 this._eventListenerBreakpointToggleElement = document.createElement("input");
     75                let toggleContainer = document.createElement("span");
     76
     77                this._eventListenerBreakpointToggleElement = toggleContainer.appendChild(document.createElement("input"));
    7678                this._eventListenerBreakpointToggleElement.type = "checkbox";
    7779                this._updateBreakpointToggle();
     
    8183                });
    8284
     85                if (WI.DOMManager.supportsEventListenerBreakpointConfiguration()) {
     86                    let revealBreakpointGoToArrow = toggleContainer.appendChild(WI.createGoToArrowButton());
     87                    revealBreakpointGoToArrow.title = WI.UIString("Reveal in Sources Tab");
     88                    revealBreakpointGoToArrow.addEventListener("click", (event) => {
     89                        console.assert(this.hasEventListenerBreakpoint);
     90
     91                        let breakpointToSelect = WI.domManager.breakpointForEventListenerId(this._eventListener.eventListenerId);
     92                        console.assert(breakpointToSelect);
     93
     94                        WI.showSourcesTab({breakpointToSelect});
     95                    });
     96                }
     97
    8398                let toggleLabel = document.createElement("span");
    8499                toggleLabel.textContent = WI.UIString("Breakpoint");
     
    87102                });
    88103
    89                 rows.push(new WI.DetailsSectionSimpleRow(toggleLabel, this._eventListenerBreakpointToggleElement));
     104                rows.push(new WI.DetailsSectionSimpleRow(toggleLabel, toggleContainer));
    90105            }
    91106        }
  • trunk/Source/WebInspectorUI/UserInterface/Views/JavaScriptBreakpointTreeElement.css

    r266073 r266074  
    2424 */
    2525
    26 .item.breakpoint .status {
    27     position: relative;
    28 }
    29 
    30 .item.breakpoint .status > .status-image {
    31     width: 23px;
    32     height: 12px;
    33     margin-top: 2px;
    34 
    35     fill: var(--breakpoint-color);
    36     stroke: hsla(0, 0%, 10%, 0.3);
     26.item.breakpoint.javascript .status > .status-image {
    3727    filter: grayscale();
    3828}
    3929
    40 .item.breakpoint .status > .status-image.resolved {
     30.item.breakpoint.javascript .status > .status-image.resolved {
    4131    filter: none;
    4232}
    4333
    44 body:not(.window-inactive, .window-docked-inactive) .tree-outline:focus-within .item.breakpoint.selected .status > .status-image.resolved {
     34body:not(.window-inactive, .window-docked-inactive) .tree-outline:focus-within .item.breakpoint.javascript.selected .status > .status-image.resolved {
    4535    stroke: var(--selected-foreground-color);
    4636}
    4737
    48 .item.breakpoint .status > .status-image.auto-continue::after {
    49     position: absolute;
    50     right: 3px;
    51     width: 3px;
    52     height: 12px;
    53     content: "";
    54     -webkit-clip-path: polygon(0 20%, 100% 50%, 0 80%);
    55     background-color: var(--selected-foreground-color);
    56 }
    57 
    58 .item.breakpoint .status > .status-image.disabled {
    59     fill: var(--breakpoint-color-disabled);
    60 }
    61 
    62 .item.breakpoint .subtitle.formatted-location {
     38.item.breakpoint.javascript .subtitle.formatted-location {
    6339    font-style: italic;
    64 }
    65 
    66 .breakpoint-debugger-statement-icon .icon {
    67     content: url(../Images/TypeIcons.svg#DebuggerStatement-light);
    68 }
    69 
    70 .breakpoint-exception-icon .icon {
    71     content: url(../Images/TypeIcons.svg#Exception-light);
    72 }
    73 
    74 .breakpoint-assertion-icon .icon {
    75     content: url(../Images/TypeIcons.svg#Assertion-light);
    76 }
    77 
    78 .breakpoint-microtask-icon .icon {
    79     content: url(../Images/TypeIcons.svg#Microtask-light);
    80 }
    81 
    82 .breakpoint-paused-icon .icon {
    83     content: url(../Images/TypeIcons.svg#PausedBreakpoint-light);
    8440}
    8541
    8642/* When animating a layer on top of a tree element's icon, move the main
    8743icon to the icon element's background so animations are layered on top. */
    88 .breakpoint-generic-line-icon .icon {
     44.item.breakpoint.javascript.line .icon {
    8945    background-image: url(../Images/TypeIcons.svg#ResultLine-light);
    9046    content: '';
    9147}
    9248
    93 .breakpoint-generic-line-icon .icon > span {
     49.item.breakpoint.javascript.line .icon > span {
    9450    position: absolute;
    9551    top: 0;
     
    10460}
    10561
    106 .data-updated.breakpoint-generic-line-icon .icon > span {
     62.data-updated.item.breakpoint.javascript.line .icon > span {
    10763    border-radius: 0;
    10864    transform: scale(0.85);
     
    11167}
    11268
     69.item.breakpoint.javascript.debugger-statement .icon {
     70    content: url(../Images/TypeIcons.svg#DebuggerStatement-light);
     71}
     72
     73.item.breakpoint.javascript.exception .icon {
     74    content: url(../Images/TypeIcons.svg#Exception-light);
     75}
     76
     77.item.breakpoint.javascript.assertion .icon {
     78    content: url(../Images/TypeIcons.svg#Assertion-light);
     79}
     80
     81.item.breakpoint.javascript.microtask .icon {
     82    content: url(../Images/TypeIcons.svg#Microtask-light);
     83}
     84
    11385@media (prefers-color-scheme: dark) {
    114     .breakpoint-debugger-statement-icon .icon {
     86    .item.breakpoint.javascript.line .icon {
     87        background-image: url(../Images/TypeIcons.svg#ResultLine-dark);
     88    }
     89
     90    .item.breakpoint.javascript.debugger-statement .icon {
    11591        content: url(../Images/TypeIcons.svg#DebuggerStatement-dark);
    11692    }
    117    
    118     .breakpoint-exception-icon .icon {
     93
     94    .item.breakpoint.javascript.exception .icon {
    11995        content: url(../Images/TypeIcons.svg#Exception-dark);
    12096    }
    12197
    122     .breakpoint-assertion-icon .icon {
     98    .item.breakpoint.javascript.assertion .icon {
    12399        content: url(../Images/TypeIcons.svg#Assertion-dark);
    124100    }
    125101
    126     .breakpoint-microtask-icon .icon {
     102    .item.breakpoint.javascript.microtask .icon {
    127103        content: url(../Images/TypeIcons.svg#Microtask-dark);
    128104    }
    129 
    130     .breakpoint-paused-icon .icon {
    131         content: url(../Images/TypeIcons.svg#PausedBreakpoint-dark);
    132     }
    133 
    134     .breakpoint-generic-line-icon .icon {
    135         background-image: url(../Images/TypeIcons.svg#ResultLine-dark);
    136     }
    137    
    138105}
  • trunk/Source/WebInspectorUI/UserInterface/Views/ProbeDetailsSidebarPanel.js

    r236845 r266074  
    6969
    7070        inspectedProbeSets.sort(function sortBySourceLocation(aProbeSet, bProbeSet) {
     71            if (!(aProbeSet instanceof WI.JavaScriptBreakpoint))
     72                return 1;
     73            if (!(bProbeSet instanceof WI.JavaScriptBreakpoint))
     74                return -1;
     75
    7176            var aLocation = aProbeSet.breakpoint.sourceCodeLocation;
    7277            var bLocation = bProbeSet.breakpoint.sourceCodeLocation;
  • trunk/Source/WebInspectorUI/UserInterface/Views/ProbeSetDetailsSection.js

    r262848 r266074  
    3131        console.assert(probeSet instanceof WI.ProbeSet, "Invalid ProbeSet argument:", probeSet);
    3232
     33        let title = "";
     34        if (probeSet.breakpoint instanceof WI.EventBreakpoint) {
     35            if (probeSet.breakpoint === WI.domDebuggerManager.allAnimationFramesBreakpoint)
     36                title = WI.UIString("All Animation Frames");
     37            else if (probeSet.breakpoint === WI.domDebuggerManager.allIntervalsBreakpoint)
     38                title = WI.UIString("All Intervals");
     39            else if (probeSet.breakpoint === WI.domDebuggerManager.allListenersBreakpoint)
     40                title = WI.UIString("All Events");
     41            else if (probeSet.breakpoint === WI.domDebuggerManager.allTimeoutsBreakpoint)
     42                title = WI.UIString("All Timeouts");
     43            else
     44                title = probeSet.breakpoint.eventName;
     45        }
     46
    3347        var optionsElement = document.createElement("div");
    3448        var dataGrid = new WI.ProbeSetDataGrid(probeSet);
     
    3953        var probeSectionGroup = new WI.DetailsSectionGroup([singletonRow]);
    4054
    41         super("probe", "", [probeSectionGroup], optionsElement);
     55        super("probe", title, [probeSectionGroup], optionsElement);
    4256
    4357        this.element.classList.add("probe-set");
     
    6680        this._listenerSet.register(this._probeSet, WI.ProbeSet.Event.SamplesCleared, this._probeSetSamplesChanged);
    6781
    68         // Update the source link when the breakpoint's resolved state changes,
    69         // so that it can become a live location link when possible.
    70         this._updateLinkElement();
    71         this._listenerSet.register(this._probeSet.breakpoint, WI.Breakpoint.Event.ResolvedStateDidChange, this._updateLinkElement);
     82        if (this._probeSet.breakpoint instanceof WI.JavaScriptBreakpoint) {
     83            // Update the source link when the breakpoint's resolved state changes,
     84            // so that it can become a live location link when possible.
     85            this._updateLinkElement();
     86            this._listenerSet.register(this._probeSet.breakpoint, WI.JavaScriptBreakpoint.Event.ResolvedStateDidChange, this._updateLinkElement);
     87        }
    7288
    7389        this._listenerSet.install();
  • trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.js

    r262302 r266074  
    6767
    6868        if (this._supportsDebugging) {
    69             WI.Breakpoint.addEventListener(WI.Breakpoint.Event.DisabledStateDidChange, this._breakpointStatusDidChange, this);
    70             WI.Breakpoint.addEventListener(WI.Breakpoint.Event.AutoContinueDidChange, this._breakpointStatusDidChange, this);
    71             WI.Breakpoint.addEventListener(WI.Breakpoint.Event.ResolvedStateDidChange, this._breakpointStatusDidChange, this);
    72             WI.Breakpoint.addEventListener(WI.Breakpoint.Event.LocationDidChange, this._updateBreakpointLocation, this);
     69            WI.JavaScriptBreakpoint.addEventListener(WI.Breakpoint.Event.DisabledStateDidChange, this._breakpointStatusDidChange, this);
     70            WI.JavaScriptBreakpoint.addEventListener(WI.Breakpoint.Event.AutoContinueDidChange, this._breakpointStatusDidChange, this);
     71
     72            WI.JavaScriptBreakpoint.addEventListener(WI.JavaScriptBreakpoint.Event.ResolvedStateDidChange, this._breakpointStatusDidChange, this);
     73            WI.JavaScriptBreakpoint.addEventListener(WI.JavaScriptBreakpoint.Event.LocationDidChange, this._updateBreakpointLocation, this);
    7374
    7475            WI.targetManager.addEventListener(WI.TargetManager.Event.TargetAdded, this._targetAdded, this);
     
    168169    {
    169170        if (this._supportsDebugging) {
    170             WI.Breakpoint.removeEventListener(null, null, this);
     171            WI.JavaScriptBreakpoint.removeEventListener(null, null, this);
    171172            WI.debuggerManager.removeEventListener(null, null, this);
    172173            WI.targetManager.removeEventListener(null, null, this);
     
    13061307        var unformattedLineInfo = this._unformattedLineInfoForEditorLineInfo(editorLineInfo);
    13071308        var sourceCodeLocation = this._sourceCode.createSourceCodeLocation(unformattedLineInfo.lineNumber, unformattedLineInfo.columnNumber);
    1308         var breakpoint = new WI.Breakpoint(sourceCodeLocation);
     1309        var breakpoint = new WI.JavaScriptBreakpoint(sourceCodeLocation);
    13091310
    13101311        var lineInfo = this._editorLineInfoForSourceCodeLocation(breakpoint.sourceCodeLocation);
  • trunk/Source/WebInspectorUI/UserInterface/Views/SourcesNavigationSidebarPanel.js

    r266072 r266074  
    170170            console.assert(selectedTreeElement.selected);
    171171
    172             if (!WI.debuggerManager.isBreakpointRemovable(selectedTreeElement.representedObject)) {
     172            if (!selectedTreeElement.representedObject.removable) {
    173173                let treeElementToSelect = selectedTreeElement.nextSelectableSibling;
    174174                if (treeElementToSelect) {
     
    327327        WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.WaitingToPause, this._handleDebuggerWaitingToPause, this);
    328328
    329         WI.Breakpoint.addEventListener(WI.Breakpoint.Event.DisplayLocationDidChange, this._handleDebuggerObjectDisplayLocationDidChange, this);
     329        WI.JavaScriptBreakpoint.addEventListener(WI.JavaScriptBreakpoint.Event.DisplayLocationDidChange, this._handleDebuggerObjectDisplayLocationDidChange, this);
    330330        WI.IssueMessage.addEventListener(WI.IssueMessage.Event.DisplayLocationDidChange, this._handleDebuggerObjectDisplayLocationDidChange, this);
    331331
     
    389389
    390390        if (WI.domDebuggerManager.supported) {
    391             if (WI.settings.showAllAnimationFramesBreakpoint.value)
    392                 WI.domDebuggerManager.addEventBreakpoint(WI.domDebuggerManager.allAnimationFramesBreakpoint);
    393 
    394             if (WI.settings.showAllTimeoutsBreakpoint.value)
    395                 WI.domDebuggerManager.addEventBreakpoint(WI.domDebuggerManager.allTimeoutsBreakpoint);
    396 
    397             if (WI.settings.showAllIntervalsBreakpoint.value)
    398                 WI.domDebuggerManager.addEventBreakpoint(WI.domDebuggerManager.allIntervalsBreakpoint);
    399 
    400             if (WI.settings.showAllListenersBreakpoint.value)
    401                 WI.domDebuggerManager.addEventBreakpoint(WI.domDebuggerManager.allListenersBreakpoint);
     391            if (WI.domDebuggerManager.allAnimationFramesBreakpoint)
     392                this._addBreakpoint(WI.domDebuggerManager.allAnimationFramesBreakpoint);
     393
     394            if (WI.domDebuggerManager.allTimeoutsBreakpoint)
     395                this._addBreakpoint(WI.domDebuggerManager.allTimeoutsBreakpoint);
     396
     397            if (WI.domDebuggerManager.allIntervalsBreakpoint)
     398                this._addBreakpoint(WI.domDebuggerManager.allIntervalsBreakpoint);
     399
     400            if (WI.domDebuggerManager.allListenersBreakpoint)
     401                this._addBreakpoint(WI.domDebuggerManager.allListenersBreakpoint);
    402402
    403403            for (let eventBreakpoint of WI.domDebuggerManager.listenerBreakpoints)
     
    454454        WI.debuggerManager.removeEventListener(null, null, this);
    455455        WI.domDebuggerManager.removeEventListener(null, null, this);
    456         WI.Breakpoint.removeEventListener(null, null, this);
     456        WI.JavaScriptBreakpoint.removeEventListener(null, null, this);
    457457        WI.IssueMessage.removeEventListener(null, null, this);
    458458        WI.DOMBreakpoint.removeEventListener(null, null, this);
     
    12031203                (treeElement) => treeElement.representedObject === WI.debuggerManager.uncaughtExceptionsBreakpoint,
    12041204                (treeElement) => treeElement.representedObject === WI.debuggerManager.assertionFailuresBreakpoint,
    1205                 (treeElement) => treeElement instanceof WI.BreakpointTreeElement || treeElement instanceof WI.ResourceTreeElement || treeElement instanceof WI.ScriptTreeElement,
     1205                (treeElement) => treeElement instanceof WI.JavaScriptBreakpointTreeElement || treeElement instanceof WI.ResourceTreeElement || treeElement instanceof WI.ScriptTreeElement,
    12061206                (treeElement) => treeElement.representedObject === WI.debuggerManager.allMicrotasksBreakpoint,
    12071207                (treeElement) => treeElement.representedObject === WI.domDebuggerManager.allAnimationFramesBreakpoint,
     
    12261226            }
    12271227
    1228             if (a instanceof WI.BreakpointTreeElement && b instanceof WI.BreakpointTreeElement)
    1229                 return this._compareBreakpointTreeElements(a, b);
     1228            if (a instanceof WI.JavaScriptBreakpointTreeElement && b instanceof WI.JavaScriptBreakpointTreeElement)
     1229                return this._compareJavaScriptBreakpointTreeElements(a, b);
    12301230
    12311231            return a.mainTitle.extendedLocaleCompare(b.mainTitle) || a.subtitle.extendedLocaleCompare(b.subtitle);
     
    12351235    }
    12361236
    1237     _compareBreakpointTreeElements(a, b)
     1237    _compareJavaScriptBreakpointTreeElements(a, b)
    12381238    {
    12391239        if (!a.representedObject || !b.representedObject)
     
    12531253            return null;
    12541254
    1255         let constructor = WI.BreakpointTreeElement;
     1255        let constructor = WI.JavaScriptBreakpointTreeElement;
    12561256        let options = {};
    12571257        let parentTreeElement = this._breakpointsTreeOutline;
     
    12711271
    12721272        if (breakpoint === WI.debuggerManager.debuggerStatementsBreakpoint) {
    1273             options.className = "breakpoint-debugger-statement-icon";
     1273            options.classNames = ["debugger-statement"];
    12741274            options.title = WI.UIString("Debugger Statements");
    12751275        } else if (breakpoint === WI.debuggerManager.allExceptionsBreakpoint) {
    1276             options.className = "breakpoint-exception-icon";
     1276            options.classNames = ["exception"];
    12771277            options.title = WI.repeatedUIString.allExceptions();
    12781278        } else if (breakpoint === WI.debuggerManager.uncaughtExceptionsBreakpoint) {
    1279             options.className = "breakpoint-exception-icon";
     1279            options.classNames = ["exception"];
    12801280            options.title = WI.repeatedUIString.uncaughtExceptions();
    12811281        } else if (breakpoint === WI.debuggerManager.assertionFailuresBreakpoint) {
    1282             options.className = "breakpoint-assertion-icon";
     1282            options.classNames = ["assertion"];
    12831283            options.title = WI.repeatedUIString.assertionFailures();
    12841284        } else if (breakpoint === WI.debuggerManager.allMicrotasksBreakpoint) {
    1285             options.className = "breakpoint-microtask-icon";
     1285            options.classNames = ["microtask"];
    12861286            options.title = WI.UIString("All Microtasks");
    12871287        } else if (breakpoint instanceof WI.DOMBreakpoint) {
     
    13661366    {
    13671367        for (let breakpoint of breakpoints) {
    1368             if (WI.debuggerManager.isBreakpointRemovable(breakpoint))
     1368            if (breakpoint.removable)
    13691369                WI.debuggerManager.removeBreakpoint(breakpoint);
    13701370        }
     
    13851385        let breakpoints = [];
    13861386        for (let child of treeElement.children) {
    1387             console.assert(child instanceof WI.BreakpointTreeElement);
     1387            console.assert(child instanceof WI.JavaScriptBreakpointTreeElement);
    13881388            let breakpoint = child.breakpoint;
    13891389            console.assert(breakpoint);
     
    14051405            issueTreeElement = new WI.IssueTreeElement(issueMessage);
    14061406
    1407             parentTreeElement.insertChild(issueTreeElement, insertionIndexForObjectInListSortedByFunction(issueTreeElement, parentTreeElement.children, this._compareBreakpointTreeElements));
     1407            parentTreeElement.insertChild(issueTreeElement, insertionIndexForObjectInListSortedByFunction(issueTreeElement, parentTreeElement.children, this._compareJavaScriptBreakpointTreeElements));
    14081408            if (parentTreeElement.children.length === 1)
    14091409                parentTreeElement.expand();
     
    15521552
    15531553            let eventBreakpointTreeElement = new WI.EventBreakpointTreeElement(WI.domDebuggerManager.allAnimationFramesBreakpoint, {
    1554                 className: "breakpoint-paused-icon",
     1554                classNames: ["paused"],
    15551555                title: WI.UIString("requestAnimationFrame Fired"),
    15561556            });
     
    15971597
    15981598            let breakpoint = WI.debuggerManager.breakpointForIdentifier(pauseData.breakpointId);
    1599             let breakpointTreeElement = new WI.BreakpointTreeElement(breakpoint, {
    1600                 className: "breakpoint-paused-icon",
     1599            let breakpointTreeElement = new WI.JavaScriptBreakpointTreeElement(breakpoint, {
     1600                classNames: ["paused"],
    16011601                title: WI.UIString("Triggered Breakpoint"),
    16021602            });
     
    16471647            let type = WI.DOMBreakpointTreeElement.displayNameForType(domBreakpoint.type);
    16481648            let domBreakpointTreeElement = new WI.DOMBreakpointTreeElement(domBreakpoint, {
    1649                 className: "breakpoint-paused-icon",
     1649                classNames: ["paused"],
    16501650                title: type,
    16511651            });
     
    17171717
    17181718            let eventBreakpointTreeElement = new WI.EventBreakpointTreeElement(eventBreakpoint, {
    1719                 className: "breakpoint-paused-icon",
     1719                classNames: ["paused"],
    17201720                title: WI.UIString("\u201C%s\u201D Event Fired").format(pauseData.eventName),
    17211721            });
     
    17601760
    17611761            let eventBreakpointTreeElement = new WI.EventBreakpointTreeElement(WI.domDebuggerManager.allIntervalsBreakpoint, {
    1762                 className: "breakpoint-paused-icon",
     1762                classNames: ["paused"],
    17631763                title: WI.UIString("setInterval Fired"),
    17641764            });
     
    18041804
    18051805            let eventBreakpointTreeElement = new WI.EventBreakpointTreeElement(eventBreakpoint, {
    1806                 className: "breakpoint-paused-icon",
     1806                classNames: ["paused"],
    18071807                title: WI.UIString("%s Fired").format(pauseData.eventName),
    18081808            });
     
    18201820
    18211821            let eventBreakpointTreeElement = new WI.EventBreakpointTreeElement(WI.domDebuggerManager.allTimeoutsBreakpoint, {
    1822                 className: "breakpoint-paused-icon",
     1822                classNames: ["paused"],
    18231823                title: WI.UIString("setTimeout Fired"),
    18241824            });
     
    18461846
    18471847                let urlBreakpointTreeElement = new WI.URLBreakpointTreeElement(urlBreakpoint, {
    1848                     className: "breakpoint-paused-icon",
     1848                    classNames: ["paused"],
    18491849                    title: WI.UIString("Triggered URL Breakpoint"),
    18501850                });
     
    19521952        }
    19531953
    1954         if (treeElement instanceof WI.BreakpointTreeElement) {
     1954        if (treeElement instanceof WI.JavaScriptBreakpointTreeElement) {
    19551955            let breakpoint = treeElement.breakpoint;
    1956             if (WI.debuggerManager.isBreakpointSpecial(breakpoint))
     1956            if (breakpoint.special)
    19571957                return;
    19581958
     
    19831983            break;
    19841984
    1985         case WI.domDebuggerManager.allAnimationFramesBreakpoint:
    1986             setting = WI.settings.showAllAnimationFramesBreakpoint;
    1987             break;
    1988 
    1989         case WI.domDebuggerManager.allIntervalsBreakpoint:
    1990             setting = WI.settings.showAllIntervalsBreakpoint;
    1991             break;
    1992 
    1993         case WI.domDebuggerManager.allListenersBreakpoint:
    1994             setting = WI.settings.showAllListenersBreakpoint;
    1995             break;
    1996 
    19971985        case WI.domDebuggerManager.allRequestsBreakpoint:
    19981986            setting = WI.settings.showAllRequestsBreakpoint;
    19991987            break;
    2000 
    2001         case WI.domDebuggerManager.allTimeoutsBreakpoint:
    2002             setting = WI.settings.showAllTimeoutsBreakpoint;
    2003             break;
    20041988        }
    20051989
     
    20101994            let selectedTreeElement = this._breakpointsTreeOutline.selectedTreeElement;
    20111995            if (selectedTreeElement) {
    2012                 if (selectedTreeElement.representedObject === WI.debuggerManager.assertionFailuresBreakpoint || !WI.debuggerManager.isBreakpointRemovable(selectedTreeElement.representedObject)) {
     1996                if (selectedTreeElement.representedObject === WI.debuggerManager.assertionFailuresBreakpoint || !selectedTreeElement.representedObject.removable) {
    20131997                    const skipUnrevealed = true;
    20141998                    const dontPopulate = true;
     
    20542038
    20552039        if (WI.DOMDebuggerManager.supportsEventBreakpoints() || WI.DOMDebuggerManager.supportsEventListenerBreakpoints()) {
    2056             function addToggleForSpecialEventBreakpoint(breakpoint, label, checked) {
     2040            function addToggleForSpecialEventBreakpoint(label, breakpoint, type) {
    20572041                contextMenu.appendCheckboxItem(label, () => {
    2058                     if (checked)
     2042                    if (breakpoint)
    20592043                        WI.domDebuggerManager.removeEventBreakpoint(breakpoint);
    2060                     else {
    2061                         breakpoint.disabled = false;
    2062                         WI.domDebuggerManager.addEventBreakpoint(breakpoint);
    2063                     }
    2064                 }, checked);
    2065             }
    2066 
    2067             addToggleForSpecialEventBreakpoint(WI.domDebuggerManager.allAnimationFramesBreakpoint, WI.UIString("All Animation Frames"), WI.settings.showAllAnimationFramesBreakpoint.value);
    2068             addToggleForSpecialEventBreakpoint(WI.domDebuggerManager.allTimeoutsBreakpoint, WI.UIString("All Timeouts"), WI.settings.showAllTimeoutsBreakpoint.value);
    2069             addToggleForSpecialEventBreakpoint(WI.domDebuggerManager.allIntervalsBreakpoint, WI.UIString("All Intervals"), WI.settings.showAllIntervalsBreakpoint.value);
     2044                    else
     2045                        WI.domDebuggerManager.addEventBreakpoint(new WI.EventBreakpoint(type));
     2046                }, !!breakpoint);
     2047            }
     2048
     2049            addToggleForSpecialEventBreakpoint(WI.UIString("All Animation Frames"), WI.domDebuggerManager.allAnimationFramesBreakpoint, WI.EventBreakpoint.Type.AnimationFrame);
     2050            addToggleForSpecialEventBreakpoint(WI.UIString("All Timeouts"), WI.domDebuggerManager.allTimeoutsBreakpoint, WI.EventBreakpoint.Type.Timeout);
     2051            addToggleForSpecialEventBreakpoint(WI.UIString("All Intervals"), WI.domDebuggerManager.allIntervalsBreakpoint, WI.EventBreakpoint.Type.Interval);
    20702052
    20712053            contextMenu.appendSeparator();
    20722054
    20732055            if (WI.DOMDebuggerManager.supportsAllListenersBreakpoint())
    2074                 addToggleForSpecialEventBreakpoint(WI.domDebuggerManager.allListenersBreakpoint, WI.UIString("All Events"), WI.settings.showAllListenersBreakpoint.value);
     2056                addToggleForSpecialEventBreakpoint(WI.UIString("All Events"), WI.domDebuggerManager.allListenersBreakpoint, WI.EventBreakpoint.Type.Listener);
    20752057
    20762058            contextMenu.appendItem(WI.UIString("Event Breakpoint\u2026"), () => {
     
    24232405        let oldDebuggerTreeElement = null;
    24242406        let newDebuggerTreeElement = null;
    2425         if (debuggerObject instanceof WI.Breakpoint) {
     2407        if (debuggerObject instanceof WI.JavaScriptBreakpoint) {
    24262408            oldDebuggerTreeElement = this._breakpointsTreeOutline.findTreeElement(debuggerObject);
    24272409            if (oldDebuggerTreeElement)
  • trunk/Source/WebInspectorUI/UserInterface/Views/TextResourceContentView.js

    r253241 r266074  
    9999    {
    100100        let objects = WI.debuggerManager.probeSets.filter(function(probeSet) {
    101             return this._resource.contentIdentifier === probeSet.breakpoint.contentIdentifier;
     101            return !(probeSet.breakpoint instanceof WI.JavaScriptBreakpoint) || this._resource.contentIdentifier === probeSet.breakpoint.contentIdentifier;
    102102        }, this);
    103103
     
    320320    {
    321321        var breakpoint = event.data.probeSet.breakpoint;
    322         if (breakpoint.sourceCodeLocation.sourceCode === this.resource)
     322        if (!(breakpoint instanceof WI.JavaScriptBreakpoint) || breakpoint.sourceCodeLocation.sourceCode === this.resource)
    323323            this.dispatchEventToListeners(WI.ContentView.Event.SupplementalRepresentedObjectsDidChange);
    324324    }
  • trunk/Source/WebInspectorUI/UserInterface/Views/URLBreakpointTreeElement.css

    r256774 r266074  
    2424 */
    2525
    26 .breakpoint.url .subtitle {
     26.item.breakpoint.url .subtitle {
    2727    font-family: Menlo, monospace;
    2828}
    2929
    30 .breakpoint.url:not(.breakpoint-paused-icon) .icon {
     30.item.breakpoint.url:not(.paused) .icon {
    3131    content: url(../Images/TypeIcons.svg#URLBreakpoint-light);
    3232}
    3333
    3434@media (prefers-color-scheme: dark) {
    35     .breakpoint.url:not(.breakpoint-paused-icon) .icon {
     35    .item.breakpoint.url:not(.paused) .icon {
    3636        content: url(../Images/TypeIcons.svg#URLBreakpoint-dark);
    3737    }
  • trunk/Source/WebInspectorUI/UserInterface/Views/URLBreakpointTreeElement.js

    r249291 r266074  
    2424 */
    2525
    26 WI.URLBreakpointTreeElement = class URLBreakpointTreeElement extends WI.GeneralTreeElement
     26WI.URLBreakpointTreeElement = class URLBreakpointTreeElement extends WI.BreakpointTreeElement
    2727{
    28     constructor(breakpoint, {className, title} = {})
     28    constructor(breakpoint, {classNames, title} = {})
    2929    {
    3030        console.assert(breakpoint instanceof WI.URLBreakpoint);
    3131
    32         let classNames = ["breakpoint", "url"];
    33         if (className)
    34             classNames.push(className);
     32        if (!Array.isArray(classNames))
     33            classNames = [];
     34        classNames.push("url");
    3535
    3636        let subtitle;
     
    4343        }
    4444
    45         super(classNames, title, subtitle, breakpoint);
    46 
    47         this.status = WI.ImageUtilities.useSVGSymbol("Images/Breakpoint.svg");
    48         this.status.className = WI.BreakpointTreeElement.StatusImageElementStyleClassName;
    49 
    50         this.tooltipHandledSeparately = true;
    51     }
    52 
    53     // Protected
    54 
    55     onattach()
    56     {
    57         super.onattach();
    58 
    59         this.representedObject.addEventListener(WI.URLBreakpoint.Event.DisabledStateChanged, this._updateStatus, this);
    60         WI.debuggerManager.addEventListener(WI.DebuggerManager.Event.BreakpointsEnabledDidChange, this._updateStatus, this);
    61 
    62         this._boundStatusImageElementClicked = this._statusImageElementClicked.bind(this);
    63         this._boundStatusImageElementFocused = this._statusImageElementFocused.bind(this);
    64         this._boundStatusImageElementMouseDown = this._statusImageElementMouseDown.bind(this);
    65 
    66         this.status.addEventListener("click", this._boundStatusImageElementClicked);
    67         this.status.addEventListener("focus", this._boundStatusImageElementFocused);
    68         this.status.addEventListener("mousedown", this._boundStatusImageElementMouseDown);
    69 
    70         this._updateStatus();
    71     }
    72 
    73     ondetach()
    74     {
    75         super.ondetach();
    76 
    77         this.representedObject.removeEventListener(null, null, this);
    78         WI.debuggerManager.removeEventListener(null, null, this);
    79 
    80         this.status.removeEventListener("click", this._boundStatusImageElementClicked);
    81         this.status.removeEventListener("focus", this._boundStatusImageElementFocused);
    82         this.status.removeEventListener("mousedown", this._boundStatusImageElementMouseDown);
    83 
    84         this._boundStatusImageElementClicked = null;
    85         this._boundStatusImageElementFocused = null;
    86         this._boundStatusImageElementMouseDown = null;
    87     }
    88 
    89     ondelete()
    90     {
    91         // We set this flag so that TreeOutlines that will remove this
    92         // BreakpointTreeElement will know whether it was deleted from
    93         // within the TreeOutline or from outside it (e.g. TextEditor).
    94         this.__deletedViaDeleteKeyboardShortcut = true;
    95 
    96         WI.domDebuggerManager.removeURLBreakpoint(this.representedObject);
    97 
    98         return true;
    99     }
    100 
    101     onenter()
    102     {
    103         this._toggleBreakpoint();
    104         return true;
    105     }
    106 
    107     onspace()
    108     {
    109         this._toggleBreakpoint();
    110         return true;
    111     }
    112 
    113     populateContextMenu(contextMenu, event)
    114     {
    115         let breakpoint = this.representedObject;
    116         let label = breakpoint.disabled ? WI.UIString("Enable Breakpoint") : WI.UIString("Disable Breakpoint");
    117         contextMenu.appendItem(label, this._toggleBreakpoint.bind(this));
    118 
    119         contextMenu.appendItem(WI.UIString("Delete Breakpoint"), () => {
    120             WI.domDebuggerManager.removeURLBreakpoint(breakpoint);
    121         });
    122     }
    123 
    124     // Private
    125 
    126     _statusImageElementClicked(event)
    127     {
    128         this._toggleBreakpoint();
    129     }
    130 
    131     _statusImageElementFocused(event)
    132     {
    133         // Prevent tree outline focus.
    134         event.stopPropagation();
    135     }
    136 
    137     _statusImageElementMouseDown(event)
    138     {
    139         // Prevent tree element selection.
    140         event.stopPropagation();
    141     }
    142 
    143     _toggleBreakpoint()
    144     {
    145         this.representedObject.disabled = !this.representedObject.disabled;
    146     }
    147 
    148     _updateStatus()
    149     {
    150         if (!this.status)
    151             return;
    152 
    153         this.status.classList.toggle(WI.BreakpointTreeElement.StatusImageDisabledStyleClassName, this.representedObject.disabled);
    154         this.status.classList.toggle(WI.BreakpointTreeElement.StatusImageResolvedStyleClassName, WI.debuggerManager.breakpointsEnabled);
     45        super(breakpoint, {classNames, title, subtitle});
    15546    }
    15647};
Note: See TracChangeset for help on using the changeset viewer.