Web Inspector: should be possible to step through all event listeners when event...
authoryurys@chromium.org <yurys@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 31 Jan 2012 07:37:28 +0000 (07:37 +0000)
committeryurys@chromium.org <yurys@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 31 Jan 2012 07:37:28 +0000 (07:37 +0000)
https://bugs.webkit.org/show_bug.cgi?id=77331

Source/WebCore:

Inspector instrumentation is called before and after each event handler invokation.
In case inspector front-end is closed it is no-op, otherwise it may stop execution
on an event listener breakpoint.

Reviewed by Pavel Feldman.

Test: inspector/debugger/step-through-event-listeners.html

* dom/EventTarget.cpp:
(WebCore::EventTarget::fireEventListeners):
* inspector/InspectorInstrumentation.cpp:
(WebCore::InspectorInstrumentation::willDispatchEventImpl):
(WebCore::InspectorInstrumentation::willHandleEventImpl):
(WebCore):
(WebCore::InspectorInstrumentation::didHandleEventImpl):
(WebCore::InspectorInstrumentation::didDispatchEventImpl):
(WebCore::InspectorInstrumentation::willDispatchEventOnWindowImpl):
(WebCore::InspectorInstrumentation::didDispatchEventOnWindowImpl):
* inspector/InspectorInstrumentation.h:
(InspectorInstrumentation):
(WebCore::InspectorInstrumentation::willHandleEvent):
(WebCore):
(WebCore::InspectorInstrumentation::didHandleEvent):

LayoutTests:

Test that debugger will stop in each event listener when pausing on an event listener
breakpoint.

Reviewed by Pavel Feldman.

* inspector/debugger/step-through-event-listeners-expected.txt: Added.
* inspector/debugger/step-through-event-listeners.html: Added.
* platform/gtk/Skipped:
* platform/mac/Skipped:
* platform/qt/Skipped:
* platform/win/Skipped:
* platform/wincairo/Skipped:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@106337 268f45cc-cd09-0410-ab3c-d52691b4dbfc

12 files changed:
LayoutTests/ChangeLog
LayoutTests/inspector/debugger/step-through-event-listeners-expected.txt [new file with mode: 0644]
LayoutTests/inspector/debugger/step-through-event-listeners.html [new file with mode: 0644]
LayoutTests/platform/gtk/Skipped
LayoutTests/platform/mac/Skipped
LayoutTests/platform/qt/Skipped
LayoutTests/platform/win/Skipped
LayoutTests/platform/wincairo/Skipped
Source/WebCore/ChangeLog
Source/WebCore/dom/EventTarget.cpp
Source/WebCore/inspector/InspectorInstrumentation.cpp
Source/WebCore/inspector/InspectorInstrumentation.h

index 9f38ca7..31b971f 100644 (file)
@@ -1,3 +1,21 @@
+2012-01-30  Yury Semikhatsky  <yurys@chromium.org>
+
+        Web Inspector: should be possible to step through all event listeners when event listener breakpoint is hit
+        https://bugs.webkit.org/show_bug.cgi?id=77331
+
+        Test that debugger will stop in each event listener when pausing on an event listener
+        breakpoint.
+
+        Reviewed by Pavel Feldman.
+
+        * inspector/debugger/step-through-event-listeners-expected.txt: Added.
+        * inspector/debugger/step-through-event-listeners.html: Added.
+        * platform/gtk/Skipped:
+        * platform/mac/Skipped:
+        * platform/qt/Skipped:
+        * platform/win/Skipped:
+        * platform/wincairo/Skipped:
+
 2011-01-30  Hayato Ito  <hayato@chromium.org>
 
         Attach light children after removing a shadow root.
