Replace scoped flag in Event by composed flag
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 8 Jul 2016 01:57:44 +0000 (01:57 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 8 Jul 2016 01:57:44 +0000 (01:57 +0000)
https://bugs.webkit.org/show_bug.cgi?id=158415

Reviewed by Chris Dumez.

Source/WebCore:

Replace `scoped` flag with `composed` flag and negate its meaning per the latest spec:
https://dom.spec.whatwg.org/#dom-event-composed
https://github.com/w3c/webcomponents/issues/513

In the old spec, every event was assumed to be "composed" (crosses shadow boundaries)
by default and there was `scoped` flag which prevented the event from crossing bondaries,
and there was a handful of events for which `scoped` was set true when dispatched by UA.

In the new spec, every event is assumed to be "scoped" and a handful of user-initiated
events set `composed` flag to true, which is also exposed in EventInit dictionary.
`relatedTargetScoped` flag has been removed. New behavior is identical to when this flag
was set to true.

No new tests since existing tests are updated to test the new flag and behavior.

* dom/CompositionEvent.cpp:
(WebCore::CompositionEvent::isCompositionEvent): Added.
* dom/CompositionEvent.h:
* dom/Event.cpp:
(WebCore::Event::Event): Initialize m_composed. Also re-ordered m_type and m_isInitialized
for better packing.
(WebCore::Event::composed): Renamed from Event::composed. We return true whenever composed
is set to true in EventInit, or the engine is dispatching an user-initiated event listed in:
https://github.com/w3c/webcomponents/issues/513#issuecomment-224183937
as well as keypress, cut, paste, and, copy as discussed in:
https://github.com/w3c/webcomponents/issues/513#issuecomment-230988170
(WebCore::Event::isCompositionEvent): Added.
* dom/Event.h:
(WebCore::Event::composed): Added.
(WebCore::Event::scoped): Deleted.
(WebCore::Event::relatedTargetScoped): Deleted.
(WebCore::Event): Reordered m_type and m_isInitialized for better packing. Added m_composed
and removed m_scoped and m_relatedTargetScoped.
* dom/Event.idl:
* dom/EventPath.cpp:
(WebCore::shouldEventCrossShadowBoundary): Returns true if the event did not originate from
a shadow tree (this event entered the current shadow tree via a slot so we need to proceed with
the normal bubble path outside the shadow tree) or composed flag is set true.
(WebCore::EventPath::EventPath): m_event no longer exists, which was only used to get the value
of relatedTargetScoped which has been removed.
(WebCore::EventPath::setRelatedTarget): Behave as if relatedTargetScoped is always set true
since the flag has been removed.
* dom/EventPath.h:
* dom/FocusEvent.cpp:
(WebCore::FocusEvent::relatedTargetScoped): Deleted.
* dom/FocusEvent.h:
* dom/MouseEvent.cpp:
(WebCore::MouseEvent::relatedTargetScoped): Deleted.
* dom/MouseEvent.h:

LayoutTests:

Updated the tests to reflect the rename of scoped to composed and the negation of its semantics.
Now every Event is assumed to be scoped / non-composed by default, and we need to explicitly set
composed to true in order for events to cross shadow boundaries.

Also, every Event behaves as if related target is assumed to be scoped in the old terminology
althoug the flag no longer exists.

* fast/shadow-dom/Extensions-to-Event-Interface-expected.txt:
* fast/shadow-dom/Extensions-to-Event-Interface.html: Removed a test case that was testing
relatedTargetScoped to false since this flag no longer exists.
* fast/shadow-dom/MouseEvent-prototype-offsetX-offsetY.html:
* fast/shadow-dom/event-inside-shadow-tree.html:
* fast/shadow-dom/event-inside-slotted-node.html:
* fast/shadow-dom/event-with-related-target.html:
* fast/shadow-dom/trusted-event-scoped-flags-expected.txt:
* fast/shadow-dom/trusted-event-scoped-flags.html:
* fast/xmlhttprequest/xmlhttprequest-get-expected.txt:
* http/tests/workers/worker-importScriptsOnError-expected.txt:
* inspector/model/remote-object-get-properties-expected.txt:

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

24 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/shadow-dom/Extensions-to-Event-Interface-expected.txt
LayoutTests/fast/shadow-dom/Extensions-to-Event-Interface.html
LayoutTests/fast/shadow-dom/MouseEvent-prototype-offsetX-offsetY.html
LayoutTests/fast/shadow-dom/event-inside-shadow-tree.html
LayoutTests/fast/shadow-dom/event-inside-slotted-node.html
LayoutTests/fast/shadow-dom/event-with-related-target.html
LayoutTests/fast/shadow-dom/trusted-event-scoped-flags-expected.txt
LayoutTests/fast/shadow-dom/trusted-event-scoped-flags.html
LayoutTests/fast/xmlhttprequest/xmlhttprequest-get-expected.txt
LayoutTests/http/tests/workers/worker-importScriptsOnError-expected.txt
LayoutTests/inspector/model/remote-object-get-properties-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/dom/CompositionEvent.cpp
Source/WebCore/dom/CompositionEvent.h
Source/WebCore/dom/Event.cpp
Source/WebCore/dom/Event.h
Source/WebCore/dom/Event.idl
Source/WebCore/dom/EventPath.cpp
Source/WebCore/dom/EventPath.h
Source/WebCore/dom/FocusEvent.cpp
Source/WebCore/dom/FocusEvent.h
Source/WebCore/dom/MouseEvent.cpp
Source/WebCore/dom/MouseEvent.h

index 911d3f1..90b7f7a 100644 (file)
@@ -1,3 +1,30 @@
+2016-07-07  Ryosuke Niwa  <rniwa@webkit.org>
+
+        Replace scoped flag in Event by composed flag
+        https://bugs.webkit.org/show_bug.cgi?id=158415
+
+        Reviewed by Chris Dumez.
+
+        Updated the tests to reflect the rename of scoped to composed and the negation of its semantics.
+        Now every Event is assumed to be scoped / non-composed by default, and we need to explicitly set
+        composed to true in order for events to cross shadow boundaries.
+
+        Also, every Event behaves as if related target is assumed to be scoped in the old terminology
+        althoug the flag no longer exists.
+
+        * fast/shadow-dom/Extensions-to-Event-Interface-expected.txt:
+        * fast/shadow-dom/Extensions-to-Event-Interface.html: Removed a test case that was testing 
+        relatedTargetScoped to false since this flag no longer exists.
+        * fast/shadow-dom/MouseEvent-prototype-offsetX-offsetY.html:
+        * fast/shadow-dom/event-inside-shadow-tree.html:
+        * fast/shadow-dom/event-inside-slotted-node.html:
+        * fast/shadow-dom/event-with-related-target.html:
+        * fast/shadow-dom/trusted-event-scoped-flags-expected.txt:
+        * fast/shadow-dom/trusted-event-scoped-flags.html:
+        * fast/xmlhttprequest/xmlhttprequest-get-expected.txt:
+        * http/tests/workers/worker-importScriptsOnError-expected.txt:
+        * inspector/model/remote-object-get-properties-expected.txt:
+
 2016-07-07  Dean Jackson  <dino@apple.com>
 
         REGRESSION(r200769): animations are no longer overridden
index db083e2..ba77e0a 100644 (file)
@@ -2,20 +2,15 @@
 PASS composedPath() must exist on Event 
 PASS composedPath() must return an empty array when the event has not been dispatched 
 PASS composedPath() must return an empty array when the event is no longer dispatched 
-PASS scoped must exist on Event 
-PASS scoped on EventInit must default to false 
-PASS scoped on EventInit must set the scoped flag 
-PASS relatedTargetScoped must exist on Event 
-PASS relatedTargetScoped on EventInit must default to false 
-PASS relatedTargetScoped on EventInit must set the scoped flag 
-PASS The event must propagate out of open mode shadow boundaries when the scoped flag is unset 
-PASS The event must propagate out of closed mode shadow boundaries when the scoped flag is unset 
-PASS The event must not propagate out of open mode shadow boundaries when the scoped flag is set 
-PASS The event must not propagate out of closed mode shadow boundaries when the scoped flag is set 
-PASS The event must propagate out of open mode shadow boundaries when the scoped flag is unset on an event with relatedTarget 
-PASS The event must propagate out of closed mode shadow boundaries when the scoped flag is unset on an event with relatedTarget 
-PASS The event must not propagate out of open mode shadow boundaries when the scoped flag is set on an event with relatedTarget 
-PASS The event must not propagate out of closed mode shadow boundaries when the scoped flag is set on an event with relatedTarget 
+PASS composed must exist on Event 
+PASS composed on EventInit must default to false 
+PASS composed on EventInit must set the composed flag 
+PASS The event must propagate out of open mode shadow boundaries when the composed flag is set 
+PASS The event must propagate out of closed mode shadow boundaries when the composed flag is set 
+PASS The event must not propagate out of open mode shadow boundaries when the composed flag is unset 
+PASS The event must not propagate out of closed mode shadow boundaries when the composed flag is unset 
+PASS The event must not propagate out of open mode shadow boundaries when the composed flag is unset on an event with relatedTarget 
+PASS The event must not propagate out of closed mode shadow boundaries when the composed flag is unset on an event with relatedTarget 
 PASS The event must not propagate out of open mode shadow tree of the target but must propagate out of inner shadow trees when the scoped flag is set 
 PASS The event must not propagate out of closed mode shadow tree of the target but must propagate out of inner shadow trees when the scoped flag is set 
 PASS The event must propagate out of open mode shadow tree in which the relative target and the relative related target are the same 
index aa56099..2a2763e 100644 (file)
@@ -31,40 +31,22 @@ test(function () {
 }, 'composedPath() must return an empty array when the event is no longer dispatched');
 
 test(function () {
-    assert_true('scoped' in Event.prototype);
-    assert_true('scoped' in new Event('my-event'));
-}, 'scoped must exist on Event');
+    assert_true('composed' in Event.prototype);
+    assert_true('composed' in new Event('my-event'));
+}, 'composed must exist on Event');
 
 test(function () {
     var event = new Event('my-event');
-    assert_false(event.scoped);
-}, 'scoped on EventInit must default to false');
+    assert_false(event.composed);
+}, 'composed on EventInit must default to false');
 
 test(function () {
-    var event = new Event('my-event', {scoped: true});
-    assert_true(event.scoped);
+    var event = new Event('my-event', {composed: true});
+    assert_true(event.composed);
 
-    event = new Event('my-event', {scoped: false});
-    assert_false(event.scoped);
-}, 'scoped on EventInit must set the scoped flag');
-
-test(function () {
-    assert_true('relatedTargetScoped' in Event.prototype);
-    assert_true('relatedTargetScoped' in new Event('my-event'));
-}, 'relatedTargetScoped must exist on Event');
-
-test(function () {
-    var event = new Event('my-event');
-    assert_false(event.relatedTargetScoped);
-}, 'relatedTargetScoped on EventInit must default to false');
-
-test(function () {
-    var event = new Event('my-event', {relatedTargetScoped: true});
-    assert_true(event.relatedTargetScoped);
-
-    event = new Event('my-event', {relatedTargetScoped: false});
-    assert_false(event.relatedTargetScoped);
-}, 'relatedTargetScoped on EventInit must set the scoped flag');
+    event = new Event('my-event', {composed: false});
+    assert_false(event.composed);
+}, 'composed on EventInit must set the composed flag');
 
 /*
 -SR: ShadowRoot  -S: Slot  target: (~)  *: indicates start  digit: event path order
@@ -76,10 +58,10 @@ A (4) --------------------------- A-SR (3)
                                       + B1b2
 */
 
