Home | History | Annotate | Download | only in inspector
      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 "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 WebCore {
     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 webglErrorFiredEventName[] = "webglErrorFired";
     67 static const char webglWarningFiredEventName[] = "webglWarningFired";
     68 static const char webglErrorNameProperty[] = "webglErrorName";
     69 
     70 namespace DOMDebuggerAgentState {
     71 static const char eventListenerBreakpoints[] = "eventListenerBreakpoints";
     72 static const char pauseOnAllXHRs[] = "pauseOnAllXHRs";
     73 static const char xhrBreakpoints[] = "xhrBreakpoints";
     74 }
     75 
     76 PassOwnPtr<InspectorDOMDebuggerAgent> InspectorDOMDebuggerAgent::create(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* inspectorState, InspectorDOMAgent* domAgent, InspectorDebuggerAgent* debuggerAgent)
     77 {
     78     return adoptPtr(new InspectorDOMDebuggerAgent(instrumentingAgents, inspectorState, domAgent, debuggerAgent));
     79 }
     80 
     81 InspectorDOMDebuggerAgent::InspectorDOMDebuggerAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* inspectorState, InspectorDOMAgent* domAgent, InspectorDebuggerAgent* debuggerAgent)
     82     : InspectorBaseAgent<InspectorDOMDebuggerAgent>("DOMDebugger", instrumentingAgents, inspectorState)
     83     , m_domAgent(domAgent)
     84     , m_debuggerAgent(debuggerAgent)
     85     , m_pauseInNextEventListener(false)
     86 {
     87     m_debuggerAgent->setListener(this);
     88 }
     89 
     90 InspectorDOMDebuggerAgent::~InspectorDOMDebuggerAgent()
     91 {
     92     ASSERT(!m_debuggerAgent);
     93     ASSERT(!m_instrumentingAgents->inspectorDOMDebuggerAgent());
     94 }
     95 
     96 // Browser debugger agent enabled only when JS debugger is enabled.
     97 void InspectorDOMDebuggerAgent::debuggerWasEnabled()
     98 {
     99     m_instrumentingAgents->setInspectorDOMDebuggerAgent(this);
    100 }
    101 
    102 void InspectorDOMDebuggerAgent::debuggerWasDisabled()
    103 {
    104     disable();
    105 }
    106 
    107 void InspectorDOMDebuggerAgent::stepInto()
    108 {
    109     m_pauseInNextEventListener = true;
    110 }
    111 
    112 void InspectorDOMDebuggerAgent::didPause()
    113 {
    114     m_pauseInNextEventListener = false;
    115 }
    116 
    117 void InspectorDOMDebuggerAgent::didProcessTask()
    118 {
    119     if (!m_pauseInNextEventListener)
    120         return;
    121     if (m_debuggerAgent && m_debuggerAgent->runningNestedMessageLoop())
    122         return;
    123     m_pauseInNextEventListener = false;
    124 }
    125 
    126 void InspectorDOMDebuggerAgent::disable()
    127 {
    128     m_instrumentingAgents->setInspectorDOMDebuggerAgent(0);
    129     clear();
    130 }
    131 
    132 void InspectorDOMDebuggerAgent::clearFrontend()
    133 {
    134     disable();
    135 }
    136 
    137 void InspectorDOMDebuggerAgent::discardAgent()
    138 {
    139     m_debuggerAgent->setListener(0);
    140     m_debuggerAgent = 0;
    141 }
    142 
    143 void InspectorDOMDebuggerAgent::discardBindings()
    144 {
    145     m_domBreakpoints.clear();
    146 }
    147 
    148 void InspectorDOMDebuggerAgent::setEventListenerBreakpoint(ErrorString* error, const String& eventName)
    149 {
    150     setBreakpoint(error, String(listenerEventCategoryType) + eventName);
    151 }
    152 
    153 void InspectorDOMDebuggerAgent::setInstrumentationBreakpoint(ErrorString* error, const String& eventName)
    154 {
    155     setBreakpoint(error, String(instrumentationEventCategoryType) + eventName);
    156 }
    157 
    158 void InspectorDOMDebuggerAgent::setBreakpoint(ErrorString* error, const String& eventName)
    159 {
    160     if (eventName.isEmpty()) {
    161         *error = "Event name is empty";
    162         return;
    163     }
    164 
    165     RefPtr<JSONObject> eventListenerBreakpoints = m_state->getObject(DOMDebuggerAgentState::eventListenerBreakpoints);
    166     eventListenerBreakpoints->setBoolean(eventName, true);
    167     m_state->setObject(DOMDebuggerAgentState::eventListenerBreakpoints, eventListenerBreakpoints);
    168 }
    169 
    170 void InspectorDOMDebuggerAgent::removeEventListenerBreakpoint(ErrorString* error, const String& eventName)
    171 {
    172     removeBreakpoint(error, String(listenerEventCategoryType) + eventName);
    173 }
    174 
    175 void InspectorDOMDebuggerAgent::removeInstrumentationBreakpoint(ErrorString* error, const String& eventName)
    176 {
    177     removeBreakpoint(error, String(instrumentationEventCategoryType) + eventName);
    178 }
    179 
    180 void InspectorDOMDebuggerAgent::removeBreakpoint(ErrorString* error, const String& eventName)
    181 {
    182     if (eventName.isEmpty()) {
    183         *error = "Event name is empty";
    184         return;
    185     }
    186 
    187     RefPtr<JSONObject> eventListenerBreakpoints = m_state->getObject(DOMDebuggerAgentState::eventListenerBreakpoints);
    188     eventListenerBreakpoints->remove(eventName);
    189     m_state->setObject(DOMDebuggerAgentState::eventListenerBreakpoints, eventListenerBreakpoints);
    190 }
    191 
    192 void InspectorDOMDebuggerAgent::didInvalidateStyleAttr(Node* node)
    193 {
    194     if (hasBreakpoint(node, AttributeModified)) {
    195         RefPtr<JSONObject> eventData = JSONObject::create();
    196         descriptionForDOMEvent(node, AttributeModified, false, eventData.get());
    197         m_debuggerAgent->breakProgram(InspectorFrontend::Debugger::Reason::DOM, eventData.release());
    198     }
    199 }
    200 
    201 void InspectorDOMDebuggerAgent::didInsertDOMNode(Node* node)
    202 {
    203     if (m_domBreakpoints.size()) {
    204         uint32_t mask = m_domBreakpoints.get(InspectorDOMAgent::innerParentNode(node));
    205         uint32_t inheritableTypesMask = (mask | (mask >> domBreakpointDerivedTypeShift)) & inheritableDOMBreakpointTypesMask;
    206         if (inheritableTypesMask)
    207             updateSubtreeBreakpoints(node, inheritableTypesMask, true);
    208     }
    209 }
    210 
    211 void InspectorDOMDebuggerAgent::didRemoveDOMNode(Node* node)
    212 {
    213     if (m_domBreakpoints.size()) {
    214         // Remove subtree breakpoints.
    215         m_domBreakpoints.remove(node);
    216         Vector<Node*> stack(1, InspectorDOMAgent::innerFirstChild(node));
    217         do {
    218             Node* node = stack.last();
    219             stack.removeLast();
    220             if (!node)
    221                 continue;
    222             m_domBreakpoints.remove(node);
    223             stack.append(InspectorDOMAgent::innerFirstChild(node));
    224             stack.append(InspectorDOMAgent::innerNextSibling(node));
    225         } while (!stack.isEmpty());
    226     }
    227 }
    228 
    229 static int domTypeForName(ErrorString* errorString, const String& typeString)
    230 {
    231     if (typeString == "subtree-modified")
    232         return SubtreeModified;
    233     if (typeString == "attribute-modified")
    234         return AttributeModified;
    235     if (typeString == "node-removed")
    236         return NodeRemoved;
    237     *errorString = "Unknown DOM breakpoint type: " + typeString;
    238     return -1;
    239 }
    240 
    241 static String domTypeName(int type)
    242 {
    243     switch (type) {
    244     case SubtreeModified: return "subtree-modified";
    245     case AttributeModified: return "attribute-modified";
    246     case NodeRemoved: return "node-removed";
    247     default: break;
    248     }
    249     return "";
    250 }
    251 
    252 void InspectorDOMDebuggerAgent::setDOMBreakpoint(ErrorString* errorString, int nodeId, const String& typeString)
    253 {
    254     Node* node = m_domAgent->assertNode(errorString, nodeId);
    255     if (!node)
    256         return;
    257 
    258     int type = domTypeForName(errorString, typeString);
    259     if (type == -1)
    260         return;
    261 
    262     uint32_t rootBit = 1 << type;
    263     m_domBreakpoints.set(node, m_domBreakpoints.get(node) | rootBit);
    264     if (rootBit & inheritableDOMBreakpointTypesMask) {
    265         for (Node* child = InspectorDOMAgent::innerFirstChild(node); child; child = InspectorDOMAgent::innerNextSibling(child))
    266             updateSubtreeBreakpoints(child, rootBit, true);
    267     }
    268 }
    269 
    270 void InspectorDOMDebuggerAgent::removeDOMBreakpoint(ErrorString* errorString, int nodeId, const String& typeString)
    271 {
    272     Node* node = m_domAgent->assertNode(errorString, nodeId);
    273     if (!node)
    274         return;
    275     int type = domTypeForName(errorString, typeString);
    276     if (type == -1)
    277         return;
    278 
    279     uint32_t rootBit = 1 << type;
    280     uint32_t mask = m_domBreakpoints.get(node) & ~rootBit;
    281     if (mask)
    282         m_domBreakpoints.set(node, mask);
    283     else
    284         m_domBreakpoints.remove(node);
    285 
    286     if ((rootBit & inheritableDOMBreakpointTypesMask) && !(mask & (rootBit << domBreakpointDerivedTypeShift))) {
    287         for (Node* child = InspectorDOMAgent::innerFirstChild(node); child; child = InspectorDOMAgent::innerNextSibling(child))
    288             updateSubtreeBreakpoints(child, rootBit, false);
    289     }
    290 }
    291 
    292 void InspectorDOMDebuggerAgent::willInsertDOMNode(Node* parent)
    293 {
    294     if (hasBreakpoint(parent, SubtreeModified)) {
    295         RefPtr<JSONObject> eventData = JSONObject::create();
    296         descriptionForDOMEvent(parent, SubtreeModified, true, eventData.get());
    297         m_debuggerAgent->breakProgram(InspectorFrontend::Debugger::Reason::DOM, eventData.release());
    298     }
    299 }
    300 
    301 void InspectorDOMDebuggerAgent::willRemoveDOMNode(Node* node)
    302 {
    303     Node* parentNode = InspectorDOMAgent::innerParentNode(node);
    304     if (hasBreakpoint(node, NodeRemoved)) {
    305         RefPtr<JSONObject> eventData = JSONObject::create();
    306         descriptionForDOMEvent(node, NodeRemoved, false, eventData.get());
    307         m_debuggerAgent->breakProgram(InspectorFrontend::Debugger::Reason::DOM, eventData.release());
    308     } else if (parentNode && hasBreakpoint(parentNode, SubtreeModified)) {
    309         RefPtr<JSONObject> eventData = JSONObject::create();
    310         descriptionForDOMEvent(node, SubtreeModified, false, eventData.get());
    311         m_debuggerAgent->breakProgram(InspectorFrontend::Debugger::Reason::DOM, eventData.release());
    312     }
    313     didRemoveDOMNode(node);
    314 }
    315 
    316 void InspectorDOMDebuggerAgent::willModifyDOMAttr(Element* element, const AtomicString&, const AtomicString&)
    317 {
    318     if (hasBreakpoint(element, AttributeModified)) {
    319         RefPtr<JSONObject> eventData = JSONObject::create();
    320         descriptionForDOMEvent(element, AttributeModified, false, eventData.get());
    321         m_debuggerAgent->breakProgram(InspectorFrontend::Debugger::Reason::DOM, eventData.release());
    322     }
    323 }
    324 
    325 void InspectorDOMDebuggerAgent::descriptionForDOMEvent(Node* target, int breakpointType, bool insertion, JSONObject* description)
    326 {
    327     ASSERT(hasBreakpoint(target, breakpointType));
    328 
    329     Node* breakpointOwner = target;
    330     if ((1 << breakpointType) & inheritableDOMBreakpointTypesMask) {
    331         // For inheritable breakpoint types, target node isn't always the same as the node that owns a breakpoint.
    332         // Target node may be unknown to frontend, so we need to push it first.
    333         RefPtr<TypeBuilder::Runtime::RemoteObject> targetNodeObject = m_domAgent->resolveNode(target, InspectorDebuggerAgent::backtraceObjectGroup);
    334         description->setValue("targetNode", targetNodeObject);
    335 
    336         // Find breakpoint owner node.
    337         if (!insertion)
    338             breakpointOwner = InspectorDOMAgent::innerParentNode(target);
    339         ASSERT(breakpointOwner);
    340         while (!(m_domBreakpoints.get(breakpointOwner) & (1 << breakpointType))) {
    341             Node* parentNode = InspectorDOMAgent::innerParentNode(breakpointOwner);
    342             if (!parentNode)
    343                 break;
    344             breakpointOwner = parentNode;
    345         }
    346 
    347         if (breakpointType == SubtreeModified)
    348             description->setBoolean("insertion", insertion);
    349     }
    350 
    351     int breakpointOwnerNodeId = m_domAgent->boundNodeId(breakpointOwner);
    352     ASSERT(breakpointOwnerNodeId);
    353     description->setNumber("nodeId", breakpointOwnerNodeId);
    354     description->setString("type", domTypeName(breakpointType));
    355 }
    356 
    357 bool InspectorDOMDebuggerAgent::hasBreakpoint(Node* node, int type)
    358 {
    359     uint32_t rootBit = 1 << type;
    360     uint32_t derivedBit = rootBit << domBreakpointDerivedTypeShift;
    361     return m_domBreakpoints.get(node) & (rootBit | derivedBit);
    362 }
    363 
    364 void InspectorDOMDebuggerAgent::updateSubtreeBreakpoints(Node* node, uint32_t rootMask, bool set)
    365 {
    366     uint32_t oldMask = m_domBreakpoints.get(node);
    367     uint32_t derivedMask = rootMask << domBreakpointDerivedTypeShift;
    368     uint32_t newMask = set ? oldMask | derivedMask : oldMask & ~derivedMask;
    369     if (newMask)
    370         m_domBreakpoints.set(node, newMask);
    371     else
    372         m_domBreakpoints.remove(node);
    373 
    374     uint32_t newRootMask = rootMask & ~newMask;
    375     if (!newRootMask)
    376         return;
    377 
    378     for (Node* child = InspectorDOMAgent::innerFirstChild(node); child; child = InspectorDOMAgent::innerNextSibling(child))
    379         updateSubtreeBreakpoints(child, newRootMask, set);
    380 }
    381 
    382 void InspectorDOMDebuggerAgent::pauseOnNativeEventIfNeeded(PassRefPtr<JSONObject> eventData, bool synchronous)
    383 {
    384     if (!eventData)
    385         return;
    386     if (synchronous)
    387         m_debuggerAgent->breakProgram(InspectorFrontend::Debugger::Reason::EventListener, eventData);
    388     else
    389         m_debuggerAgent->schedulePauseOnNextStatement(InspectorFrontend::Debugger::Reason::EventListener, eventData);
    390 }
    391 
    392 PassRefPtr<JSONObject> InspectorDOMDebuggerAgent::preparePauseOnNativeEventData(bool isDOMEvent, const String& eventName)
    393 {
    394     String fullEventName = (isDOMEvent ? listenerEventCategoryType : instrumentationEventCategoryType) + eventName;
    395     if (m_pauseInNextEventListener)
    396         m_pauseInNextEventListener = false;
    397     else {
    398         RefPtr<JSONObject> eventListenerBreakpoints = m_state->getObject(DOMDebuggerAgentState::eventListenerBreakpoints);
    399         if (eventListenerBreakpoints->find(fullEventName) == eventListenerBreakpoints->end())
    400             return 0;
    401     }
    402 
    403     RefPtr<JSONObject> eventData = JSONObject::create();
    404     eventData->setString("eventName", fullEventName);
    405     return eventData.release();
    406 }
    407 
    408 void InspectorDOMDebuggerAgent::didInstallTimer(ExecutionContext* context, int timerId, int timeout, bool singleShot)
    409 {
    410     pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(false, setTimerEventName), true);
    411 }
    412 
    413 void InspectorDOMDebuggerAgent::didRemoveTimer(ExecutionContext* context, int timerId)
    414 {
    415     pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(false, clearTimerEventName), true);
    416 }
    417 
    418 void InspectorDOMDebuggerAgent::willFireTimer(ExecutionContext* context, int timerId)
    419 {
    420     pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(false, timerFiredEventName), false);
    421 }
    422 
    423 void InspectorDOMDebuggerAgent::didRequestAnimationFrame(Document* document, int callbackId)
    424 {
    425     pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(false, requestAnimationFrameEventName), true);
    426 }
    427 
    428 void InspectorDOMDebuggerAgent::didCancelAnimationFrame(Document* document, int callbackId)
    429 {
    430     pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(false, cancelAnimationFrameEventName), true);
    431 }
    432 
    433 void InspectorDOMDebuggerAgent::willFireAnimationFrame(Document* document, int callbackId)
    434 {
    435     pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(false, animationFrameFiredEventName), false);
    436 }
    437 
    438 void InspectorDOMDebuggerAgent::willHandleEvent(Event* event)
    439 {
    440     pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(true, event->type()), false);
    441 }
    442 
    443 void InspectorDOMDebuggerAgent::didFireWebGLError(const String& errorName)
    444 {
    445     RefPtr<JSONObject> eventData = preparePauseOnNativeEventData(false, webglErrorFiredEventName);
    446     if (!eventData)
    447         return;
    448     if (!errorName.isEmpty())
    449         eventData->setString(webglErrorNameProperty, errorName);
    450     pauseOnNativeEventIfNeeded(eventData.release(), m_debuggerAgent->canBreakProgram());
    451 }
    452 
    453 void InspectorDOMDebuggerAgent::didFireWebGLWarning()
    454 {
    455     pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(false, webglWarningFiredEventName), m_debuggerAgent->canBreakProgram());
    456 }
    457 
    458 void InspectorDOMDebuggerAgent::didFireWebGLErrorOrWarning(const String& message)
    459 {
    460     if (message.findIgnoringCase("error") != WTF::kNotFound)
    461         didFireWebGLError(String());
    462     else
    463         didFireWebGLWarning();
    464 }
    465 
    466 void InspectorDOMDebuggerAgent::setXHRBreakpoint(ErrorString*, const String& url)
    467 {
    468     if (url.isEmpty()) {
    469         m_state->setBoolean(DOMDebuggerAgentState::pauseOnAllXHRs, true);
    470         return;
    471     }
    472 
    473     RefPtr<JSONObject> xhrBreakpoints = m_state->getObject(DOMDebuggerAgentState::xhrBreakpoints);
    474     xhrBreakpoints->setBoolean(url, true);
    475     m_state->setObject(DOMDebuggerAgentState::xhrBreakpoints, xhrBreakpoints);
    476 }
    477 
    478 void InspectorDOMDebuggerAgent::removeXHRBreakpoint(ErrorString*, const String& url)
    479 {
    480     if (url.isEmpty()) {
    481         m_state->setBoolean(DOMDebuggerAgentState::pauseOnAllXHRs, false);
    482         return;
    483     }
    484 
    485     RefPtr<JSONObject> xhrBreakpoints = m_state->getObject(DOMDebuggerAgentState::xhrBreakpoints);
    486     xhrBreakpoints->remove(url);
    487     m_state->setObject(DOMDebuggerAgentState::xhrBreakpoints, xhrBreakpoints);
    488 }
    489 
    490 void InspectorDOMDebuggerAgent::willSendXMLHttpRequest(const String& url)
    491 {
    492     String breakpointURL;
    493     if (m_state->getBoolean(DOMDebuggerAgentState::pauseOnAllXHRs))
    494         breakpointURL = "";
    495     else {
    496         RefPtr<JSONObject> xhrBreakpoints = m_state->getObject(DOMDebuggerAgentState::xhrBreakpoints);
    497         for (JSONObject::iterator it = xhrBreakpoints->begin(); it != xhrBreakpoints->end(); ++it) {
    498             if (url.contains(it->key)) {
    499                 breakpointURL = it->key;
    500                 break;
    501             }
    502         }
    503     }
    504 
    505     if (breakpointURL.isNull())
    506         return;
    507 
    508     RefPtr<JSONObject> eventData = JSONObject::create();
    509     eventData->setString("breakpointURL", breakpointURL);
    510     eventData->setString("url", url);
    511     m_debuggerAgent->breakProgram(InspectorFrontend::Debugger::Reason::XHR, eventData.release());
    512 }
    513 
    514 void InspectorDOMDebuggerAgent::clear()
    515 {
    516     m_domBreakpoints.clear();
    517     m_pauseInNextEventListener = false;
    518 }
    519 
    520 } // namespace WebCore
    521 
    522