diff --git a/LayoutTests/inspector/debugger/step-through-event-listeners-expected.txt b/LayoutTests/inspector/debugger/step-through-event-listeners-expected.txt
new file mode 100644 (file)
index 0000000..fe1ef31
--- /dev/null
@@ -0,0 +1,32 @@
+Test that debugger will pause in all event listeners when corresponding breakpoint is set. Bug 77331.
+
+
+Debugger was enabled.
+
+Running: testClickBreakpoint
+Script execution paused.
+Call stack:
+    0) listener3 (step-through-event-listeners.html:15)
+    1) addListenerAndClick (step-through-event-listeners.html:26)
+    2)  (:1)
+Script execution resumed.
+Script execution paused.
+Call stack:
+    0) listener1 (step-through-event-listeners.html:7)
+    1) addListenerAndClick (step-through-event-listeners.html:26)
+    2)  (:1)
+Script execution resumed.
+Script execution paused.
+Call stack:
+    0) listener2 (step-through-event-listeners.html:11)
+    1) addListenerAndClick (step-through-event-listeners.html:26)
+    2)  (:1)
+Script execution resumed.
+Script execution paused.
+Call stack:
+    0) listener3 (step-through-event-listeners.html:15)
+    1) addListenerAndClick (step-through-event-listeners.html:26)
+    2)  (:1)
+Script execution resumed.
+Debugger was disabled.
+
diff --git a/LayoutTests/inspector/debugger/step-through-event-listeners.html b/LayoutTests/inspector/debugger/step-through-event-listeners.html
new file mode 100644 (file)
index 0000000..012c810
--- /dev/null
@@ -0,0 +1,94 @@
+<html>
+<head>
+<script src="../../http/tests/inspector/inspector-test.js"></script>
+<script src="../../http/tests/inspector/debugger-test.js"></script>
+<script>
+
+function listener1()
+{
+}
+
+function listener2()
+{
+}
+
+function listener3()
+{
+}
+
+function addListenerAndClick()
+{
+    var element = document.getElementById("test");
+    element.addEventListener("click", listener1, true);
+    element.addEventListener("click", listener2, true);
+    document.body.addEventListener("click", listener3, true);
+    document.body.addEventListener("click", listener3, false);
+    element.click();
+}
+
+function test()
+{
+    var pane = WebInspector.panels.scripts.sidebarPanes.eventListenerBreakpoints;
+    InspectorTest.runDebuggerTestSuite([
+        function testClickBreakpoint(next)
+        {
+            pane._setBreakpoint("listener:click");
+            InspectorTest.waitUntilPaused(paused1);
+            InspectorTest.evaluateInPageWithTimeout("addListenerAndClick()");
+
+            function paused1(callFrames)
+            {
+                InspectorTest.captureStackTrace(callFrames);
+                InspectorTest.resumeExecution(resumed1);
+            }
+
+            function resumed1()
+            {
+                InspectorTest.waitUntilPaused(paused2);
+            }
+
+            function paused2(callFrames)
+            {
+                InspectorTest.captureStackTrace(callFrames);
+                InspectorTest.resumeExecution(resumed2);
+            }
+
+            function resumed2()
+            {
+                InspectorTest.waitUntilPaused(paused3);
+            }
+
+            function paused3(callFrames)
+            {
+                InspectorTest.captureStackTrace(callFrames);
+                InspectorTest.resumeExecution(resumed3);
+            }
+
+            function resumed3()
+            {
+                InspectorTest.waitUntilPaused(paused4);
+            }
+
+            function paused4(callFrames)
+            {
+                InspectorTest.captureStackTrace(callFrames);
+                pane._removeBreakpoint("listener:click");
+                InspectorTest.resumeExecution(next);
+            }
+        }
+    ]);
+}
+
+</script>
+</head>
+
+<body onload="runTest()">
+<p>
+Test that debugger will pause in all event listeners when corresponding breakpoint is set.
+<a href="https://bugs.webkit.org/show_bug.cgi?id=77331">Bug 77331.</a>
+</p>
+
+<input type=button id="test"></input>
+
+</body>
+</html>
index 6ef3370..313319b 100644 (file)
@@ -1100,6 +1100,7 @@ sputnik/Unicode/Unicode_510/S7.6_A5.3_T2.html
 # https://bugs.webkit.org/show_bug.cgi?id=43332
 inspector/debugger/dom-breakpoints.html
 inspector/debugger/event-listener-breakpoints.html
+inspector/debugger/step-through-event-listeners.html
 inspector/debugger/xhr-breakpoints.html
 
 # https://bugs.webkit.org/show_bug.cgi?id=40300
index 7833ea9..46811a7 100644 (file)
@@ -258,6 +258,7 @@ inspector/debugger/selected-call-frame-after-formatting-source.html
 # https://bugs.webkit.org/show_bug.cgi?id=43332
 inspector/debugger/dom-breakpoints.html
 inspector/debugger/event-listener-breakpoints.html
+inspector/debugger/step-through-event-listeners.html
 inspector/debugger/xhr-breakpoints.html
 
 # Skipping newly added tests while I'm finding out what is wrong.
index fcd9d04..1bcbded 100644 (file)
@@ -208,6 +208,7 @@ fast/text/soft-hyphen-4.html
 # https://bugs.webkit.org/show_bug.cgi?id=43332
 inspector/debugger/dom-breakpoints.html
 inspector/debugger/event-listener-breakpoints.html
+inspector/debugger/step-through-event-listeners.html
 inspector/debugger/xhr-breakpoints.html
 
 # https://bugs.webkit.org/show_bug.cgi?id=40300