-function testUnscopedEvent(mode) {
+function testComposedEvent(mode) {
     test(function () {
         var nodes = createTestTree(mode);
-        var log = dispatchEventWithLog(nodes, nodes.A1a, new Event('my-event', {scoped: false, bubbles: true}));
+        var log = dispatchEventWithLog(nodes, nodes.A1a, new Event('my-event', {composed: true, bubbles: true}));
 
         var expectedPath = ['A1a', 'A1-SR', 'A1', 'A-SR', 'A'];
         assert_array_equals(log.eventPath, expectedPath);
@@ -88,11 +70,11 @@ function testUnscopedEvent(mode) {
         assert_array_equals(log.pathAtTargets[1], expectedPath);
         assert_array_equals(log.pathAtTargets[2], mode == 'open' ? expectedPath : ['A1', 'A-SR', 'A'],
             'composedPath must only contain unclosed nodes of the current target.');
-    }, 'The event must propagate out of ' + mode + ' mode shadow boundaries when the scoped flag is unset');
+    }, 'The event must propagate out of ' + mode + ' mode shadow boundaries when the composed flag is set');
 }
 
-testUnscopedEvent('open');
-testUnscopedEvent('closed');
+testComposedEvent('open');
+testComposedEvent('closed');
 
 /*
 -SR: ShadowRoot  -S: Slot  target: (~)  *: indicates start  digit: event path order
@@ -104,53 +86,21 @@ A ------------------------------- A-SR
                                     + B1b2
 */
 
-function testScopedEvent(mode) {
+function testNonComposedEvent(mode) {
     test(function () {
         var nodes = createTestTree(mode);
-        var log = dispatchEventWithLog(nodes, nodes.A1a, new Event('my-event', {scoped: true, bubbles: true}));
+        var log = dispatchEventWithLog(nodes, nodes.A1a, new Event('my-event', {composed: false, bubbles: true}));
 
         var expectedPath = ['A1a', 'A1-SR'];
         assert_array_equals(log.eventPath, expectedPath);
         assert_array_equals(log.eventPath.length, log.pathAtTargets.length);
         assert_array_equals(log.pathAtTargets[0], expectedPath);
         assert_array_equals(log.pathAtTargets[1], expectedPath);
-    }, 'The event must not propagate out of ' + mode + ' mode shadow boundaries when the scoped flag is set');
-}
-
-testScopedEvent('open');
-testScopedEvent('closed');
-
-/*
--SR: ShadowRoot  -S: Slot  target: (~)  relatedTarget: [~]  *: indicates start  digit: event path order
-A (4) [4] ----------------------- A-SR (3)
-+ B ------------ B-SR             + A1 (2) ------- A1-SR (1)
-  + C            + B1 --- B1-SR   + A2-S [*; 0-3]  + A1a (*; 0)
-  + D --- D-SR     + B1a  + B1b --- B1b-SR
-          + D1            + B1c-S   + B1b1
-                                    + B1b2
-*/
-
-function testUnscopedEventWithUnscopedRelatedTarget(mode) {
-    test(function () {
-        var nodes = createTestTree(mode);
-        var log = dispatchEventWithLog(nodes, nodes.A1a, new MouseEvent('foo', {scoped: false, relatedTargetScoped: false, bubbles: true, relatedTarget: nodes['A2-S']}));
-
-        var expectedPath = ['A1a', 'A1-SR', 'A1', 'A-SR', 'A'];
-        var pathExposedToA1 = ['A1', 'A-SR', 'A'];
-        var pathExposedToA = ['A'];
-        assert_array_equals(log.eventPath, expectedPath);
-        assert_array_equals(log.eventPath.length, log.pathAtTargets.length);
-        assert_array_equals(log.pathAtTargets[0], expectedPath);
-        assert_array_equals(log.pathAtTargets[1], expectedPath);
-        assert_array_equals(log.pathAtTargets[2], mode == 'open' ? expectedPath : pathExposedToA1);
-        assert_array_equals(log.pathAtTargets[3], mode == 'open' ? expectedPath : pathExposedToA1);
-        assert_array_equals(log.pathAtTargets[4], mode == 'open' ? expectedPath : pathExposedToA);
-        assert_array_equals(log.relatedTargets, ['A2-S', 'A2-S', 'A2-S', 'A2-S', 'A']);
-    }, 'The event must propagate out of ' + mode + ' mode shadow boundaries when the scoped flag is unset on an event with relatedTarget');
+    }, 'The event must not propagate out of ' + mode + ' mode shadow boundaries when the composed flag is unset');
 }
 
-testUnscopedEventWithUnscopedRelatedTarget('open');
-testUnscopedEventWithUnscopedRelatedTarget('closed');
+testNonComposedEvent('open');
+testNonComposedEvent('closed');
 
 /*
 -SR: ShadowRoot  -S: Slot  target: (~)  relatedTarget: [~]  *: indicates start  digit: event path order
@@ -162,10 +112,10 @@ A ------------------------------- A-SR
                                     + B1b2
 */
 
-function testScopedEventWithUnscopedRelatedTarget(mode) {
+function testNonComposedEventWithRelatedTarget(mode) {
     test(function () {
         var nodes = createTestTree(mode);
-        var log = dispatchEventWithLog(nodes, nodes.A1a, new MouseEvent('foo', {scoped: true, relatedTargetScoped: false, bubbles: true, relatedTarget: nodes['A2-S']}));
+        var log = dispatchEventWithLog(nodes, nodes.A1a, new MouseEvent('foo', {composed: false, bubbles: true, relatedTarget: nodes['A2-S']}));
 
         var expectedPath = ['A1a', 'A1-SR'];
         assert_array_equals(log.eventPath, expectedPath);
@@ -173,11 +123,11 @@ function testScopedEventWithUnscopedRelatedTarget(mode) {
         assert_array_equals(log.pathAtTargets[0], expectedPath);
         assert_array_equals(log.pathAtTargets[1], expectedPath);
         assert_array_equals(log.relatedTargets, ['A2-S', 'A2-S']);
-    }, 'The event must not propagate out of ' + mode + ' mode shadow boundaries when the scoped flag is set on an event with relatedTarget');
+    }, 'The event must not propagate out of ' + mode + ' mode shadow boundaries when the composed flag is unset on an event with relatedTarget');
 }
 
-testScopedEventWithUnscopedRelatedTarget('open');
-testScopedEventWithUnscopedRelatedTarget('closed');
+testNonComposedEventWithRelatedTarget('open');
+testNonComposedEventWithRelatedTarget('closed');
 
 /*
 -SR: ShadowRoot  -S: Slot  target: (~)  relatedTarget: [~]  *: indicates start  digit: event path order
@@ -220,10 +170,10 @@ A ------------------------------- A-SR (3)
                                     + B1b2
 */
 
-function testUnscopedEventWithScopedRelatedTarget(mode) {
+function testComposedEventWithRelatedTarget(mode) {
     test(function () {
         var nodes = createTestTree(mode);
-        log = dispatchEventWithLog(nodes, nodes.A1a, new MouseEvent('foo', {scoped: false, relatedTargetScoped: true, bubbles: true, relatedTarget: nodes['A2-S']}));
+        log = dispatchEventWithLog(nodes, nodes.A1a, new MouseEvent('foo', {composed: true, bubbles: true, relatedTarget: nodes['A2-S']}));
 
         var expectedPath = ['A1a', 'A1-SR', 'A1', 'A-SR'];
         var pathExposedToA1 = ['A1', 'A-SR'];
@@ -237,8 +187,8 @@ function testUnscopedEventWithScopedRelatedTarget(mode) {
     }, 'The event must propagate out of ' + mode + ' mode shadow tree in which the relative target and the relative related target are the same');
 }
 
-testUnscopedEventWithScopedRelatedTarget('open');
-testUnscopedEventWithScopedRelatedTarget('closed');
+testComposedEventWithRelatedTarget('open');
+testComposedEventWithRelatedTarget('closed');
 
 /*
 -SR: ShadowRoot  -S: Slot  target: (~)  relatedTarget: [~]  *: indicates start  digit: event path order
@@ -250,10 +200,10 @@ A (8) [0-5,8] ---------------------------------------- A-SR (7)
                                                 + B1b2
 */
 
-function testUnscopedEventWithScopedRelatedTargetThroughSlot(mode) {
+function testComposedEventThroughSlot(mode) {
     test(function () {
         var nodes = createTestTree(mode);
-        log = dispatchEventWithLog(nodes, nodes.B1a, new MouseEvent('foo', {scoped: false, relatedTargetScoped: true, bubbles: true, relatedTarget: nodes.A1a}));
+        log = dispatchEventWithLog(nodes, nodes.B1a, new MouseEvent('foo', {composed: true, bubbles: true, relatedTarget: nodes.A1a}));
 
         var expectedPath =          ['B1a', 'B1c-S', 'B1-SR', 'B1', 'B-SR', 'B', 'A2-S', 'A-SR', 'A'];
         var expectedRelatedTarget = ['A',   'A',     'A',     'A',   'A',   'A', 'A1',   'A1',   'A'];
@@ -277,8 +227,8 @@ function testUnscopedEventWithScopedRelatedTargetThroughSlot(mode) {
     }, 'composedPath() must contain and only contain the unclosed nodes of target in ' + mode + ' mode shadow trees');
 }
 
-testUnscopedEventWithScopedRelatedTargetThroughSlot('open');
-testUnscopedEventWithScopedRelatedTargetThroughSlot('closed');
+testComposedEventThroughSlot('open');
+testComposedEventThroughSlot('closed');
 
 </script>
 </body>
index 9c10f0e..896ca36 100644 (file)
@@ -41,7 +41,7 @@ test(function () {
     var container = host.querySelector('#container');
 
     var eventLogs = attachLoggers([target, container, host, document.body]);
-    var mouseEvent = new MouseEvent('mousedown', {clientX: 51, clientY: 37, scoped: false, bubbles: true});
+    var mouseEvent = new MouseEvent('mousedown', {clientX: 51, clientY: 37, composed: true, bubbles: true});
     target.dispatchEvent(mouseEvent);
 
     assert_equals(host.offsetLeft, 20, 'The host must be at (20px, 10px)');
@@ -78,7 +78,7 @@ test(function () {
     var container = shadowRoot.querySelector('#container');
 
     var eventLogs = attachLoggers([target, container, shadowRoot, host, document.body]);
-    var mouseEvent = new MouseEvent('mousedown', {clientX: 51, clientY: 37, scoped: false, bubbles: true});
+    var mouseEvent = new MouseEvent('mousedown', {clientX: 51, clientY: 37, composed: true, bubbles: true});
     target.dispatchEvent(mouseEvent);
 
     assert_equals(host.offsetLeft, 20, 'The host must be at (20px, 10px)');
index c2471ae..3d5714d 100644 (file)
@@ -43,7 +43,7 @@ function testEventInDetachedShadowTree(mode) {
     test(function () {
         var shadow = createShadowRootWithGrandChild(mode);
 
-        log = dispatchEventWithLog(shadow.target, new Event('foo', {bubbles: true}));
+        log = dispatchEventWithLog(shadow.target, new Event('foo', {composed: true, bubbles: true}));
 
         assert_array_equals(log.length, 4, 'EventPath must contain [target, parent, shadow root, shadow host]');
         assert_array_equals(log[0], [shadow.target, shadow.target], 'EventPath[0] must be the target');
@@ -62,7 +62,7 @@ function testEventInShadowTreeInsideDocument(mode) {
         var shadow = createShadowRootWithGrandChild(mode);
         document.body.appendChild(shadow.host);
 
-        log = dispatchEventWithLog(shadow.target, new Event('foo', {bubbles: true}));
+        log = dispatchEventWithLog(shadow.target, new Event('foo', {composed: true, bubbles: true}));
 
         assert_array_equals(log.length, 7, 'EventPath must contain [target, parent, shadow root, shadow host, body, html, document]');
         assert_array_equals(log[0], [shadow.target, shadow.target], 'EventPath[0] must be the target');
@@ -100,7 +100,7 @@ function testEventInDetachedNestedShadowTree(innerMode, outerMode) {
     test(function () {
         var shadow = createNestedShadowRoot(innerMode, outerMode);
 
-        log = dispatchEventWithLog(shadow.target, new Event('bar', {bubbles: true}));
+        log = dispatchEventWithLog(shadow.target, new Event('bar', {composed: true, bubbles: true}));
 
         assert_array_equals(log.length, 6, 'EventPath must contain [target, inner root, inner host, parent, outer root, outer host]');
         assert_array_equals(log[0], [shadow.target, shadow.target], 'EventPath[0] must be the target');
@@ -123,7 +123,7 @@ function testEventInNestedShadowTreeInsideDocument(innerMode, outerMode) {
         var shadow = createNestedShadowRoot(innerMode, outerMode);
         document.body.appendChild(shadow.outerHost);
 
-        log = dispatchEventWithLog(shadow.target, new Event('bar', {bubbles: true}));
+        log = dispatchEventWithLog(shadow.target, new Event('bar', {composed: true, bubbles: true}));
 
         assert_array_equals(log.length, 6, 'EventPath must contain [target, inner root, inner host, parent, outer root, outer host]');
         assert_array_equals(log[0], [shadow.target, shadow.target], 'EventPath[0] must be the target');
index a4a2a52..d1c4a72 100644 (file)
@@ -75,7 +75,7 @@
             test(function () {
                 var shadow = createShadowHostWithAssignedGrandChild(mode);
 
-                log = dispatchEventWithLog(shadow, new Event('foo', {bubbles: true}));
+                log = dispatchEventWithLog(shadow, new Event('foo', {bubbles: true, composed: true}));
 
                 assert_equals(log.length, 6, 'EventPath must contain [target, target parent, slot, slot parent, shadow root, shadow host]');
                 assert_array_equals(log[0], [shadow.target, shadow.target], 'EventPath[0] must be the target');
@@ -96,7 +96,7 @@
                 var shadow = createShadowHostWithAssignedGrandChild(mode);
                 document.body.appendChild(shadow.host);
 
-                log = dispatchEventWithLog(shadow, new Event('foo', {bubbles: true}));
+                log = dispatchEventWithLog(shadow, new Event('foo', {bubbles: true, composed: true}));
 
                 assert_equals(log.length, 9, 'EventPath must contain [target, target parent, slot, slot parent, shadow root, shadow host, body, html, document]');
                 assert_array_equals(log[0], [shadow.target, shadow.target], 'EventPath[0] must be the target');
             test(function () {
                 var shadow = createNestedShadowTreesWithSlots(innerMode, outerUpperMode, outerLowerMode);
 
-                log = dispatchEventWithLog(shadow, new Event('foo', {bubbles: true}));
+                log = dispatchEventWithLog(shadow, new Event('foo', {bubbles: true, composed: true}));
 
                 assert_equals(log.length, 15, 'EventPath must contain 15 targets');
 
                 shadow.deepestNodeInLightDOM = shadow.target; // Needed for dispatchEventWithLog to attach event listeners. 
                 shadow.target = shadow.innerSlot;
 
-                log = dispatchEventWithLog(shadow, new Event('foo', {bubbles: true}));
+                log = dispatchEventWithLog(shadow, new Event('foo', {bubbles: true, composed: true}));
 
                 assert_equals(log.length, 12, 'EventPath must contain 12 targets');
 
index 112bb06..5d25644 100644 (file)
 
         /*
         -SR: ShadowRoot  -S: Slot  target: (~)  relatedTarget: [~]  *: indicates start  digit: event path order
-        A (8) --------------------------------------------- A-SR (7)
-        + B (5) [5-8] --- B-SR (4)                          + A1 -------- A1-SR
-          + C             + B1 (3) [*; 0-4] --- B1-SR (2)   + A2-S (6)    + A1a
-          + D --- D-SR      + B1a (*; 0)        + B1b [1,2] --- B1b-SR
-                  + D1                          + B1c-S (1)     + B1b1
-                                                                + B1b2
+        A ----------------------------------------------- A-SR
+        + B ----------- B-SR (4)                          + A1 --- A1-SR
+          + C           + B1 (3) [*; 0-4] --- B1-SR (2)   + A2-S   + A1a
+          + D --- D-SR    + B1a (*; 0)        + B1b [1,2] --- B1b-SR
+                  + D1                        + B1c-S (1)     + B1b1
+                                                              + B1b2
         */
         function testEventAtB1aWithB1a(mode) {
             test(function () {
                 var nodes = createTestTree(mode);
 
-                log = dispatchEventWithLog(nodes, nodes.B1a, new MouseEvent('foo', {bubbles: true, relatedTarget: nodes.B1}));
+                log = dispatchEventWithLog(nodes, nodes.B1a, new MouseEvent('foo', {bubbles: true, composed: true, relatedTarget: nodes.B1}));
 
                 assert_array_equals(log.eventPath,
-                    ['B1a', 'B1c-S', 'B1-SR', 'B1', 'B-SR', 'B', 'A2-S', 'A-SR', 'A'], 'The event path must be correct.');
+                    ['B1a', 'B1c-S', 'B1-SR', 'B1', 'B-SR'], 'The event path must be correct.');
                 assert_array_equals(log.relatedTargets,
-                    ['B1',  'B1',    'B1',    'B1', 'B1',   'B', 'B',    'B',    'B'], 'The related targets must be correct.');
+                    ['B1',  'B1',    'B1',    'B1', 'B1'], 'The related targets must be correct.');
 
             }, 'Firing an event at B1a with relatedNode at B1 with ' + mode + ' mode shadow trees');
         }
 
         /*
         -SR: ShadowRoot  -S: Slot  target: (~)  relatedTarget: [~]  *: indicates start  digit: event path order
-        A (8) -------------------------------------------- A-SR (7)
-        + B (5) [5-8] --- B-SR (4)                         + A1 ------ A1-SR
-          + C             + B1 (3) [0,3-4] --- B1-SR (2)   + A2-S (6)  + A1a
-          + D --- D-SR      + B1a (*; 0)       + B1b [1,2] --- B1b-SR
-                  + D1                         + B1c-S (1)     + B1b1 [*]
-                                                               + B1b2
+        A ------------------------------------------------- A-SR
+        + B ----------- B-SR (4)                            + A1 --- A1-SR
+          + C           + B1 (3) [0,3-4] --- B1-SR (2)      + A2-S   + A1a
+          + D --- D-SR    + B1a (*; 0)       + B1b [1,2] --- B1b-SR
+                  + D1                       + B1c-S (1)     + B1b1 [*]
+                                                             + B1b2
         */
         function testEventAtB1aWithB1b1(mode) {
             test(function () {
                 var nodes = createTestTree(mode);
 
-                log = dispatchEventWithLog(nodes, nodes.B1a, new MouseEvent('foo', {bubbles: true, relatedTarget: nodes.B1b1}));
+                log = dispatchEventWithLog(nodes, nodes.B1a, new MouseEvent('foo', {bubbles: true, composed: true, relatedTarget: nodes.B1b1}));
 
                 assert_array_equals(log.eventPath,
-                    ['B1a', 'B1c-S', 'B1-SR', 'B1', 'B-SR', 'B', 'A2-S', 'A-SR', 'A'], 'The event path must be correct.');
+                    ['B1a', 'B1c-S', 'B1-SR', 'B1', 'B-SR'], 'The event path must be correct.');
                 assert_array_equals(log.relatedTargets,
-                    ['B1',  'B1b',   'B1b',   'B1', 'B1',   'B', 'B',    'B',    'B'], 'The related targets must be correct.');
+                    ['B1',  'B1b',   'B1b',   'B1', 'B1'], 'The related targets must be correct.');
 
             }, 'Firing an event at B1a with relatedNode at B1b1 with ' + mode + ' mode shadow trees');
         }
 
         /*
         -SR: ShadowRoot  -S: Slot  target: (~)  relatedTarget: [~]  *: indicates start  digit: event path order
-        A (9) ------------------------------------------------------- A-SR (8)
-        + B (6) [6-9] --- B-SR (5)                                    + A1 ------ A1-SR
-          + C             + B1 (4) --------- B1-SR (3)                + A2-S (7)  + A1a
-          + D --- D-SR      + B1a [*; 0-5]   + B1b (2) --- B1b-SR (1)
-                  + D1                       + B1c-S       + B1b1 (*; 0)
-                                                           + B1b2
+        A -------------------------------------------------- A-SR
+        + B ------------- B-SR (5)                           + A1 --- A1-SR
+          + C             + B1 (4) ------- B1-SR (3)         + A2-S   + A1a
+          + D --- D-SR    + B1a [*; 0-5]   + B1b (2) --- B1b-SR (1)
+                  + D1                     + B1c-S       + B1b1 (*; 0)
+                                                         + B1b2
         */
         function testEventAtB1b1WithB1a(mode) {
             test(function () {
                 var nodes = createTestTree(mode);
 
-                log = dispatchEventWithLog(nodes, nodes.B1b1, new MouseEvent('foo', {bubbles: true, relatedTarget: nodes.B1a}));
+                log = dispatchEventWithLog(nodes, nodes.B1b1, new MouseEvent('foo', {bubbles: true, composed: true, relatedTarget: nodes.B1a}));
 
                 assert_array_equals(log.eventPath,
-                    ['B1b1', 'B1b-SR', 'B1b', 'B1-SR', 'B1', 'B-SR', 'B', 'A2-S', 'A-SR', 'A'], 'The event path must be correct.');
+                    ['B1b1', 'B1b-SR', 'B1b', 'B1-SR', 'B1', 'B-SR'], 'The event path must be correct.');
                 assert_array_equals(log.relatedTargets,
-                    ['B1a',  'B1a',    'B1a', 'B1a',   'B1a', 'B1a', 'B', 'B',    'B',    'B'], 'The related targets must be correct.');
+                    ['B1a',  'B1a',    'B1a', 'B1a',   'B1a', 'B1a'], 'The related targets must be correct.');
 
             }, 'Firing an event at B1b1 with relatedNode at B1a with ' + mode + ' mode shadow trees');
         }
             test(function () {
                 var nodes = createTestTree(mode);
 
-                log = dispatchEventWithLog(nodes, nodes.B1a, new MouseEvent('foo', {bubbles: true, relatedTarget: nodes.D1}));
+                log = dispatchEventWithLog(nodes, nodes.B1a, new MouseEvent('foo', {bubbles: true, composed: true, relatedTarget: nodes.D1}));
 
                 assert_array_equals(log.eventPath,
                     ['B1a', 'B1c-S', 'B1-SR', 'B1', 'B-SR', 'B', 'A2-S', 'A-SR', 'A'], 'The event path must be correct.');
             test(function () {
                 var nodes = createTestTree(mode);
 
-                log = dispatchEventWithLog(nodes, nodes.D1, new MouseEvent('foo', {bubbles: true, relatedTarget: nodes.B1a}));
+                log = dispatchEventWithLog(nodes, nodes.D1, new MouseEvent('foo', {bubbles: true, composed: true, relatedTarget: nodes.B1a}));
 
                 assert_array_equals(log.eventPath,
                     ['D1', 'D-SR', 'D', 'B', 'A2-S', 'A-SR', 'A'], 'The event path must be correct.');
             test(function () {
                 var nodes = createTestTree(mode);
 
-                log = dispatchEventWithLog(nodes, nodes.B1a, new MouseEvent('foo', {bubbles: true, relatedTarget: nodes.A1a}));
+                log = dispatchEventWithLog(nodes, nodes.B1a, new MouseEvent('foo', {bubbles: true, composed: true, relatedTarget: nodes.A1a}));
 
                 assert_array_equals(log.eventPath,
                     ['B1a', 'B1c-S', 'B1-SR', 'B1', 'B-SR', 'B', 'A2-S', 'A-SR', 'A'], 'The event path must be correct.');
             test(function () {
                 var nodes = createTestTree(mode);
 
-                log = dispatchEventWithLog(nodes, nodes.A1a, new MouseEvent('foo', {bubbles: true, relatedTarget: nodes.B1a}));
+                log = dispatchEventWithLog(nodes, nodes.A1a, new MouseEvent('foo', {bubbles: true, composed: true, relatedTarget: nodes.B1a}));
 
                 assert_array_equals(log.eventPath,
                     ['A1a', 'A1-SR', 'A1', 'A-SR', 'A'], 'The event path must be correct.');
                 var nodes = createTestTree(mode);
 
                 nodes['A-SR'].removeChild(nodes.A1);
-                log = dispatchEventWithLog(nodes, nodes.B1a, new MouseEvent('foo', {bubbles: true, relatedTarget: nodes.A1a}));
+                log = dispatchEventWithLog(nodes, nodes.B1a, new MouseEvent('foo', {bubbles: true, composed: true, relatedTarget: nodes.A1a}));
 
                 assert_array_equals(log.eventPath,
                     ['B1a', 'B1c-S', 'B1-SR', 'B1', 'B-SR', 'B', 'A2-S', 'A-SR', 'A'], 'The event path must be correct.');
                 var nodes = createTestTree(mode);
 
                 nodes['A-SR'].removeChild(nodes.A1);
-                log = dispatchEventWithLog(nodes, nodes.A1a, new MouseEvent('foo', {bubbles: true, relatedTarget: nodes.B1a}));
+                log = dispatchEventWithLog(nodes, nodes.A1a, new MouseEvent('foo', {bubbles: true, composed: true, relatedTarget: nodes.B1a}));
 
                 assert_array_equals(log.eventPath,      ['A1a', 'A1-SR', 'A1'], 'The event path must be correct.');
                 assert_array_equals(log.relatedTargets, ['B',   'B',     'B' ], 'The related targets must be correct.');
index 3abbb8f..4d77557 100644 (file)
@@ -1,65 +1,50 @@
 
 world
 PASS input.type = "radio"; log(input, "change"); input.click(); eventType is "change"
-PASS scoped is true
-PASS relatedTargetScoped is false
+PASS composed is false
 
 PASS log(form, "reset"); form.reset(); eventType is "reset"
-PASS scoped is true
-PASS relatedTargetScoped is false
+PASS composed is false
 
 PASS form.focus(); log(input, "focus"); input.focus(); eventType is "focus"
-PASS scoped is false
-PASS relatedTargetScoped is true
+PASS composed is true
 
 PASS log(input, "blur"); form.focus(); eventType is "blur"
-PASS scoped is false
-PASS relatedTargetScoped is true
+PASS composed is true
 
 PASS input.type = "text"; log(input, "mousemove"); eventSender.mouseMoveTo(x, y); eventType is "mousemove"
-PASS scoped is false
-PASS relatedTargetScoped is false
+PASS composed is true
 
 PASS log(input, "mousedown"); eventSender.mouseDown(); eventType is "mousedown"
-PASS scoped is false
-PASS relatedTargetScoped is false
+PASS composed is true
 
 PASS log(input, "mouseup"); eventSender.mouseUp(); eventType is "mouseup"
-PASS scoped is false
-PASS relatedTargetScoped is false
+PASS composed is true
 
 PASS log(input, "mouseout"); eventSender.mouseMoveTo(0, 0); eventType is "mouseout"
-PASS scoped is false
-PASS relatedTargetScoped is true
+PASS composed is true
 
 PASS log(input, "mouseover"); eventSender.mouseMoveTo(x, y); eventType is "mouseover"
-PASS scoped is false
-PASS relatedTargetScoped is true
+PASS composed is true
 
 input.value = "hello"; eventSender.mouseMoveTo(input.offsetLeft + 1, y); eventSender.mouseDown();
 PASS log(input, "select"); eventSender.mouseMoveTo(input.offsetLeft + input.offsetWidth - 2, y); eventSender.mouseUp(); eventType is "select"
-PASS scoped is true
-PASS relatedTargetScoped is false
+PASS composed is false
 
 PASS log(editableElement, "selectstart"); eventSender.mouseMoveTo(editableElement.offsetLeft + 1, y); eventSender.mouseDown(); eventType is "selectstart"
-PASS scoped is true
-PASS relatedTargetScoped is false
+PASS composed is false
 
 PASS eventType is "load"
-PASS scoped is true
-PASS relatedTargetScoped is false
+PASS composed is false
 
 PASS eventType is "error"
-PASS scoped is true
-PASS relatedTargetScoped is false
+PASS composed is false
 
 PASS eventType is "scroll"
-PASS scoped is true
-PASS relatedTargetScoped is false
+PASS composed is false
 
 PASS eventType is "resize"
-PASS scoped is true
-PASS relatedTargetScoped is false
+PASS composed is false
 
 PASS successfullyParsed is true
 
index 08f4dc2..60f4902 100644 (file)
@@ -8,19 +8,16 @@
 <script>
 
 var eventType;
-var scoped;
-var relatedTargetScoped;
+var composed;
 
 function logEvent(event) {
     eventType = event.type;
-    scoped = event.scoped;
-    relatedTargetScoped = event.relatedTargetScoped;
+    composed = event.composed;
 }
 
 function checkFlags(code, expected) {
     shouldBeEqualToString(code ? code + '; eventType' : 'eventType', expected.eventType);
-    shouldBe('scoped', expected.scoped.toString());
-    shouldBe('relatedTargetScoped', expected.relatedTargetScoped.toString());
+    shouldBe('composed', expected.composed.toString());
     debug('');
 }
 
@@ -28,8 +25,7 @@ var lastTarget;
 var lastEventName;
 function log(target, eventName) {
     eventType = undefined;
-    scoped = undefined;
-    relatedTargetScoped = undefined;
+    composed = undefined;
     if (lastTarget)
         lastTarget.removeEventListener(lastEventName, logEvent);
     target.addEventListener(eventName, logEvent);
@@ -41,11 +37,11 @@ var input = document.querySelector('input');
 var form = document.querySelector('form');
 form.tabIndex = 0;
 
-checkFlags('input.type = "radio"; log(input, "change"); input.click()', {eventType: 'change', scoped: true, relatedTargetScoped: false});
-checkFlags('log(form, "reset"); form.reset()', {eventType: 'reset', scoped: true, relatedTargetScoped: false});
+checkFlags('input.type = "radio"; log(input, "change"); input.click()', {eventType: 'change', composed: false});
+checkFlags('log(form, "reset"); form.reset()', {eventType: 'reset', composed: false});
 
-checkFlags('form.focus(); log(input, "focus"); input.focus()', {eventType: 'focus', scoped: false, relatedTargetScoped: true});
-checkFlags('log(input, "blur"); form.focus()', {eventType: 'blur', scoped: false, relatedTargetScoped: true});
+checkFlags('form.focus(); log(input, "focus"); input.focus()', {eventType: 'focus', composed: true});
+checkFlags('log(input, "blur"); form.focus()', {eventType: 'blur', composed: true});
 
 if (!window.eventSender)
     testFailed('This test requires eventSender');
@@ -57,20 +53,20 @@ else {
     var x = input.offsetLeft + input.offsetWidth / 2;
     var y = input.offsetTop + input.offsetHeight / 2;
 
-    checkFlags('input.type = "text"; log(input, "mousemove"); eventSender.mouseMoveTo(x, y)', {eventType: 'mousemove', scoped: false, relatedTargetScoped: false});
-    checkFlags('log(input, "mousedown"); eventSender.mouseDown()', {eventType: 'mousedown', scoped: false, relatedTargetScoped: false});
-    checkFlags('log(input, "mouseup"); eventSender.mouseUp()', {eventType: 'mouseup', scoped: false, relatedTargetScoped: false});
-    checkFlags('log(input, "mouseout"); eventSender.mouseMoveTo(0, 0)', {eventType: 'mouseout', scoped: false, relatedTargetScoped: true});
-    checkFlags('log(input, "mouseover"); eventSender.mouseMoveTo(x, y)', {eventType: 'mouseover', scoped: false, relatedTargetScoped: true});
+    checkFlags('input.type = "text"; log(input, "mousemove"); eventSender.mouseMoveTo(x, y)', {eventType: 'mousemove', composed: true});
+    checkFlags('log(input, "mousedown"); eventSender.mouseDown()', {eventType: 'mousedown', composed: true});
+    checkFlags('log(input, "mouseup"); eventSender.mouseUp()', {eventType: 'mouseup', composed: true});
+    checkFlags('log(input, "mouseout"); eventSender.mouseMoveTo(0, 0)', {eventType: 'mouseout', composed: true});
+    checkFlags('log(input, "mouseover"); eventSender.mouseMoveTo(x, y)', {eventType: 'mouseover', composed: true});
 
     evalAndLog('input.value = "hello"; eventSender.mouseMoveTo(input.offsetLeft + 1, y); eventSender.mouseDown();');
     checkFlags('log(input, "select"); eventSender.mouseMoveTo(input.offsetLeft + input.offsetWidth - 2, y); eventSender.mouseUp()',
-        {eventType: 'select', scoped: true, relatedTargetScoped: false});
+        {eventType: 'select', composed: false});
 
     var editableElement = document.getElementById('editor');
     y = editableElement.offsetTop + editableElement.offsetHeight / 2;
     checkFlags('log(editableElement, "selectstart"); eventSender.mouseMoveTo(editableElement.offsetLeft + 1, y); eventSender.mouseDown()',
-        {eventType: 'selectstart', scoped: true, relatedTargetScoped: false});
+        {eventType: 'selectstart', composed: false});
 }
 
 function testLoadEvent() {
@@ -78,7 +74,7 @@ function testLoadEvent() {
     scriptThatLoads.src = "resources/event-path-test-helpers.js";
     scriptThatLoads.onload = function (event) {
         logEvent(event);
-        checkFlags('', {eventType: 'load', scoped: true, relatedTargetScoped: false});
+        checkFlags('', {eventType: 'load', composed: false});
         testErrorEvent();
     }
     document.body.appendChild(scriptThatLoads);
@@ -89,7 +85,7 @@ function testErrorEvent() {
     scriptThatFailsToLoad.src = "bad.js";
     scriptThatFailsToLoad.onerror = function (event) {
         logEvent(event);
-        checkFlags('', {eventType: 'error', scoped: true, relatedTargetScoped: false});
+        checkFlags('', {eventType: 'error', composed: false});
         testScrollEvent();
     }
     document.body.appendChild(scriptThatFailsToLoad);
@@ -101,7 +97,7 @@ function testScrollEvent() {
     setTimeout(function () {
         window.scrollTo(0, 1000);
         setTimeout(function () {
-            checkFlags('', {eventType: 'scroll', scoped: true, relatedTargetScoped: false});
+            checkFlags('', {eventType: 'scroll', composed: false});
             window.scrollTo(0, 0);
             testResizeEvent();
         }, 0);
@@ -121,7 +117,7 @@ function testResizeEvent() {
             iframe.style.height = '200px';
             iframe.contentDocument.body.getBoundingClientRect();
             setTimeout(function () {
-                checkFlags('', {eventType: 'resize', scoped: true, relatedTargetScoped: false});
+                checkFlags('', {eventType: 'resize', composed: false});
                 finishJSTest();
             }, 0);
         }, 0);
index f2334dd..bc9713e 100644 (file)
@@ -47,6 +47,7 @@ bubbles : 'false'
 cancelBubble : 'false'
 cancelable : 'false'
 clipboardData : 'undefined'
+composed : 'false'
 composedPath : 'function composedPath() {
     [native code]
 }'
@@ -63,9 +64,7 @@ position : '174'
 preventDefault : 'function preventDefault() {
     [native code]
 }'
-relatedTargetScoped : 'false'
 returnValue : 'true'
-scoped : 'true'
 srcElement : '[object XMLHttpRequest]'
 stopImmediatePropagation : 'function stopImmediatePropagation() {
     [native code]
index 08995e8..91e7492 100644 (file)
@@ -27,6 +27,7 @@ cancelBubble: false,
 cancelable: true,
 clipboardData: undefined,
 colno: 14,
+composed: false,
 composedPath: function composedPath() { [native code] },
 currentTarget: [object Worker],
 defaultPrevented: false,
@@ -38,9 +39,7 @@ isTrusted: true,
 lineno: 2,
 message: Error: Script error.,
 preventDefault: function preventDefault() { [native code] },
-relatedTargetScoped: false,
 returnValue: true,
-scoped: true,
 srcElement: [object Worker],
 stopImmediatePropagation: function stopImmediatePropagation() { [native code] },
 stopPropagation: function stopPropagation() { [native code] },
index 2d5411f..91f5103 100644 (file)
@@ -48,8 +48,7 @@ DISPLAYABLE PROPERTIES:
     eventPhase
     bubbles
     cancelable
-    scoped
-    relatedTargetScoped
+    composed
     timeStamp
     defaultPrevented
     srcElement
@@ -67,8 +66,7 @@ ALL PROPERTIES:
     eventPhase
     bubbles
     cancelable
-    scoped
-    relatedTargetScoped
+    composed
     timeStamp
     defaultPrevented
     srcElement
index 42d8e2e..1e4a77b 100644 (file)
@@ -1,3 +1,60 @@
+2016-07-07  Ryosuke Niwa  <rniwa@webkit.org>
+
+        Replace scoped flag in Event by composed flag
+        https://bugs.webkit.org/show_bug.cgi?id=158415
+
+        Reviewed by Chris Dumez.
+
+        Replace `scoped` flag with `composed` flag and negate its meaning per the latest spec:
+        https://dom.spec.whatwg.org/#dom-event-composed
+        https://github.com/w3c/webcomponents/issues/513
+
+        In the old spec, every event was assumed to be "composed" (crosses shadow boundaries)
+        by default and there was `scoped` flag which prevented the event from crossing bondaries,
+        and there was a handful of events for which `scoped` was set true when dispatched by UA.
+
+        In the new spec, every event is assumed to be "scoped" and a handful of user-initiated
+        events set `composed` flag to true, which is also exposed in EventInit dictionary.
+        `relatedTargetScoped` flag has been removed. New behavior is identical to when this flag
+        was set to true.
+
+        No new tests since existing tests are updated to test the new flag and behavior.
+
+        * dom/CompositionEvent.cpp:
+        (WebCore::CompositionEvent::isCompositionEvent): Added.
+        * dom/CompositionEvent.h:
+        * dom/Event.cpp:
+        (WebCore::Event::Event): Initialize m_composed. Also re-ordered m_type and m_isInitialized
+        for better packing.
+        (WebCore::Event::composed): Renamed from Event::composed. We return true whenever composed
+        is set to true in EventInit, or the engine is dispatching an user-initiated event listed in:
+        https://github.com/w3c/webcomponents/issues/513#issuecomment-224183937
+        as well as keypress, cut, paste, and, copy as discussed in:
+        https://github.com/w3c/webcomponents/issues/513#issuecomment-230988170
+        (WebCore::Event::isCompositionEvent): Added.
+        * dom/Event.h:
+        (WebCore::Event::composed): Added.
+        (WebCore::Event::scoped): Deleted.
+        (WebCore::Event::relatedTargetScoped): Deleted.
+        (WebCore::Event): Reordered m_type and m_isInitialized for better packing. Added m_composed
+        and removed m_scoped and m_relatedTargetScoped.
+        * dom/Event.idl:
+        * dom/EventPath.cpp:
+        (WebCore::shouldEventCrossShadowBoundary): Returns true if the event did not originate from
+        a shadow tree (this event entered the current shadow tree via a slot so we need to proceed with
+        the normal bubble path outside the shadow tree) or composed flag is set true.
+        (WebCore::EventPath::EventPath): m_event no longer exists, which was only used to get the value
+        of relatedTargetScoped which has been removed.
+        (WebCore::EventPath::setRelatedTarget): Behave as if relatedTargetScoped is always set true
+        since the flag has been removed.
+        * dom/EventPath.h:
+        * dom/FocusEvent.cpp:
+        (WebCore::FocusEvent::relatedTargetScoped): Deleted.
+        * dom/FocusEvent.h:
+        * dom/MouseEvent.cpp:
+        (WebCore::MouseEvent::relatedTargetScoped): Deleted.
+        * dom/MouseEvent.h:
+
 2016-07-07  Chris Dumez  <cdumez@apple.com>
 
         tdody.deleteRow(-1) and tr.deleteCell(-1) should not throw when there are no rows / cells
index 0c98dc0..3335a51 100644 (file)
@@ -66,4 +66,9 @@ EventInterface CompositionEvent::eventInterface() const
     return CompositionEventInterfaceType;
 }
 
+bool CompositionEvent::isCompositionEvent() const
+{
+    return true;
+}
+
 } // namespace WebCore
index 4953625..c3b5c17 100644 (file)
@@ -65,6 +65,8 @@ private:
     CompositionEvent(const AtomicString& type, AbstractView*, const String&);
     CompositionEvent(const AtomicString& type, const CompositionEventInit&);
 
+    bool isCompositionEvent() const override;
+
     String m_data;
 };
 
index 43086a4..aac7e32 100644 (file)
@@ -37,8 +37,8 @@ Event::Event()
 }
 
 Event::Event(const AtomicString& eventType, bool canBubbleArg, bool cancelableArg)
-    : m_isInitialized(true)
-    , m_type(eventType)
+    : m_type(eventType)
+    , m_isInitialized(true)
     , m_canBubble(canBubbleArg)
     , m_cancelable(cancelableArg)
     , m_isTrusted(true)
@@ -47,8 +47,8 @@ Event::Event(const AtomicString& eventType, bool canBubbleArg, bool cancelableAr
 }
 
 Event::Event(const AtomicString& eventType, bool canBubbleArg, bool cancelableArg, double timestamp)
-    : m_isInitialized(true)
-    , m_type(eventType)
+    : m_type(eventType)
+    , m_isInitialized(true)
     , m_canBubble(canBubbleArg)
     , m_cancelable(cancelableArg)
     , m_isTrusted(true)
@@ -57,12 +57,11 @@ Event::Event(const AtomicString& eventType, bool canBubbleArg, bool cancelableAr
 }
 
 Event::Event(const AtomicString& eventType, const EventInit& initializer)
-    : m_isInitialized(true)
-    , m_type(eventType)
+    : m_type(eventType)
+    , m_isInitialized(true)
     , m_canBubble(initializer.bubbles)
     , m_cancelable(initializer.cancelable)
-    , m_scoped(initializer.scoped)
-    , m_relatedTargetScoped(initializer.relatedTargetScoped)
+    , m_composed(initializer.composed)
     , m_createTime(convertSecondsToDOMTimeStamp(currentTime()))
 {
 }
@@ -87,25 +86,23 @@ void Event::initEvent(const AtomicString& eventTypeArg, bool canBubbleArg, bool
     m_cancelable = cancelableArg;
 }
 
-bool Event::scoped() const
+bool Event::composed() const
 {
-    if (m_scoped)
+    if (m_composed)
         return true;
 
     // http://w3c.github.io/webcomponents/spec/shadow/#scoped-flag
     if (!isTrusted())
         return false;
 
-    return m_type == eventNames().abortEvent
-        || m_type == eventNames().changeEvent
-        || m_type == eventNames().errorEvent
-        || m_type == eventNames().loadEvent
-        || m_type == eventNames().resetEvent
-        || m_type == eventNames().resizeEvent
-        || m_type == eventNames().scrollEvent
-        || m_type == eventNames().selectEvent
-        || m_type == eventNames().selectstartEvent
-        || m_type == eventNames().slotchangeEvent;
+    return m_type == eventNames().inputEvent
+        || m_type == eventNames().textInputEvent
+        || isCompositionEvent()
+        || isClipboardEvent()
+        || isFocusEvent()
+        || isKeyboardEvent()
+        || isMouseEvent()
+        || isTouchEvent();
 }
 
 EventInterface Event::eventInterface() const
@@ -133,6 +130,11 @@ bool Event::isKeyboardEvent() const
     return false;
 }
 
+bool Event::isCompositionEvent() const
+{
+    return false;
+}
+
 bool Event::isTouchEvent() const
 {
     return false;
index e81ffc4..dc1e07f 100644 (file)
@@ -43,8 +43,7 @@ class HTMLIFrameElement;
 struct EventInit {
     bool bubbles { false };
     bool cancelable { false };
-    bool scoped { false };
-    bool relatedTargetScoped { false };
+    bool composed { false };
 };
 
 enum EventInterface {
@@ -117,8 +116,7 @@ public:
 
     bool bubbles() const { return m_canBubble; }
     bool cancelable() const { return m_cancelable; }
-    bool scoped() const;
-    virtual bool relatedTargetScoped() const { return m_relatedTargetScoped; }
+    bool composed() const;
 
     DOMTimeStamp timeStamp() const { return m_createTime; }
 
@@ -147,6 +145,7 @@ public:
     virtual bool isMouseEvent() const;
     virtual bool isFocusEvent() const;
     virtual bool isKeyboardEvent() const;
+    virtual bool isCompositionEvent() const;
     virtual bool isTouchEvent() const;
 
     // Drag events are a subset of mouse events.
@@ -206,12 +205,12 @@ protected:
     bool dispatched() const { return m_target; }
 
 private:
-    bool m_isInitialized { false };
     AtomicString m_type;
+
+    bool m_isInitialized { false };
     bool m_canBubble { false };
     bool m_cancelable { false };
-    bool m_scoped { false };
-    bool m_relatedTargetScoped { false };
+    bool m_composed { false };
 
     bool m_propagationStopped { false };
     bool m_immediatePropagationStopped { false };
index f138d70..86ca19e 100644 (file)
@@ -58,8 +58,7 @@
     readonly attribute unsigned short   eventPhase;
     [InitializedByEventConstructor] readonly attribute boolean bubbles;
     [InitializedByEventConstructor] readonly attribute boolean cancelable;
-    [InitializedByEventConstructor, EnabledAtRuntime=ShadowDOM] readonly attribute boolean scoped;
-    [InitializedByEventConstructor, EnabledAtRuntime=ShadowDOM] readonly attribute boolean relatedTargetScoped;
+    [InitializedByEventConstructor, EnabledAtRuntime=ShadowDOM] readonly attribute boolean composed;
     readonly attribute DOMTimeStamp     timeStamp;
 
     [EnabledAtRuntime=ShadowDOM] sequence<Node> composedPath();
index d43e5f3..5b5bb96 100644 (file)
@@ -50,7 +50,7 @@ static inline bool shouldEventCrossShadowBoundary(Event& event, ShadowRoot& shad
 #endif
 
     bool targetIsInShadowRoot = targetNode && &targetNode->treeScope().rootNode() == &shadowRoot;
-    return !targetIsInShadowRoot || !event.scoped();
+    return !targetIsInShadowRoot || event.composed();
 }
 
 static Node* nodeOrHostIfPseudoElement(Node* node)
@@ -84,7 +84,6 @@ private:
 };
 
 EventPath::EventPath(Node& originalTarget, Event& event)
-    : m_event(event)
 {
     bool isMouseOrFocusEvent = event.isMouseEvent() || event.isFocusEvent();
 #if ENABLE(TOUCH_EVENTS)
@@ -141,7 +140,6 @@ void EventPath::setRelatedTarget(Node& origin, EventTarget& relatedTarget)
     RelatedNodeRetargeter retargeter(*relatedNode, *m_path[0]->node());
 
     bool originIsRelatedTarget = &origin == relatedNode;
-    bool relatedTargetScoped = m_event.relatedTargetScoped();
     Node& rootNodeInOriginTreeScope = origin.treeScope().rootNode();
     TreeScope* previousTreeScope = nullptr;
     size_t originalEventPathSize = m_path.size();
@@ -154,14 +152,14 @@ void EventPath::setRelatedTarget(Node& origin, EventTarget& relatedTarget)
             retargeter.moveToNewTreeScope(previousTreeScope, currentTreeScope);
 
         Node* currentRelatedNode = retargeter.currentNode(currentTarget);
-        if (UNLIKELY(relatedTargetScoped && !originIsRelatedTarget && context.target() == currentRelatedNode)) {
+        if (UNLIKELY(!originIsRelatedTarget && context.target() == currentRelatedNode)) {
             m_path.shrink(contextIndex);
             break;
         }
 
         context.setRelatedTarget(currentRelatedNode);
 
-        if (UNLIKELY(relatedTargetScoped && originIsRelatedTarget && context.node() == &rootNodeInOriginTreeScope)) {
+        if (UNLIKELY(originIsRelatedTarget && context.node() == &rootNodeInOriginTreeScope)) {
             m_path.shrink(contextIndex + 1);
             break;
         }
index a6c2005..fe7ef00 100644 (file)
@@ -69,7 +69,6 @@ private:
     void retargetTouch(TouchEventContext::TouchListType, const Touch&);
 #endif
 
-    Event& m_event;
     Vector<std::unique_ptr<EventContext>, 32> m_path;
 };
 
index 33023b6..37c0756 100644 (file)
@@ -52,9 +52,4 @@ FocusEvent::FocusEvent(const AtomicString& type, const FocusEventInit& initializ
 {
 }
 
-bool FocusEvent::relatedTargetScoped() const
-{
-    return (isTrusted() && m_relatedTarget) || UIEvent::relatedTargetScoped();
-}
-
 } // namespace WebCore
index 0327036..5df487e 100644 (file)
@@ -58,8 +58,6 @@ private:
     FocusEvent(const AtomicString& type, bool canBubble, bool cancelable, AbstractView*, int, RefPtr<EventTarget>&&);
     FocusEvent(const AtomicString& type, const FocusEventInit&);
 
-    bool relatedTargetScoped() const override;
-
     bool isFocusEvent() const override;
 
     RefPtr<EventTarget> m_relatedTarget;
index 1824f6f..9944fa6 100644 (file)
@@ -189,11 +189,6 @@ bool MouseEvent::canTriggerActivationBehavior(const Event& event)
     return event.type() == eventNames().clickEvent && (!is<MouseEvent>(event) || downcast<MouseEvent>(event).button() != RightButton);
 }
 
-bool MouseEvent::relatedTargetScoped() const
-{
-    return (isTrusted() && m_relatedTarget) || UIEvent::relatedTargetScoped();
-}
-
 int MouseEvent::which() const
 {
     // For the DOM, the return values for left, middle and right mouse buttons are 0, 1, 2, respectively.
index c2e6b70..3a4f963 100644 (file)
@@ -121,8 +121,6 @@ protected:
 
     MouseEvent();
 
-    bool relatedTargetScoped() const override;
-
 private:
     unsigned short m_button;
     bool m_buttonDown;