[MutationObservers] V8LazyEventHandler breaks microtask delivery semantics
https://bugs.webkit.org/show_bug.cgi?id=73492

Reviewed by Adam Barth.

Source/WebCore:

Test: fast/mutation/inline-event-listener.html

* bindings/v8/V8LazyEventListener.cpp:
(WebCore::V8LazyEventListener::prepareListenerObject): Call v8::Script::Run directly instead of going through V8Proxy.

Tools:

Add eventSender.scheduleAsynchronousKeyDown, needed to cause a
keypress event without any script on the stack.

* DumpRenderTree/chromium/EventSender.cpp:
(EventSender::EventSender):
(EventSender::keyDown):
(KeyDownTask::KeyDownTask):
(KeyDownTask::runIfValid):
(EventSender::scheduleAsynchronousKeyDown):
* DumpRenderTree/chromium/EventSender.h:

LayoutTests:

* fast/mutation/inline-event-listener-expected.txt: Added.
* fast/mutation/inline-event-listener.html: Added.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@102424 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 96101fb..65c9d34 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,13 @@
+2011-12-08  Adam Klein  <adamk@chromium.org>
+
+        [MutationObservers] V8LazyEventHandler breaks microtask delivery semantics
+        https://bugs.webkit.org/show_bug.cgi?id=73492
+
+        Reviewed by Adam Barth.
+
+        * fast/mutation/inline-event-listener-expected.txt: Added.
+        * fast/mutation/inline-event-listener.html: Added.
+
 2011-12-08  Hayato Ito  <hayato@chromium.org>
 
         Suppress rendering of light children when ShadowRoot is dynamically created.
diff --git a/LayoutTests/fast/mutation/inline-event-listener-expected.txt b/LayoutTests/fast/mutation/inline-event-listener-expected.txt
new file mode 100644
index 0000000..53cdf1e
--- /dev/null
+++ b/LayoutTests/fast/mutation/inline-event-listener-expected.txt
@@ -0,0 +1 @@
+PASSED
diff --git a/LayoutTests/fast/mutation/inline-event-listener.html b/LayoutTests/fast/mutation/inline-event-listener.html
new file mode 100644
index 0000000..30968e1
--- /dev/null
+++ b/LayoutTests/fast/mutation/inline-event-listener.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<ol contenteditable oninput="document.body.innerHTML = observerRan ? 'FAILED' : 'PASSED'; if (window.layoutTestController) layoutTestController.notifyDone()">
+    <li>Press enter
+</ol>
+<script>
+    if (window.layoutTestController) {
+        layoutTestController.dumpAsText();
+        layoutTestController.waitUntilDone();
+    }
+
+    var list = document.querySelector('ol');
+    var observerRan = false;
+    var observer = new WebKitMutationObserver(function() { observerRan = true; });
+    observer.observe(list, {childList: true, characterData: true});
+    list.focus();
+    if (window.eventSender)
+        eventSender.scheduleAsynchronousKeyDown('\n');
+</script>
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 0f2e584..c82b93f 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,15 @@
+2011-12-08  Adam Klein  <adamk@chromium.org>
+
+        [MutationObservers] V8LazyEventHandler breaks microtask delivery semantics
+        https://bugs.webkit.org/show_bug.cgi?id=73492
+
+        Reviewed by Adam Barth.
+
+        Test: fast/mutation/inline-event-listener.html
+
+        * bindings/v8/V8LazyEventListener.cpp:
+        (WebCore::V8LazyEventListener::prepareListenerObject): Call v8::Script::Run directly instead of going through V8Proxy.
+
 2011-12-08  Hayato Ito  <hayato@chromium.org>
 
         Suppress rendering of light children when ShadowRoot is dynamically created.
