Commit 161d3b6f authored by aandrey@chromium.org's avatar aandrey@chromium.org

DevTools: Support async call stacks for scripted animation events (like scroll).

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

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

git-svn-id: svn://svn.chromium.org/blink/trunk@176221 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent ba484895
Tests asynchronous call stacks for scripted scroll events.
Set timer for test function.
Captured call stacks in no particular order:
Call stack:
0) onScroll1 (async-callstack-scripted-scroll.html:26)
[scroll]
0) timeout (async-callstack-scripted-scroll.html:18)
[setTimeout]
0) testFunction (async-callstack-scripted-scroll.html:9)
Call stack:
0) onScroll2 (async-callstack-scripted-scroll.html:33)
[scroll]
0) timeout (async-callstack-scripted-scroll.html:18)
[setTimeout]
0) testFunction (async-callstack-scripted-scroll.html:9)
<html>
<head>
<script src="../../../http/tests/inspector/inspector-test.js"></script>
<script src="../../../http/tests/inspector/debugger-test.js"></script>
<script>
function testFunction()
{
setTimeout(timeout, 0);
}
function timeout()
{
var outer = document.getElementById("outer");
outer.scrollTop = 0;
outer.addEventListener("scroll", onScroll1, false);
outer.addEventListener("scroll", onScroll2, false);
outer.scrollTop = 40;
outer.scrollTop = 60;
}
function onScroll1()
{
var outer = document.getElementById("outer");
outer.removeEventListener("scroll", onScroll1, false);
debugger;
}
function onScroll2()
{
var outer = document.getElementById("outer");
outer.removeEventListener("scroll", onScroll2, false);
debugger;
}
var test = function()
{
var totalDebuggerStatements = 2;
var maxAsyncCallStackDepth = 4;
InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements, maxAsyncCallStackDepth);
}
</script>
</head>
<body onload="runTest()">
<p>
Tests asynchronous call stacks for scripted scroll events.
</p>
<div id="outer" style="width: 100px; height: 100px; overflow:auto">
<div id="inner" style="width: 200px; height: 200px;"></div>
</div>
</body>
</html>
...@@ -123,6 +123,8 @@ void ScriptedAnimationController::dispatchEvents() ...@@ -123,6 +123,8 @@ void ScriptedAnimationController::dispatchEvents()
window->dispatchEvent(events[i], nullptr); window->dispatchEvent(events[i], nullptr);
else else
eventTarget->dispatchEvent(events[i]); eventTarget->dispatchEvent(events[i]);
InspectorInstrumentation::didDispatchEvent(eventTarget, events[i].get());
} }
} }
...@@ -176,6 +178,7 @@ void ScriptedAnimationController::serviceScriptedAnimations(double monotonicTime ...@@ -176,6 +178,7 @@ void ScriptedAnimationController::serviceScriptedAnimations(double monotonicTime
void ScriptedAnimationController::enqueueEvent(PassRefPtrWillBeRawPtr<Event> event) void ScriptedAnimationController::enqueueEvent(PassRefPtrWillBeRawPtr<Event> event)
{ {
InspectorInstrumentation::didEnqueueEvent(event->target(), event.get());
m_eventQueue.append(event); m_eventQueue.append(event);
scheduleAnimationIfNeeded(); scheduleAnimationIfNeeded();
} }
......
...@@ -331,7 +331,7 @@ void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventList ...@@ -331,7 +331,7 @@ void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventList
if (!context) if (!context)
break; break;
InspectorInstrumentationCookie cookie = InspectorInstrumentation::willHandleEvent(this, event->type(), registeredListener.listener.get(), registeredListener.useCapture); InspectorInstrumentationCookie cookie = InspectorInstrumentation::willHandleEvent(this, event, registeredListener.listener.get(), registeredListener.useCapture);
// To match Mozilla, the AT_TARGET phase fires both capturing and bubbling // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling
// event listeners, even though that violates some versions of the DOM spec. // event listeners, even though that violates some versions of the DOM spec.
registeredListener.listener->handleEvent(context, event); registeredListener.listener->handleEvent(context, event);
......
...@@ -76,6 +76,7 @@ public: ...@@ -76,6 +76,7 @@ public:
HashSet<int> m_intervalTimerIds; HashSet<int> m_intervalTimerIds;
HashMap<int, RefPtr<AsyncCallChain> > m_timerCallChains; HashMap<int, RefPtr<AsyncCallChain> > m_timerCallChains;
HashMap<int, RefPtr<AsyncCallChain> > m_animationFrameCallChains; HashMap<int, RefPtr<AsyncCallChain> > m_animationFrameCallChains;
HashMap<Event*, RefPtr<AsyncCallChain> > m_eventCallChains;
HashMap<EventTarget*, RefPtr<AsyncCallChain> > m_xhrCallChains; HashMap<EventTarget*, RefPtr<AsyncCallChain> > m_xhrCallChains;
HashMap<MutationObserver*, RefPtr<AsyncCallChain> > m_mutationObserverCallChains; HashMap<MutationObserver*, RefPtr<AsyncCallChain> > m_mutationObserverCallChains;
}; };
...@@ -197,14 +198,36 @@ void AsyncCallStackTracker::willFireAnimationFrame(ExecutionContext* context, in ...@@ -197,14 +198,36 @@ void AsyncCallStackTracker::willFireAnimationFrame(ExecutionContext* context, in
setCurrentAsyncCallChain(nullptr); setCurrentAsyncCallChain(nullptr);
} }
void AsyncCallStackTracker::willHandleEvent(EventTarget* eventTarget, const AtomicString& eventType, EventListener* listener, bool useCapture) void AsyncCallStackTracker::didEnqueueEvent(EventTarget* eventTarget, Event* event, const ScriptValue& callFrames)
{ {
ASSERT(eventTarget->executionContext()); ASSERT(eventTarget->executionContext());
ASSERT(isEnabled()); ASSERT(isEnabled());
if (XMLHttpRequest* xhr = toXmlHttpRequest(eventTarget)) if (!validateCallFrames(callFrames))
willHandleXHREvent(xhr, eventTarget, eventType); return;
ExecutionContextData* data = createContextDataIfNeeded(eventTarget->executionContext());
data->m_eventCallChains.set(event, createAsyncCallChain(event->type(), callFrames));
}
void AsyncCallStackTracker::didDispatchEvent(EventTarget* eventTarget, Event* event)
{
ASSERT(eventTarget->executionContext());
ASSERT(isEnabled());
if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget->executionContext()))
data->m_eventCallChains.remove(event);
}
void AsyncCallStackTracker::willHandleEvent(EventTarget* eventTarget, Event* event, EventListener* listener, bool useCapture)
{
ASSERT(eventTarget->executionContext());
ASSERT(isEnabled());
if (XMLHttpRequest* xhr = toXmlHttpRequest(eventTarget)) {
willHandleXHREvent(xhr, eventTarget, event);
} else {
if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget->executionContext()))
setCurrentAsyncCallChain(data->m_eventCallChains.get(event));
else else
setCurrentAsyncCallChain(nullptr); setCurrentAsyncCallChain(nullptr);
}
} }
void AsyncCallStackTracker::willLoadXHR(XMLHttpRequest* xhr, const ScriptValue& callFrames) void AsyncCallStackTracker::willLoadXHR(XMLHttpRequest* xhr, const ScriptValue& callFrames)
...@@ -217,13 +240,13 @@ void AsyncCallStackTracker::willLoadXHR(XMLHttpRequest* xhr, const ScriptValue& ...@@ -217,13 +240,13 @@ void AsyncCallStackTracker::willLoadXHR(XMLHttpRequest* xhr, const ScriptValue&
data->m_xhrCallChains.set(xhr, createAsyncCallChain(xhrSendName, callFrames)); data->m_xhrCallChains.set(xhr, createAsyncCallChain(xhrSendName, callFrames));
} }
void AsyncCallStackTracker::willHandleXHREvent(XMLHttpRequest* xhr, EventTarget* eventTarget, const AtomicString& eventType) void AsyncCallStackTracker::willHandleXHREvent(XMLHttpRequest* xhr, EventTarget* eventTarget, Event* event)
{ {
ASSERT(xhr->executionContext()); ASSERT(xhr->executionContext());
ASSERT(isEnabled()); ASSERT(isEnabled());
if (ExecutionContextData* data = m_executionContextDataMap.get(xhr->executionContext())) { if (ExecutionContextData* data = m_executionContextDataMap.get(xhr->executionContext())) {
bool isXHRDownload = (xhr == eventTarget); bool isXHRDownload = (xhr == eventTarget);
if (isXHRDownload && eventType == EventTypeNames::loadend) if (isXHRDownload && event->type() == EventTypeNames::loadend)
setCurrentAsyncCallChain(data->m_xhrCallChains.take(xhr)); setCurrentAsyncCallChain(data->m_xhrCallChains.take(xhr));
else else
setCurrentAsyncCallChain(data->m_xhrCallChains.get(xhr)); setCurrentAsyncCallChain(data->m_xhrCallChains.get(xhr));
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
namespace WebCore { namespace WebCore {
class Event;
class EventListener; class EventListener;
class EventTarget; class EventTarget;
class ExecutionContext; class ExecutionContext;
...@@ -87,7 +88,9 @@ public: ...@@ -87,7 +88,9 @@ public:
void didCancelAnimationFrame(ExecutionContext*, int callbackId); void didCancelAnimationFrame(ExecutionContext*, int callbackId);
void willFireAnimationFrame(ExecutionContext*, int callbackId); void willFireAnimationFrame(ExecutionContext*, int callbackId);
void willHandleEvent(EventTarget*, const AtomicString& eventType, EventListener*, bool useCapture); void didEnqueueEvent(EventTarget*, Event*, const ScriptValue& callFrames);
void didDispatchEvent(EventTarget*, Event*);
void willHandleEvent(EventTarget*, Event*, EventListener*, bool useCapture);
void willLoadXHR(XMLHttpRequest*, const ScriptValue& callFrames); void willLoadXHR(XMLHttpRequest*, const ScriptValue& callFrames);
void didEnqueueMutationRecord(ExecutionContext*, MutationObserver*, const ScriptValue& callFrames); void didEnqueueMutationRecord(ExecutionContext*, MutationObserver*, const ScriptValue& callFrames);
...@@ -99,7 +102,7 @@ public: ...@@ -99,7 +102,7 @@ public:
void clear(); void clear();
private: private:
void willHandleXHREvent(XMLHttpRequest*, EventTarget*, const AtomicString& eventType); void willHandleXHREvent(XMLHttpRequest*, EventTarget*, Event*);
PassRefPtr<AsyncCallChain> createAsyncCallChain(const String& description, const ScriptValue& callFrames); PassRefPtr<AsyncCallChain> createAsyncCallChain(const String& description, const ScriptValue& callFrames);
void setCurrentAsyncCallChain(PassRefPtr<AsyncCallChain>); void setCurrentAsyncCallChain(PassRefPtr<AsyncCallChain>);
......
...@@ -473,9 +473,9 @@ void InspectorDOMDebuggerAgent::willFireAnimationFrame(Document*, int) ...@@ -473,9 +473,9 @@ void InspectorDOMDebuggerAgent::willFireAnimationFrame(Document*, int)
pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(animationFrameFiredEventName, 0), false); pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(animationFrameFiredEventName, 0), false);
} }
void InspectorDOMDebuggerAgent::willHandleEvent(EventTarget* target, const AtomicString& eventType, EventListener*, bool) void InspectorDOMDebuggerAgent::willHandleEvent(EventTarget* target, Event* event, EventListener*, bool)
{ {
pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(eventType, &target->interfaceName()), false); pauseOnNativeEventIfNeeded(preparePauseOnNativeEventData(event->type(), &target->interfaceName()), false);
} }
void InspectorDOMDebuggerAgent::willExecuteCustomElementCallback(Element*) void InspectorDOMDebuggerAgent::willExecuteCustomElementCallback(Element*)
......
...@@ -43,6 +43,7 @@ namespace WebCore { ...@@ -43,6 +43,7 @@ namespace WebCore {
class Document; class Document;
class Element; class Element;
class Event;
class EventListener; class EventListener;
class EventTarget; class EventTarget;
class InspectorDOMAgent; class InspectorDOMAgent;
...@@ -89,7 +90,7 @@ public: ...@@ -89,7 +90,7 @@ public:
void didRequestAnimationFrame(Document*, int callbackId); void didRequestAnimationFrame(Document*, int callbackId);
void didCancelAnimationFrame(Document*, int callbackId); void didCancelAnimationFrame(Document*, int callbackId);
void willFireAnimationFrame(Document*, int callbackId); void willFireAnimationFrame(Document*, int callbackId);
void willHandleEvent(EventTarget*, const AtomicString& eventType, EventListener*, bool useCapture); void willHandleEvent(EventTarget*, Event*, EventListener*, bool useCapture);
void didFireWebGLError(const String& errorName); void didFireWebGLError(const String& errorName);
void didFireWebGLWarning(); void didFireWebGLWarning();
void didFireWebGLErrorOrWarning(const String& message); void didFireWebGLErrorOrWarning(const String& message);
......
...@@ -714,10 +714,22 @@ void InspectorDebuggerAgent::didFireAnimationFrame() ...@@ -714,10 +714,22 @@ void InspectorDebuggerAgent::didFireAnimationFrame()
m_asyncCallStackTracker.didFireAsyncCall(); m_asyncCallStackTracker.didFireAsyncCall();
} }
void InspectorDebuggerAgent::willHandleEvent(EventTarget* eventTarget, const AtomicString& eventType, EventListener* listener, bool useCapture) void InspectorDebuggerAgent::didEnqueueEvent(EventTarget* eventTarget, Event* event)
{ {
if (m_asyncCallStackTracker.isEnabled()) if (m_asyncCallStackTracker.isEnabled())
m_asyncCallStackTracker.willHandleEvent(eventTarget, eventType, listener, useCapture); m_asyncCallStackTracker.didEnqueueEvent(eventTarget, event, scriptDebugServer().currentCallFramesForAsyncStack());
}
void InspectorDebuggerAgent::didDispatchEvent(EventTarget* eventTarget, Event* event)
{
if (m_asyncCallStackTracker.isEnabled())
m_asyncCallStackTracker.didDispatchEvent(eventTarget, event);
}
void InspectorDebuggerAgent::willHandleEvent(EventTarget* eventTarget, Event* event, EventListener* listener, bool useCapture)
{
if (m_asyncCallStackTracker.isEnabled())
m_asyncCallStackTracker.willHandleEvent(eventTarget, event, listener, useCapture);
} }
void InspectorDebuggerAgent::didHandleEvent() void InspectorDebuggerAgent::didHandleEvent()
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
namespace WebCore { namespace WebCore {
class Document; class Document;
class Event;
class EventListener; class EventListener;
class EventTarget; class EventTarget;
class FormData; class FormData;
...@@ -148,7 +149,9 @@ public: ...@@ -148,7 +149,9 @@ public:
void didCancelAnimationFrame(Document*, int callbackId); void didCancelAnimationFrame(Document*, int callbackId);
bool willFireAnimationFrame(Document*, int callbackId); bool willFireAnimationFrame(Document*, int callbackId);
void didFireAnimationFrame(); void didFireAnimationFrame();
void willHandleEvent(EventTarget*, const AtomicString& eventType, EventListener*, bool useCapture); void didEnqueueEvent(EventTarget*, Event*);
void didDispatchEvent(EventTarget*, Event*);
void willHandleEvent(EventTarget*, Event*, EventListener*, bool useCapture);
void didHandleEvent(); void didHandleEvent();
void willLoadXHR(XMLHttpRequest*, ThreadableLoaderClient*, const AtomicString& method, const KURL&, bool async, FormData* body, const HTTPHeaderMap& headers, bool includeCrendentials); void willLoadXHR(XMLHttpRequest*, ThreadableLoaderClient*, const AtomicString& method, const KURL&, bool async, FormData* body, const HTTPHeaderMap& headers, bool includeCrendentials);
void didEnqueueMutationRecord(ExecutionContext*, MutationObserver*); void didEnqueueMutationRecord(ExecutionContext*, MutationObserver*);
......
...@@ -160,8 +160,14 @@ interface InspectorInstrumentation { ...@@ -160,8 +160,14 @@ interface InspectorInstrumentation {
[Timeline, Inline=FastReturn] [Timeline, Inline=FastReturn]
void didDispatchEvent(const InspectorInstrumentationCookie&); void didDispatchEvent(const InspectorInstrumentationCookie&);
[Debugger, Inline=FastReturn]
void didEnqueueEvent([Keep] EventTarget*, Event*);
[Debugger, Inline=FastReturn]
void didDispatchEvent([Keep] EventTarget*, Event*);
[Debugger, DOMDebugger, Inline=FastReturn] [Debugger, DOMDebugger, Inline=FastReturn]
InspectorInstrumentationCookie willHandleEvent([Keep] EventTarget*, const AtomicString& eventType, EventListener* listener, bool useCapture); InspectorInstrumentationCookie willHandleEvent([Keep] EventTarget*, Event*, EventListener* listener, bool useCapture);
[Debugger, Inline=FastReturn] [Debugger, Inline=FastReturn]
void didHandleEvent(const InspectorInstrumentationCookie&); void didHandleEvent(const InspectorInstrumentationCookie&);
......
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