<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[198056] trunk</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/198056">198056</a></dd>
<dt>Author</dt> <dd>rniwa@webkit.org</dd>
<dt>Date</dt> <dd>2016-03-11 19:11:04 -0800 (Fri, 11 Mar 2016)</dd>
</dl>
<h3>Log Message</h3>
<pre>Add Event.deepPath() and Event.scoped
https://bugs.webkit.org/show_bug.cgi?id=153538
<rdar://problem/24363836>
Reviewed by Darin Adler.
Source/WebCore:
Added the support for deepPath(), scoped, and relatedTargetScoped on Event.prototype for shadow DOM:
http://w3c.github.io/webcomponents/spec/shadow/#extensions-to-event-interface
and updated the EventPath class to respect scoped and relatedTargetScoped flags as specified at:
http://w3c.github.io/webcomponents/spec/shadow/#get-the-parent
Tests: fast/shadow-dom/Extensions-to-Event-Interface.html
fast/shadow-dom/trusted-event-scoped-flags.html
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateConstructorDefinition): Added the support for Conditional for InitializedByEventConstructor.
* bindings/scripts/test/GObject/WebKitDOMTestEventConstructor.cpp:
* bindings/scripts/test/GObject/WebKitDOMTestEventConstructor.h:
* bindings/scripts/test/JS/JSTestEventConstructor.cpp:
* bindings/scripts/test/ObjC/DOMTestEventConstructor.h:
* bindings/scripts/test/ObjC/DOMTestEventConstructor.mm:
* bindings/scripts/test/TestEventConstructor.idl: Added a test case for using InitializedByEventConstructor
with Conditional.
* dom/Event.cpp:
(WebCore::Event::Event): Initialize m_scoped and m_relatedTargetScoped from EventInit dictionary.
(WebCore::Event::scoped): Added. Implements http://w3c.github.io/webcomponents/spec/shadow/#scoped-flag
(WebCore::Event::deepPath): Added.
* dom/Event.h:
(WebCore::Event::relatedTargetScoped): Added. Overridden by FocusEvent and MouseEvent to implement
http://w3c.github.io/webcomponents/spec/shadow/#relatedtargetscoped-flag
(WebCore::Event::setEventPath): Added.
(WebCore::Event::clearEventPath): Added.
* dom/Event.idl: Added scoped, relatedTargetScoped, and deepPath() conditionally enabled for shadow DOM.
* dom/EventContext.h:
(WebCore::EventContext::currentTarget):
* dom/EventDispatcher.cpp:
(WebCore::EventDispatcher::dispatchEvent): Set the event path while the event is being dispatched.
* dom/EventPath.cpp:
(WebCore::shouldEventCrossShadowBoundary): Check event.scoped flag instead of hard-coding a list of events here
which has been moved to Event::scoped. See above.
(WebCore::EventPath::setRelatedTarget): Check m_event.relatedTargetScoped() instead of hard-coding a list of
events here. relatedTargetScoped is overridden by FocusEvent and MouseEvent.
(WebCore::EventPath::hasEventListeners): Fixed the misleading variable name.
(WebCore::isUnclosedNodeOf): Added. Implements http://w3c.github.io/webcomponents/spec/shadow/#dfn-unclosed-node
(WebCore::EventPath::computePathDisclosedToTarget): Added. Implements the algorithm to filter event targets:
http://w3c.github.io/webcomponents/spec/shadow/#widl-Event-deepPath-sequence-EventTarget
* dom/EventPath.h:
* dom/FocusEvent.cpp:
(WebCore::FocusEvent::relatedTargetScoped): Returns true when this is a trusted event per:
http://w3c.github.io/webcomponents/spec/shadow/#relatedtargetscoped-flag
* dom/FocusEvent.h:
* dom/MouseEvent.cpp:
(WebCore::MouseEvent::relatedTargetScoped): Ditto.
* dom/MouseEvent.h:
LayoutTests:
Added a W3C style testharness.js tests for Event.prototype.scoped, Event.prototype.scopedRelatedTarget,
Event.prototype.deepPath() and a test that uses eventSender to verify the values of the scoped and
scopedRelatedTarget flags on trusted events.
* fast/shadow-dom/Extensions-to-Event-Interface-expected.txt: Added.
* fast/shadow-dom/Extensions-to-Event-Interface.html: Added.
* fast/shadow-dom/event-with-related-target.html:
* fast/shadow-dom/resources: Added.
* fast/shadow-dom/resources/event-path-test-helpers.js: Added. Extracted from event-with-related-target.html.
* fast/shadow-dom/trusted-event-scoped-flags-expected.txt: Added.
* fast/shadow-dom/trusted-event-scoped-flags.html: Added.
* fast/xmlhttprequest/xmlhttprequest-get-expected.txt:
* http/tests/workers/worker-importScriptsOnError-expected.txt:
* inspector/model/remote-object-get-properties-expected.txt:
* platform/ios-simulator/fast/shadow-dom/trusted-event-scoped-flags-expected.txt: Added.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsfastshadowdomeventwithrelatedtargethtml">trunk/LayoutTests/fast/shadow-dom/event-with-related-target.html</a></li>
<li><a href="#trunkLayoutTestsfastshadowdomnegativetabindexonshadowhostexpectedtxt">trunk/LayoutTests/fast/shadow-dom/negative-tabindex-on-shadow-host-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastshadowdomnegativetabindexonshadowhosthtml">trunk/LayoutTests/fast/shadow-dom/negative-tabindex-on-shadow-host.html</a></li>
<li><a href="#trunkLayoutTestsfastxmlhttprequestxmlhttprequestgetexpectedtxt">trunk/LayoutTests/fast/xmlhttprequest/xmlhttprequest-get-expected.txt</a></li>
<li><a href="#trunkLayoutTestshttptestsworkersworkerimportScriptsOnErrorexpectedtxt">trunk/LayoutTests/http/tests/workers/worker-importScriptsOnError-expected.txt</a></li>
<li><a href="#trunkLayoutTestsinspectormodelremoteobjectgetpropertiesexpectedtxt">trunk/LayoutTests/inspector/model/remote-object-get-properties-expected.txt</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorebindingsscriptsCodeGeneratorJSpm">trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm</a></li>
<li><a href="#trunkSourceWebCorebindingsscriptstestGObjectWebKitDOMTestEventConstructorcpp">trunk/Source/WebCore/bindings/scripts/test/GObject/WebKitDOMTestEventConstructor.cpp</a></li>
<li><a href="#trunkSourceWebCorebindingsscriptstestGObjectWebKitDOMTestEventConstructorh">trunk/Source/WebCore/bindings/scripts/test/GObject/WebKitDOMTestEventConstructor.h</a></li>
<li><a href="#trunkSourceWebCorebindingsscriptstestJSJSTestEventConstructorcpp">trunk/Source/WebCore/bindings/scripts/test/JS/JSTestEventConstructor.cpp</a></li>
<li><a href="#trunkSourceWebCorebindingsscriptstestObjCDOMTestEventConstructorh">trunk/Source/WebCore/bindings/scripts/test/ObjC/DOMTestEventConstructor.h</a></li>
<li><a href="#trunkSourceWebCorebindingsscriptstestObjCDOMTestEventConstructormm">trunk/Source/WebCore/bindings/scripts/test/ObjC/DOMTestEventConstructor.mm</a></li>
<li><a href="#trunkSourceWebCorebindingsscriptstestTestEventConstructoridl">trunk/Source/WebCore/bindings/scripts/test/TestEventConstructor.idl</a></li>
<li><a href="#trunkSourceWebCoredomEventcpp">trunk/Source/WebCore/dom/Event.cpp</a></li>
<li><a href="#trunkSourceWebCoredomEventh">trunk/Source/WebCore/dom/Event.h</a></li>
<li><a href="#trunkSourceWebCoredomEventidl">trunk/Source/WebCore/dom/Event.idl</a></li>
<li><a href="#trunkSourceWebCoredomEventContexth">trunk/Source/WebCore/dom/EventContext.h</a></li>
<li><a href="#trunkSourceWebCoredomEventDispatchercpp">trunk/Source/WebCore/dom/EventDispatcher.cpp</a></li>
<li><a href="#trunkSourceWebCoredomEventPathcpp">trunk/Source/WebCore/dom/EventPath.cpp</a></li>
<li><a href="#trunkSourceWebCoredomEventPathh">trunk/Source/WebCore/dom/EventPath.h</a></li>
<li><a href="#trunkSourceWebCoredomFocusEventcpp">trunk/Source/WebCore/dom/FocusEvent.cpp</a></li>
<li><a href="#trunkSourceWebCoredomFocusEventh">trunk/Source/WebCore/dom/FocusEvent.h</a></li>
<li><a href="#trunkSourceWebCoredomMouseEventcpp">trunk/Source/WebCore/dom/MouseEvent.cpp</a></li>
<li><a href="#trunkSourceWebCoredomMouseEventh">trunk/Source/WebCore/dom/MouseEvent.h</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastshadowdomExtensionstoEventInterfaceexpectedtxt">trunk/LayoutTests/fast/shadow-dom/Extensions-to-Event-Interface-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastshadowdomExtensionstoEventInterfacehtml">trunk/LayoutTests/fast/shadow-dom/Extensions-to-Event-Interface.html</a></li>
<li>trunk/LayoutTests/fast/shadow-dom/resources/</li>
<li><a href="#trunkLayoutTestsfastshadowdomresourceseventpathtesthelpersjs">trunk/LayoutTests/fast/shadow-dom/resources/event-path-test-helpers.js</a></li>
<li><a href="#trunkLayoutTestsfastshadowdomtrustedeventscopedflagsexpectedtxt">trunk/LayoutTests/fast/shadow-dom/trusted-event-scoped-flags-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastshadowdomtrustedeventscopedflagshtml">trunk/LayoutTests/fast/shadow-dom/trusted-event-scoped-flags.html</a></li>
<li>trunk/LayoutTests/platform/ios-simulator/fast/shadow-dom/</li>
<li><a href="#trunkLayoutTestsplatformiossimulatorfastshadowdomtrustedeventscopedflagsexpectedtxt">trunk/LayoutTests/platform/ios-simulator/fast/shadow-dom/trusted-event-scoped-flags-expected.txt</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/LayoutTests/ChangeLog        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -1,3 +1,27 @@
</span><ins>+2016-03-11 Ryosuke Niwa <rniwa@webkit.org>
+
+ Add Event.deepPath() and Event.scoped
+ https://bugs.webkit.org/show_bug.cgi?id=153538
+ <rdar://problem/24363836>
+
+ Reviewed by Darin Adler.
+
+ Added a W3C style testharness.js tests for Event.prototype.scoped, Event.prototype.scopedRelatedTarget,
+ Event.prototype.deepPath() and a test that uses eventSender to verify the values of the scoped and
+ scopedRelatedTarget flags on trusted events.
+
+ * fast/shadow-dom/Extensions-to-Event-Interface-expected.txt: Added.
+ * fast/shadow-dom/Extensions-to-Event-Interface.html: Added.
+ * fast/shadow-dom/event-with-related-target.html:
+ * fast/shadow-dom/resources: Added.
+ * fast/shadow-dom/resources/event-path-test-helpers.js: Added. Extracted from event-with-related-target.html.
+ * fast/shadow-dom/trusted-event-scoped-flags-expected.txt: Added.
+ * fast/shadow-dom/trusted-event-scoped-flags.html: Added.
+ * fast/xmlhttprequest/xmlhttprequest-get-expected.txt:
+ * http/tests/workers/worker-importScriptsOnError-expected.txt:
+ * inspector/model/remote-object-get-properties-expected.txt:
+ * platform/ios-simulator/fast/shadow-dom/trusted-event-scoped-flags-expected.txt: Added.
+
</ins><span class="cx"> 2016-03-11 Jiewen Tan <jiewen_tan@apple.com>
</span><span class="cx">
</span><span class="cx"> WebKit should not be redirected to an invalid URL
</span></span></pre></div>
<a id="trunkLayoutTestsfastshadowdomExtensionstoEventInterfaceexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/shadow-dom/Extensions-to-Event-Interface-expected.txt (0 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/shadow-dom/Extensions-to-Event-Interface-expected.txt         (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/Extensions-to-Event-Interface-expected.txt        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -0,0 +1,25 @@
</span><ins>+
+PASS deepPath() must exist on Event
+PASS deepPath() must return an empty array when the event has not been dispatched
+PASS deepPath() 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 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
+PASS The event must propagate out of closed mode shadow tree in which the relative target and the relative related target are the same
+PASS deepPath() must contain and only contain the unclosed nodes of target in open mode shadow trees
+PASS deepPath() must contain and only contain the unclosed nodes of target in closed mode shadow trees
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastshadowdomExtensionstoEventInterfacehtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/shadow-dom/Extensions-to-Event-Interface.html (0 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/shadow-dom/Extensions-to-Event-Interface.html         (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/Extensions-to-Event-Interface.html        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -0,0 +1,285 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<title>Shadow DOM: Extensions to Event Interface</title>
+<meta name="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org">
+<meta name="assert" content="Event interface must have deepPath() as a method">
+<link rel="help" href="http://w3c.github.io/webcomponents/spec/shadow/#extensions-to-event-interface">
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="resources/event-path-test-helpers.js"></script>
+<link rel='stylesheet' href='../../resources/testharness.css'>
+</head>
+<body>
+<div id="log"></div>
+<script>
+
+test(function () {
+ assert_true('deepPath' in Event.prototype);
+ assert_true('deepPath' in new Event('my-event'));
+}, 'deepPath() must exist on Event');
+
+test(function () {
+ var event = new Event('my-event');
+ assert_array_equals(event.deepPath(), []);
+}, 'deepPath() must return an empty array when the event has not been dispatched');
+
+test(function () {
+ var event = new Event('my-event');
+ document.body.dispatchEvent(event);
+ assert_array_equals(event.deepPath(), []);
+}, 'deepPath() 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');
+
+test(function () {
+ var event = new Event('my-event');
+ assert_false(event.scoped);
+}, 'scoped on EventInit must default to false');
+
+test(function () {
+ var event = new Event('my-event', {scoped: true});
+ assert_true(event.scoped);
+
+ 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');
+
+/*
+-SR: ShadowRoot -S: Slot target: (~) *: indicates start digit: event path order
+A (4) --------------------------- A-SR (3)
++ B ------------ B-SR + A1 (2) --- A1-SR (1)
+ + C + B1 --- B1-SR + A2-S + A1a (*; 0)
+ + D --- D-SR + B1a + B1b --- B1b-SR
+ + D1 + B1c-S + B1b1
+ + B1b2
+*/
+
+function testUnscopedEvent(mode) {
+ test(function () {
+ var nodes = createTestTree(mode);
+ var log = dispatchEventWithLog(nodes, nodes.A1a, new Event('my-event', {scoped: false, bubbles: true}));
+
+ var expectedPath = ['A1a', 'A1-SR', 'A1', 'A-SR', '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 : ['A1', 'A-SR', 'A'],
+ 'deepPath 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');
+}
+
+testUnscopedEvent('open');
+testUnscopedEvent('closed');
+
+/*
+-SR: ShadowRoot -S: Slot target: (~) *: indicates start digit: event path order
+A ------------------------------- A-SR
++ B ------------ B-SR + A1 --- A1-SR (1)
+ + C + B1 --- B1-SR + A2-S + A1a (*; 0)
+ + D --- D-SR + B1a + B1b --- B1b-SR
+ + D1 + B1c-S + B1b1
+ + B1b2
+*/
+
+function testScopedEvent(mode) {
+ test(function () {
+ var nodes = createTestTree(mode);
+ var log = dispatchEventWithLog(nodes, nodes.A1a, new Event('my-event', {scoped: true, 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');
+}
+
+testUnscopedEventWithUnscopedRelatedTarget('open');
+testUnscopedEventWithUnscopedRelatedTarget('closed');
+
+/*
+-SR: ShadowRoot -S: Slot target: (~) relatedTarget: [~] *: indicates start digit: event path order
+A ------------------------------- A-SR
++ B ------------ B-SR + A1 ----------- A1-SR (1)
+ + C + B1 --- B1-SR + A2-S [*; 0-1] + A1a (*; 0)
+ + D --- D-SR + B1a + B1b --- B1b-SR
+ + D1 + B1c-S + B1b1
+ + B1b2
+*/
+
+function testScopedEventWithUnscopedRelatedTarget(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 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');
+}
+
+testScopedEventWithUnscopedRelatedTarget('open');
+testScopedEventWithUnscopedRelatedTarget('closed');
+
+/*
+-SR: ShadowRoot -S: Slot target: (~) relatedTarget: [~] *: indicates start digit: event path order
+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 testScopedEventWithUnscopedRelatedTargetThroughSlot(mode) {
+ test(function () {
+ var nodes = createTestTree(mode);
+ var log = dispatchEventWithLog(nodes, nodes.B1a, new MouseEvent('foo', {scoped: true, relatedTargetScoped: false, bubbles: true, relatedTarget: nodes['B1b2']}));
+
+ var expectedPath = ['B1a', 'B1c-S', 'B1-SR', 'B1', 'B-SR'];
+ var pathExposedToB1a = ['B1a', 'B1', 'B-SR'];
+ assert_array_equals(log.eventPath, expectedPath);
+ assert_array_equals(log.eventPath.length, log.pathAtTargets.length);
+ assert_array_equals(log.pathAtTargets[0], mode == 'open' ? expectedPath : pathExposedToB1a);
+ assert_array_equals(log.pathAtTargets[1], expectedPath);
+ assert_array_equals(log.pathAtTargets[2], expectedPath);
+ assert_array_equals(log.pathAtTargets[3], mode == 'open' ? expectedPath : pathExposedToB1a);
+ assert_array_equals(log.pathAtTargets[4], mode == 'open' ? expectedPath : pathExposedToB1a);
+ assert_array_equals(log.relatedTargets, ['B1', 'B1b', 'B1b', 'B1', 'B1']);
+ }, 'The event must not propagate out of ' + mode + ' mode shadow tree of the target but must propagate out of inner shadow trees when the scoped flag is set');
+}
+
+testScopedEventWithUnscopedRelatedTargetThroughSlot('open');
+testScopedEventWithUnscopedRelatedTargetThroughSlot('closed');
+
+/*
+-SR: ShadowRoot -S: Slot target: (~) relatedTarget: [~] *: indicates start digit: event path order
+A ------------------------------- 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 testUnscopedEventWithScopedRelatedTarget(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']}));
+
+ var expectedPath = ['A1a', 'A1-SR', 'A1', 'A-SR'];
+ var pathExposedToA1 = ['A1', 'A-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.pathAtTargets[2], mode == 'open' ? expectedPath : pathExposedToA1);
+ assert_array_equals(log.pathAtTargets[3], mode == 'open' ? expectedPath : pathExposedToA1);
+ assert_array_equals(log.relatedTargets, ['A2-S', 'A2-S', 'A2-S', 'A2-S']);
+ }, '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');
+
+/*
+-SR: ShadowRoot -S: Slot target: (~) relatedTarget: [~] *: indicates start digit: event path order
+A (8) [0-5,8] ---------------------------------------- A-SR (7)
++ B (5) ------- B-SR (4) + A1 [6,7] --- A1-SR
+ + C + B1 (3) ------- B1-SR (2) + A2-S (6) + A1a [*]
+ + D --- D-SR + B1a (*; 0) + B1b ------- B1b-SR
+ + D1 + B1c-S (1) + B1b1
+ + B1b2
+*/
+
+function testUnscopedEventWithScopedRelatedTargetThroughSlot(mode) {
+ test(function () {
+ var nodes = createTestTree(mode);
+ log = dispatchEventWithLog(nodes, nodes.B1a, new MouseEvent('foo', {scoped: false, relatedTargetScoped: 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'];
+ var pathExposedToB1a = ['B1a', 'B1', 'B-SR', 'B', 'A'];
+ var pathExposedToB1cS = ['B1a', 'B1c-S', 'B1-SR', 'B1', 'B-SR', 'B', 'A'];
+ var pathExposedToB = [ 'B', 'A'];
+ var pathExposedToA1 = [ 'B', 'A2-S', 'A-SR', 'A'];
+
+ assert_array_equals(log.eventPath, expectedPath);
+ assert_array_equals(log.eventPath.length, log.pathAtTargets.length);
+ assert_array_equals(log.pathAtTargets[0], mode == 'open' ? expectedPath : pathExposedToB1a);
+ assert_array_equals(log.pathAtTargets[1], mode == 'open' ? expectedPath : pathExposedToB1cS);
+ assert_array_equals(log.pathAtTargets[2], mode == 'open' ? expectedPath : pathExposedToB1cS);
+ assert_array_equals(log.pathAtTargets[3], mode == 'open' ? expectedPath : pathExposedToB1a);
+ assert_array_equals(log.pathAtTargets[4], mode == 'open' ? expectedPath : pathExposedToB1a);
+ assert_array_equals(log.pathAtTargets[5], mode == 'open' ? expectedPath : pathExposedToB);
+ assert_array_equals(log.pathAtTargets[6], mode == 'open' ? expectedPath : pathExposedToA1);
+ assert_array_equals(log.pathAtTargets[7], mode == 'open' ? expectedPath : pathExposedToA1);
+ assert_array_equals(log.pathAtTargets[8], mode == 'open' ? expectedPath : pathExposedToB);
+ assert_array_equals(log.relatedTargets, expectedRelatedTarget);
+ }, 'deepPath() must contain and only contain the unclosed nodes of target in ' + mode + ' mode shadow trees');
+}
+
+testUnscopedEventWithScopedRelatedTargetThroughSlot('open');
+testUnscopedEventWithScopedRelatedTargetThroughSlot('closed');
+
+</script>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkLayoutTestsfastshadowdomeventwithrelatedtargethtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/shadow-dom/event-with-related-target.html (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/shadow-dom/event-with-related-target.html        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/LayoutTests/fast/shadow-dom/event-with-related-target.html        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -7,100 +7,14 @@
</span><span class="cx"> <link rel="help" href="https://w3c.github.io/webcomponents/spec/shadow/#retargeting-relatedtarget">
</span><span class="cx"> <script src="../../resources/testharness.js"></script>
</span><span class="cx"> <script src="../../resources/testharnessreport.js"></script>
</span><ins>+ <script src="resources/event-path-test-helpers.js"></script>
</ins><span class="cx"> <link rel='stylesheet' href='../../resources/testharness.css'>
</span><span class="cx"> </head>
</span><span class="cx"> <body>
</span><span class="cx"> <div id="log"></div>
</span><span class="cx"> <script>
</span><span class="cx">
</span><del>- function dispatchEventWithLog(shadow, target, event) {
- var eventPath = [];
- var relatedTargets = [];
-
- var attachedNodes = [];
- for (var nodeKey in shadow) {
- var startingNode = shadow[nodeKey];
- for (var node = startingNode; node; node = node.parentNode) {
- if (attachedNodes.indexOf(node) >= 0)
- continue;
- attachedNodes.push(node);
- node.addEventListener(event.type, (function (event) {
- eventPath.push(this.label);
- relatedTargets.push(event.relatedTarget.label);
- }).bind(node));
- }
- }
-
- target.dispatchEvent(event);
-
- return {eventPath: eventPath, relatedTargets: relatedTargets};
- }
-
</del><span class="cx"> /*
</span><del>- -SR: ShadowRoot -S: Slot
- A ------------------------------- A-SR
- + B ------------ B-SR + A1 --- A1-SR
- + C + B1 --- B1-SR + A2-S + A1a
- + D --- D-SR + B1a + B1b --- B1b-SR
- + D1 + B1c-S + B1b1
- + B1b2
- */
- function createTestTree(mode) {
- var namedNodes = {};
-
- function element(name) {
- var element = document.createElement(name.indexOf('-S') > 0 ? 'slot' : 'div');
- element.label = name;
- namedNodes[name] = element;
- for (var i = 1; i < arguments.length; i++) {
- var item = arguments[i];
- if (typeof(item) == 'function')
- item(element);
- else
- element.appendChild(item);
- }
- return element;
- }
-
- function shadow(name) {
- var children = [];
- for (var i = 1; i < arguments.length; i++)
- children.push(arguments[i]);
- return function (element) {
- var shadowRoot = element.attachShadow({mode: mode});
- shadowRoot.label = name;
- namedNodes[name] = shadowRoot;
- for (var child of children)
- shadowRoot.appendChild(child);
- }
- }
-
- var host = element('A',
- shadow('A-SR',
- element('A1',
- shadow('A1-SR',
- element('A1a'))),
- element('A2-S')
- ),
- element('B',
- shadow('B-SR',
- element('B1',
- shadow('B1-SR',
- element('B1b',
- shadow('B1b-SR',
- element('B1b1'),
- element('B1b2'))),
- element('B1c-S')),
- element('B1a'))),
- element('C'),
- element('D',
- shadow('D-SR',
- element('D1')))));
-
- return namedNodes;
- }
-
- /*
</del><span class="cx"> -SR: ShadowRoot -S: Slot target: (~) relatedTarget: [~] *: indicates start digit: event path order
</span><span class="cx"> A (8) --------------------------------------------- A-SR (7)
</span><span class="cx"> + B (5) [5-8] --- B-SR (4) + A1 -------- A1-SR
</span></span></pre></div>
<a id="trunkLayoutTestsfastshadowdomnegativetabindexonshadowhostexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/shadow-dom/negative-tabindex-on-shadow-host-expected.txt (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/shadow-dom/negative-tabindex-on-shadow-host-expected.txt        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/LayoutTests/fast/shadow-dom/negative-tabindex-on-shadow-host-expected.txt        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -2,9 +2,8 @@
</span><span class="cx"> To manually test, press tab key four times. It should traverse focusable elements in the increasing numerical order.
</span><span class="cx">
</span><span class="cx"> 1. First sequentially focusable element outside shadow trees
</span><del>-2. / 3.2. Shadow host with a positive tabindex
-3.1. Focusable element inside a shadow host with a positive tabindex
-2. / 3.2. Shadow host with a positive tabindex
</del><ins>+2. Shadow host with a positive tabindex
+3. Focusable element inside a shadow host with a positive tabindex
</ins><span class="cx"> 4.1. Focusable element inside a shadow host with no tabindex
</span><span class="cx"> 4.2. Shadow host with no tabindex
</span><span class="cx"> 5. Last sequentially focusable element outside shadow trees
</span></span></pre></div>
<a id="trunkLayoutTestsfastshadowdomnegativetabindexonshadowhosthtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/shadow-dom/negative-tabindex-on-shadow-host.html (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/shadow-dom/negative-tabindex-on-shadow-host.html        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/LayoutTests/fast/shadow-dom/negative-tabindex-on-shadow-host.html        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -7,7 +7,7 @@
</span><span class="cx"> <div id="first" tabindex="1" onfocus="log(this)">1. First sequentially focusable element outside shadow trees</div>
</span><span class="cx"> <div id="host-with-negative-tabindex" tabindex="-1" onfocus="log(this)">Shadow host with a negative tabindex</div>
</span><span class="cx"> <div id="host-with-no-tabindex" onfocus="log(this)">4.2. Shadow host with no tabindex</div>
</span><del>-<div id="host-with-positive-tabindex" tabindex="2" onfocus="log(this)">2. / 3.2. Shadow host with a positive tabindex</div>
</del><ins>+<div id="host-with-positive-tabindex" tabindex="2" onfocus="log(this)">2. Shadow host with a positive tabindex</div>
</ins><span class="cx"> <div tabindex="0" onfocus="log(this)">5. Last sequentially focusable element outside shadow trees</div>
</span><span class="cx"> </div>
</span><span class="cx"> <pre></pre>
</span><span class="lines">@@ -23,7 +23,7 @@
</span><span class="cx">
</span><span class="cx"> document.getElementById('host-with-positive-tabindex').attachShadow({mode: 'closed'}).innerHTML = `
</span><span class="cx"> <slot></slot>
</span><del>- <div tabindex="0" onfocus="log(this)">3.1. Focusable element inside a shadow host with a positive tabindex</div>
</del><ins>+ <div tabindex="0" onfocus="log(this)">3. Focusable element inside a shadow host with a positive tabindex</div>
</ins><span class="cx"> `;
</span><span class="cx">
</span><span class="cx"> function log(element) {
</span></span></pre></div>
<a id="trunkLayoutTestsfastshadowdomresourceseventpathtesthelpersjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/shadow-dom/resources/event-path-test-helpers.js (0 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/shadow-dom/resources/event-path-test-helpers.js         (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/resources/event-path-test-helpers.js        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -0,0 +1,93 @@
</span><ins>+
+function dispatchEventWithLog(shadow, target, event) {
+ var eventPath = [];
+ var relatedTargets = [];
+ var pathAtTargets = [];
+
+ var attachedNodes = [];
+ for (var nodeKey in shadow) {
+ var startingNode = shadow[nodeKey];
+ for (var node = startingNode; node; node = node.parentNode) {
+ if (attachedNodes.indexOf(node) >= 0)
+ continue;
+ attachedNodes.push(node);
+ node.addEventListener(event.type, (function (event) {
+ eventPath.push(this.label);
+ relatedTargets.push(event.relatedTarget ? event.relatedTarget.label : null);
+
+ if (!event.deepPath) // Don't fail all tests just for the lack of deepPath.
+ return;
+
+ pathAtTargets.push(event.deepPath().map(function (node) { return node.label; }));
+ }).bind(node));
+ }
+ }
+
+ target.dispatchEvent(event);
+
+ return {eventPath: eventPath, relatedTargets: relatedTargets, pathAtTargets: pathAtTargets};
+}
+
+/*
+-SR: ShadowRoot -S: Slot
+A ------------------------------- A-SR
++ B ------------ B-SR + A1 --- A1-SR
+ + C + B1 --- B1-SR + A2-S + A1a
+ + D --- D-SR + B1a + B1b --- B1b-SR
+ + D1 + B1c-S + B1b1
+ + B1b2
+*/
+function createTestTree(mode) {
+ var namedNodes = {};
+
+ function element(name) {
+ var element = document.createElement(name.indexOf('-S') > 0 ? 'slot' : 'div');
+ element.label = name;
+ namedNodes[name] = element;
+ for (var i = 1; i < arguments.length; i++) {
+ var item = arguments[i];
+ if (typeof(item) == 'function')
+ item(element);
+ else
+ element.appendChild(item);
+ }
+ return element;
+ }
+
+ function shadow(name) {
+ var children = [];
+ for (var i = 1; i < arguments.length; i++)
+ children.push(arguments[i]);
+ return function (element) {
+ var shadowRoot = element.attachShadow({mode: mode});
+ shadowRoot.label = name;
+ namedNodes[name] = shadowRoot;
+ for (var child of children)
+ shadowRoot.appendChild(child);
+ }
+ }
+
+ var host = element('A',
+ shadow('A-SR',
+ element('A1',
+ shadow('A1-SR',
+ element('A1a'))),
+ element('A2-S')
+ ),
+ element('B',
+ shadow('B-SR',
+ element('B1',
+ shadow('B1-SR',
+ element('B1b',
+ shadow('B1b-SR',
+ element('B1b1'),
+ element('B1b2'))),
+ element('B1c-S')),
+ element('B1a'))),
+ element('C'),
+ element('D',
+ shadow('D-SR',
+ element('D1')))));
+
+ return namedNodes;
+}
</ins></span></pre></div>
<a id="trunkLayoutTestsfastshadowdomtrustedeventscopedflagsexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/shadow-dom/trusted-event-scoped-flags-expected.txt (0 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/shadow-dom/trusted-event-scoped-flags-expected.txt         (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/trusted-event-scoped-flags-expected.txt        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -0,0 +1,67 @@
</span><ins>+
+world
+PASS input.type = "radio"; log(input, "change"); input.click(); eventType is "change"
+PASS scoped is true
+PASS relatedTargetScoped is false
+
+PASS log(form, "reset"); form.reset(); eventType is "reset"
+PASS scoped is true
+PASS relatedTargetScoped is false
+
+PASS form.focus(); log(input, "focus"); input.focus(); eventType is "focus"
+PASS scoped is false
+PASS relatedTargetScoped is true
+
+PASS log(input, "blur"); form.focus(); eventType is "blur"
+PASS scoped is false
+PASS relatedTargetScoped 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 log(input, "mousedown"); eventSender.mouseDown(); eventType is "mousedown"
+PASS scoped is false
+PASS relatedTargetScoped is false
+
+PASS log(input, "mouseup"); eventSender.mouseUp(); eventType is "mouseup"
+PASS scoped is false
+PASS relatedTargetScoped is false
+
+PASS log(input, "mouseout"); eventSender.mouseMoveTo(0, 0); eventType is "mouseout"
+PASS scoped is false
+PASS relatedTargetScoped is true
+
+PASS log(input, "mouseover"); eventSender.mouseMoveTo(x, y); eventType is "mouseover"
+PASS scoped is false
+PASS relatedTargetScoped 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 log(editableElement, "selectstart"); eventSender.mouseMoveTo(editableElement.offsetLeft + 1, y); eventSender.mouseDown(); eventType is "selectstart"
+PASS scoped is true
+PASS relatedTargetScoped is false
+
+PASS eventType is "load"
+PASS scoped is true
+PASS relatedTargetScoped is false
+
+PASS eventType is "error"
+PASS scoped is true
+PASS relatedTargetScoped is false
+
+PASS eventType is "scroll"
+PASS scoped is true
+PASS relatedTargetScoped is false
+
+PASS eventType is "resize"
+PASS scoped is true
+PASS relatedTargetScoped is false
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastshadowdomtrustedeventscopedflagshtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/shadow-dom/trusted-event-scoped-flags.html (0 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/shadow-dom/trusted-event-scoped-flags.html         (rev 0)
+++ trunk/LayoutTests/fast/shadow-dom/trusted-event-scoped-flags.html        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -0,0 +1,142 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<body>
+<form><input></form>
+<div id="editor" contenteditable>world</div>
+<div id="console"></div>
+<script src="../../resources/js-test-pre.js"></script>
+<script>
+
+var eventType;
+var scoped;
+var relatedTargetScoped;
+
+function logEvent(event) {
+ eventType = event.type;
+ scoped = event.scoped;
+ relatedTargetScoped = event.relatedTargetScoped;
+}
+
+function checkFlags(code, expected) {
+ shouldBeEqualToString(code ? code + '; eventType' : 'eventType', expected.eventType);
+ shouldBe('scoped', expected.scoped.toString());
+ shouldBe('relatedTargetScoped', expected.relatedTargetScoped.toString());
+ debug('');
+}
+
+var lastTarget;
+var lastEventName;
+function log(target, eventName) {
+ eventType = undefined;
+ scoped = undefined;
+ relatedTargetScoped = undefined;
+ if (lastTarget)
+ lastTarget.removeEventListener(lastEventName, logEvent);
+ target.addEventListener(eventName, logEvent);
+ lastTarget = target;
+ lastEventName = eventName;
+}
+
+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('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});
+
+if (!window.eventSender)
+ testFailed('This test requires eventSender');
+else {
+ testRunner.waitUntilDone();
+
+ eventSender.dragMode = false;
+
+ 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});
+
+ 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});
+
+ 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});
+}
+
+function testLoadEvent() {
+ var scriptThatLoads = document.createElement('script');
+ scriptThatLoads.src = "resources/event-path-test-helpers.js";
+ scriptThatLoads.onload = function (event) {
+ logEvent(event);
+ checkFlags('', {eventType: 'load', scoped: true, relatedTargetScoped: false});
+ testErrorEvent();
+ }
+ document.body.appendChild(scriptThatLoads);
+}
+
+function testErrorEvent() {
+ var scriptThatFailsToLoad = document.createElement('script');
+ scriptThatFailsToLoad.src = "bad.js";
+ scriptThatFailsToLoad.onerror = function (event) {
+ logEvent(event);
+ checkFlags('', {eventType: 'error', scoped: true, relatedTargetScoped: false});
+ testScrollEvent();
+ }
+ document.body.appendChild(scriptThatFailsToLoad);
+}
+
+function testScrollEvent() {
+ document.body.style.marginBottom = '1000px';
+ log(window, 'scroll');
+ setTimeout(function () {
+ window.scrollTo(0, 1000);
+ setTimeout(function () {
+ checkFlags('', {eventType: 'scroll', scoped: true, relatedTargetScoped: false});
+ window.scrollTo(0, 0);
+ testResizeEvent();
+ }, 0);
+ }, 0);
+}
+
+function testResizeEvent() {
+ var iframe = document.createElement('iframe');
+ iframe.style.width = '100px';
+ iframe.style.height = '100px';
+
+ iframe.onload = function () {
+ iframe.contentDocument.body.getBoundingClientRect();
+ log(iframe.contentWindow, "resize");
+ setTimeout(function () {
+ iframe.style.width = '200px';
+ iframe.style.height = '200px';
+ iframe.contentDocument.body.getBoundingClientRect();
+ setTimeout(function () {
+ checkFlags('', {eventType: 'resize', scoped: true, relatedTargetScoped: false});
+ finishJSTest();
+ }, 0);
+ }, 0);
+ }
+
+ document.body.appendChild(iframe);
+}
+
+testLoadEvent();
+
+// FIXME: Test abort and loadedmetadata events.
+
+jsTestIsAsync = true;
+
+</script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkLayoutTestsfastxmlhttprequestxmlhttprequestgetexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/xmlhttprequest/xmlhttprequest-get-expected.txt (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/xmlhttprequest/xmlhttprequest-get-expected.txt        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/LayoutTests/fast/xmlhttprequest/xmlhttprequest-get-expected.txt        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -48,6 +48,9 @@
</span><span class="cx"> cancelable : 'false'
</span><span class="cx"> clipboardData : 'undefined'
</span><span class="cx"> currentTarget : '[object XMLHttpRequest]'
</span><ins>+deepPath : 'function deepPath() {
+ [native code]
+}'
</ins><span class="cx"> defaultPrevented : 'false'
</span><span class="cx"> eventPhase : '2'
</span><span class="cx"> initEvent : 'function initEvent() {
</span><span class="lines">@@ -60,7 +63,9 @@
</span><span class="cx"> preventDefault : 'function preventDefault() {
</span><span class="cx"> [native code]
</span><span class="cx"> }'
</span><ins>+relatedTargetScoped : 'false'
</ins><span class="cx"> returnValue : 'true'
</span><ins>+scoped : 'true'
</ins><span class="cx"> srcElement : '[object XMLHttpRequest]'
</span><span class="cx"> stopImmediatePropagation : 'function stopImmediatePropagation() {
</span><span class="cx"> [native code]
</span></span></pre></div>
<a id="trunkLayoutTestshttptestsworkersworkerimportScriptsOnErrorexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/workers/worker-importScriptsOnError-expected.txt (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/workers/worker-importScriptsOnError-expected.txt        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/LayoutTests/http/tests/workers/worker-importScriptsOnError-expected.txt        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx"> clipboardData: undefined,
</span><span class="cx"> colno: 14,
</span><span class="cx"> currentTarget: [object Worker],
</span><ins>+deepPath: function deepPath() { [native code] },
</ins><span class="cx"> defaultPrevented: false,
</span><span class="cx"> eventPhase: 2,
</span><span class="cx"> filename: http://127.0.0.1:8000/workers/resources/worker-importScripts-error.js,
</span><span class="lines">@@ -36,7 +37,9 @@
</span><span class="cx"> lineno: 2,
</span><span class="cx"> message: Error: Script error.,
</span><span class="cx"> preventDefault: function preventDefault() { [native code] },
</span><ins>+relatedTargetScoped: false,
</ins><span class="cx"> returnValue: true,
</span><ins>+scoped: true,
</ins><span class="cx"> srcElement: [object Worker],
</span><span class="cx"> stopImmediatePropagation: function stopImmediatePropagation() { [native code] },
</span><span class="cx"> stopPropagation: function stopPropagation() { [native code] },
</span></span></pre></div>
<a id="trunkLayoutTestsinspectormodelremoteobjectgetpropertiesexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/inspector/model/remote-object-get-properties-expected.txt (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/inspector/model/remote-object-get-properties-expected.txt        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/LayoutTests/inspector/model/remote-object-get-properties-expected.txt        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -48,6 +48,8 @@
</span><span class="cx"> eventPhase
</span><span class="cx"> bubbles
</span><span class="cx"> cancelable
</span><ins>+ scoped
+ relatedTargetScoped
</ins><span class="cx"> timeStamp
</span><span class="cx"> defaultPrevented
</span><span class="cx"> srcElement
</span><span class="lines">@@ -65,12 +67,15 @@
</span><span class="cx"> eventPhase
</span><span class="cx"> bubbles
</span><span class="cx"> cancelable
</span><ins>+ scoped
+ relatedTargetScoped
</ins><span class="cx"> timeStamp
</span><span class="cx"> defaultPrevented
</span><span class="cx"> srcElement
</span><span class="cx"> returnValue
</span><span class="cx"> cancelBubble
</span><span class="cx"> clipboardData
</span><ins>+ deepPath
</ins><span class="cx"> stopPropagation
</span><span class="cx"> preventDefault
</span><span class="cx"> initEvent
</span></span></pre></div>
<a id="trunkLayoutTestsplatformiossimulatorfastshadowdomtrustedeventscopedflagsexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/platform/ios-simulator/fast/shadow-dom/trusted-event-scoped-flags-expected.txt (0 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/ios-simulator/fast/shadow-dom/trusted-event-scoped-flags-expected.txt         (rev 0)
+++ trunk/LayoutTests/platform/ios-simulator/fast/shadow-dom/trusted-event-scoped-flags-expected.txt        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -0,0 +1,67 @@
</span><ins>+
+world
+PASS input.type = "radio"; log(input, "change"); input.click(); eventType is "change"
+PASS scoped is true
+PASS relatedTargetScoped is false
+
+PASS log(form, "reset"); form.reset(); eventType is "reset"
+PASS scoped is true
+PASS relatedTargetScoped is false
+
+PASS form.focus(); log(input, "focus"); input.focus(); eventType is "focus"
+PASS scoped is false
+PASS relatedTargetScoped is true
+
+PASS log(input, "blur"); form.focus(); eventType is "blur"
+PASS scoped is false
+PASS relatedTargetScoped is true
+
+FAIL input.type = "text"; log(input, "mousemove"); eventSender.mouseMoveTo(x, y); eventType should be mousemove (of type string). Was undefined (of type undefined).
+FAIL scoped should be false (of type boolean). Was undefined (of type undefined).
+FAIL relatedTargetScoped should be false (of type boolean). Was undefined (of type undefined).
+
+FAIL log(input, "mousedown"); eventSender.mouseDown(); eventType should be mousedown (of type string). Was undefined (of type undefined).
+FAIL scoped should be false (of type boolean). Was undefined (of type undefined).
+FAIL relatedTargetScoped should be false (of type boolean). Was undefined (of type undefined).
+
+FAIL log(input, "mouseup"); eventSender.mouseUp(); eventType should be mouseup (of type string). Was undefined (of type undefined).
+FAIL scoped should be false (of type boolean). Was undefined (of type undefined).
+FAIL relatedTargetScoped should be false (of type boolean). Was undefined (of type undefined).
+
+FAIL log(input, "mouseout"); eventSender.mouseMoveTo(0, 0); eventType should be mouseout (of type string). Was undefined (of type undefined).
+FAIL scoped should be false (of type boolean). Was undefined (of type undefined).
+FAIL relatedTargetScoped should be true (of type boolean). Was undefined (of type undefined).
+
+FAIL log(input, "mouseover"); eventSender.mouseMoveTo(x, y); eventType should be mouseover (of type string). Was undefined (of type undefined).
+FAIL scoped should be false (of type boolean). Was undefined (of type undefined).
+FAIL relatedTargetScoped should be true (of type boolean). Was undefined (of type undefined).
+
+input.value = "hello"; eventSender.mouseMoveTo(input.offsetLeft + 1, y); eventSender.mouseDown();
+FAIL log(input, "select"); eventSender.mouseMoveTo(input.offsetLeft + input.offsetWidth - 2, y); eventSender.mouseUp(); eventType should be select (of type string). Was undefined (of type undefined).
+FAIL scoped should be true (of type boolean). Was undefined (of type undefined).
+FAIL relatedTargetScoped should be false (of type boolean). Was undefined (of type undefined).
+
+FAIL log(editableElement, "selectstart"); eventSender.mouseMoveTo(editableElement.offsetLeft + 1, y); eventSender.mouseDown(); eventType should be selectstart (of type string). Was undefined (of type undefined).
+FAIL scoped should be true (of type boolean). Was undefined (of type undefined).
+FAIL relatedTargetScoped should be false (of type boolean). Was undefined (of type undefined).
+
+PASS eventType is "load"
+PASS scoped is true
+PASS relatedTargetScoped is false
+
+PASS eventType is "error"
+PASS scoped is true
+PASS relatedTargetScoped is false
+
+PASS eventType is "scroll"
+PASS scoped is true
+PASS relatedTargetScoped is false
+
+PASS eventType is "resize"
+PASS scoped is true
+PASS relatedTargetScoped is false
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/Source/WebCore/ChangeLog        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -1,3 +1,60 @@
</span><ins>+2016-03-11 Ryosuke Niwa <rniwa@webkit.org>
+
+ Add Event.deepPath() and Event.scoped
+ https://bugs.webkit.org/show_bug.cgi?id=153538
+ <rdar://problem/24363836>
+
+ Reviewed by Darin Adler.
+
+ Added the support for deepPath(), scoped, and relatedTargetScoped on Event.prototype for shadow DOM:
+ http://w3c.github.io/webcomponents/spec/shadow/#extensions-to-event-interface
+ and updated the EventPath class to respect scoped and relatedTargetScoped flags as specified at:
+ http://w3c.github.io/webcomponents/spec/shadow/#get-the-parent
+
+ Tests: fast/shadow-dom/Extensions-to-Event-Interface.html
+ fast/shadow-dom/trusted-event-scoped-flags.html
+
+ * bindings/scripts/CodeGeneratorJS.pm:
+ (GenerateConstructorDefinition): Added the support for Conditional for InitializedByEventConstructor.
+ * bindings/scripts/test/GObject/WebKitDOMTestEventConstructor.cpp:
+ * bindings/scripts/test/GObject/WebKitDOMTestEventConstructor.h:
+ * bindings/scripts/test/JS/JSTestEventConstructor.cpp:
+ * bindings/scripts/test/ObjC/DOMTestEventConstructor.h:
+ * bindings/scripts/test/ObjC/DOMTestEventConstructor.mm:
+ * bindings/scripts/test/TestEventConstructor.idl: Added a test case for using InitializedByEventConstructor
+ with Conditional.
+ * dom/Event.cpp:
+ (WebCore::Event::Event): Initialize m_scoped and m_relatedTargetScoped from EventInit dictionary.
+ (WebCore::Event::scoped): Added. Implements http://w3c.github.io/webcomponents/spec/shadow/#scoped-flag
+ (WebCore::Event::deepPath): Added.
+ * dom/Event.h:
+ (WebCore::Event::relatedTargetScoped): Added. Overridden by FocusEvent and MouseEvent to implement
+ http://w3c.github.io/webcomponents/spec/shadow/#relatedtargetscoped-flag
+ (WebCore::Event::setEventPath): Added.
+ (WebCore::Event::clearEventPath): Added.
+ * dom/Event.idl: Added scoped, relatedTargetScoped, and deepPath() conditionally enabled for shadow DOM.
+ * dom/EventContext.h:
+ (WebCore::EventContext::currentTarget):
+ * dom/EventDispatcher.cpp:
+ (WebCore::EventDispatcher::dispatchEvent): Set the event path while the event is being dispatched.
+ * dom/EventPath.cpp:
+ (WebCore::shouldEventCrossShadowBoundary): Check event.scoped flag instead of hard-coding a list of events here
+ which has been moved to Event::scoped. See above.
+ (WebCore::EventPath::setRelatedTarget): Check m_event.relatedTargetScoped() instead of hard-coding a list of
+ events here. relatedTargetScoped is overridden by FocusEvent and MouseEvent.
+ (WebCore::EventPath::hasEventListeners): Fixed the misleading variable name.
+ (WebCore::isUnclosedNodeOf): Added. Implements http://w3c.github.io/webcomponents/spec/shadow/#dfn-unclosed-node
+ (WebCore::EventPath::computePathDisclosedToTarget): Added. Implements the algorithm to filter event targets:
+ http://w3c.github.io/webcomponents/spec/shadow/#widl-Event-deepPath-sequence-EventTarget
+ * dom/EventPath.h:
+ * dom/FocusEvent.cpp:
+ (WebCore::FocusEvent::relatedTargetScoped): Returns true when this is a trusted event per:
+ http://w3c.github.io/webcomponents/spec/shadow/#relatedtargetscoped-flag
+ * dom/FocusEvent.h:
+ * dom/MouseEvent.cpp:
+ (WebCore::MouseEvent::relatedTargetScoped): Ditto.
+ * dom/MouseEvent.h:
+
</ins><span class="cx"> 2016-03-11 John Wilander <wilander@apple.com>
</span><span class="cx">
</span><span class="cx"> Move prevalent resource classifier from WebCore to WebKit.
</span></span></pre></div>
<a id="trunkSourceWebCorebindingsscriptsCodeGeneratorJSpm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -4856,10 +4856,16 @@
</span><span class="cx"> if ($attribute->signature->extendedAttributes->{"InitializedByEventConstructor"}) {
</span><span class="cx"> my $attributeName = $attribute->signature->name;
</span><span class="cx"> my $attributeImplName = $attribute->signature->extendedAttributes->{"ImplementedAs"} || $attributeName;
</span><ins>+ my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
+
+ push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
+
</ins><span class="cx"> push(@implContent, <<END);
</span><span class="cx"> if (!dictionary.tryGetProperty("${attributeName}", eventInit.${attributeImplName}))
</span><span class="cx"> return false;
</span><span class="cx"> END
</span><ins>+ push(@implContent, "#endif\n") if $conditionalString;
+
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceWebCorebindingsscriptstestGObjectWebKitDOMTestEventConstructorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/bindings/scripts/test/GObject/WebKitDOMTestEventConstructor.cpp (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/bindings/scripts/test/GObject/WebKitDOMTestEventConstructor.cpp        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/Source/WebCore/bindings/scripts/test/GObject/WebKitDOMTestEventConstructor.cpp        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -71,6 +71,7 @@
</span><span class="cx"> PROP_0,
</span><span class="cx"> PROP_ATTR1,
</span><span class="cx"> PROP_ATTR2,
</span><ins>+ PROP_ATTR3,
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> static void webkit_dom_test_event_constructor_finalize(GObject* object)
</span><span class="lines">@@ -94,6 +95,9 @@
</span><span class="cx"> case PROP_ATTR2:
</span><span class="cx"> g_value_take_string(value, webkit_dom_test_event_constructor_get_attr2(self));
</span><span class="cx"> break;
</span><ins>+ case PROP_ATTR3:
+ g_value_take_string(value, webkit_dom_test_event_constructor_get_attr3(self));
+ break;
</ins><span class="cx"> default:
</span><span class="cx"> G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propertyId, pspec);
</span><span class="cx"> break;
</span><span class="lines">@@ -139,6 +143,16 @@
</span><span class="cx"> "",
</span><span class="cx"> WEBKIT_PARAM_READABLE));
</span><span class="cx">
</span><ins>+ g_object_class_install_property(
+ gobjectClass,
+ PROP_ATTR3,
+ g_param_spec_string(
+ "attr3",
+ "TestEventConstructor:attr3",
+ "read-only gchar* TestEventConstructor:attr3",
+ "",
+ WEBKIT_PARAM_READABLE));
+
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> static void webkit_dom_test_event_constructor_init(WebKitDOMTestEventConstructor* request)
</span><span class="lines">@@ -165,3 +179,18 @@
</span><span class="cx"> return result;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+gchar* webkit_dom_test_event_constructor_get_attr3(WebKitDOMTestEventConstructor* self)
+{
+#if ENABLE(SPECIAL_EVENT)
+ WebCore::JSMainThreadNullState state;
+ g_return_val_if_fail(WEBKIT_DOM_IS_TEST_EVENT_CONSTRUCTOR(self), 0);
+ WebCore::TestEventConstructor* item = WebKit::core(self);
+ gchar* result = convertToUTF8String(item->attr3());
+ return result;
+#else
+ UNUSED_PARAM(self);
+ WEBKIT_WARN_FEATURE_NOT_PRESENT("Special Event")
+ return 0;
+#endif /* ENABLE(SPECIAL_EVENT) */
+}
+
</ins></span></pre></div>
<a id="trunkSourceWebCorebindingsscriptstestGObjectWebKitDOMTestEventConstructorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/bindings/scripts/test/GObject/WebKitDOMTestEventConstructor.h (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/bindings/scripts/test/GObject/WebKitDOMTestEventConstructor.h        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/Source/WebCore/bindings/scripts/test/GObject/WebKitDOMTestEventConstructor.h        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -69,6 +69,17 @@
</span><span class="cx"> WEBKIT_API gchar*
</span><span class="cx"> webkit_dom_test_event_constructor_get_attr2(WebKitDOMTestEventConstructor* self);
</span><span class="cx">
</span><ins>+/**
+ * webkit_dom_test_event_constructor_get_attr3:
+ * @self: A #WebKitDOMTestEventConstructor
+ *
+ * Returns: A #gchar
+ *
+ * Stability: Unstable
+**/
+WEBKIT_API gchar*
+webkit_dom_test_event_constructor_get_attr3(WebKitDOMTestEventConstructor* self);
+
</ins><span class="cx"> G_END_DECLS
</span><span class="cx">
</span><span class="cx"> #endif /* WEBKIT_DOM_USE_UNSTABLE_API */
</span></span></pre></div>
<a id="trunkSourceWebCorebindingsscriptstestJSJSTestEventConstructorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/bindings/scripts/test/JS/JSTestEventConstructor.cpp (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/bindings/scripts/test/JS/JSTestEventConstructor.cpp        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/Source/WebCore/bindings/scripts/test/JS/JSTestEventConstructor.cpp        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -38,6 +38,9 @@
</span><span class="cx">
</span><span class="cx"> JSC::EncodedJSValue jsTestEventConstructorAttr1(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
</span><span class="cx"> JSC::EncodedJSValue jsTestEventConstructorAttr2(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
</span><ins>+#if ENABLE(SPECIAL_EVENT)
+JSC::EncodedJSValue jsTestEventConstructorAttr3(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
+#endif
</ins><span class="cx"> JSC::EncodedJSValue jsTestEventConstructorConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
</span><span class="cx"> bool setJSTestEventConstructorConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);
</span><span class="cx">
</span><span class="lines">@@ -106,6 +109,10 @@
</span><span class="cx"> {
</span><span class="cx"> if (!dictionary.tryGetProperty("attr2", eventInit.attr2))
</span><span class="cx"> return false;
</span><ins>+#if ENABLE(SPECIAL_EVENT)
+ if (!dictionary.tryGetProperty("attr3", eventInit.attr3))
+ return false;
+#endif
</ins><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -131,6 +138,11 @@
</span><span class="cx"> { "constructor", DontEnum, NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsTestEventConstructorConstructor), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(setJSTestEventConstructorConstructor) } },
</span><span class="cx"> { "attr1", ReadOnly | CustomAccessor, NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsTestEventConstructorAttr1), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(0) } },
</span><span class="cx"> { "attr2", ReadOnly | CustomAccessor, NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsTestEventConstructorAttr2), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(0) } },
</span><ins>+#if ENABLE(SPECIAL_EVENT)
+ { "attr3", ReadOnly | CustomAccessor, NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsTestEventConstructorAttr3), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(0) } },
+#else
+ { 0, 0, NoIntrinsic, { 0, 0 } },
+#endif
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> const ClassInfo JSTestEventConstructorPrototype::s_info = { "TestEventConstructorPrototype", &Base::s_info, 0, CREATE_METHOD_TABLE(JSTestEventConstructorPrototype) };
</span><span class="lines">@@ -194,6 +206,23 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx">
</span><ins>+#if ENABLE(SPECIAL_EVENT)
+EncodedJSValue jsTestEventConstructorAttr3(ExecState* state, EncodedJSValue thisValue, PropertyName)
+{
+ UNUSED_PARAM(state);
+ UNUSED_PARAM(thisValue);
+ JSValue decodedThisValue = JSValue::decode(thisValue);
+ auto* castedThis = jsDynamicCast<JSTestEventConstructor*>(decodedThisValue);
+ if (UNLIKELY(!castedThis)) {
+ return throwGetterTypeError(*state, "TestEventConstructor", "attr3");
+ }
+ auto& impl = castedThis->wrapped();
+ JSValue result = jsStringWithCache(state, impl.attr3());
+ return JSValue::encode(result);
+}
+
+#endif
+
</ins><span class="cx"> EncodedJSValue jsTestEventConstructorConstructor(ExecState* state, EncodedJSValue thisValue, PropertyName)
</span><span class="cx"> {
</span><span class="cx"> JSTestEventConstructorPrototype* domObject = jsDynamicCast<JSTestEventConstructorPrototype*>(JSValue::decode(thisValue));
</span></span></pre></div>
<a id="trunkSourceWebCorebindingsscriptstestObjCDOMTestEventConstructorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/bindings/scripts/test/ObjC/DOMTestEventConstructor.h (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/bindings/scripts/test/ObjC/DOMTestEventConstructor.h        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/Source/WebCore/bindings/scripts/test/ObjC/DOMTestEventConstructor.h        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -32,4 +32,5 @@
</span><span class="cx"> WEBCORE_EXPORT @interface DOMTestEventConstructor : DOMObject
</span><span class="cx"> @property (readonly, copy) NSString *attr1;
</span><span class="cx"> @property (readonly, copy) NSString *attr2;
</span><ins>+@property (readonly, copy) NSString *attr3;
</ins><span class="cx"> @end
</span></span></pre></div>
<a id="trunkSourceWebCorebindingsscriptstestObjCDOMTestEventConstructormm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/bindings/scripts/test/ObjC/DOMTestEventConstructor.mm (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/bindings/scripts/test/ObjC/DOMTestEventConstructor.mm        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/Source/WebCore/bindings/scripts/test/ObjC/DOMTestEventConstructor.mm        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -67,6 +67,14 @@
</span><span class="cx"> return IMPL->attr2();
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+#if ENABLE(SPECIAL_EVENT)
+- (NSString *)attr3
+{
+ WebCore::JSMainThreadNullState state;
+ return IMPL->attr3();
+}
+#endif
+
</ins><span class="cx"> @end
</span><span class="cx">
</span><span class="cx"> WebCore::TestEventConstructor* core(DOMTestEventConstructor *wrapper)
</span></span></pre></div>
<a id="trunkSourceWebCorebindingsscriptstestTestEventConstructoridl"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/bindings/scripts/test/TestEventConstructor.idl (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/bindings/scripts/test/TestEventConstructor.idl        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/Source/WebCore/bindings/scripts/test/TestEventConstructor.idl        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -34,4 +34,5 @@
</span><span class="cx"> // Attributes
</span><span class="cx"> readonly attribute DOMString attr1;
</span><span class="cx"> [InitializedByEventConstructor] readonly attribute DOMString attr2;
</span><ins>+ [InitializedByEventConstructor, Conditional=SPECIAL_EVENT] readonly attribute DOMString attr3;
</ins><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceWebCoredomEventcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Event.cpp (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Event.cpp        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/Source/WebCore/dom/Event.cpp        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -23,6 +23,7 @@
</span><span class="cx"> #include "config.h"
</span><span class="cx"> #include "Event.h"
</span><span class="cx">
</span><ins>+#include "EventPath.h"
</ins><span class="cx"> #include "EventTarget.h"
</span><span class="cx"> #include "UserGestureIndicator.h"
</span><span class="cx"> #include <wtf/CurrentTime.h>
</span><span class="lines">@@ -59,6 +60,8 @@
</span><span class="cx"> , m_type(eventType)
</span><span class="cx"> , m_canBubble(initializer.bubbles)
</span><span class="cx"> , m_cancelable(initializer.cancelable)
</span><ins>+ , m_scoped(initializer.scoped)
+ , m_relatedTargetScoped(initializer.relatedTargetScoped)
</ins><span class="cx"> , m_createTime(convertSecondsToDOMTimeStamp(currentTime()))
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="lines">@@ -83,6 +86,26 @@
</span><span class="cx"> m_cancelable = cancelableArg;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+bool Event::scoped() const
+{
+ if (m_scoped)
+ 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;
+}
+
</ins><span class="cx"> EventInterface Event::eventInterface() const
</span><span class="cx"> {
</span><span class="cx"> return EventInterfaceType;
</span><span class="lines">@@ -163,6 +186,13 @@
</span><span class="cx"> receivedTarget();
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+Vector<EventTarget*> Event::deepPath() const
+{
+ if (!m_eventPath)
+ return Vector<EventTarget*>();
+ return m_eventPath->computePathDisclosedToTarget(*m_target);
+}
+
</ins><span class="cx"> void Event::receivedTarget()
</span><span class="cx"> {
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCoredomEventh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Event.h (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Event.h        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/Source/WebCore/dom/Event.h        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -36,12 +36,15 @@
</span><span class="cx"> namespace WebCore {
</span><span class="cx">
</span><span class="cx"> class DataTransfer;
</span><ins>+class EventPath;
</ins><span class="cx"> class EventTarget;
</span><span class="cx"> class HTMLIFrameElement;
</span><span class="cx">
</span><span class="cx"> struct EventInit {
</span><span class="cx"> bool bubbles { false };
</span><span class="cx"> bool cancelable { false };
</span><ins>+ bool scoped { false };
+ bool relatedTargetScoped { false };
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> enum EventInterface {
</span><span class="lines">@@ -114,8 +117,15 @@
</span><span class="cx">
</span><span class="cx"> bool bubbles() const { return m_canBubble; }
</span><span class="cx"> bool cancelable() const { return m_cancelable; }
</span><ins>+ bool scoped() const;
+ virtual bool relatedTargetScoped() const { return m_relatedTargetScoped; }
+
</ins><span class="cx"> DOMTimeStamp timeStamp() const { return m_createTime; }
</span><span class="cx">
</span><ins>+ void setEventPath(const EventPath& path) { m_eventPath = &path; }
+ void clearEventPath() { m_eventPath = nullptr; }
+ Vector<EventTarget*> deepPath() const;
+
</ins><span class="cx"> void stopPropagation() { m_propagationStopped = true; }
</span><span class="cx"> void stopImmediatePropagation() { m_immediatePropagationStopped = true; }
</span><span class="cx">
</span><span class="lines">@@ -198,6 +208,8 @@
</span><span class="cx"> AtomicString m_type;
</span><span class="cx"> bool m_canBubble { false };
</span><span class="cx"> bool m_cancelable { false };
</span><ins>+ bool m_scoped { false };
+ bool m_relatedTargetScoped { false };
</ins><span class="cx">
</span><span class="cx"> bool m_propagationStopped { false };
</span><span class="cx"> bool m_immediatePropagationStopped { false };
</span><span class="lines">@@ -208,6 +220,7 @@
</span><span class="cx">
</span><span class="cx"> unsigned short m_eventPhase { 0 };
</span><span class="cx"> EventTarget* m_currentTarget { nullptr };
</span><ins>+ const EventPath* m_eventPath { nullptr };
</ins><span class="cx"> RefPtr<EventTarget> m_target;
</span><span class="cx"> DOMTimeStamp m_createTime;
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceWebCoredomEventidl"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Event.idl (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Event.idl        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/Source/WebCore/dom/Event.idl        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -57,8 +57,12 @@
</span><span class="cx"> readonly attribute unsigned short eventPhase;
</span><span class="cx"> [InitializedByEventConstructor] readonly attribute boolean bubbles;
</span><span class="cx"> [InitializedByEventConstructor] readonly attribute boolean cancelable;
</span><ins>+ [InitializedByEventConstructor, Conditional=SHADOW_DOM, EnabledAtRuntime=ShadowDOM] readonly attribute boolean scoped;
+ [InitializedByEventConstructor, Conditional=SHADOW_DOM, EnabledAtRuntime=ShadowDOM] readonly attribute boolean relatedTargetScoped;
</ins><span class="cx"> readonly attribute DOMTimeStamp timeStamp;
</span><span class="cx">
</span><ins>+ [Conditional=SHADOW_DOM, EnabledAtRuntime=ShadowDOM] sequence<Node> deepPath();
+
</ins><span class="cx"> void stopPropagation();
</span><span class="cx"> void preventDefault();
</span><span class="cx"> [ObjCLegacyUnnamedParameters] void initEvent([Default=Undefined] optional DOMString eventTypeArg,
</span></span></pre></div>
<a id="trunkSourceWebCoredomEventContexth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/EventContext.h (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/EventContext.h        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/Source/WebCore/dom/EventContext.h        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -47,6 +47,7 @@
</span><span class="cx"> virtual ~EventContext();
</span><span class="cx">
</span><span class="cx"> Node* node() const { return m_node.get(); }
</span><ins>+ EventTarget* currentTarget() const { return m_currentTarget.get(); }
</ins><span class="cx"> EventTarget* target() const { return m_target.get(); }
</span><span class="cx"> bool currentTargetSameAsTarget() const { return m_currentTarget.get() == m_target.get(); }
</span><span class="cx"> virtual void handleLocalEvents(Event&) const;
</span></span></pre></div>
<a id="trunkSourceWebCoredomEventDispatchercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/EventDispatcher.cpp (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/EventDispatcher.cpp        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/Source/WebCore/dom/EventDispatcher.cpp        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -177,8 +177,11 @@
</span><span class="cx"> if (is<HTMLInputElement>(*node))
</span><span class="cx"> downcast<HTMLInputElement>(*node).willDispatchEvent(event, clickHandlingState);
</span><span class="cx">
</span><del>- if (!event.propagationStopped() && !eventPath.isEmpty())
</del><ins>+ if (!event.propagationStopped() && !eventPath.isEmpty()) {
+ event.setEventPath(eventPath);
</ins><span class="cx"> dispatchEventInDOM(event, eventPath, windowEventContext);
</span><ins>+ event.clearEventPath();
+ }
</ins><span class="cx">
</span><span class="cx"> event.setTarget(EventPath::eventTargetRespectingTargetRules(*node));
</span><span class="cx"> event.setCurrentTarget(nullptr);
</span></span></pre></div>
<a id="trunkSourceWebCoredomEventPathcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/EventPath.cpp (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/EventPath.cpp        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/Source/WebCore/dom/EventPath.cpp        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -49,21 +49,8 @@
</span><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="cx">
</span><del>- // 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.
- const AtomicString& eventType = event.type();
</del><span class="cx"> bool targetIsInShadowRoot = targetNode && &targetNode->treeScope().rootNode() == &shadowRoot;
</span><del>- return !targetIsInShadowRoot
- || !(eventType == eventNames().abortEvent
- || eventType == eventNames().changeEvent
- || eventType == eventNames().errorEvent
- || eventType == eventNames().loadEvent
- || eventType == eventNames().resetEvent
- || eventType == eventNames().resizeEvent
- || eventType == eventNames().scrollEvent
- || eventType == eventNames().selectEvent
- || eventType == eventNames().selectstartEvent);
</del><ins>+ return !targetIsInShadowRoot || !event.scoped();
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> static Node* nodeOrHostIfPseudoElement(Node* node)
</span><span class="lines">@@ -174,10 +161,7 @@
</span><span class="cx"> RelatedNodeRetargeter retargeter(*relatedNode, downcast<MouseOrFocusEventContext>(*m_path[0]).node()->treeScope());
</span><span class="cx">
</span><span class="cx"> bool originIsRelatedTarget = &origin == relatedNode;
</span><del>- // FIXME: We should add a new flag on Event instead.
- bool shouldTrimEventPath = m_event.type() == eventNames().mouseoverEvent
- || m_event.type() == eventNames().mousemoveEvent
- || m_event.type() == eventNames().mouseoutEvent;
</del><ins>+ bool relatedTargetScoped = m_event.relatedTargetScoped();
</ins><span class="cx"> Node& rootNodeInOriginTreeScope = origin.treeScope().rootNode();
</span><span class="cx"> TreeScope* previousTreeScope = nullptr;
</span><span class="cx"> size_t originalEventPathSize = m_path.size();
</span><span class="lines">@@ -189,14 +173,14 @@
</span><span class="cx"> retargeter.moveToNewTreeScope(previousTreeScope, currentTreeScope);
</span><span class="cx">
</span><span class="cx"> Node* currentRelatedNode = retargeter.currentNode(currentTreeScope);
</span><del>- if (UNLIKELY(shouldTrimEventPath && !originIsRelatedTarget && context.target() == currentRelatedNode)) {
</del><ins>+ if (UNLIKELY(relatedTargetScoped && !originIsRelatedTarget && context.target() == currentRelatedNode)) {
</ins><span class="cx"> m_path.shrink(contextIndex);
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> context.setRelatedTarget(currentRelatedNode);
</span><span class="cx">
</span><del>- if (UNLIKELY(shouldTrimEventPath && originIsRelatedTarget && context.node() == &rootNodeInOriginTreeScope)) {
</del><ins>+ if (UNLIKELY(relatedTargetScoped && originIsRelatedTarget && context.node() == &rootNodeInOriginTreeScope)) {
</ins><span class="cx"> m_path.shrink(contextIndex + 1);
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="lines">@@ -251,14 +235,53 @@
</span><span class="cx">
</span><span class="cx"> bool EventPath::hasEventListeners(const AtomicString& eventType) const
</span><span class="cx"> {
</span><del>- for (auto& eventPath : m_path) {
- if (eventPath->node()->hasEventListeners(eventType))
</del><ins>+ for (auto& context : m_path) {
+ if (context->node()->hasEventListeners(eventType))
</ins><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> return false;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+// http://w3c.github.io/webcomponents/spec/shadow/#dfn-unclosed-node
+static bool isUnclosedNodeOf(const Node& a, const Node& b)
+{
+ // Use Vector instead of HashSet since we expect the number of ancestor tree scopes to be small.
+ Vector<TreeScope*, 8> treeScopesOpenToB;
+
+ for (auto* scope = &b.treeScope(); scope; scope = scope->parentTreeScope())
+ treeScopesOpenToB.append(scope);
+
+ for (auto* treeScopeThatCanAccessA = &a.treeScope(); treeScopeThatCanAccessA; treeScopeThatCanAccessA = treeScopeThatCanAccessA->parentTreeScope()) {
+ for (auto* openToB : treeScopesOpenToB) {
+ if (openToB == treeScopeThatCanAccessA)
+ return true;
+ }
+ auto& root = treeScopeThatCanAccessA->rootNode();
+ if (is<ShadowRoot>(root) && downcast<ShadowRoot>(root).type() != ShadowRoot::Type::Open)
+ break;
+ }
+
+ return false;
+}
+
+Vector<EventTarget*> EventPath::computePathDisclosedToTarget(const EventTarget& target) const
+{
+ Vector<EventTarget*> path;
+ const Node* targetNode = const_cast<EventTarget&>(target).toNode();
+ if (!targetNode)
+ return path;
+
+ for (auto& context : m_path) {
+ if (Node* nodeInPath = context->currentTarget()->toNode()) {
+ if (isUnclosedNodeOf(*nodeInPath, *targetNode))
+ path.append(context->currentTarget());
+ }
+ }
+
+ return path;
+}
+
</ins><span class="cx"> RelatedNodeRetargeter::RelatedNodeRetargeter(Node& relatedNode, TreeScope& targetTreeScope)
</span><span class="cx"> : m_relatedNode(relatedNode)
</span><span class="cx"> , m_retargetedRelatedNode(&relatedNode)
</span></span></pre></div>
<a id="trunkSourceWebCoredomEventPathh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/EventPath.h (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/EventPath.h        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/Source/WebCore/dom/EventPath.h        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -48,6 +48,8 @@
</span><span class="cx">
</span><span class="cx"> EventContext* lastContextIfExists() { return m_path.isEmpty() ? nullptr : m_path.last().get(); }
</span><span class="cx">
</span><ins>+ Vector<EventTarget*> computePathDisclosedToTarget(const EventTarget&) const;
+
</ins><span class="cx"> static EventTarget* eventTargetRespectingTargetRules(Node& referenceNode)
</span><span class="cx"> {
</span><span class="cx"> if (is<PseudoElement>(referenceNode))
</span></span></pre></div>
<a id="trunkSourceWebCoredomFocusEventcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/FocusEvent.cpp (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/FocusEvent.cpp        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/Source/WebCore/dom/FocusEvent.cpp        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -52,4 +52,9 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+bool FocusEvent::relatedTargetScoped() const
+{
+ return (isTrusted() && m_relatedTarget) || UIEvent::relatedTargetScoped();
+}
+
</ins><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoredomFocusEventh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/FocusEvent.h (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/FocusEvent.h        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/Source/WebCore/dom/FocusEvent.h        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -58,6 +58,8 @@
</span><span class="cx"> FocusEvent(const AtomicString& type, bool canBubble, bool cancelable, AbstractView*, int, RefPtr<EventTarget>&&);
</span><span class="cx"> FocusEvent(const AtomicString& type, const FocusEventInit&);
</span><span class="cx">
</span><ins>+ bool relatedTargetScoped() const override;
+
</ins><span class="cx"> bool isFocusEvent() const override;
</span><span class="cx">
</span><span class="cx"> RefPtr<EventTarget> m_relatedTarget;
</span></span></pre></div>
<a id="trunkSourceWebCoredomMouseEventcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/MouseEvent.cpp (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/MouseEvent.cpp        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/Source/WebCore/dom/MouseEvent.cpp        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -189,6 +189,11 @@
</span><span class="cx"> return event.type() == eventNames().clickEvent && (!is<MouseEvent>(event) || downcast<MouseEvent>(event).button() != RightButton);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+bool MouseEvent::relatedTargetScoped() const
+{
+ return (isTrusted() && m_relatedTarget) || UIEvent::relatedTargetScoped();
+}
+
</ins><span class="cx"> int MouseEvent::which() const
</span><span class="cx"> {
</span><span class="cx"> // For the DOM, the return values for left, middle and right mouse buttons are 0, 1, 2, respectively.
</span></span></pre></div>
<a id="trunkSourceWebCoredomMouseEventh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/MouseEvent.h (198055 => 198056)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/MouseEvent.h        2016-03-12 00:36:17 UTC (rev 198055)
+++ trunk/Source/WebCore/dom/MouseEvent.h        2016-03-12 03:11:04 UTC (rev 198056)
</span><span class="lines">@@ -121,6 +121,8 @@
</span><span class="cx">
</span><span class="cx"> MouseEvent();
</span><span class="cx">
</span><ins>+ bool relatedTargetScoped() const override;
+
</ins><span class="cx"> private:
</span><span class="cx"> unsigned short m_button;
</span><span class="cx"> bool m_buttonDown;
</span></span></pre>
</div>
</div>
</body>
</html>