2 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include "core/inspector/InspectorDOMDebuggerAgent.h"
34 #include "core/InspectorFrontend.h"
35 #include "core/events/Event.h"
36 #include "core/inspector/InspectorDOMAgent.h"
37 #include "core/inspector/InspectorState.h"
38 #include "core/inspector/InstrumentingAgents.h"
39 #include "platform/JSONValues.h"
43 enum DOMBreakpointType {
47 DOMBreakpointTypesCount
50 static const char listenerEventCategoryType[] = "listener:";
51 static const char instrumentationEventCategoryType[] = "instrumentation:";
53 const uint32_t inheritableDOMBreakpointTypesMask = (1 << SubtreeModified);
54 const int domBreakpointDerivedTypeShift = 16;
60 static const char requestAnimationFrameEventName[] = "requestAnimationFrame";
61 static const char cancelAnimationFrameEventName[] = "cancelAnimationFrame";
62 static const char animationFrameFiredEventName[] = "animationFrameFired";
63 static const char setTimerEventName[] = "setTimer";
64 static const char clearTimerEventName[] = "clearTimer";
65 static const char timerFiredEventName[] = "timerFired";
66 static const char newPromiseEventName[] = "newPromise";
67 static const char promiseResolvedEventName[] = "promiseResolved";
68 static const char promiseRejectedEventName[] = "promiseRejected";
69 static const char windowCloseEventName[] = "close";
70 static const char customElementCallbackName[] = "customElementCallback";
71 static const char webglErrorFiredEventName[] = "webglErrorFired";
72 static const char webglWarningFiredEventName[] = "webglWarningFired";
73 static const char webglErrorNameProperty[] = "webglErrorName";
75 namespace DOMDebuggerAgentState {
76 static const char eventListenerBreakpoints[] = "eventListenerBreakpoints";
77 static const char eventTargetAny[] = "*";
78 static const char pauseOnAllXHRs[] = "pauseOnAllXHRs";
79 static const char xhrBreakpoints[] = "xhrBreakpoints";
82 PassOwnPtrWillBeRawPtr<InspectorDOMDebuggerAgent> InspectorDOMDebuggerAgent::create(InspectorDOMAgent* domAgent, InspectorDebuggerAgent* debuggerAgent)
84 return adoptPtrWillBeNoop(new InspectorDOMDebuggerAgent(domAgent, debuggerAgent));
87 InspectorDOMDebuggerAgent::InspectorDOMDebuggerAgent(InspectorDOMAgent* domAgent, InspectorDebuggerAgent* debuggerAgent)
88 : InspectorBaseAgent<InspectorDOMDebuggerAgent>("DOMDebugger")
89 , m_domAgent(domAgent)
90 , m_debuggerAgent(debuggerAgent)
91 , m_pauseInNextEventListener(false)
93 m_debuggerAgent->setListener(this);
94 m_domAgent->setListener(this);
97 InspectorDOMDebuggerAgent::~InspectorDOMDebuggerAgent()
100 ASSERT(!m_debuggerAgent);
101 ASSERT(!m_instrumentingAgents->inspectorDOMDebuggerAgent());
105 void InspectorDOMDebuggerAgent::trace(Visitor* visitor)
107 visitor->trace(m_domAgent);
108 visitor->trace(m_debuggerAgent);
110 visitor->trace(m_domBreakpoints);
112 InspectorBaseAgent::trace(visitor);
115 // Browser debugger agent enabled only when JS debugger is enabled.
116 void InspectorDOMDebuggerAgent::debuggerWasEnabled()
118 if (m_domAgent->enabled() && m_debuggerAgent->enabled())
119 m_instrumentingAgents->setInspectorDOMDebuggerAgent(this);
122 void InspectorDOMDebuggerAgent::debuggerWasDisabled()
127 void InspectorDOMDebuggerAgent::domAgentWasEnabled()
129 if (m_domAgent->enabled() && m_debuggerAgent->enabled())
130 m_instrumentingAgents->setInspectorDOMDebuggerAgent(this);
133 void InspectorDOMDebuggerAgent::domAgentWasDisabled()
138 void InspectorDOMDebuggerAgent::stepInto()
140 m_pauseInNextEventListener = true;
143 void InspectorDOMDebuggerAgent::didPause()
145 m_pauseInNextEventListener = false;
148 void InspectorDOMDebuggerAgent::didProcessTask()
150 if (!m_pauseInNextEventListener)
152 if (m_debuggerAgent && m_debuggerAgent->runningNestedMessageLoop())
154 m_pauseInNextEventListener = false;
157 void InspectorDOMDebuggerAgent::disable()
159 m_instrumentingAgents->setInspectorDOMDebuggerAgent(0);
163 void InspectorDOMDebuggerAgent::clearFrontend()
168 void InspectorDOMDebuggerAgent::discardAgent()
170 m_debuggerAgent->setListener(0);
171 m_debuggerAgent = nullptr;
174 void InspectorDOMDebuggerAgent::setEventListenerBreakpoint(ErrorString* error, const String& eventName, const String* targetName)
176 setBreakpoint(error, String(listenerEventCategoryType) + eventName, targetName);
179 void InspectorDOMDebuggerAgent::setInstrumentationBreakpoint(ErrorString* error, const String& eventName)
181 setBreakpoint(error, String(instrumentationEventCategoryType) + eventName, 0);
184 static PassRefPtr<JSONObject> ensurePropertyObject(JSONObject* object, const String& propertyName)
186 JSONObject::iterator it = object->find(propertyName);
187 if (it != object->end())
188 return it->value->asObject();
190 RefPtr<JSONObject> result = JSONObject::create();
191 object->setObject(propertyName, result);
192 return result.release();
195 void InspectorDOMDebuggerAgent::setBreakpoint(ErrorString* error, const String& eventName, const String* targetName)
197 if (eventName.isEmpty()) {
198 *error = "Event name is empty";
202 // Backward compatibility. Some extensions expect that DOMDebuggerAgent is always enabled.
203 // See https://stackoverflow.com/questions/25764336/chrome-extension-domdebugger-api-does-not-work-anymore
204 if (!m_domAgent->enabled())
205 m_domAgent->enable(error);
210 RefPtr<JSONObject> eventListenerBreakpoints = m_state->getObject(DOMDebuggerAgentState::eventListenerBreakpoints);
211 RefPtr<JSONObject> breakpointsByTarget = ensurePropertyObject(eventListenerBreakpoints.get(), eventName);
212 if (!targetName || targetName->isEmpty())
213 breakpointsByTarget->setBoolean(DOMDebuggerAgentState::eventTargetAny, true);
215 breakpointsByTarget->setBoolean(targetName->lower(), true);
216 m_state->setObject(DOMDebuggerAgentState::eventListenerBreakpoints, eventListenerBreakpoints.release());
219 void InspectorDOMDebuggerAgent::removeEventListenerBreakpoint(ErrorString* error, const String& eventName, const String* targetName)
221 removeBreakpoint(error, String(listenerEventCategoryType) + eventName, targetName);
224 void InspectorDOMDebuggerAgent::removeInstrumentationBreakpoint(ErrorString* error, const String& eventName)
226 removeBreakpoint(error, String(instrumentationEventCategoryType) + eventName, 0);
229 void InspectorDOMDebuggerAgent::removeBreakpoint(ErrorString* error, const String& eventName, const String* targetName)
231 if (eventName.isEmpty()) {
232 *error = "Event name is empty";
236 RefPtr<JSONObject> eventListenerBreakpoints = m_state->getObject(DOMDebuggerAgentState::eventListenerBreakpoints);
237 RefPtr<JSONObject> breakpointsByTarget = ensurePropertyObject(eventListenerBreakpoints.get(), eventName);
238 if (!targetName || targetName->isEmpty())
239 breakpointsByTarget->remove(DOMDebuggerAgentState::eventTargetAny);
241 breakpointsByTarget->remove(targetName->lower());
242 m_state->setObject(DOMDebuggerAgentState::eventListenerBreakpoints, eventListenerBreakpoints.release());
245 void InspectorDOMDebuggerAgent::didInvalidateStyleAttr(Node* node)
247 if (hasBreakpoint(node, AttributeModified)) {
248 RefPtr<JSONObject> eventData = JSONObject::create();
249 descriptionForDOMEvent(node, AttributeModified, false, eventData.get());
250 m_debuggerAgent->breakProgram(InspectorFrontend::Debugger::Reason::DOM, eventData.release());
254 void InspectorDOMDebuggerAgent::didInsertDOMNode(Node* node)
256 if (m_domBreakpoints.size()) {
257 uint32_t mask = m_domBreakpoints.get(InspectorDOMAgent::innerParentNode(node));
258 uint32_t inheritableTypesMask = (mask | (mask >> domBreakpointDerivedTypeShift)) & inheritableDOMBreakpointTypesMask;
259 if (inheritableTypesMask)
260 updateSubtreeBreakpoints(node, inheritableTypesMask, true);
264 void InspectorDOMDebuggerAgent::didRemoveDOMNode(Node* node)
266 if (m_domBreakpoints.size()) {
267 // Remove subtree breakpoints.
268 m_domBreakpoints.remove(node);
269 WillBeHeapVector<RawPtrWillBeMember<Node> > stack(1, InspectorDOMAgent::innerFirstChild(node));
271 Node* node = stack.last();
275 m_domBreakpoints.remove(node);
276 stack.append(InspectorDOMAgent::innerFirstChild(node));
277 stack.append(InspectorDOMAgent::innerNextSibling(node));
278 } while (!stack.isEmpty());
282 static int domTypeForName(ErrorString* errorString, const String& typeString)
284 if (typeString == "subtree-modified")
285 return SubtreeModified;
286 if (typeString == "attribute-modified")
287 return AttributeModified;
288 if (typeString == "node-removed")
290 *errorString = "Unknown DOM breakpoint type: " + typeString;
294 static String domTypeName(int type)
297 case SubtreeModified: return "subtree-modified";
298 case AttributeModified: return "attribute-modified";
299 case NodeRemoved: return "node-removed";
305 void InspectorDOMDebuggerAgent::setDOMBreakpoint(ErrorString* errorString, int nodeId, const String& typeString)
307 Node* node = m_domAgent->assertNode(errorString, nodeId);
311 int type = domTypeForName(errorString, typeString);
315 uint32_t rootBit = 1 << type;
316 m_domBreakpoints.set(node, m_domBreakpoints.get(node) | rootBit);
317 if (rootBit & inheritableDOMBreakpointTypesMask) {
318 for (Node* child = InspectorDOMAgent::innerFirstChild(node); child; child = InspectorDOMAgent::innerNextSibling(child))
319 updateSubtreeBreakpoints(child, rootBit, true);
323 void InspectorDOMDebuggerAgent::removeDOMBreakpoint(ErrorString* errorString, int nodeId, const String& typeString)
325 Node* node = m_domAgent->assertNode(errorString, nodeId);
328 int type = domTypeForName(errorString, typeString);
332 uint32_t rootBit = 1 << type;
333 uint32_t mask = m_domBreakpoints.get(node) & ~rootBit;
335 m_domBreakpoints.set(node, mask);
337 m_domBreakpoints.remove(node);
339 if ((rootBit & inheritableDOMBreakpointTypesMask) && !(mask & (rootBit << domBreakpointDerivedTypeShift))) {
340 for (Node* child = InspectorDOMAgent::innerFirstChild(node); child; child = InspectorDOMAgent::innerNextSibling(child))
341 updateSubtreeBreakpoints(child, rootBit, false);
345 void InspectorDOMDebuggerAgent::willInsertDOMNode(Node* parent)
347 if (hasBreakpoint(parent, SubtreeModified)) {
348 RefPtr<JSONObject> eventData = JSONObject::create();
349 descriptionForDOMEvent(parent, SubtreeModified, true, eventData.get());
350 m_debuggerAgent->breakProgram(InspectorFrontend::Debugger::Reason::DOM, eventData.release());
354 void InspectorDOMDebuggerAgent::willRemoveDOMNode(Node* node)
356 Node* parentNode = InspectorDOMAgent::innerParentNode(node);
357 if (hasBreakpoint(node, NodeRemoved)) {
358 RefPtr<JSONObject> eventData = JSONObject::create();
359 descriptionForDOMEvent(node, NodeRemoved, false, eventData.get());
360 m_debuggerAgent->breakProgram(InspectorFrontend::Debugger::Reason::DOM, eventData.release());
361 } else if (parentNode && hasBreakpoint(parentNode, SubtreeModified)) {
362 RefPtr<JSONObject> eventData = JSONObject::create();
363 descriptionForDOMEvent(node, SubtreeModified, false, eventData.get());
364 m_debuggerAgent->breakProgram(InspectorFrontend::Debugger::Reason::DOM, eventData.release());
366 didRemoveDOMNode(node);
369 void InspectorDOMDebuggerAgent::willModifyDOMAttr(Element* element, const AtomicString&, const AtomicString&)
371 if (hasBreakpoint(element, AttributeModified)) {
372 RefPtr<JSONObject> eventData = JSONObject::create();
373 descriptionForDOMEvent(element, AttributeModified, false, eventData.get());
374 m_debuggerAgent->breakProgram(InspectorFrontend::Debugger::Reason::DOM, eventData.release());
378 void InspectorDOMDebuggerAgent::descriptionForDOMEvent(Node* target, int breakpointType, bool insertion, JSONObject* description)
380 ASSERT(hasBreakpoint(target, breakpointType));
382 Node* breakpointOwner = target;
383 if ((1 << breakpointType) & inheritableDOMBreakpointTypesMask) {
384 // For inheritable breakpoint types, target node isn't always the same as the node that owns a breakpoint.
385 // Target node may be unknown to frontend, so we need to push it first.
386 RefPtr<TypeBuilder::Runtime::RemoteObject> targetNodeObject = m_domAgent->resolveNode(target, InspectorDebuggerAgent::backtraceObjectGroup);
387 description->setValue("targetNode", targetNodeObject);
389 // Find breakpoint owner node.
391 breakpointOwner = InspectorDOMAgent::innerParentNode(target);
392 ASSERT(breakpointOwner);
393 while (!(m_domBreakpoints.get(breakpointOwner) & (1 << breakpointType))) {
394 Node* parentNode = InspectorDOMAgent::innerParentNode(breakpointOwner);
397 breakpointOwner = parentNode;
400 if (breakpointType == SubtreeModified)
401 description->setBoolean("insertion", insertion);
404 int breakpointOwnerNodeId = m_domAgent->boundNodeId(breakpointOwner);
405 ASSERT(breakpointOwnerNodeId);
406 description->setNumber("nodeId", breakpointOwnerNodeId);
407 description->setString("type", domTypeName(breakpointType));
410 bool InspectorDOMDebuggerAgent::hasBreakpoint(Node* node, int type)
412 uint32_t rootBit = 1 << type;
413 uint32_t derivedBit = rootBit << domBreakpointDerivedTypeShift;
414 return m_domBreakpoints.get(node) & (rootBit | derivedBit);
417 void InspectorDOMDebuggerAgent::updateSubtreeBreakpoints(Node* node, uint32_t rootMask, bool set)
419 uint32_t oldMask = m_domBreakpoints.get(node);
420 uint32_t derivedMask = rootMask << domBreakpointDerivedTypeShift;
421 uint32_t newMask = set ? oldMask | derivedMask : oldMask & ~derivedMask;
423 m_domBreakpoints.set(node, newMask);
425 m_domBreakpoints.remove(node);
427 uint32_t newRootMask = rootMask & ~newMask;
431 for (Node* child = InspectorDOMAgent::innerFirstChild(node); child; child = InspectorDOMAgent::innerNextSibling(child))
432 updateSubtreeBreakpoints(child, newRootMask, set);
435 void InspectorDOMDebuggerAgent::pauseOnNativeEventIfNeeded(PassRefPtr<JSONObject> eventData, bool synchronous)
440 m_debuggerAgent->breakProgram(InspectorFrontend::Debugger::Reason::EventListener, eventData);
442 m_debuggerAgent->schedulePauseOnNextStatement(InspectorFrontend::Debugger::Reason::EventListener, eventData);
445 PassRefPtr<JSONObject> InspectorDOMDebuggerAgent::preparePauseOnNativeEventData(const String& eventName, const String* targetName)
447 String fullEventName = (targetName ? listenerEventCategoryType : instrumentationEventCategoryType) + eventName;
448 if (m_pauseInNextEventListener) {
449 m_pauseInNextEventListener = false;
451 RefPtr<JSONObject> eventListenerBreakpoints = m_state->getObject(DOMDebuggerAgentState::eventListenerBreakpoints);
452 JSONObject::iterator it = eventListenerBreakpoints->find(fullEventName);
453 if (it == eventListenerBreakpoints->end())
456 RefPtr<JSONObject> breakpointsByTarget = it->value->asObject();
457 breakpointsByTarget->getBoolean(DOMDebuggerAgentState::eventTargetAny, &match);
458 if (!match && targetName)
459 breakpointsByTarget->getBoolean(targetName->lower(), &match);
464 RefPtr<JSONObject> eventData = JSONObject::create();
465 eventData->setString("eventName", fullEventName);
467 eventData->setString("targetName", *targetName);
468 return eventData.release();
471 void InspectorDOMDebuggerAgent::didInstallTimer(ExecutionContext*, int, int, bool)
473 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(setTimerEventName, 0), true);
476 void InspectorDOMDebuggerAgent::didRemoveTimer(ExecutionContext*, int)
478 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(clearTimerEventName, 0), true);
481 void InspectorDOMDebuggerAgent::willFireTimer(ExecutionContext*, int)
483 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(timerFiredEventName, 0), false);
486 bool InspectorDOMDebuggerAgent::canPauseOnPromiseEvent()
488 if (m_pauseInNextEventListener)
490 RefPtr<JSONObject> eventListenerBreakpoints = m_state->getObject(DOMDebuggerAgentState::eventListenerBreakpoints);
491 JSONObject::iterator end = eventListenerBreakpoints->end();
492 return eventListenerBreakpoints->find(String(instrumentationEventCategoryType) + newPromiseEventName) != end
493 || eventListenerBreakpoints->find(String(instrumentationEventCategoryType) + promiseResolvedEventName) != end
494 || eventListenerBreakpoints->find(String(instrumentationEventCategoryType) + promiseRejectedEventName) != end;
497 void InspectorDOMDebuggerAgent::didCreatePromise()
499 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(newPromiseEventName, 0), true);
502 void InspectorDOMDebuggerAgent::didResolvePromise()
504 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(promiseResolvedEventName, 0), true);
507 void InspectorDOMDebuggerAgent::didRejectPromise()
509 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(promiseRejectedEventName, 0), true);
512 void InspectorDOMDebuggerAgent::didRequestAnimationFrame(Document*, int)
514 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(requestAnimationFrameEventName, 0), true);
517 void InspectorDOMDebuggerAgent::didCancelAnimationFrame(Document*, int)
519 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(cancelAnimationFrameEventName, 0), true);
522 void InspectorDOMDebuggerAgent::willFireAnimationFrame(Document*, int)
524 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(animationFrameFiredEventName, 0), false);
527 void InspectorDOMDebuggerAgent::willHandleEvent(EventTarget* target, Event* event, EventListener*, bool)
529 Node* node = target->toNode();
530 String targetName = node ? node->nodeName() : target->interfaceName();
531 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(event->type(), &targetName), false);
534 void InspectorDOMDebuggerAgent::willCloseWindow()
536 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(windowCloseEventName, 0), true);
539 void InspectorDOMDebuggerAgent::willExecuteCustomElementCallback(Element*)
541 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(customElementCallbackName, 0), false);
544 void InspectorDOMDebuggerAgent::didFireWebGLError(const String& errorName)
546 RefPtr<JSONObject> eventData = preparePauseOnNativeEventData(webglErrorFiredEventName, 0);
549 if (!errorName.isEmpty())
550 eventData->setString(webglErrorNameProperty, errorName);
551 pauseOnNativeEventIfNeeded(eventData.release(), m_debuggerAgent->canBreakProgram());
554 void InspectorDOMDebuggerAgent::didFireWebGLWarning()
556 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(webglWarningFiredEventName, 0), m_debuggerAgent->canBreakProgram());
559 void InspectorDOMDebuggerAgent::didFireWebGLErrorOrWarning(const String& message)
561 if (message.findIgnoringCase("error") != WTF::kNotFound)
562 didFireWebGLError(String());
564 didFireWebGLWarning();
567 void InspectorDOMDebuggerAgent::setXHRBreakpoint(ErrorString*, const String& url)
570 m_state->setBoolean(DOMDebuggerAgentState::pauseOnAllXHRs, true);
574 RefPtr<JSONObject> xhrBreakpoints = m_state->getObject(DOMDebuggerAgentState::xhrBreakpoints);
575 xhrBreakpoints->setBoolean(url, true);
576 m_state->setObject(DOMDebuggerAgentState::xhrBreakpoints, xhrBreakpoints.release());
579 void InspectorDOMDebuggerAgent::removeXHRBreakpoint(ErrorString*, const String& url)
582 m_state->setBoolean(DOMDebuggerAgentState::pauseOnAllXHRs, false);
586 RefPtr<JSONObject> xhrBreakpoints = m_state->getObject(DOMDebuggerAgentState::xhrBreakpoints);
587 xhrBreakpoints->remove(url);
588 m_state->setObject(DOMDebuggerAgentState::xhrBreakpoints, xhrBreakpoints.release());
591 void InspectorDOMDebuggerAgent::willSendXMLHttpRequest(const String& url)
593 String breakpointURL;
594 if (m_state->getBoolean(DOMDebuggerAgentState::pauseOnAllXHRs))
597 RefPtr<JSONObject> xhrBreakpoints = m_state->getObject(DOMDebuggerAgentState::xhrBreakpoints);
598 for (JSONObject::iterator it = xhrBreakpoints->begin(); it != xhrBreakpoints->end(); ++it) {
599 if (url.contains(it->key)) {
600 breakpointURL = it->key;
606 if (breakpointURL.isNull())
609 RefPtr<JSONObject> eventData = JSONObject::create();
610 eventData->setString("breakpointURL", breakpointURL);
611 eventData->setString("url", url);
612 m_debuggerAgent->breakProgram(InspectorFrontend::Debugger::Reason::XHR, eventData.release());
615 void InspectorDOMDebuggerAgent::clear()
617 m_domBreakpoints.clear();
618 m_pauseInNextEventListener = false;