2011-01-11 Dimitri Glazkov <dglazkov@chromium.org>
authordglazkov@chromium.org <dglazkov@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 11 Jan 2011 20:44:52 +0000 (20:44 +0000)
committerdglazkov@chromium.org <dglazkov@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 11 Jan 2011 20:44:52 +0000 (20:44 +0000)
        Reviewed by Eric Seidel.

        REGRESSION(r71934) Can't type in search edit field on skin-one.com
        https://bugs.webkit.org/show_bug.cgi?id=52195

        Restored original (pre-71934) check in the test to ensure that
        selectstart does not propagate outside of the shadow DOM.

        Consolidated shadow-boundary-crossing-2.html into shadow-boundary-crossing.html.

        * fast/events/shadow-boundary-crossing-2-expected.txt: Renamed to
            shadow-boundary-crossing-expected.txt.
        * fast/events/shadow-boundary-crossing-2.html: Renamed to
            shadow-boundary-crossing.html.
        * fast/events/shadow-boundary-crossing-expected.txt: Removed.
        * fast/events/shadow-boundary-crossing.html: Removed after folding the
            test into the new shadow-boundary-crossing.html.
2011-01-11  Dimitri Glazkov  <dglazkov@chromium.org>

        Reviewed by Eric Seidel.

        REGRESSION(r71934) Can't type in search edit field on skin-one.com
        https://bugs.webkit.org/show_bug.cgi?id=52195

        Restored the original behavior, where the selectstart event is not
        dispatched when selection changes inside of the shadow DOM.

        * dom/Node.cpp:
        (WebCore::determineDispatchBehavior): Moved EventDispatchBehavior-determining
            logic into a helper function, also added a check to keep selectstart
                events inside of the shadow DOM.
        (WebCore::Node::dispatchGenericEvent): Changed to use the helper function.

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

LayoutTests/ChangeLog
LayoutTests/fast/events/shadow-boundary-crossing-2-expected.txt [deleted file]
LayoutTests/fast/events/shadow-boundary-crossing-2.html [deleted file]
LayoutTests/fast/events/shadow-boundary-crossing-expected.txt
LayoutTests/fast/events/shadow-boundary-crossing.html
Source/WebCore/ChangeLog
Source/WebCore/dom/Node.cpp

index 568064d..0307058 100644 (file)
@@ -1,3 +1,23 @@
+2011-01-11  Dimitri Glazkov  <dglazkov@chromium.org>
+
+        Reviewed by Eric Seidel.
+
+        REGRESSION(r71934) Can't type in search edit field on skin-one.com
+        https://bugs.webkit.org/show_bug.cgi?id=52195
+
+        Restored original (pre-71934) check in the test to ensure that
+        selectstart does not propagate outside of the shadow DOM.
+
+        Consolidated shadow-boundary-crossing-2.html into shadow-boundary-crossing.html.
+
+        * fast/events/shadow-boundary-crossing-2-expected.txt: Renamed to
+            shadow-boundary-crossing-expected.txt.
+        * fast/events/shadow-boundary-crossing-2.html: Renamed to
+            shadow-boundary-crossing.html.
+        * fast/events/shadow-boundary-crossing-expected.txt: Removed.
+        * fast/events/shadow-boundary-crossing.html: Removed after folding the
+            test into the new shadow-boundary-crossing.html.
+
 2011-01-11  Zhenyao Mo  <zmo@google.com>
 
         Unreviewed, test expectation update.