index 9d607a2..acc2243 100644 (file)
@@ -1216,6 +1216,7 @@ http/tests/appcache/origin-quota-continued-download-multiple-manifests.html
 # https://bugs.webkit.org/show_bug.cgi?id=43332
 inspector/debugger/dom-breakpoints.html
 inspector/debugger/event-listener-breakpoints.html
+inspector/debugger/step-through-event-listeners.html
 inspector/debugger/xhr-breakpoints.html
 
 # https://bugs.webkit.org/show_bug.cgi?id=40300
index c607269..9dfacb4 100644 (file)
@@ -1752,6 +1752,7 @@ http/tests/appcache/origin-quota-continued-download-multiple-manifests.html
 # https://bugs.webkit.org/show_bug.cgi?id=43332
 inspector/debugger/dom-breakpoints.html
 inspector/debugger/event-listener-breakpoints.html
+inspector/debugger/step-through-event-listeners.html
 inspector/debugger/xhr-breakpoints.html
 
 # https://bugs.webkit.org/show_bug.cgi?id=40300
index 18835da..21683e9 100644 (file)
@@ -1,3 +1,32 @@
+2012-01-30  Yury Semikhatsky  <yurys@chromium.org>
+
+        Web Inspector: should be possible to step through all event listeners when event listener breakpoint is hit
+        https://bugs.webkit.org/show_bug.cgi?id=77331
+
+        Inspector instrumentation is called before and after each event handler invokation.
+        In case inspector front-end is closed it is no-op, otherwise it may stop execution
+        on an event listener breakpoint.
+
+        Reviewed by Pavel Feldman.
+
+        Test: inspector/debugger/step-through-event-listeners.html
+
+        * dom/EventTarget.cpp:
+        (WebCore::EventTarget::fireEventListeners):
+        * inspector/InspectorInstrumentation.cpp:
+        (WebCore::InspectorInstrumentation::willDispatchEventImpl):
+        (WebCore::InspectorInstrumentation::willHandleEventImpl):
+        (WebCore):
+        (WebCore::InspectorInstrumentation::didHandleEventImpl):
+        (WebCore::InspectorInstrumentation::didDispatchEventImpl):
+        (WebCore::InspectorInstrumentation::willDispatchEventOnWindowImpl):
+        (WebCore::InspectorInstrumentation::didDispatchEventOnWindowImpl):
+        * inspector/InspectorInstrumentation.h:
+        (InspectorInstrumentation):
+        (WebCore::InspectorInstrumentation::willHandleEvent):
+        (WebCore):
+        (WebCore::InspectorInstrumentation::didHandleEvent):
+
 2011-01-30  Hayato Ito  <hayato@chromium.org>
 
         Attach light children after removing a shadow root.
index 21a1725..6272afb 100644 (file)
@@ -34,6 +34,7 @@
 
 #include "Event.h"
 #include "EventException.h"
+#include "InspectorInstrumentation.h"
 #include <wtf/MainThread.h>
 #include <wtf/StdLibExtras.h>
 #include <wtf/Vector.h>
@@ -223,9 +224,12 @@ void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventList
         if (event->immediatePropagationStopped())
             break;
 
+        ScriptExecutionContext* context = scriptExecutionContext();
+        InspectorInstrumentationCookie cookie = InspectorInstrumentation::willHandleEvent(context, event);
         // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling
         // event listeners, even though that violates some versions of the DOM spec.
-        registeredListener.listener->handleEvent(scriptExecutionContext(), event);
+        registeredListener.listener->handleEvent(context, event);
+        InspectorInstrumentation::didHandleEvent(cookie);
     }
     d->firingEventIterators.removeLast();
 }