diff --git a/Source/WebCore/bindings/v8/V8LazyEventListener.cpp b/Source/WebCore/bindings/v8/V8LazyEventListener.cpp
index 789fbd2..92c2e79 100644
--- a/Source/WebCore/bindings/v8/V8LazyEventListener.cpp
+++ b/Source/WebCore/bindings/v8/V8LazyEventListener.cpp
@@ -123,7 +123,9 @@
     v8::Handle<v8::String> codeExternalString = v8ExternalString(code);
     v8::Handle<v8::Script> script = V8Proxy::compileScript(codeExternalString, m_sourceURL, m_position);
     if (!script.IsEmpty()) {
-        v8::Local<v8::Value> value = proxy->runScript(script);
+        // Call v8::Script::Run() directly to avoid an erroneous call to V8RecursionScope::didLeaveScriptContext().
+        // FIXME: Remove this code when we stop doing the 'with' hack above.
+        v8::Local<v8::Value> value = script->Run();
         if (!value.IsEmpty()) {
             ASSERT(value->IsFunction());
 
diff --git a/Tools/ChangeLog b/Tools/ChangeLog
index 0070d87..23ba6de 100644
--- a/Tools/ChangeLog
+++ b/Tools/ChangeLog
@@ -1,3 +1,21 @@
+2011-12-08  Adam Klein  <adamk@chromium.org>
+
+        [MutationObservers] V8LazyEventHandler breaks microtask delivery semantics
+        https://bugs.webkit.org/show_bug.cgi?id=73492
+
+        Reviewed by Adam Barth.
+
+        Add eventSender.scheduleAsynchronousKeyDown, needed to cause a
+        keypress event without any script on the stack.
+
+        * DumpRenderTree/chromium/EventSender.cpp:
+        (EventSender::EventSender):
+        (EventSender::keyDown):
+        (KeyDownTask::KeyDownTask):
+        (KeyDownTask::runIfValid):
+        (EventSender::scheduleAsynchronousKeyDown):
+        * DumpRenderTree/chromium/EventSender.h:
+
 2011-12-08  Hayato Ito  <hayato@chromium.org>
 
         [gdb] Pretty printer for a 8-bit version of WTF::StringImpl and LChar*.
diff --git a/Tools/DumpRenderTree/chromium/EventSender.cpp b/Tools/DumpRenderTree/chromium/EventSender.cpp
index debdd5e..9acc42d 100644
--- a/Tools/DumpRenderTree/chromium/EventSender.cpp
+++ b/Tools/DumpRenderTree/chromium/EventSender.cpp
@@ -270,6 +270,7 @@
     bindMethod("mouseUp", &EventSender::mouseUp);
     bindMethod("releaseTouchPoint", &EventSender::releaseTouchPoint);
     bindMethod("scheduleAsynchronousClick", &EventSender::scheduleAsynchronousClick);
+    bindMethod("scheduleAsynchronousKeyDown", &EventSender::scheduleAsynchronousKeyDown);
     bindMethod("setTouchModifier", &EventSender::setTouchModifier);
     bindMethod("textZoomIn", &EventSender::textZoomIn);
     bindMethod("textZoomOut", &EventSender::textZoomOut);
@@ -500,7 +501,8 @@
 
 void EventSender::keyDown(const CppArgumentList& arguments, CppVariant* result)
 {
-    result->setNull();
+    if (result)
+        result->setNull();
     if (arguments.size() < 1 || !arguments[0].isString())
         return;
     bool generateChar = false;
@@ -847,6 +849,22 @@
     postTask(new MouseUpTask(this, arguments));
 }
 
+class KeyDownTask : public MethodTask<EventSender> {
+public:
+    KeyDownTask(EventSender* obj, const CppArgumentList& arg)
+        : MethodTask<EventSender>(obj), m_arguments(arg) { }
+    virtual void runIfValid() { m_object->keyDown(m_arguments, 0); }
+
+private:
+    CppArgumentList m_arguments;
+};
+
+void EventSender::scheduleAsynchronousKeyDown(const CppArgumentList& arguments, CppVariant* result)
+{
+    result->setNull();
+    postTask(new KeyDownTask(this, arguments));
+}
+
 void EventSender::beginDragWithFiles(const CppArgumentList& arguments, CppVariant* result)
 {
     currentDragData.initialize();
diff --git a/Tools/DumpRenderTree/chromium/EventSender.h b/Tools/DumpRenderTree/chromium/EventSender.h
index f3f8cf4..bbecc54 100644
--- a/Tools/DumpRenderTree/chromium/EventSender.h
+++ b/Tools/DumpRenderTree/chromium/EventSender.h
@@ -82,6 +82,7 @@
     void mouseScrollBy(const CppArgumentList&, CppVariant*);
     void continuousMouseScrollBy(const CppArgumentList&, CppVariant*);
     void scheduleAsynchronousClick(const CppArgumentList&, CppVariant*);
+    void scheduleAsynchronousKeyDown(const CppArgumentList&, CppVariant*);
     void beginDragWithFiles(const CppArgumentList&, CppVariant*);
     CppVariant dragMode;