1 /*
2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32 #include "core/inspector/InspectorDOMDebuggerAgent.h"
33
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"
40
41 namespace {
42
43 enum DOMBreakpointType {
44 SubtreeModified = 0,
45 AttributeModified,
46 NodeRemoved,
47 DOMBreakpointTypesCount
48 };
49
50 static const char listenerEventCategoryType[] = "listener:";
51 static const char instrumentationEventCategoryType[] = "instrumentation:";
52
53 const uint32_t inheritableDOMBreakpointTypesMask = (1 << SubtreeModified);
54 const int domBreakpointDerivedTypeShift = 16;
55
56 }
57
58 namespace blink {
59
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";
74
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";
80 }
81
create(InspectorDOMAgent * domAgent,InspectorDebuggerAgent * debuggerAgent)82 PassOwnPtrWillBeRawPtr<InspectorDOMDebuggerAgent> InspectorDOMDebuggerAgent::create(InspectorDOMAgent* domAgent, InspectorDebuggerAgent* debuggerAgent)
83 {
84 return adoptPtrWillBeNoop(new InspectorDOMDebuggerAgent(domAgent, debuggerAgent));
85 }
86
InspectorDOMDebuggerAgent(InspectorDOMAgent * domAgent,InspectorDebuggerAgent * debuggerAgent)87 InspectorDOMDebuggerAgent::InspectorDOMDebuggerAgent(InspectorDOMAgent* domAgent, InspectorDebuggerAgent* debuggerAgent)
88 : InspectorBaseAgent<InspectorDOMDebuggerAgent>("DOMDebugger")
89 , m_domAgent(domAgent)
90 , m_debuggerAgent(debuggerAgent)
91 , m_pauseInNextEventListener(false)
92 {
93 m_debuggerAgent->setListener(this);
94 m_domAgent->setListener(this);
95 }
96
~InspectorDOMDebuggerAgent()97 InspectorDOMDebuggerAgent::~InspectorDOMDebuggerAgent()
98 {
99 #if !ENABLE(OILPAN)
100 ASSERT(!m_debuggerAgent);
101 ASSERT(!m_instrumentingAgents->inspectorDOMDebuggerAgent());
102 #endif
103 }
104
trace(Visitor * visitor)105 void InspectorDOMDebuggerAgent::trace(Visitor* visitor)
106 {
107 visitor->trace(m_domAgent);
108 visitor->trace(m_debuggerAgent);
109 #if ENABLE(OILPAN)
110 visitor->trace(m_domBreakpoints);
111 #endif
112 InspectorBaseAgent::trace(visitor);
113 }
114
115 // Browser debugger agent enabled only when JS debugger is enabled.
debuggerWasEnabled()116 void InspectorDOMDebuggerAgent::debuggerWasEnabled()
117 {
118 if (m_domAgent->enabled() && m_debuggerAgent->enabled())
119 m_instrumentingAgents->setInspectorDOMDebuggerAgent(this);
120 }
121
debuggerWasDisabled()122 void InspectorDOMDebuggerAgent::debuggerWasDisabled()
123 {
124 disable();
125 }
126
domAgentWasEnabled()127 void InspectorDOMDebuggerAgent::domAgentWasEnabled()
128 {
129 if (m_domAgent->enabled() && m_debuggerAgent->enabled())
130 m_instrumentingAgents->setInspectorDOMDebuggerAgent(this);
131 }
132
domAgentWasDisabled()133 void InspectorDOMDebuggerAgent::domAgentWasDisabled()
134 {
135 disable();
136 }
137
stepInto()138 void InspectorDOMDebuggerAgent::stepInto()
139 {
140 m_pauseInNextEventListener = true;
141 }
142
didPause()143 void InspectorDOMDebuggerAgent::didPause()
144 {
145 m_pauseInNextEventListener = false;
146 }
147
didProcessTask()148 void InspectorDOMDebuggerAgent::didProcessTask()
149 {
150 if (!m_pauseInNextEventListener)
151 return;
152 if (m_debuggerAgent && m_debuggerAgent->runningNestedMessageLoop())
153 return;
154 m_pauseInNextEventListener = false;
155 }
156
disable()157 void InspectorDOMDebuggerAgent::disable()
158 {
159 m_instrumentingAgents->setInspectorDOMDebuggerAgent(0);
160 clear();
161 }
162
clearFrontend()163 void InspectorDOMDebuggerAgent::clearFrontend()
164 {
165 disable();
166 }
167
discardAgent()168 void InspectorDOMDebuggerAgent::discardAgent()
169 {
170 m_debuggerAgent->setListener(0);
171 m_debuggerAgent = nullptr;
172 }
173
setEventListenerBreakpoint(ErrorString * error,const String & eventName,const String * targetName)174 void InspectorDOMDebuggerAgent::setEventListenerBreakpoint(ErrorString* error, const String& eventName, const String* targetName)
175 {
176 setBreakpoint(error, String(listenerEventCategoryType) + eventName, targetName);
177 }
178
setInstrumentationBreakpoint(ErrorString * error,const String & eventName)179 void InspectorDOMDebuggerAgent::setInstrumentationBreakpoint(ErrorString* error, const String& eventName)
180 {
181 setBreakpoint(error, String(instrumentationEventCategoryType) + eventName, 0);
182 }
183
ensurePropertyObject(JSONObject * object,const String & propertyName)184 static PassRefPtr<JSONObject> ensurePropertyObject(JSONObject* object, const String& propertyName)
185 {
186 JSONObject::iterator it = object->find(propertyName);
187 if (it != object->end())
188 return it->value->asObject();
189
190 RefPtr<JSONObject> result = JSONObject::create();
191 object->setObject(propertyName, result);
192 return result.release();
193 }
194
setBreakpoint(ErrorString * error,const String & eventName,const String * targetName)195 void InspectorDOMDebuggerAgent::setBreakpoint(ErrorString* error, const String& eventName, const String* targetName)
196 {
197 if (eventName.isEmpty()) {
198 *error = "Event name is empty";
199 return;
200 }
201
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);
206
207 if (error->length())
208 return;
209
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);
214 else
215 breakpointsByTarget->setBoolean(targetName->lower(), true);
216 m_state->setObject(DOMDebuggerAgentState::eventListenerBreakpoints, eventListenerBreakpoints.release());
217 }
218
removeEventListenerBreakpoint(ErrorString * error,const String & eventName,const String * targetName)219 void InspectorDOMDebuggerAgent::removeEventListenerBreakpoint(ErrorString* error, const String& eventName, const String* targetName)
220 {
221 removeBreakpoint(error, String(listenerEventCategoryType) + eventName, targetName);
222 }
223
removeInstrumentationBreakpoint(ErrorString * error,const String & eventName)224 void InspectorDOMDebuggerAgent::removeInstrumentationBreakpoint(ErrorString* error, const String& eventName)
225 {
226 removeBreakpoint(error, String(instrumentationEventCategoryType) + eventName, 0);
227 }
228
removeBreakpoint(ErrorString * error,const String & eventName,const String * targetName)229 void InspectorDOMDebuggerAgent::removeBreakpoint(ErrorString* error, const String& eventName, const String* targetName)
230 {
231 if (eventName.isEmpty()) {
232 *error = "Event name is empty";
233 return;
234 }
235
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);
240 else
241 breakpointsByTarget->remove(targetName->lower());
242 m_state->setObject(DOMDebuggerAgentState::eventListenerBreakpoints, eventListenerBreakpoints.release());
243 }
244
didInvalidateStyleAttr(Node * node)245 void InspectorDOMDebuggerAgent::didInvalidateStyleAttr(Node* node)
246 {
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());
251 }
252 }
253
didInsertDOMNode(Node * node)254 void InspectorDOMDebuggerAgent::didInsertDOMNode(Node* node)
255 {
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);
261 }
262 }
263
didRemoveDOMNode(Node * node)264 void InspectorDOMDebuggerAgent::didRemoveDOMNode(Node* node)
265 {
266 if (m_domBreakpoints.size()) {
267 // Remove subtree breakpoints.
268 m_domBreakpoints.remove(node);
269 WillBeHeapVector<RawPtrWillBeMember<Node> > stack(1, InspectorDOMAgent::innerFirstChild(node));
270 do {
271 Node* node = stack.last();
272 stack.removeLast();
273 if (!node)
274 continue;
275 m_domBreakpoints.remove(node);
276 stack.append(InspectorDOMAgent::innerFirstChild(node));
277 stack.append(InspectorDOMAgent::innerNextSibling(node));
278 } while (!stack.isEmpty());
279 }
280 }
281
domTypeForName(ErrorString * errorString,const String & typeString)282 static int domTypeForName(ErrorString* errorString, const String& typeString)
283 {
284 if (typeString == "subtree-modified")
285 return SubtreeModified;
286 if (typeString == "attribute-modified")
287 return AttributeModified;
288 if (typeString == "node-removed")
289 return NodeRemoved;
290 *errorString = "Unknown DOM breakpoint type: " + typeString;
291 return -1;
292 }
293
domTypeName(int type)294 static String domTypeName(int type)
295 {
296 switch (type) {
297 case SubtreeModified: return "subtree-modified";
298 case AttributeModified: return "attribute-modified";
299 case NodeRemoved: return "node-removed";
300 default: break;
301 }
302 return "";
303 }
304
setDOMBreakpoint(ErrorString * errorString,int nodeId,const String & typeString)305 void InspectorDOMDebuggerAgent::setDOMBreakpoint(ErrorString* errorString, int nodeId, const String& typeString)
306 {
307 Node* node = m_domAgent->assertNode(errorString, nodeId);
308 if (!node)
309 return;
310
311 int type = domTypeForName(errorString, typeString);
312 if (type == -1)
313 return;
314
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);
320 }
321 }
322
removeDOMBreakpoint(ErrorString * errorString,int nodeId,const String & typeString)323 void InspectorDOMDebuggerAgent::removeDOMBreakpoint(ErrorString* errorString, int nodeId, const String& typeString)
324 {
325 Node* node = m_domAgent->assertNode(errorString, nodeId);
326 if (!node)
327 return;
328 int type = domTypeForName(errorString, typeString);
329 if (type == -1)
330 return;
331
332 uint32_t rootBit = 1 << type;
333 uint32_t mask = m_domBreakpoints.get(node) & ~rootBit;
334 if (mask)
335 m_domBreakpoints.set(node, mask);
336 else
337 m_domBreakpoints.remove(node);
338
339 if ((rootBit & inheritableDOMBreakpointTypesMask) && !(mask & (rootBit << domBreakpointDerivedTypeShift))) {
340 for (Node* child = InspectorDOMAgent::innerFirstChild(node); child; child = InspectorDOMAgent::innerNextSibling(child))
341 updateSubtreeBreakpoints(child, rootBit, false);
342 }
343 }
344
willInsertDOMNode(Node * parent)345 void InspectorDOMDebuggerAgent::willInsertDOMNode(Node* parent)
346 {
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());
351 }
352 }
353
willRemoveDOMNode(Node * node)354 void InspectorDOMDebuggerAgent::willRemoveDOMNode(Node* node)
355 {
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());
365 }
366 didRemoveDOMNode(node);
367 }
368
willModifyDOMAttr(Element * element,const AtomicString &,const AtomicString &)369 void InspectorDOMDebuggerAgent::willModifyDOMAttr(Element* element, const AtomicString&, const AtomicString&)
370 {
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());
375 }
376 }
377
descriptionForDOMEvent(Node * target,int breakpointType,bool insertion,JSONObject * description)378 void InspectorDOMDebuggerAgent::descriptionForDOMEvent(Node* target, int breakpointType, bool insertion, JSONObject* description)
379 {
380 ASSERT(hasBreakpoint(target, breakpointType));
381
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);
388
389 // Find breakpoint owner node.
390 if (!insertion)
391 breakpointOwner = InspectorDOMAgent::innerParentNode(target);
392 ASSERT(breakpointOwner);
393 while (!(m_domBreakpoints.get(breakpointOwner) & (1 << breakpointType))) {
394 Node* parentNode = InspectorDOMAgent::innerParentNode(breakpointOwner);
395 if (!parentNode)
396 break;
397 breakpointOwner = parentNode;
398 }
399
400 if (breakpointType == SubtreeModified)
401 description->setBoolean("insertion", insertion);
402 }
403
404 int breakpointOwnerNodeId = m_domAgent->boundNodeId(breakpointOwner);
405 ASSERT(breakpointOwnerNodeId);
406 description->setNumber("nodeId", breakpointOwnerNodeId);
407 description->setString("type", domTypeName(breakpointType));
408 }
409
hasBreakpoint(Node * node,int type)410 bool InspectorDOMDebuggerAgent::hasBreakpoint(Node* node, int type)
411 {
412 uint32_t rootBit = 1 << type;
413 uint32_t derivedBit = rootBit << domBreakpointDerivedTypeShift;
414 return m_domBreakpoints.get(node) & (rootBit | derivedBit);
415 }
416
updateSubtreeBreakpoints(Node * node,uint32_t rootMask,bool set)417 void InspectorDOMDebuggerAgent::updateSubtreeBreakpoints(Node* node, uint32_t rootMask, bool set)
418 {
419 uint32_t oldMask = m_domBreakpoints.get(node);
420 uint32_t derivedMask = rootMask << domBreakpointDerivedTypeShift;
421 uint32_t newMask = set ? oldMask | derivedMask : oldMask & ~derivedMask;
422 if (newMask)
423 m_domBreakpoints.set(node, newMask);
424 else
425 m_domBreakpoints.remove(node);
426
427 uint32_t newRootMask = rootMask & ~newMask;
428 if (!newRootMask)
429 return;
430
431 for (Node* child = InspectorDOMAgent::innerFirstChild(node); child; child = InspectorDOMAgent::innerNextSibling(child))
432 updateSubtreeBreakpoints(child, newRootMask, set);
433 }
434
pauseOnNativeEventIfNeeded(PassRefPtr<JSONObject> eventData,bool synchronous)435 void InspectorDOMDebuggerAgent::pauseOnNativeEventIfNeeded(PassRefPtr<JSONObject> eventData, bool synchronous)
436 {
437 if (!eventData)
438 return;
439 if (synchronous)
440 m_debuggerAgent->breakProgram(InspectorFrontend::Debugger::Reason::EventListener, eventData);
441 else
442 m_debuggerAgent->schedulePauseOnNextStatement(InspectorFrontend::Debugger::Reason::EventListener, eventData);
443 }
444
preparePauseOnNativeEventData(const String & eventName,const String * targetName)445 PassRefPtr<JSONObject> InspectorDOMDebuggerAgent::preparePauseOnNativeEventData(const String& eventName, const String* targetName)
446 {
447 String fullEventName = (targetName ? listenerEventCategoryType : instrumentationEventCategoryType) + eventName;
448 if (m_pauseInNextEventListener) {
449 m_pauseInNextEventListener = false;
450 } else {
451 RefPtr<JSONObject> eventListenerBreakpoints = m_state->getObject(DOMDebuggerAgentState::eventListenerBreakpoints);
452 JSONObject::iterator it = eventListenerBreakpoints->find(fullEventName);
453 if (it == eventListenerBreakpoints->end())
454 return nullptr;
455 bool match = false;
456 RefPtr<JSONObject> breakpointsByTarget = it->value->asObject();
457 breakpointsByTarget->getBoolean(DOMDebuggerAgentState::eventTargetAny, &match);
458 if (!match && targetName)
459 breakpointsByTarget->getBoolean(targetName->lower(), &match);
460 if (!match)
461 return nullptr;
462 }
463
464 RefPtr<JSONObject> eventData = JSONObject::create();
465 eventData->setString("eventName", fullEventName);
466 if (targetName)
467 eventData->setString("targetName", *targetName);
468 return eventData.release();
469 }
470
didInstallTimer(ExecutionContext *,int,int,bool)471 void InspectorDOMDebuggerAgent::didInstallTimer(ExecutionContext*, int, int, bool)
472 {
473 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(setTimerEventName, 0), true);
474 }
475
didRemoveTimer(ExecutionContext *,int)476 void InspectorDOMDebuggerAgent::didRemoveTimer(ExecutionContext*, int)
477 {
478 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(clearTimerEventName, 0), true);
479 }
480
willFireTimer(ExecutionContext *,int)481 void InspectorDOMDebuggerAgent::willFireTimer(ExecutionContext*, int)
482 {
483 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(timerFiredEventName, 0), false);
484 }
485
canPauseOnPromiseEvent()486 bool InspectorDOMDebuggerAgent::canPauseOnPromiseEvent()
487 {
488 if (m_pauseInNextEventListener)
489 return true;
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;
495 }
496
didCreatePromise()497 void InspectorDOMDebuggerAgent::didCreatePromise()
498 {
499 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(newPromiseEventName, 0), true);
500 }
501
didResolvePromise()502 void InspectorDOMDebuggerAgent::didResolvePromise()
503 {
504 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(promiseResolvedEventName, 0), true);
505 }
506
didRejectPromise()507 void InspectorDOMDebuggerAgent::didRejectPromise()
508 {
509 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(promiseRejectedEventName, 0), true);
510 }
511
didRequestAnimationFrame(Document *,int)512 void InspectorDOMDebuggerAgent::didRequestAnimationFrame(Document*, int)
513 {
514 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(requestAnimationFrameEventName, 0), true);
515 }
516
didCancelAnimationFrame(Document *,int)517 void InspectorDOMDebuggerAgent::didCancelAnimationFrame(Document*, int)
518 {
519 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(cancelAnimationFrameEventName, 0), true);
520 }
521
willFireAnimationFrame(Document *,int)522 void InspectorDOMDebuggerAgent::willFireAnimationFrame(Document*, int)
523 {
524 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(animationFrameFiredEventName, 0), false);
525 }
526
willHandleEvent(EventTarget * target,Event * event,EventListener *,bool)527 void InspectorDOMDebuggerAgent::willHandleEvent(EventTarget* target, Event* event, EventListener*, bool)
528 {
529 Node* node = target->toNode();
530 String targetName = node ? node->nodeName() : target->interfaceName();
531 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(event->type(), &targetName), false);
532 }
533
willCloseWindow()534 void InspectorDOMDebuggerAgent::willCloseWindow()
535 {
536 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(windowCloseEventName, 0), true);
537 }
538
willExecuteCustomElementCallback(Element *)539 void InspectorDOMDebuggerAgent::willExecuteCustomElementCallback(Element*)
540 {
541 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(customElementCallbackName, 0), false);
542 }
543
didFireWebGLError(const String & errorName)544 void InspectorDOMDebuggerAgent::didFireWebGLError(const String& errorName)
545 {
546 RefPtr<JSONObject> eventData = preparePauseOnNativeEventData(webglErrorFiredEventName, 0);
547 if (!eventData)
548 return;
549 if (!errorName.isEmpty())
550 eventData->setString(webglErrorNameProperty, errorName);
551 pauseOnNativeEventIfNeeded(eventData.release(), m_debuggerAgent->canBreakProgram());
552 }
553
didFireWebGLWarning()554 void InspectorDOMDebuggerAgent::didFireWebGLWarning()
555 {
556 pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(webglWarningFiredEventName, 0), m_debuggerAgent->canBreakProgram());
557 }
558
didFireWebGLErrorOrWarning(const String & message)559 void InspectorDOMDebuggerAgent::didFireWebGLErrorOrWarning(const String& message)
560 {
561 if (message.findIgnoringCase("error") != WTF::kNotFound)
562 didFireWebGLError(String());
563 else
564 didFireWebGLWarning();
565 }
566
setXHRBreakpoint(ErrorString *,const String & url)567 void InspectorDOMDebuggerAgent::setXHRBreakpoint(ErrorString*, const String& url)
568 {
569 if (url.isEmpty()) {
570 m_state->setBoolean(DOMDebuggerAgentState::pauseOnAllXHRs, true);
571 return;
572 }
573
574 RefPtr<JSONObject> xhrBreakpoints = m_state->getObject(DOMDebuggerAgentState::xhrBreakpoints);
575 xhrBreakpoints->setBoolean(url, true);
576 m_state->setObject(DOMDebuggerAgentState::xhrBreakpoints, xhrBreakpoints.release());
577 }
578
removeXHRBreakpoint(ErrorString *,const String & url)579 void InspectorDOMDebuggerAgent::removeXHRBreakpoint(ErrorString*, const String& url)
580 {
581 if (url.isEmpty()) {
582 m_state->setBoolean(DOMDebuggerAgentState::pauseOnAllXHRs, false);
583 return;
584 }
585
586 RefPtr<JSONObject> xhrBreakpoints = m_state->getObject(DOMDebuggerAgentState::xhrBreakpoints);
587 xhrBreakpoints->remove(url);
588 m_state->setObject(DOMDebuggerAgentState::xhrBreakpoints, xhrBreakpoints.release());
589 }
590
willSendXMLHttpRequest(const String & url)591 void InspectorDOMDebuggerAgent::willSendXMLHttpRequest(const String& url)
592 {
593 String breakpointURL;
594 if (m_state->getBoolean(DOMDebuggerAgentState::pauseOnAllXHRs))
595 breakpointURL = "";
596 else {
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;
601 break;
602 }
603 }
604 }
605
606 if (breakpointURL.isNull())
607 return;
608
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());
613 }
614
clear()615 void InspectorDOMDebuggerAgent::clear()
616 {
617 m_domBreakpoints.clear();
618 m_pauseInNextEventListener = false;
619 }
620
621 } // namespace blink
622
623