index f5aaa8b..b4af182 100644 (file)
@@ -279,8 +279,6 @@ void InspectorInstrumentation::didChangeXHRReadyStateImpl(const InspectorInstrum
 
 InspectorInstrumentationCookie InspectorInstrumentation::willDispatchEventImpl(InstrumentingAgents* instrumentingAgents, const Event& event, DOMWindow* window, Node* node, const Vector<EventContext>& ancestors)
 {
-    pauseOnNativeEventIfNeeded(instrumentingAgents, listenerEventCategoryType, event.type(), false);
-
     int timelineAgentId = 0;
     InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent();
     if (timelineAgent && eventHasListeners(event.type(), window, node, ancestors)) {
@@ -290,18 +288,25 @@ InspectorInstrumentationCookie InspectorInstrumentation::willDispatchEventImpl(I
     return InspectorInstrumentationCookie(instrumentingAgents, timelineAgentId);
 }
 
-void InspectorInstrumentation::didDispatchEventImpl(const InspectorInstrumentationCookie& cookie)
+InspectorInstrumentationCookie InspectorInstrumentation::willHandleEventImpl(InstrumentingAgents* instrumentingAgents, Event* event)
+{
+    pauseOnNativeEventIfNeeded(instrumentingAgents, listenerEventCategoryType, event->type(), false);
+    return InspectorInstrumentationCookie(instrumentingAgents, 0);
+}
+
+void InspectorInstrumentation::didHandleEventImpl(const InspectorInstrumentationCookie& cookie)
 {
     cancelPauseOnNativeEvent(cookie.first);
+}
 
+void InspectorInstrumentation::didDispatchEventImpl(const InspectorInstrumentationCookie& cookie)
+{
     if (InspectorTimelineAgent* timelineAgent = retrieveTimelineAgent(cookie))
         timelineAgent->didDispatchEvent();
 }
 
 InspectorInstrumentationCookie InspectorInstrumentation::willDispatchEventOnWindowImpl(InstrumentingAgents* instrumentingAgents, const Event& event, DOMWindow* window)
 {
-    pauseOnNativeEventIfNeeded(instrumentingAgents, listenerEventCategoryType, event.type(), false);
-
     int timelineAgentId = 0;
     InspectorTimelineAgent* timelineAgent = instrumentingAgents->inspectorTimelineAgent();
     if (timelineAgent && window->hasEventListeners(event.type())) {
@@ -313,8 +318,6 @@ InspectorInstrumentationCookie InspectorInstrumentation::willDispatchEventOnWind
 
 void InspectorInstrumentation::didDispatchEventOnWindowImpl(const InspectorInstrumentationCookie& cookie)
 {
-    cancelPauseOnNativeEvent(cookie.first);
-
     if (InspectorTimelineAgent* timelineAgent = retrieveTimelineAgent(cookie))
         timelineAgent->didDispatchEvent();
 }
index 92c4ec7..298099b 100644 (file)
@@ -107,6 +107,8 @@ public:
     static void didChangeXHRReadyState(const InspectorInstrumentationCookie&);
     static InspectorInstrumentationCookie willDispatchEvent(Document*, const Event& event, DOMWindow* window, Node* node, const Vector<EventContext>& ancestors);
     static void didDispatchEvent(const InspectorInstrumentationCookie&);
+    static InspectorInstrumentationCookie willHandleEvent(ScriptExecutionContext*, Event*);
+    static void didHandleEvent(const InspectorInstrumentationCookie&);
     static InspectorInstrumentationCookie willDispatchEventOnWindow(Frame*, const Event& event, DOMWindow* window);
     static void didDispatchEventOnWindow(const InspectorInstrumentationCookie&);
     static InspectorInstrumentationCookie willEvaluateScript(Frame*, const String& url, int lineNumber);
@@ -253,6 +255,8 @@ private:
     static InspectorInstrumentationCookie willChangeXHRReadyStateImpl(InstrumentingAgents*, XMLHttpRequest*);
     static void didChangeXHRReadyStateImpl(const InspectorInstrumentationCookie&);
     static InspectorInstrumentationCookie willDispatchEventImpl(InstrumentingAgents*, const Event&, DOMWindow*, Node*, const Vector<EventContext>& ancestors);
+    static InspectorInstrumentationCookie willHandleEventImpl(InstrumentingAgents*, Event*);
+    static void didHandleEventImpl(const InspectorInstrumentationCookie&);
     static void didDispatchEventImpl(const InspectorInstrumentationCookie&);
     static InspectorInstrumentationCookie willDispatchEventOnWindowImpl(InstrumentingAgents*, const Event&, DOMWindow*);
     static void didDispatchEventOnWindowImpl(const InspectorInstrumentationCookie&);
@@ -592,6 +596,25 @@ inline void InspectorInstrumentation::didDispatchEvent(const InspectorInstrument
 #endif
 }
 
+inline InspectorInstrumentationCookie InspectorInstrumentation::willHandleEvent(ScriptExecutionContext* context, Event* event)
+{
+#if ENABLE(INSPECTOR)
+    FAST_RETURN_IF_NO_FRONTENDS(InspectorInstrumentationCookie());
+    if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context))
+        return willHandleEventImpl(instrumentingAgents, event);
+#endif
+    return InspectorInstrumentationCookie();
+}
+
+inline void InspectorInstrumentation::didHandleEvent(const InspectorInstrumentationCookie& cookie)
+{
+#if ENABLE(INSPECTOR)
+    FAST_RETURN_IF_NO_FRONTENDS(void());
+    if (cookie.first)
+        didHandleEventImpl(cookie);
+#endif
+}
+
 inline InspectorInstrumentationCookie InspectorInstrumentation::willDispatchEventOnWindow(Frame* frame, const Event& event, DOMWindow* window)
 {
 #if ENABLE(INSPECTOR)