Changeset 198056 in webkit


Ignore:
Timestamp:
Mar 11, 2016 7:11:04 PM (8 years ago)
Author:
rniwa@webkit.org
Message:

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.
Location:
trunk
Files:
8 added
26 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r198050 r198056  
     12016-03-11  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Add Event.deepPath() and Event.scoped
     4        https://bugs.webkit.org/show_bug.cgi?id=153538
     5        <rdar://problem/24363836>
     6
     7        Reviewed by Darin Adler.
     8
     9        Added a W3C style testharness.js tests for Event.prototype.scoped, Event.prototype.scopedRelatedTarget,
     10        Event.prototype.deepPath() and a test that uses eventSender to verify the values of the scoped and
     11        scopedRelatedTarget flags on trusted events.
     12
     13        * fast/shadow-dom/Extensions-to-Event-Interface-expected.txt: Added.
     14        * fast/shadow-dom/Extensions-to-Event-Interface.html: Added.
     15        * fast/shadow-dom/event-with-related-target.html:
     16        * fast/shadow-dom/resources: Added.
     17        * fast/shadow-dom/resources/event-path-test-helpers.js: Added. Extracted from event-with-related-target.html.
     18        * fast/shadow-dom/trusted-event-scoped-flags-expected.txt: Added.
     19        * fast/shadow-dom/trusted-event-scoped-flags.html: Added.
     20        * fast/xmlhttprequest/xmlhttprequest-get-expected.txt:
     21        * http/tests/workers/worker-importScriptsOnError-expected.txt:
     22        * inspector/model/remote-object-get-properties-expected.txt:
     23        * platform/ios-simulator/fast/shadow-dom/trusted-event-scoped-flags-expected.txt: Added.
     24
    1252016-03-11  Jiewen Tan  <jiewen_tan@apple.com>
    226
  • trunk/LayoutTests/fast/shadow-dom/event-with-related-target.html

    r190288 r198056  
    88    <script src="../../resources/testharness.js"></script>
    99    <script src="../../resources/testharnessreport.js"></script>
     10    <script src="resources/event-path-test-helpers.js"></script>
    1011    <link rel='stylesheet' href='../../resources/testharness.css'>
    1112</head>
     
    1314    <div id="log"></div>
    1415    <script>
    15 
    16         function dispatchEventWithLog(shadow, target, event) {
    17             var eventPath = [];
    18             var relatedTargets = [];
    19 
    20             var attachedNodes = [];
    21             for (var nodeKey in shadow) {
    22                 var startingNode = shadow[nodeKey];
    23                 for (var node = startingNode; node; node = node.parentNode) {
    24                     if (attachedNodes.indexOf(node) >= 0)
    25                         continue;
    26                     attachedNodes.push(node);
    27                     node.addEventListener(event.type, (function (event) {
    28                         eventPath.push(this.label);
    29                         relatedTargets.push(event.relatedTarget.label);
    30                     }).bind(node));
    31                 }
    32             }
    33 
    34             target.dispatchEvent(event);
    35 
    36             return {eventPath: eventPath, relatedTargets: relatedTargets};
    37         }
    38 
    39         /*
    40         -SR: ShadowRoot  -S: Slot
    41         A ------------------------------- A-SR
    42         + B ------------ B-SR             + A1 --- A1-SR
    43           + C            + B1 --- B1-SR   + A2-S   + A1a
    44           + D --- D-SR   + B1a    + B1b --- B1b-SR
    45                   + D1            + B1c-S   + B1b1
    46                                             + B1b2
    47         */
    48         function createTestTree(mode) {
    49             var namedNodes = {};
    50 
    51             function element(name) {
    52                 var element = document.createElement(name.indexOf('-S') > 0 ? 'slot' : 'div');
    53                 element.label = name;
    54                 namedNodes[name] = element;
    55                 for (var i = 1; i < arguments.length; i++) {
    56                     var item = arguments[i];
    57                     if (typeof(item) == 'function')
    58                         item(element);
    59                     else
    60                         element.appendChild(item);
    61                 }
    62                 return element;
    63             }
    64 
    65             function shadow(name) {
    66                 var children = [];
    67                 for (var i = 1; i < arguments.length; i++)
    68                     children.push(arguments[i]);
    69                 return function (element) {
    70                     var shadowRoot = element.attachShadow({mode: mode});
    71                     shadowRoot.label = name;
    72                     namedNodes[name] = shadowRoot;
    73                     for (var child of children)
    74                         shadowRoot.appendChild(child);
    75                 }
    76             }
    77 
    78             var host = element('A',
    79                 shadow('A-SR',
    80                     element('A1',
    81                         shadow('A1-SR',
    82                             element('A1a'))),
    83                     element('A2-S')
    84                 ),
    85                 element('B',
    86                     shadow('B-SR',
    87                         element('B1',
    88                             shadow('B1-SR',
    89                                 element('B1b',
    90                                     shadow('B1b-SR',
    91                                         element('B1b1'),
    92                                         element('B1b2'))),
    93                                 element('B1c-S')),
    94                             element('B1a'))),
    95                     element('C'),
    96                     element('D',
    97                         shadow('D-SR',
    98                             element('D1')))));
    99 
    100             return namedNodes;
    101         }
    10216
    10317        /*
  • trunk/LayoutTests/fast/shadow-dom/negative-tabindex-on-shadow-host-expected.txt

    r197439 r198056  
    33
    441. First sequentially focusable element outside shadow trees
    5 2. / 3.2. Shadow host with a positive tabindex
    6 3.1. Focusable element inside a shadow host with a positive tabindex
    7 2. / 3.2. Shadow host with a positive tabindex
     52. Shadow host with a positive tabindex
     63. Focusable element inside a shadow host with a positive tabindex
    874.1. Focusable element inside a shadow host with no tabindex
    984.2. Shadow host with no tabindex
  • trunk/LayoutTests/fast/shadow-dom/negative-tabindex-on-shadow-host.html

    r197439 r198056  
    88<div id="host-with-negative-tabindex" tabindex="-1" onfocus="log(this)">Shadow host with a negative tabindex</div>
    99<div id="host-with-no-tabindex" onfocus="log(this)">4.2. Shadow host with no tabindex</div>
    10 <div id="host-with-positive-tabindex" tabindex="2" onfocus="log(this)">2. / 3.2. Shadow host with a positive tabindex</div>
     10<div id="host-with-positive-tabindex" tabindex="2" onfocus="log(this)">2. Shadow host with a positive tabindex</div>
    1111<div tabindex="0" onfocus="log(this)">5. Last sequentially focusable element outside shadow trees</div>
    1212</div>
     
    2424document.getElementById('host-with-positive-tabindex').attachShadow({mode: 'closed'}).innerHTML = `
    2525    <slot></slot>
    26     <div tabindex="0" onfocus="log(this)">3.1. Focusable element inside a shadow host with a positive tabindex</div>
     26    <div tabindex="0" onfocus="log(this)">3. Focusable element inside a shadow host with a positive tabindex</div>
    2727`;
    2828
  • trunk/LayoutTests/fast/xmlhttprequest/xmlhttprequest-get-expected.txt

    r196520 r198056  
    4949clipboardData : 'undefined'
    5050currentTarget : '[object XMLHttpRequest]'
     51deepPath : 'function deepPath() {
     52    [native code]
     53}'
    5154defaultPrevented : 'false'
    5255eventPhase : '2'
     
    6164    [native code]
    6265}'
     66relatedTargetScoped : 'false'
    6367returnValue : 'true'
     68scoped : 'true'
    6469srcElement : '[object XMLHttpRequest]'
    6570stopImmediatePropagation : 'function stopImmediatePropagation() {
  • trunk/LayoutTests/http/tests/workers/worker-importScriptsOnError-expected.txt

    r196520 r198056  
    2929colno: 14,
    3030currentTarget: [object Worker],
     31deepPath: function deepPath() { [native code] },
    3132defaultPrevented: false,
    3233eventPhase: 2,
     
    3738message: Error: Script error.,
    3839preventDefault: function preventDefault() { [native code] },
     40relatedTargetScoped: false,
    3941returnValue: true,
     42scoped: true,
    4043srcElement: [object Worker],
    4144stopImmediatePropagation: function stopImmediatePropagation() { [native code] },
  • trunk/LayoutTests/inspector/model/remote-object-get-properties-expected.txt

    r197815 r198056  
    4949    bubbles
    5050    cancelable
     51    scoped
     52    relatedTargetScoped
    5153    timeStamp
    5254    defaultPrevented
     
    6668    bubbles
    6769    cancelable
     70    scoped
     71    relatedTargetScoped
    6872    timeStamp
    6973    defaultPrevented
     
    7276    cancelBubble
    7377    clipboardData
     78    deepPath
    7479    stopPropagation
    7580    preventDefault
  • trunk/Source/WebCore/ChangeLog

    r198055 r198056  
     12016-03-11  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Add Event.deepPath() and Event.scoped
     4        https://bugs.webkit.org/show_bug.cgi?id=153538
     5        <rdar://problem/24363836>
     6
     7        Reviewed by Darin Adler.
     8
     9        Added the support for deepPath(), scoped, and relatedTargetScoped on Event.prototype for shadow DOM:
     10        http://w3c.github.io/webcomponents/spec/shadow/#extensions-to-event-interface
     11        and updated the EventPath class to respect scoped and relatedTargetScoped flags as specified at:
     12        http://w3c.github.io/webcomponents/spec/shadow/#get-the-parent
     13
     14        Tests: fast/shadow-dom/Extensions-to-Event-Interface.html
     15               fast/shadow-dom/trusted-event-scoped-flags.html
     16
     17        * bindings/scripts/CodeGeneratorJS.pm:
     18        (GenerateConstructorDefinition): Added the support for Conditional for InitializedByEventConstructor.
     19        * bindings/scripts/test/GObject/WebKitDOMTestEventConstructor.cpp:
     20        * bindings/scripts/test/GObject/WebKitDOMTestEventConstructor.h:
     21        * bindings/scripts/test/JS/JSTestEventConstructor.cpp:
     22        * bindings/scripts/test/ObjC/DOMTestEventConstructor.h:
     23        * bindings/scripts/test/ObjC/DOMTestEventConstructor.mm:
     24        * bindings/scripts/test/TestEventConstructor.idl: Added a test case for using InitializedByEventConstructor
     25        with Conditional.
     26        * dom/Event.cpp:
     27        (WebCore::Event::Event): Initialize m_scoped and m_relatedTargetScoped from EventInit dictionary.
     28        (WebCore::Event::scoped): Added. Implements http://w3c.github.io/webcomponents/spec/shadow/#scoped-flag
     29        (WebCore::Event::deepPath): Added.
     30        * dom/Event.h:
     31        (WebCore::Event::relatedTargetScoped): Added. Overridden by FocusEvent and MouseEvent to implement
     32        http://w3c.github.io/webcomponents/spec/shadow/#relatedtargetscoped-flag
     33        (WebCore::Event::setEventPath): Added.
     34        (WebCore::Event::clearEventPath): Added.
     35        * dom/Event.idl: Added scoped, relatedTargetScoped, and deepPath() conditionally enabled for shadow DOM.
     36        * dom/EventContext.h:
     37        (WebCore::EventContext::currentTarget):
     38        * dom/EventDispatcher.cpp:
     39        (WebCore::EventDispatcher::dispatchEvent): Set the event path while the event is being dispatched.
     40        * dom/EventPath.cpp:
     41        (WebCore::shouldEventCrossShadowBoundary): Check event.scoped flag instead of hard-coding a list of events here
     42        which has been moved to Event::scoped. See above.
     43        (WebCore::EventPath::setRelatedTarget): Check m_event.relatedTargetScoped() instead of hard-coding a list of
     44        events here. relatedTargetScoped is overridden by FocusEvent and MouseEvent.
     45        (WebCore::EventPath::hasEventListeners): Fixed the misleading variable name.
     46        (WebCore::isUnclosedNodeOf): Added. Implements http://w3c.github.io/webcomponents/spec/shadow/#dfn-unclosed-node
     47        (WebCore::EventPath::computePathDisclosedToTarget): Added. Implements the algorithm to filter event targets:
     48        http://w3c.github.io/webcomponents/spec/shadow/#widl-Event-deepPath-sequence-EventTarget
     49        * dom/EventPath.h:
     50        * dom/FocusEvent.cpp:
     51        (WebCore::FocusEvent::relatedTargetScoped): Returns true when this is a trusted event per:
     52        http://w3c.github.io/webcomponents/spec/shadow/#relatedtargetscoped-flag
     53        * dom/FocusEvent.h:
     54        * dom/MouseEvent.cpp:
     55        (WebCore::MouseEvent::relatedTargetScoped): Ditto.
     56        * dom/MouseEvent.h:
     57
    1582016-03-11  John Wilander  <wilander@apple.com>
    259
  • trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm

    r198023 r198056  
    48574857                    my $attributeName = $attribute->signature->name;
    48584858                    my $attributeImplName = $attribute->signature->extendedAttributes->{"ImplementedAs"} || $attributeName;
     4859                    my $conditionalString = $codeGenerator->GenerateConditionalString($attribute->signature);
     4860
     4861                    push(@implContent, "#if ${conditionalString}\n") if $conditionalString;
     4862
    48594863                    push(@implContent, <<END);
    48604864    if (!dictionary.tryGetProperty("${attributeName}", eventInit.${attributeImplName}))
    48614865        return false;
    48624866END
     4867                    push(@implContent, "#endif\n") if $conditionalString;
     4868
    48634869                }
    48644870            }
  • trunk/Source/WebCore/bindings/scripts/test/GObject/WebKitDOMTestEventConstructor.cpp

    r171294 r198056  
    7272    PROP_ATTR1,
    7373    PROP_ATTR2,
     74    PROP_ATTR3,
    7475};
    7576
     
    9495    case PROP_ATTR2:
    9596        g_value_take_string(value, webkit_dom_test_event_constructor_get_attr2(self));
     97        break;
     98    case PROP_ATTR3:
     99        g_value_take_string(value, webkit_dom_test_event_constructor_get_attr3(self));
    96100        break;
    97101    default:
     
    140144            WEBKIT_PARAM_READABLE));
    141145
     146    g_object_class_install_property(
     147        gobjectClass,
     148        PROP_ATTR3,
     149        g_param_spec_string(
     150            "attr3",
     151            "TestEventConstructor:attr3",
     152            "read-only gchar* TestEventConstructor:attr3",
     153            "",
     154            WEBKIT_PARAM_READABLE));
     155
    142156}
    143157
     
    166180}
    167181
     182gchar* webkit_dom_test_event_constructor_get_attr3(WebKitDOMTestEventConstructor* self)
     183{
     184#if ENABLE(SPECIAL_EVENT)
     185    WebCore::JSMainThreadNullState state;
     186    g_return_val_if_fail(WEBKIT_DOM_IS_TEST_EVENT_CONSTRUCTOR(self), 0);
     187    WebCore::TestEventConstructor* item = WebKit::core(self);
     188    gchar* result = convertToUTF8String(item->attr3());
     189    return result;
     190#else
     191    UNUSED_PARAM(self);
     192    WEBKIT_WARN_FEATURE_NOT_PRESENT("Special Event")
     193    return 0;
     194#endif /* ENABLE(SPECIAL_EVENT) */
     195}
     196
  • trunk/Source/WebCore/bindings/scripts/test/GObject/WebKitDOMTestEventConstructor.h

    r170422 r198056  
    7070webkit_dom_test_event_constructor_get_attr2(WebKitDOMTestEventConstructor* self);
    7171
     72/**
     73 * webkit_dom_test_event_constructor_get_attr3:
     74 * @self: A #WebKitDOMTestEventConstructor
     75 *
     76 * Returns: A #gchar
     77 *
     78 * Stability: Unstable
     79**/
     80WEBKIT_API gchar*
     81webkit_dom_test_event_constructor_get_attr3(WebKitDOMTestEventConstructor* self);
     82
    7283G_END_DECLS
    7384
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestEventConstructor.cpp

    r198023 r198056  
    3939JSC::EncodedJSValue jsTestEventConstructorAttr1(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
    4040JSC::EncodedJSValue jsTestEventConstructorAttr2(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
     41#if ENABLE(SPECIAL_EVENT)
     42JSC::EncodedJSValue jsTestEventConstructorAttr3(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
     43#endif
    4144JSC::EncodedJSValue jsTestEventConstructorConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
    4245bool setJSTestEventConstructorConstructor(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue);
     
    107110    if (!dictionary.tryGetProperty("attr2", eventInit.attr2))
    108111        return false;
     112#if ENABLE(SPECIAL_EVENT)
     113    if (!dictionary.tryGetProperty("attr3", eventInit.attr3))
     114        return false;
     115#endif
    109116    return true;
    110117}
     
    132139    { "attr1", ReadOnly | CustomAccessor, NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsTestEventConstructorAttr1), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(0) } },
    133140    { "attr2", ReadOnly | CustomAccessor, NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsTestEventConstructorAttr2), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(0) } },
     141#if ENABLE(SPECIAL_EVENT)
     142    { "attr3", ReadOnly | CustomAccessor, NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(jsTestEventConstructorAttr3), (intptr_t) static_cast<PutPropertySlot::PutValueFunc>(0) } },
     143#else
     144    { 0, 0, NoIntrinsic, { 0, 0 } },
     145#endif
    134146};
    135147
     
    194206}
    195207
     208
     209#if ENABLE(SPECIAL_EVENT)
     210EncodedJSValue jsTestEventConstructorAttr3(ExecState* state, EncodedJSValue thisValue, PropertyName)
     211{
     212    UNUSED_PARAM(state);
     213    UNUSED_PARAM(thisValue);
     214    JSValue decodedThisValue = JSValue::decode(thisValue);
     215    auto* castedThis = jsDynamicCast<JSTestEventConstructor*>(decodedThisValue);
     216    if (UNLIKELY(!castedThis)) {
     217        return throwGetterTypeError(*state, "TestEventConstructor", "attr3");
     218    }
     219    auto& impl = castedThis->wrapped();
     220    JSValue result = jsStringWithCache(state, impl.attr3());
     221    return JSValue::encode(result);
     222}
     223
     224#endif
    196225
    197226EncodedJSValue jsTestEventConstructorConstructor(ExecState* state, EncodedJSValue thisValue, PropertyName)
  • trunk/Source/WebCore/bindings/scripts/test/ObjC/DOMTestEventConstructor.h

    r183350 r198056  
    3333@property (readonly, copy) NSString *attr1;
    3434@property (readonly, copy) NSString *attr2;
     35@property (readonly, copy) NSString *attr3;
    3536@end
  • trunk/Source/WebCore/bindings/scripts/test/ObjC/DOMTestEventConstructor.mm

    r193378 r198056  
    6868}
    6969
     70#if ENABLE(SPECIAL_EVENT)
     71- (NSString *)attr3
     72{
     73    WebCore::JSMainThreadNullState state;
     74    return IMPL->attr3();
     75}
     76#endif
     77
    7078@end
    7179
  • trunk/Source/WebCore/bindings/scripts/test/TestEventConstructor.idl

    r165676 r198056  
    3535    readonly attribute DOMString attr1;
    3636    [InitializedByEventConstructor] readonly attribute DOMString attr2;
     37    [InitializedByEventConstructor, Conditional=SPECIAL_EVENT] readonly attribute DOMString attr3;
    3738};
  • trunk/Source/WebCore/dom/Event.cpp

    r196520 r198056  
    2424#include "Event.h"
    2525
     26#include "EventPath.h"
    2627#include "EventTarget.h"
    2728#include "UserGestureIndicator.h"
     
    6061    , m_canBubble(initializer.bubbles)
    6162    , m_cancelable(initializer.cancelable)
     63    , m_scoped(initializer.scoped)
     64    , m_relatedTargetScoped(initializer.relatedTargetScoped)
    6265    , m_createTime(convertSecondsToDOMTimeStamp(currentTime()))
    6366{
     
    8487}
    8588
     89bool Event::scoped() const
     90{
     91    if (m_scoped)
     92        return true;
     93
     94    // http://w3c.github.io/webcomponents/spec/shadow/#scoped-flag
     95    if (!isTrusted())
     96        return false;
     97
     98    return m_type == eventNames().abortEvent
     99        || m_type == eventNames().changeEvent
     100        || m_type == eventNames().errorEvent
     101        || m_type == eventNames().loadEvent
     102        || m_type == eventNames().resetEvent
     103        || m_type == eventNames().resizeEvent
     104        || m_type == eventNames().scrollEvent
     105        || m_type == eventNames().selectEvent
     106        || m_type == eventNames().selectstartEvent;
     107}
     108
    86109EventInterface Event::eventInterface() const
    87110{
     
    162185    if (m_target)
    163186        receivedTarget();
     187}
     188
     189Vector<EventTarget*> Event::deepPath() const
     190{
     191    if (!m_eventPath)
     192        return Vector<EventTarget*>();
     193    return m_eventPath->computePathDisclosedToTarget(*m_target);
    164194}
    165195
  • trunk/Source/WebCore/dom/Event.h

    r196520 r198056  
    3737
    3838class DataTransfer;
     39class EventPath;
    3940class EventTarget;
    4041class HTMLIFrameElement;
     
    4344    bool bubbles { false };
    4445    bool cancelable { false };
     46    bool scoped { false };
     47    bool relatedTargetScoped { false };
    4548};
    4649
     
    115118    bool bubbles() const { return m_canBubble; }
    116119    bool cancelable() const { return m_cancelable; }
     120    bool scoped() const;
     121    virtual bool relatedTargetScoped() const { return m_relatedTargetScoped; }
     122
    117123    DOMTimeStamp timeStamp() const { return m_createTime; }
     124
     125    void setEventPath(const EventPath& path) { m_eventPath = &path; }
     126    void clearEventPath() { m_eventPath = nullptr; }
     127    Vector<EventTarget*> deepPath() const;
    118128
    119129    void stopPropagation() { m_propagationStopped = true; }
     
    199209    bool m_canBubble { false };
    200210    bool m_cancelable { false };
     211    bool m_scoped { false };
     212    bool m_relatedTargetScoped { false };
    201213
    202214    bool m_propagationStopped { false };
     
    209221    unsigned short m_eventPhase { 0 };
    210222    EventTarget* m_currentTarget { nullptr };
     223    const EventPath* m_eventPath { nullptr };
    211224    RefPtr<EventTarget> m_target;
    212225    DOMTimeStamp m_createTime;
  • trunk/Source/WebCore/dom/Event.idl

    r196520 r198056  
    5858    [InitializedByEventConstructor] readonly attribute boolean bubbles;
    5959    [InitializedByEventConstructor] readonly attribute boolean cancelable;
     60    [InitializedByEventConstructor, Conditional=SHADOW_DOM, EnabledAtRuntime=ShadowDOM] readonly attribute boolean scoped;
     61    [InitializedByEventConstructor, Conditional=SHADOW_DOM, EnabledAtRuntime=ShadowDOM] readonly attribute boolean relatedTargetScoped;
    6062    readonly attribute DOMTimeStamp     timeStamp;
     63
     64    [Conditional=SHADOW_DOM, EnabledAtRuntime=ShadowDOM] sequence<Node> deepPath();
    6165
    6266    void               stopPropagation();
  • trunk/Source/WebCore/dom/EventContext.h

    r197563 r198056  
    4848
    4949    Node* node() const { return m_node.get(); }
     50    EventTarget* currentTarget() const { return m_currentTarget.get(); }
    5051    EventTarget* target() const { return m_target.get(); }
    5152    bool currentTargetSameAsTarget() const { return m_currentTarget.get() == m_target.get(); }
  • trunk/Source/WebCore/dom/EventDispatcher.cpp

    r197924 r198056  
    178178        downcast<HTMLInputElement>(*node).willDispatchEvent(event, clickHandlingState);
    179179
    180     if (!event.propagationStopped() && !eventPath.isEmpty())
     180    if (!event.propagationStopped() && !eventPath.isEmpty()) {
     181        event.setEventPath(eventPath);
    181182        dispatchEventInDOM(event, eventPath, windowEventContext);
     183        event.clearEventPath();
     184    }
    182185
    183186    event.setTarget(EventPath::eventTargetRespectingTargetRules(*node));
  • trunk/Source/WebCore/dom/EventPath.cpp

    r197924 r198056  
    5050#endif
    5151
    52     // WebKit never allowed selectstart event to cross the the shadow DOM boundary.
    53     // Changing this breaks existing sites.
    54     // See https://bugs.webkit.org/show_bug.cgi?id=52195 for details.
    55     const AtomicString& eventType = event.type();
    5652    bool targetIsInShadowRoot = targetNode && &targetNode->treeScope().rootNode() == &shadowRoot;
    57     return !targetIsInShadowRoot
    58         || !(eventType == eventNames().abortEvent
    59         || eventType == eventNames().changeEvent
    60         || eventType == eventNames().errorEvent
    61         || eventType == eventNames().loadEvent
    62         || eventType == eventNames().resetEvent
    63         || eventType == eventNames().resizeEvent
    64         || eventType == eventNames().scrollEvent
    65         || eventType == eventNames().selectEvent
    66         || eventType == eventNames().selectstartEvent);
     53    return !targetIsInShadowRoot || !event.scoped();
    6754}
    6855
     
    175162
    176163    bool originIsRelatedTarget = &origin == relatedNode;
    177     // FIXME: We should add a new flag on Event instead.
    178     bool shouldTrimEventPath = m_event.type() == eventNames().mouseoverEvent
    179         || m_event.type() == eventNames().mousemoveEvent
    180         || m_event.type() == eventNames().mouseoutEvent;
     164    bool relatedTargetScoped = m_event.relatedTargetScoped();
    181165    Node& rootNodeInOriginTreeScope = origin.treeScope().rootNode();
    182166    TreeScope* previousTreeScope = nullptr;
     
    190174
    191175        Node* currentRelatedNode = retargeter.currentNode(currentTreeScope);
    192         if (UNLIKELY(shouldTrimEventPath && !originIsRelatedTarget && context.target() == currentRelatedNode)) {
     176        if (UNLIKELY(relatedTargetScoped && !originIsRelatedTarget && context.target() == currentRelatedNode)) {
    193177            m_path.shrink(contextIndex);
    194178            break;
     
    197181        context.setRelatedTarget(currentRelatedNode);
    198182
    199         if (UNLIKELY(shouldTrimEventPath && originIsRelatedTarget && context.node() == &rootNodeInOriginTreeScope)) {
     183        if (UNLIKELY(relatedTargetScoped && originIsRelatedTarget && context.node() == &rootNodeInOriginTreeScope)) {
    200184            m_path.shrink(contextIndex + 1);
    201185            break;
     
    252236bool EventPath::hasEventListeners(const AtomicString& eventType) const
    253237{
    254     for (auto& eventPath : m_path) {
    255         if (eventPath->node()->hasEventListeners(eventType))
     238    for (auto& context : m_path) {
     239        if (context->node()->hasEventListeners(eventType))
    256240            return true;
    257241    }
    258242
    259243    return false;
     244}
     245
     246// http://w3c.github.io/webcomponents/spec/shadow/#dfn-unclosed-node
     247static bool isUnclosedNodeOf(const Node& a, const Node& b)
     248{
     249    // Use Vector instead of HashSet since we expect the number of ancestor tree scopes to be small.
     250    Vector<TreeScope*, 8> treeScopesOpenToB;
     251
     252    for (auto* scope = &b.treeScope(); scope; scope = scope->parentTreeScope())
     253        treeScopesOpenToB.append(scope);
     254
     255    for (auto* treeScopeThatCanAccessA = &a.treeScope(); treeScopeThatCanAccessA; treeScopeThatCanAccessA = treeScopeThatCanAccessA->parentTreeScope()) {
     256        for (auto* openToB : treeScopesOpenToB) {
     257            if (openToB == treeScopeThatCanAccessA)
     258                return true;
     259        }
     260        auto& root = treeScopeThatCanAccessA->rootNode();
     261        if (is<ShadowRoot>(root) && downcast<ShadowRoot>(root).type() != ShadowRoot::Type::Open)
     262            break;
     263    }
     264
     265    return false;
     266}
     267
     268Vector<EventTarget*> EventPath::computePathDisclosedToTarget(const EventTarget& target) const
     269{
     270    Vector<EventTarget*> path;
     271    const Node* targetNode = const_cast<EventTarget&>(target).toNode();
     272    if (!targetNode)
     273        return path;
     274
     275    for (auto& context : m_path) {
     276        if (Node* nodeInPath = context->currentTarget()->toNode()) {
     277            if (isUnclosedNodeOf(*nodeInPath, *targetNode))
     278                path.append(context->currentTarget());
     279        }
     280    }
     281
     282    return path;
    260283}
    261284
  • trunk/Source/WebCore/dom/EventPath.h

    r197924 r198056  
    4949    EventContext* lastContextIfExists() { return m_path.isEmpty() ? nullptr : m_path.last().get(); }
    5050
     51    Vector<EventTarget*> computePathDisclosedToTarget(const EventTarget&) const;
     52
    5153    static EventTarget* eventTargetRespectingTargetRules(Node& referenceNode)
    5254    {
  • trunk/Source/WebCore/dom/FocusEvent.cpp

    r196400 r198056  
    5353}
    5454
     55bool FocusEvent::relatedTargetScoped() const
     56{
     57    return (isTrusted() && m_relatedTarget) || UIEvent::relatedTargetScoped();
     58}
     59
    5560} // namespace WebCore
  • trunk/Source/WebCore/dom/FocusEvent.h

    r197563 r198056  
    5959    FocusEvent(const AtomicString& type, const FocusEventInit&);
    6060
     61    bool relatedTargetScoped() const override;
     62
    6163    bool isFocusEvent() const override;
    6264
  • trunk/Source/WebCore/dom/MouseEvent.cpp

    r196598 r198056  
    190190}
    191191
     192bool MouseEvent::relatedTargetScoped() const
     193{
     194    return (isTrusted() && m_relatedTarget) || UIEvent::relatedTargetScoped();
     195}
     196
    192197int MouseEvent::which() const
    193198{
  • trunk/Source/WebCore/dom/MouseEvent.h

    r197566 r198056  
    122122    MouseEvent();
    123123
     124    bool relatedTargetScoped() const override;
     125
    124126private:
    125127    unsigned short m_button;
Note: See TracChangeset for help on using the changeset viewer.