diff --git a/LayoutTests/fast/events/shadow-boundary-crossing-2-expected.txt b/LayoutTests/fast/events/shadow-boundary-crossing-2-expected.txt
deleted file mode 100644 (file)
index a2f1ece..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-Tests to ensure that shadow DOM boundary is not crossed during event propagation. Can only run within DRT.
-
-See bug 46015 for details.
-
-Mutation events should not propagate out of the shadow DOM: PASS
-Label should look beyond shadow boundary to detect if it encloses its associated element: PASS
-Events for default event handler should not be retargeted: PASS
-Other events should be retargeted: PASS
-After event dispatch, the event object should not reveal shadow DOM: PASS
-Focusing same shadow DOM element repeatedly should not trigger multiple focus/blur events: PASS
diff --git a/LayoutTests/fast/events/shadow-boundary-crossing-2.html b/LayoutTests/fast/events/shadow-boundary-crossing-2.html
deleted file mode 100644 (file)
index 91b362f..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-<html>
-<head>
-<script>
-
-var logDiv;
-
-function log(msg, success)
-{
-    logDiv.appendChild(document.createElement('div')).textContent = msg + ': ' + (success ? 'PASS' : 'FAIL');
-}
-
-function clickOn(element)
-{
-    if (!window.eventSender)
-        return;
-
-    var x = element.offsetLeft + element.offsetWidth / 2;
-    var y = element.offsetTop + element.offsetHeight / 2;
-    eventSender.mouseMoveTo(x, y);
-    eventSender.mouseDown();
-    eventSender.mouseUp();
-}
-
-function clickOnLeftQuarterOf(element)
-{
-    if (!window.eventSender)
-        return;
-
-    var x = element.offsetLeft + element.offsetWidth / 4;
-    var y = element.offsetTop + element.offsetHeight / 2;
-    eventSender.mouseMoveTo(x, y);
-    eventSender.mouseDown();
-    eventSender.mouseUp();
-}
-
-function leapForward()
-{
-    if (!window.eventSender)
-        return;
-
-    eventSender.leapForward(1000);
-}
-
-var tests = {
-    mutationEventPropagation: function()
-    {
-        var textarea = document.body.appendChild(document.createElement('textarea'));
-        var mutationEventFired;
-        textarea.addEventListener('DOMSubtreeModified', function(e)
-        {
-            mutationEventFired = true;
-        }, false);
-        textarea.value = 'test';
-        // Trigger style recalc and sadly, the actual mutation of the textarea shadow DOM.
-        textarea.offsetHeight;
-        log('Mutation events should not propagate out of the shadow DOM', !mutationEventFired);
-        textarea.parentNode.removeChild(textarea);
-    },
-    labelSyntheticClick: function()
-    {
-        var count = 0;
-        var label = document.body.appendChild(document.createElement('label'));
-        var searchInput = label.appendChild(document.createElement('input'));
-        searchInput.setAttribute('type', 'search');
-        searchInput.setAttribute('id', 'baz');
-        label.setAttribute('for', 'baz');
-        searchInput.addEventListener('click', function(e)
-        {
-            count++;
-        }, false);
-        clickOn(searchInput);
-        log("Label should look beyond shadow boundary to detect if it encloses its associated element", count == 1);
-        label.parentNode.removeChild(label);
-    },
-    defaultEventRetargeting: function()
-    {
-        var count = 0;
-        var fileInput = document.body.appendChild(document.createElement('input'));
-        fileInput.setAttribute('type', 'file');
-        var counter = function()
-        {
-            count++;
-        }
-        document.body.addEventListener('DOMActivate', counter, false);
-        clickOnLeftQuarterOf(fileInput);
-        log("Events for default event handler should not be retargeted", count == 1);
-        document.body.removeEventListener('DOMActivate', counter, false);
-        fileInput.parentNode.removeChild(fileInput);
-    },
-    eventInProgress: function()
-    {
-        var textInput = document.body.appendChild(document.createElement('input'));
-        textInput.addEventListener('click', function(e)
-        {
-            log('Other events should be retargeted', e.target == textInput);
-        }, false);
-        clickOn(textInput);
-        textInput.parentNode.removeChild(textInput);
-    },
-    finalEventObject: function()
-    {
-        var textInput = document.body.appendChild(document.createElement('input'));
-        var storedEvent;
-        textInput.addEventListener('click', function(e)
-        {
-            storedEvent = e;
-        }, false);
-        clickOn(textInput);
-        log('After event dispatch, the event object should not reveal shadow DOM', storedEvent && storedEvent.target == textInput);
-        textInput.parentNode.removeChild(textInput);
-    },
-    focusEventPropagation: function()
-    {
-        var searchInput = document.body.appendChild(document.createElement('input'));
-        searchInput.setAttribute('type', 'search');
-        var count = 0;
-        searchInput.addEventListener('focus', function(evt)
-        {
-            count++;
-        });
-        clickOn(searchInput);
-        leapForward();
-        clickOn(searchInput);
-        log('Focusing same shadow DOM element repeatedly should not trigger multiple focus/blur events', count == 1);
-        searchInput.parentNode.removeChild(searchInput);
-    }
-};
-
-function runTest()
-{
-    if (window.layoutTestController)
-        layoutTestController.dumpAsText();
-
-    logDiv = document.getElementById('log');
-    for(var testName in tests) {
-        tests[testName]();
-    }
-}
-
-</script>
-</head>
-<body onload="runTest()">
-    <p>Tests to ensure that shadow DOM boundary is not crossed during event propagation. Can only run within DRT.
-    <p>See <a href="https://bugs.webkit.org/show_bug.cgi?id=46015">bug 46015</a> for details.
-    <div id="log"></div>
-</body>
-</html>
\ No newline at end of file
index fd729d9..678f3ab 100644 (file)
@@ -1,5 +1,11 @@
-Test for http://bugs.webkit.org/show_bug.cgi?id=12780 REGRESSION (r19341-r19385): Reproducible crash in "onselectstart" event.
-
-Result: PASS
+Tests to ensure that shadow DOM boundary is not crossed during event propagation. Can only run within DRT.
 
