Commit d73ee834 authored by aandrey@chromium.org's avatar aandrey@chromium.org

DevTools: Instrument DOMWindowEventQueue for async stacks.

This adds async stacks support for the following DOM events:
- hashchange
- selectionchange
- pointerlockchange and others
- securitypolicyviolation
- storage

BUG=272416
R=yurys, pfeldman@chromium.org

Review URL: https://codereview.chromium.org/333333002

git-svn-id: svn://svn.chromium.org/blink/trunk@176352 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 9459f56d
Tests asynchronous call stacks for various DOM events.
Set timer for test function.
Captured call stacks in no particular order:
Call stack:
0) onHashChange (async-callstack-events.html:51)
[hashchange]
0) doTestHashChange (async-callstack-events.html:45)
1) testFunction (async-callstack-events.html:11)
Call stack:
0) onSelectionChange (async-callstack-events.html:39)
[selectionchange]
0) setSelection (async-callstack-events.html:24)
1) doTestSelectionChange (async-callstack-events.html:31)
2) testFunction (async-callstack-events.html:11)
<html>
<head>
<script src="../../../http/tests/inspector/inspector-test.js"></script>
<script src="../../../http/tests/inspector/debugger-test.js"></script>
<script>
function testFunction()
{
for (var name in window) {
if (/^doTest[A-Z]/.test(name) && typeof window[name] === "function")
window[name]();
}
}
function setSelection(start, end)
{
var node = document.getElementById("content").firstChild;
var range = document.createRange();
range.setStart(node, start);
range.setEnd(node, end);
var selection = window.getSelection();
selection.removeAllRanges();
if (start !== end)
selection.addRange(range);
}
function doTestSelectionChange()
{
setSelection(0, 0);
document.addEventListener("selectionchange", onSelectionChange, false);
setSelection(0, 4);
setSelection(0, 8);
setSelection(0, 0);
}
function onSelectionChange()
{
document.removeEventListener("selectionchange", onSelectionChange, false);
debugger;
}
function doTestHashChange()
{
window.addEventListener("hashchange", onHashChange, false);
location.hash = location.hash + "x";
}
function onHashChange()
{
window.removeEventListener("hashchange", onHashChange, false);
debugger;
}
var test = function()
{
var totalDebuggerStatements = 2;
var maxAsyncCallStackDepth = 4;
InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements, maxAsyncCallStackDepth);
}
</script>
</head>
<body onload="runTest()">
<p id="content">
Tests asynchronous call stacks for various DOM events.
</p>
</body>
</html>
......@@ -133,7 +133,7 @@ void ScriptedAnimationController::dispatchEvents()
else
eventTarget->dispatchEvent(events[i]);
InspectorInstrumentation::didDispatchEvent(eventTarget, events[i].get());
InspectorInstrumentation::didRemoveEvent(eventTarget, events[i].get());
}
}
......
......@@ -31,6 +31,7 @@
#include "core/events/Event.h"
#include "core/frame/DOMWindow.h"
#include "core/frame/SuspendableTimer.h"
#include "core/inspector/InspectorInstrumentation.h"
namespace WebCore {
......@@ -77,6 +78,8 @@ bool DOMWindowEventQueue::enqueueEvent(PassRefPtrWillBeRawPtr<Event> event)
return false;
ASSERT(event->target());
InspectorInstrumentation::didEnqueueEvent(event->target(), event.get());
bool wasAdded = m_queuedEvents.add(event).isNewEntry;
ASSERT_UNUSED(wasAdded, wasAdded); // It should not have already been in the list.
......@@ -90,8 +93,10 @@ bool DOMWindowEventQueue::cancelEvent(Event* event)
{
WillBeHeapListHashSet<RefPtrWillBeMember<Event>, 16>::iterator it = m_queuedEvents.find(event);
bool found = it != m_queuedEvents.end();
if (found)
if (found) {
InspectorInstrumentation::didRemoveEvent(event->target(), event);
m_queuedEvents.remove(it);
}
if (m_queuedEvents.isEmpty())
m_pendingEventTimer->stop();
return found;
......@@ -101,6 +106,11 @@ void DOMWindowEventQueue::close()
{
m_isClosed = true;
m_pendingEventTimer->stop();
if (InspectorInstrumentation::hasFrontends()) {
WillBeHeapListHashSet<RefPtrWillBeMember<Event>, 16>::iterator it = m_queuedEvents.begin();
for (; it != m_queuedEvents.end(); ++it)
InspectorInstrumentation::didRemoveEvent((*it)->target(), it->get());
}
m_queuedEvents.clear();
}
......@@ -123,6 +133,7 @@ void DOMWindowEventQueue::pendingEventTimerFired()
if (!event)
break;
dispatchEvent(event.get());
InspectorInstrumentation::didRemoveEvent(event->target(), event.get());
}
}
......
......@@ -208,7 +208,7 @@ void AsyncCallStackTracker::didEnqueueEvent(EventTarget* eventTarget, Event* eve
data->m_eventCallChains.set(event, createAsyncCallChain(event->type(), callFrames));
}
void AsyncCallStackTracker::didDispatchEvent(EventTarget* eventTarget, Event* event)
void AsyncCallStackTracker::didRemoveEvent(EventTarget* eventTarget, Event* event)
{
ASSERT(eventTarget->executionContext());
ASSERT(isEnabled());
......
......@@ -89,7 +89,7 @@ public:
void willFireAnimationFrame(ExecutionContext*, int callbackId);
void didEnqueueEvent(EventTarget*, Event*, const ScriptValue& callFrames);
void didDispatchEvent(EventTarget*, Event*);
void didRemoveEvent(EventTarget*, Event*);
void willHandleEvent(EventTarget*, Event*, EventListener*, bool useCapture);
void willLoadXHR(XMLHttpRequest*, const ScriptValue& callFrames);
......
......@@ -720,10 +720,10 @@ void InspectorDebuggerAgent::didEnqueueEvent(EventTarget* eventTarget, Event* ev
m_asyncCallStackTracker.didEnqueueEvent(eventTarget, event, scriptDebugServer().currentCallFramesForAsyncStack());
}
void InspectorDebuggerAgent::didDispatchEvent(EventTarget* eventTarget, Event* event)
void InspectorDebuggerAgent::didRemoveEvent(EventTarget* eventTarget, Event* event)
{
if (m_asyncCallStackTracker.isEnabled())
m_asyncCallStackTracker.didDispatchEvent(eventTarget, event);
m_asyncCallStackTracker.didRemoveEvent(eventTarget, event);
}
void InspectorDebuggerAgent::willHandleEvent(EventTarget* eventTarget, Event* event, EventListener* listener, bool useCapture)
......
......@@ -150,7 +150,7 @@ public:
bool willFireAnimationFrame(Document*, int callbackId);
void didFireAnimationFrame();
void didEnqueueEvent(EventTarget*, Event*);
void didDispatchEvent(EventTarget*, Event*);
void didRemoveEvent(EventTarget*, Event*);
void willHandleEvent(EventTarget*, Event*, EventListener*, bool useCapture);
void didHandleEvent();
void willLoadXHR(XMLHttpRequest*, ThreadableLoaderClient*, const AtomicString& method, const KURL&, bool async, FormData* body, const HTTPHeaderMap& headers, bool includeCrendentials);
......
......@@ -164,7 +164,7 @@ interface InspectorInstrumentation {
void didEnqueueEvent([Keep] EventTarget*, Event*);
[Debugger, Inline=FastReturn]
void didDispatchEvent([Keep] EventTarget*, Event*);
void didRemoveEvent([Keep] EventTarget*, Event*);
[Debugger, DOMDebugger, Inline=FastReturn]
InspectorInstrumentationCookie willHandleEvent([Keep] EventTarget*, Event*, EventListener* listener, bool useCapture);
......
......@@ -30,6 +30,7 @@
#include "core/dom/ExecutionContext.h"
#include "core/dom/ExecutionContextTask.h"
#include "core/events/Event.h"
#include "core/inspector/InspectorInstrumentation.h"
namespace WebCore {
......@@ -104,6 +105,7 @@ private:
void WorkerEventQueue::removeEvent(Event* event)
{
InspectorInstrumentation::didRemoveEvent(event->target(), event);
m_eventTaskMap.remove(event);
}
......@@ -112,6 +114,7 @@ bool WorkerEventQueue::enqueueEvent(PassRefPtrWillBeRawPtr<Event> prpEvent)
if (m_isClosed)
return false;
RefPtrWillBeRawPtr<Event> event = prpEvent;
InspectorInstrumentation::didEnqueueEvent(event->target(), event.get());
OwnPtr<EventDispatcherTask> task = EventDispatcherTask::create(event, this);
m_eventTaskMap.add(event.release(), task.get());
m_executionContext->postTask(task.release());
......@@ -132,7 +135,9 @@ void WorkerEventQueue::close()
{
m_isClosed = true;
for (EventTaskMap::iterator it = m_eventTaskMap.begin(); it != m_eventTaskMap.end(); ++it) {
Event* event = it->key.get();
EventDispatcherTask* task = it->value;
InspectorInstrumentation::didRemoveEvent(event->target(), event);
task->cancel();
}
m_eventTaskMap.clear();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment