Skip to content

Commit

Permalink
Replace scoped flag in Event by composed flag
Browse files Browse the repository at this point in the history
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
WICG/webcomponents#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:
WICG/webcomponents#513 (comment)
as well as keypress, cut, paste, and, copy as discussed in:
WICG/webcomponents#513 (comment)
(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: http://svn.webkit.org/repository/webkit/trunk@202953 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
[email protected] authored and matteoceraico committed Jul 5, 2017
1 parent 6aac2e8 commit 07c8579
Show file tree
Hide file tree
Showing 23 changed files with 242 additions and 371 deletions.
27 changes: 27 additions & 0 deletions LayoutTests/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
2016-07-07 Ryosuke Niwa <[email protected]>

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-05-09 Ryosuke Niwa <[email protected]>

REGRESSION (198056): Unable to use edit buttons on WordPress
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
116 changes: 33 additions & 83 deletions LayoutTests/fast/shadow-dom/Extensions-to-Event-Interface.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,40 +31,22 @@
}, '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
Expand All @@ -76,10 +58,10 @@
+ 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);
Expand All @@ -88,11 +70,11 @@
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
Expand All @@ -104,53 +86,21 @@
+ 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
Expand All @@ -162,22 +112,22 @@
+ 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);
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.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
Expand Down Expand Up @@ -220,10 +170,10 @@
+ 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'];
Expand All @@ -237,8 +187,8 @@
}, '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
Expand All @@ -250,10 +200,10 @@
+ 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'];
Expand All @@ -277,8 +227,8 @@
}, '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>
Expand Down
8 changes: 4 additions & 4 deletions LayoutTests/fast/shadow-dom/event-inside-shadow-tree.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
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');
Expand All @@ -62,7 +62,7 @@
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');
Expand Down Expand Up @@ -100,7 +100,7 @@
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');
Expand All @@ -123,7 +123,7 @@
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');
Expand Down
8 changes: 4 additions & 4 deletions LayoutTests/fast/shadow-dom/event-inside-slotted-node.html
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -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');
Expand Down Expand Up @@ -174,7 +174,7 @@
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');

Expand Down Expand Up @@ -224,7 +224,7 @@
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');

Expand Down
Loading

0 comments on commit 07c8579

Please sign in to comment.