+See bug 46015 for details.
 
+Mutation events should not propagate out of the shadow DOM: PASS
+The selectstart event should not propagate out of the shadow DOM: PASS
+Label should look beyond shadow boundary to detect if it encloses its associated element: PASS
+Events for default event handler should not be retargeted: PASS
+Other events should be retargeted: PASS
+After event dispatch, the event object should not reveal shadow DOM: PASS
+Focusing same shadow DOM element repeatedly should not trigger multiple focus/blur events: PASS
index e002333..4e8486b 100644 (file)
 <html>
 <head>
-    <title></title>
-    <script type="text/javascript">
-        var success;
-        var target;
+<script>
 
-        function selectStart(event)
-        {
-            success = event.target == target;
-        }
+var logDiv;
 
-        function test()
-        {
-            if (!window.layoutTestController)
-                return;
-            layoutTestController.dumpAsText();
+function log(msg, success)
+{
+    logDiv.appendChild(document.createElement('div')).textContent = msg + ': ' + (success ? 'PASS' : 'FAIL');
+}
+
+function clickOn(element)
+{
+    if (!window.eventSender)
+        return;
+
+    var x = element.offsetLeft + element.offsetWidth / 2;
+    var y = element.offsetTop + element.offsetHeight / 2;
+    eventSender.mouseMoveTo(x, y);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+}
 
-            target = document.getElementById("target");
-            var x = target.offsetLeft + target.offsetWidth / 2;
-            var y = target.offsetTop + target.offsetHeight / 2;
+function clickOnLeftQuarterOf(element)
+{
+    if (!window.eventSender)
+        return;
 
-            eventSender.mouseMoveTo(x, y);
-            eventSender.mouseDown();
-            eventSender.mouseUp();
+    var x = element.offsetLeft + element.offsetWidth / 4;
+    var y = element.offsetTop + element.offsetHeight / 2;
+    eventSender.mouseMoveTo(x, y);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+}
 
-            document.getElementById("result").innerText = !success ? "FAIL" : "PASS";
+function leapForward()
+{
+    if (!window.eventSender)
+        return;
+
+    eventSender.leapForward(1000);
+}
+
+var tests = {
+    mutationEventPropagation: function()
+    {
+        var textarea = document.body.appendChild(document.createElement('textarea'));
+        var mutationEventFired;
+        textarea.addEventListener('DOMSubtreeModified', function(e)
+        {
+            mutationEventFired = true;
+        }, false);
+        textarea.value = 'test';
+        // Trigger style recalc and sadly, the actual mutation of the textarea shadow DOM.
+        textarea.offsetHeight;
+        log('Mutation events should not propagate out of the shadow DOM', !mutationEventFired);
+        textarea.parentNode.removeChild(textarea);
+    },
+    selectstartEventPropagation: function()
+    {
+        var textInput = document.body.appendChild(document.createElement('input'));
+        var selectstartEventFired = false;
+        document.selectstart = function()
+        {
+            selectstartEventFired = true;
         }
+        clickOn(textInput);
+        log('The selectstart event should not propagate out of the shadow DOM', !selectstartEventFired);
+        textInput.parentNode.removeChild(textInput);
+        document.selectstart = null;
+    },
+    labelSyntheticClick: function()
+    {
+        var count = 0;
+        var label = document.body.appendChild(document.createElement('label'));
+        var searchInput = label.appendChild(document.createElement('input'));
+        searchInput.setAttribute('type', 'search');
+        searchInput.setAttribute('id', 'baz');
+        label.setAttribute('for', 'baz');
+        searchInput.addEventListener('click', function(e)
+        {
+            count++;
+        }, false);
+        clickOn(searchInput);
+        log("Label should look beyond shadow boundary to detect if it encloses its associated element", count == 1);
+        label.parentNode.removeChild(label);
+    },
+    defaultEventRetargeting: function()
+    {
+        var count = 0;
+        var fileInput = document.body.appendChild(document.createElement('input'));
+        fileInput.setAttribute('type', 'file');
+        var counter = function()
+        {
+            count++;
+        }
+        document.body.addEventListener('DOMActivate', counter, false);
+        clickOnLeftQuarterOf(fileInput);
+        log("Events for default event handler should not be retargeted", count == 1);
+        document.body.removeEventListener('DOMActivate', counter, false);
+        fileInput.parentNode.removeChild(fileInput);
+    },
+    eventInProgress: function()
+    {
+        var textInput = document.body.appendChild(document.createElement('input'));
+        textInput.addEventListener('click', function(e)
+        {
+            log('Other events should be retargeted', e.target == textInput);
+        }, false);
+        clickOn(textInput);
+        textInput.parentNode.removeChild(textInput);
+    },
+    finalEventObject: function()
+    {
+        var textInput = document.body.appendChild(document.createElement('input'));
+        var storedEvent;
+        textInput.addEventListener('click', function(e)
+        {
+            storedEvent = e;
+        }, false);
+        clickOn(textInput);
+        log('After event dispatch, the event object should not reveal shadow DOM', storedEvent && storedEvent.target == textInput);
+        textInput.parentNode.removeChild(textInput);
+    },
+    focusEventPropagation: function()
+    {
+        var searchInput = document.body.appendChild(document.createElement('input'));
+        searchInput.setAttribute('type', 'search');
+        var count = 0;
+        searchInput.addEventListener('focus', function(evt)
+        {
+            count++;
+        });
+        clickOn(searchInput);
+        leapForward();
+        clickOn(searchInput);
+        log('Focusing same shadow DOM element repeatedly should not trigger multiple focus/blur events', count == 1);
+        searchInput.parentNode.removeChild(searchInput);
+    }
+};
+
+function runTest()
+{
+    if (window.layoutTestController)
+        layoutTestController.dumpAsText();
+
+    logDiv = document.getElementById('log');
+    for(var testName in tests) {
+        tests[testName]();
+    }
+}
 
-        addEventListener("selectstart", selectStart, true);
-    </script>
+</script>
 </head>
-<body onload="test()">
-    <p>
-        Test for <i><a href="http://bugs.webkit.org/show_bug.cgi?id=12780">http://bugs.webkit.org/show_bug.cgi?id=12780</a>
-        REGRESSION (r19341-r19385): Reproducible crash in "onselectstart" event</i>.
-    </p>
-    <p>
-        Result: <span id="result">cannot run interactively</span>
-    </p>
-    <input id="target">
+<body onload="runTest()">
+    <p>Tests to ensure that shadow DOM boundary is not crossed during event propagation. Can only run within DRT.
+    <p>See <a href="https://bugs.webkit.org/show_bug.cgi?id=46015">bug 46015</a> for details.
+    <div id="log"></div>
 </body>
-</html>
+</html>
\ No newline at end of file
index fcad05c..0e7641c 100644 (file)
@@ -1,3 +1,19 @@
+2011-01-11  Dimitri Glazkov  <dglazkov@chromium.org>
+
+        Reviewed by Eric Seidel.
+
+        REGRESSION(r71934) Can't type in search edit field on skin-one.com
+        https://bugs.webkit.org/show_bug.cgi?id=52195
+
+        Restored the original behavior, where the selectstart event is not
+        dispatched when selection changes inside of the shadow DOM.
+
+        * dom/Node.cpp:
+        (WebCore::determineDispatchBehavior): Moved EventDispatchBehavior-determining
+            logic into a helper function, also added a check to keep selectstart
+                events inside of the shadow DOM.
+        (WebCore::Node::dispatchGenericEvent): Changed to use the helper function.
+
 2011-01-11  Viatcheslav Ostapenko  <ostapenko.viatcheslav@nokia.com>
 
         Reviewed by Eric Seidel.
index a589282..26e8187 100644 (file)
@@ -2611,6 +2611,22 @@ static const EventContext* topEventContext(const Vector<EventContext>& ancestors
     return ancestors.isEmpty() ? 0 : &ancestors.last();
 }
 
+static EventDispatchBehavior determineDispatchBehavior(Event* event)
+{
+    // Per XBL 2.0 spec, mutation events should never cross shadow DOM boundary:
+    // http://dev.w3.org/2006/xbl2/#event-flow-and-targeting-across-shadow-s
+    if (event->isMutationEvent())
+        return StayInsideShadowDOM;
+
+    // WebKit never allowed selectstart event to cross the the shadow DOM boundary.
+    // Changing this breaks existing sites.
+    // See https://bugs.webkit.org/show_bug.cgi?id=52195 for details.
+    if (event->type() == eventNames().selectstartEvent)
+        return StayInsideShadowDOM;
+
+    return RetargetEvent;
+}
+
 bool Node::dispatchGenericEvent(PassRefPtr<Event> prpEvent)
 {
     RefPtr<Event> event(prpEvent);
@@ -2625,7 +2641,7 @@ bool Node::dispatchGenericEvent(PassRefPtr<Event> prpEvent)
     RefPtr<Node> thisNode(this);
     RefPtr<EventTarget> originalTarget = event->target();
     Vector<EventContext> ancestors;
-    getEventAncestors(ancestors, originalTarget.get(), event->isMutationEvent() ? StayInsideShadowDOM : RetargetEvent);
+    getEventAncestors(ancestors, originalTarget.get(), determineDispatchBehavior(event.get()));
 
     WindowEventContext windowContext(event.get(), this, topEventContext(ancestors));