Changeset 205060 in webkit


Ignore:
Timestamp:
Aug 26, 2016 5:04:08 PM (8 years ago)
Author:
rniwa@webkit.org
Message:

Adopted custom element's callbacks should continue to work
https://bugs.webkit.org/show_bug.cgi?id=161065

Reviewed by Andreas Kling.

Source/WebCore:

When a custom element is adopted into another document, its reaction callbacks need to continue to work.
Because a different document may have its own global object, each custom element needs to remember its
original global object or JSCustomElementInterface. This patch adds the latter to the element rare data.

Tests: fast/custom-elements/connected-callbacks.html

fast/custom-elements/disconnected-callbacks.html

  • bindings/js/JSCustomElementInterface.cpp:

(WebCore::JSCustomElementInterface::constructElement):
(WebCore::JSCustomElementInterface::upgradeElement):

  • dom/CustomElementReactionQueue.cpp:

(WebCore::findInterfaceForCustomElement): Deleted.
(WebCore::CustomElementReactionQueue::enqueueConnectedCallbackIfNeeded):
(WebCore::CustomElementReactionQueue::enqueueDisconnectedCallbackIfNeeded):
(WebCore::CustomElementReactionQueue::enqueueAttributeChangedCallbackIfNeeded):

  • dom/Element.cpp:

(WebCore::Element::insertedInto): Invoke callbacks even when the current document is not a HTML document.
(WebCore::Element::removedFrom): Ditto.
(WebCore::Element::setCustomElementIsResolved): Moved from Node. Add the element interface to the rare data.
(WebCore::Element::customElementInterface): Added.

  • dom/Element.h:
  • dom/ElementRareData.cpp:
  • dom/ElementRareData.h:

(WebCore::ElementRareData::customElementInterface): Added.
(WebCore::ElementRareData::setCustomElementInterface): Added.

  • dom/Node.h:

((WebCore::Node::setCustomElementIsResolved): Deleted.

LayoutTests:

Added test cases for adopting custom elements into various kinds of documents.

  • fast/custom-elements/connected-callbacks-expected.txt:
  • fast/custom-elements/connected-callbacks.html:
  • fast/custom-elements/defined-pseudo-class-expected.txt:
  • fast/custom-elements/defined-pseudo-class.html:
  • fast/custom-elements/disconnected-callbacks-expected.txt:
  • fast/custom-elements/disconnected-callbacks.html:
  • fast/custom-elements/resources/document-types.js: Added.
  • fast/custom-elements/resources/empty-html-document.html: Added.
Location:
trunk
Files:
3 added
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r205059 r205060  
     12016-08-23  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Adopted custom element's callbacks should continue to work
     4        https://bugs.webkit.org/show_bug.cgi?id=161065
     5
     6        Reviewed by Andreas Kling.
     7
     8        Added test cases for adopting custom elements into various kinds of documents.
     9
     10        * fast/custom-elements/connected-callbacks-expected.txt:
     11        * fast/custom-elements/connected-callbacks.html:
     12        * fast/custom-elements/defined-pseudo-class-expected.txt:
     13        * fast/custom-elements/defined-pseudo-class.html:
     14        * fast/custom-elements/disconnected-callbacks-expected.txt:
     15        * fast/custom-elements/disconnected-callbacks.html:
     16        * fast/custom-elements/resources/document-types.js: Added.
     17        * fast/custom-elements/resources/empty-html-document.html: Added.
     18
    1192016-08-26  Ryan Haddad  <ryanhaddad@apple.com>
    220
  • trunk/LayoutTests/fast/custom-elements/connected-callbacks-expected.txt

    r204611 r205060  
    11
    22PASS Inserting a custom element into a document must enqueue and invoke connectedCallback
    3 PASS Inserting a custom element into a detached node must not enqueue and invoke connectedCallback
    4 FAIL Inserting a custom element into a window-less document must enqueue and invoke connectedCallback assert_array_equals: lengths differ, expected 2 got 0
    5 PASS Inserting an ancestor of a custom element into a document must enqueue and invoke connectedCallback
    6 FAIL Inserting an ancestor of custom element into a window-less document must enqueue and invoke connectedCallback assert_array_equals: lengths differ, expected 2 got 0
    7 PASS Inserting a custom element into a connected shadow tree must enqueue and invoke connectedCallback
    8 PASS Inserting the shadow host of a shadow tree with a custom element into a document must enqueue and invoke connectedCallback
    9 PASS Inserting a custom element into a detached shadow tree must not enqueue and invoke connectedCallback
     3PASS Inserting an ancestor of custom element into a document must enqueue and invoke connectedCallback
     4PASS Inserting a custom element into a shadow tree in a document must enqueue and invoke connectedCallback
     5PASS Inserting the shadow host of a custom element into a document must enqueue and invoke connectedCallback
     6PASS Inserting a custom element into a detached shadow tree that belongs to a document must not enqueue and invoke connectedCallback
     7PASS Inserting a custom element into a document of a template element must enqueue and invoke connectedCallback
     8PASS Inserting an ancestor of custom element into a document of a template element must enqueue and invoke connectedCallback
     9PASS Inserting a custom element into a shadow tree in a document of a template element must enqueue and invoke connectedCallback
     10PASS Inserting the shadow host of a custom element into a document of a template element must enqueue and invoke connectedCallback
     11PASS Inserting a custom element into a detached shadow tree that belongs to a document of a template element must not enqueue and invoke connectedCallback
     12PASS Inserting a custom element into a new document must enqueue and invoke connectedCallback
     13PASS Inserting an ancestor of custom element into a new document must enqueue and invoke connectedCallback
     14PASS Inserting a custom element into a shadow tree in a new document must enqueue and invoke connectedCallback
     15PASS Inserting the shadow host of a custom element into a new document must enqueue and invoke connectedCallback
     16PASS Inserting a custom element into a detached shadow tree that belongs to a new document must not enqueue and invoke connectedCallback
     17PASS Inserting a custom element into a cloned document must enqueue and invoke connectedCallback
     18PASS Inserting an ancestor of custom element into a cloned document must enqueue and invoke connectedCallback
     19PASS Inserting a custom element into a shadow tree in a cloned document must enqueue and invoke connectedCallback
     20PASS Inserting the shadow host of a custom element into a cloned document must enqueue and invoke connectedCallback
     21PASS Inserting a custom element into a detached shadow tree that belongs to a cloned document must not enqueue and invoke connectedCallback
     22PASS Inserting a custom element into a document created by createHTMLDocument must enqueue and invoke connectedCallback
     23PASS Inserting an ancestor of custom element into a document created by createHTMLDocument must enqueue and invoke connectedCallback
     24PASS Inserting a custom element into a shadow tree in a document created by createHTMLDocument must enqueue and invoke connectedCallback
     25PASS Inserting the shadow host of a custom element into a document created by createHTMLDocument must enqueue and invoke connectedCallback
     26PASS Inserting a custom element into a detached shadow tree that belongs to a document created by createHTMLDocument must not enqueue and invoke connectedCallback
     27PASS Inserting a custom element into a HTML document created by createDocument must enqueue and invoke connectedCallback
     28PASS Inserting an ancestor of custom element into a HTML document created by createDocument must enqueue and invoke connectedCallback
     29PASS Inserting a custom element into a shadow tree in a HTML document created by createDocument must enqueue and invoke connectedCallback
     30PASS Inserting the shadow host of a custom element into a HTML document created by createDocument must enqueue and invoke connectedCallback
     31PASS Inserting a custom element into a detached shadow tree that belongs to a HTML document created by createDocument must not enqueue and invoke connectedCallback
     32PASS Inserting a custom element into a document in an iframe must enqueue and invoke connectedCallback
     33PASS Inserting an ancestor of custom element into a document in an iframe must enqueue and invoke connectedCallback
     34PASS Inserting a custom element into a shadow tree in a document in an iframe must enqueue and invoke connectedCallback
     35PASS Inserting the shadow host of a custom element into a document in an iframe must enqueue and invoke connectedCallback
     36PASS Inserting a custom element into a detached shadow tree that belongs to a document in an iframe must not enqueue and invoke connectedCallback
     37PASS Inserting a custom element into a HTML document fetched by XHR must enqueue and invoke connectedCallback
     38PASS Inserting an ancestor of custom element into a HTML document fetched by XHR must enqueue and invoke connectedCallback
     39PASS Inserting a custom element into a shadow tree in a HTML document fetched by XHR must enqueue and invoke connectedCallback
     40PASS Inserting the shadow host of a custom element into a HTML document fetched by XHR must enqueue and invoke connectedCallback
     41PASS Inserting a custom element into a detached shadow tree that belongs to a HTML document fetched by XHR must not enqueue and invoke connectedCallback
    1042
     43
  • trunk/LayoutTests/fast/custom-elements/connected-callbacks.html

    r204611 r205060  
    88<script src="../../resources/testharness.js"></script>
    99<script src="../../resources/testharnessreport.js"></script>
     10<script src="./resources/document-types.js"></script>
    1011<link rel='stylesheet' href='../../resources/testharness.css'>
    1112</head>
     
    2122customElements.define('my-custom-element', MyCustomElement);
    2223
    23 test(function () {
    24     var instance = document.createElement('my-custom-element');
     24DocumentTypes.forEach(function (entry) {
     25    var documentName = entry.name;
     26    var getDocument = entry.create;
    2527
    26     calls = [];
    27     document.body.appendChild(instance);
    28     assert_array_equals(calls, ['connected', instance]);
    29 }, 'Inserting a custom element into a document must enqueue and invoke connectedCallback');
     28    promise_test(function () {
     29        return getDocument().then(function (doc) {
     30            var instance = document.createElement('my-custom-element');
     31            calls = [];
     32            doc.documentElement.appendChild(instance);
     33            assert_array_equals(calls, ['connected', instance]);
     34        });
     35    }, 'Inserting a custom element into a ' + documentName + ' must enqueue and invoke connectedCallback');
    3036
    31 test(function () {
    32     var instance = document.createElement('my-custom-element');
     37    promise_test(function () {
     38        return getDocument().then(function (doc) {
     39            var instance = document.createElement('my-custom-element');
     40            var parent = document.createElement('div');
     41            parent.appendChild(instance);
     42            calls = [];
     43            doc.documentElement.appendChild(parent);
     44            assert_array_equals(calls, ['connected', instance]);
     45        });
     46    }, 'Inserting an ancestor of custom element into a ' + documentName + ' must enqueue and invoke connectedCallback');
    3347
    34     calls = [];
    35     var parent = document.createElement('div');
    36     parent.appendChild(instance);
    37     assert_array_equals(calls, []);
    38 }, 'Inserting a custom element into a detached node must not enqueue and invoke connectedCallback');
     48    promise_test(function () {
     49        return getDocument().then(function (doc) {
     50            var instance = document.createElement('my-custom-element');
     51            var host = doc.createElementNS('http://www.w3.org/1999/xhtml', 'div');
     52            var shadowRoot = host.attachShadow({mode: 'closed'});
     53            doc.documentElement.appendChild(host);
    3954
    40 test(function () {
    41     var instance = document.createElement('my-custom-element');
    42     var documentWithoutWindow = document.implementation.createHTMLDocument();
     55            calls = [];
     56            shadowRoot.appendChild(instance);
     57            assert_array_equals(calls, ['connected', instance]);
     58        });
     59    }, 'Inserting a custom element into a shadow tree in a ' + documentName + ' must enqueue and invoke connectedCallback');
    4360
    44     calls = [];
    45     documentWithoutWindow.body.appendChild(instance);
    46     assert_array_equals(calls, ['connected', instance]);
    47 }, 'Inserting a custom element into a window-less document must enqueue and invoke connectedCallback');
     61    promise_test(function () {
     62        return getDocument().then(function (doc) {
     63            var instance = document.createElement('my-custom-element');
     64            var host = doc.createElementNS('http://www.w3.org/1999/xhtml', 'div');
     65            var shadowRoot = host.attachShadow({mode: 'closed'});
     66            shadowRoot.appendChild(instance);
    4867
    49 test(function () {
    50     var instance = document.createElement('my-custom-element');
    51     var parent = document.createElement('div');
    52     parent.appendChild(instance);
     68            calls = [];
     69            doc.documentElement.appendChild(host);
     70            assert_array_equals(calls, ['connected', instance]);
     71        });
     72    }, 'Inserting the shadow host of a custom element into a ' + documentName + ' must enqueue and invoke connectedCallback');
    5373
    54     calls = [];
    55     document.body.appendChild(parent);
    56     assert_array_equals(calls, ['connected', instance]);
    57 }, 'Inserting an ancestor of a custom element into a document must enqueue and invoke connectedCallback');
     74    promise_test(function () {
     75        return getDocument().then(function (doc) {
     76            var instance = document.createElement('my-custom-element');
     77            var host = doc.createElementNS('http://www.w3.org/1999/xhtml', 'div');
     78            var shadowRoot = host.attachShadow({mode: 'closed'});
    5879
    59 test(function () {
    60     var instance = document.createElement('my-custom-element');
    61     var parent = document.createElement('div');
    62     parent.appendChild(instance);
    63     var documentWithoutWindow = document.implementation.createHTMLDocument();
    64 
    65     calls = [];
    66     documentWithoutWindow.body.appendChild(parent);
    67     assert_array_equals(calls, ['connected', instance]);
    68 }, 'Inserting an ancestor of custom element into a window-less document must enqueue and invoke connectedCallback');
    69 
    70 test(function () {
    71     var instance = document.createElement('my-custom-element');
    72     var host = document.createElement('div');
    73     var shadowRoot = host.attachShadow({mode: 'closed'});
    74     document.body.appendChild(host);
    75 
    76     calls = [];
    77     shadowRoot.appendChild(instance);
    78     assert_array_equals(calls, ['connected', instance]);
    79 }, 'Inserting a custom element into a connected shadow tree must enqueue and invoke connectedCallback');
    80 
    81 test(function () {
    82     var instance = document.createElement('my-custom-element');
    83     var host = document.createElement('div');
    84     var shadowRoot = host.attachShadow({mode: 'closed'});
    85     shadowRoot.appendChild(instance);
    86 
    87     calls = [];
    88     document.body.appendChild(host);
    89     assert_array_equals(calls, ['connected', instance]);
    90 }, 'Inserting the shadow host of a shadow tree with a custom element into a document must enqueue and invoke connectedCallback');
    91 
    92 test(function () {
    93     var instance = document.createElement('my-custom-element');
    94     var host = document.createElement('div');
    95     var shadowRoot = host.attachShadow({mode: 'closed'});
    96 
    97     calls = [];
    98     shadowRoot.appendChild(instance);
    99     assert_array_equals(calls, []);
    100 }, 'Inserting a custom element into a detached shadow tree must not enqueue and invoke connectedCallback');
     80            calls = [];
     81            shadowRoot.appendChild(instance);
     82            assert_array_equals(calls, []);
     83        });
     84    }, 'Inserting a custom element into a detached shadow tree that belongs to a ' + documentName + ' must not enqueue and invoke connectedCallback');
     85});
    10186
    10287</script>
  • trunk/LayoutTests/fast/custom-elements/defined-pseudo-class-expected.txt

    r197952 r205060  
    11
    2 PASS The defined flag of a custom element must be set if a custom element has not been upgraded yet
     2PASS The defined flag of a custom element must not be set if a custom element has not been upgraded yet
    33PASS The defined flag of a custom element must be set when a custom element is successfully upgraded
    44PASS The defined flag of a custom element must be set if there is a matching definition
  • trunk/LayoutTests/fast/custom-elements/defined-pseudo-class.html

    r204367 r205060  
    1717test(function () {
    1818    assert_false(upgradeCandidate.matches(':defined'));
    19 }, 'The defined flag of a custom element must be set if a custom element has not been upgraded yet');
     19}, 'The defined flag of a custom element must not be set if a custom element has not been upgraded yet');
    2020
    2121var matchInsideConstructor;
  • trunk/LayoutTests/fast/custom-elements/disconnected-callbacks-expected.txt

    r204611 r205060  
    11
    22PASS Removing a custom element from a document must enqueue and invoke disconnectedCallback
    3 PASS Removing a custom element from a detahed node must not enqueue and invoke connectedCallback
    4 FAIL Removing a custom element from a window-less document must enqueue and invoke disconnectedCallback assert_array_equals: lengths differ, expected 2 got 0
    5 PASS Removing an ancestor of a custom element from a document must enqueue and invoke disconnectedCallback
    6 FAIL Removing an ancestor of custom element from a a window-less document must enqueue and invoke disconnectedCallback assert_array_equals: lengths differ, expected 2 got 0
    7 PASS Removing a custom element from a connected shadow tree must enqueue and invoke disconnectedCallback
    8 PASS Removing the shadow host of a shadow tree with a custom element from a document must enqueue and invoke disconnectedCallback
    9 PASS Removing a custom element from a detached shadow tree must not enqueue and invoke disconnectedCallback
     3PASS Removing an ancestor of custom element from a document must enqueue and invoke disconnectedCallback
     4PASS Removing a custom element from a shadow tree in a document must enqueue and invoke disconnectedCallback
     5PASS Removing the shadow host of a custom element from adocument must enqueue and invoke disconnectedCallback
     6PASS Removing a custom element from a detached shadow tree that belongs to a document must not enqueue and invoke disconnectedCallback
     7PASS Removing a custom element from a document of a template element must enqueue and invoke disconnectedCallback
     8PASS Removing an ancestor of custom element from a document of a template element must enqueue and invoke disconnectedCallback
     9PASS Removing a custom element from a shadow tree in a document of a template element must enqueue and invoke disconnectedCallback
     10PASS Removing the shadow host of a custom element from adocument of a template element must enqueue and invoke disconnectedCallback
     11PASS Removing a custom element from a detached shadow tree that belongs to a document of a template element must not enqueue and invoke disconnectedCallback
     12PASS Removing a custom element from a new document must enqueue and invoke disconnectedCallback
     13PASS Removing an ancestor of custom element from a new document must enqueue and invoke disconnectedCallback
     14PASS Removing a custom element from a shadow tree in a new document must enqueue and invoke disconnectedCallback
     15PASS Removing the shadow host of a custom element from anew document must enqueue and invoke disconnectedCallback
     16PASS Removing a custom element from a detached shadow tree that belongs to a new document must not enqueue and invoke disconnectedCallback
     17PASS Removing a custom element from a cloned document must enqueue and invoke disconnectedCallback
     18PASS Removing an ancestor of custom element from a cloned document must enqueue and invoke disconnectedCallback
     19PASS Removing a custom element from a shadow tree in a cloned document must enqueue and invoke disconnectedCallback
     20PASS Removing the shadow host of a custom element from acloned document must enqueue and invoke disconnectedCallback
     21PASS Removing a custom element from a detached shadow tree that belongs to a cloned document must not enqueue and invoke disconnectedCallback
     22PASS Removing a custom element from a document created by createHTMLDocument must enqueue and invoke disconnectedCallback
     23PASS Removing an ancestor of custom element from a document created by createHTMLDocument must enqueue and invoke disconnectedCallback
     24PASS Removing a custom element from a shadow tree in a document created by createHTMLDocument must enqueue and invoke disconnectedCallback
     25PASS Removing the shadow host of a custom element from adocument created by createHTMLDocument must enqueue and invoke disconnectedCallback
     26PASS Removing a custom element from a detached shadow tree that belongs to a document created by createHTMLDocument must not enqueue and invoke disconnectedCallback
     27PASS Removing a custom element from a HTML document created by createDocument must enqueue and invoke disconnectedCallback
     28PASS Removing an ancestor of custom element from a HTML document created by createDocument must enqueue and invoke disconnectedCallback
     29PASS Removing a custom element from a shadow tree in a HTML document created by createDocument must enqueue and invoke disconnectedCallback
     30PASS Removing the shadow host of a custom element from aHTML document created by createDocument must enqueue and invoke disconnectedCallback
     31PASS Removing a custom element from a detached shadow tree that belongs to a HTML document created by createDocument must not enqueue and invoke disconnectedCallback
     32PASS Removing a custom element from a document in an iframe must enqueue and invoke disconnectedCallback
     33PASS Removing an ancestor of custom element from a document in an iframe must enqueue and invoke disconnectedCallback
     34PASS Removing a custom element from a shadow tree in a document in an iframe must enqueue and invoke disconnectedCallback
     35PASS Removing the shadow host of a custom element from adocument in an iframe must enqueue and invoke disconnectedCallback
     36PASS Removing a custom element from a detached shadow tree that belongs to a document in an iframe must not enqueue and invoke disconnectedCallback
     37PASS Removing a custom element from a HTML document fetched by XHR must enqueue and invoke disconnectedCallback
     38PASS Removing an ancestor of custom element from a HTML document fetched by XHR must enqueue and invoke disconnectedCallback
     39PASS Removing a custom element from a shadow tree in a HTML document fetched by XHR must enqueue and invoke disconnectedCallback
     40PASS Removing the shadow host of a custom element from aHTML document fetched by XHR must enqueue and invoke disconnectedCallback
     41PASS Removing a custom element from a detached shadow tree that belongs to a HTML document fetched by XHR must not enqueue and invoke disconnectedCallback
    1042
     43
  • trunk/LayoutTests/fast/custom-elements/disconnected-callbacks.html

    r204611 r205060  
    88<script src="../../resources/testharness.js"></script>
    99<script src="../../resources/testharnessreport.js"></script>
     10<script src="./resources/document-types.js"></script>
    1011<link rel='stylesheet' href='../../resources/testharness.css'>
    1112</head>
     
    2122customElements.define('my-custom-element', MyCustomElement);
    2223
    23 test(function () {
    24     var instance = document.createElement('my-custom-element');
    25     document.body.appendChild(instance);
     24DocumentTypes.forEach(function (entry) {
     25    var documentName = entry.name;
     26    var getDocument = entry.create;
    2627
    27     calls = [];
    28     document.body.removeChild(instance);
    29     assert_array_equals(calls, ['disconnected', instance]);
    30 }, 'Removing a custom element from a document must enqueue and invoke disconnectedCallback');
     28    promise_test(function () {
     29        return getDocument().then(function (doc) {
     30            var instance = document.createElement('my-custom-element');
     31            doc.documentElement.appendChild(instance);
     32            calls = [];
     33            doc.documentElement.removeChild(instance);
     34            assert_array_equals(calls, ['disconnected', instance]);
     35        });
     36    }, 'Removing a custom element from a ' + documentName + ' must enqueue and invoke disconnectedCallback');
    3137
    32 test(function () {
    33     var instance = document.createElement('my-custom-element');
    34     var parent = document.createElement('div');
    35     parent.appendChild(instance);
     38    promise_test(function () {
     39        return getDocument().then(function (doc) {
     40            var instance = document.createElement('my-custom-element');
     41            var parent = document.createElement('div');
     42            parent.appendChild(instance);
     43            doc.documentElement.appendChild(parent);
     44            calls = [];
     45            doc.documentElement.removeChild(parent);
     46            assert_array_equals(calls, ['disconnected', instance]);
     47        });
     48    }, 'Removing an ancestor of custom element from a ' + documentName + ' must enqueue and invoke disconnectedCallback');
    3649
    37     calls = [];
    38     parent.removeChild(instance);
    39     assert_array_equals(calls, []);
    40 }, 'Removing a custom element from a detahed node must not enqueue and invoke connectedCallback');
     50    promise_test(function () {
     51        return getDocument().then(function (doc) {
     52            var instance = document.createElement('my-custom-element');
     53            var host = doc.createElementNS('http://www.w3.org/1999/xhtml', 'div');
     54            var shadowRoot = host.attachShadow({mode: 'closed'});
     55            doc.documentElement.appendChild(host);
     56            shadowRoot.appendChild(instance);
    4157
    42 test(function () {
    43     var instance = document.createElement('my-custom-element');
    44     var documentWithoutWindow = document.implementation.createHTMLDocument();
    45     documentWithoutWindow.body.appendChild(instance);
     58            calls = [];
     59            shadowRoot.removeChild(instance);
     60            assert_array_equals(calls, ['disconnected', instance]);
     61        });
     62    }, 'Removing a custom element from a shadow tree in a ' + documentName + ' must enqueue and invoke disconnectedCallback');
    4663
    47     calls = [];
    48     documentWithoutWindow.body.removeChild(instance);
    49     assert_array_equals(calls, ['disconnected', instance]);
    50 }, 'Removing a custom element from a window-less document must enqueue and invoke disconnectedCallback');
     64    promise_test(function () {
     65        return getDocument().then(function (doc) {
     66            var instance = document.createElement('my-custom-element');
     67            var host = doc.createElementNS('http://www.w3.org/1999/xhtml', 'div');
     68            var shadowRoot = host.attachShadow({mode: 'closed'});
     69            shadowRoot.appendChild(instance);
     70            doc.documentElement.appendChild(host);
    5171
    52 test(function () {
    53     var instance = document.createElement('my-custom-element');
    54     var parent = document.createElement('div');
    55     parent.appendChild(instance);
    56     document.body.appendChild(parent);
     72            calls = [];
     73            doc.documentElement.removeChild(host);
     74            assert_array_equals(calls, ['disconnected', instance]);
     75        });
     76    }, 'Removing the shadow host of a custom element from a' + documentName + ' must enqueue and invoke disconnectedCallback');
    5777
    58     calls = [];
    59     document.body.removeChild(parent);
    60     assert_array_equals(calls, ['disconnected', instance]);
    61 }, 'Removing an ancestor of a custom element from a document must enqueue and invoke disconnectedCallback');
     78    promise_test(function () {
     79        return getDocument().then(function (doc) {
     80            var instance = document.createElement('my-custom-element');
     81            var host = doc.createElementNS('http://www.w3.org/1999/xhtml', 'div');
     82            var shadowRoot = host.attachShadow({mode: 'closed'});
     83            shadowRoot.appendChild(instance);
    6284
    63 test(function () {
    64     var instance = document.createElement('my-custom-element');
    65     var parent = document.createElement('div');
    66     parent.appendChild(instance);
    67     var documentWithoutWindow = document.implementation.createHTMLDocument();
    68     documentWithoutWindow.body.appendChild(parent);
    69 
    70     calls = [];
    71     documentWithoutWindow.body.removeChild(parent);
    72     assert_array_equals(calls, ['disconnected', instance]);
    73 }, 'Removing an ancestor of custom element from a a window-less document must enqueue and invoke disconnectedCallback');
    74 
    75 test(function () {
    76     var instance = document.createElement('my-custom-element');
    77     var host = document.createElement('div');
    78     document.body.appendChild(host);
    79     var shadowRoot = host.attachShadow({mode: 'closed'});
    80     shadowRoot.appendChild(instance);
    81 
    82     calls = [];
    83     shadowRoot.removeChild(instance);
    84     assert_array_equals(calls, ['disconnected', instance]);
    85 }, 'Removing a custom element from a connected shadow tree must enqueue and invoke disconnectedCallback');
    86 
    87 test(function () {
    88     var instance = document.createElement('my-custom-element');
    89     var host = document.createElement('div');
    90     var shadowRoot = host.attachShadow({mode: 'closed'});
    91     shadowRoot.appendChild(instance);
    92     document.body.appendChild(host);
    93 
    94     calls = [];
    95     document.body.removeChild(host);
    96     assert_array_equals(calls, ['disconnected', instance]);
    97 }, 'Removing the shadow host of a shadow tree with a custom element from a document must enqueue and invoke disconnectedCallback');
    98 
    99 test(function () {
    100     var instance = document.createElement('my-custom-element');
    101     var host = document.createElement('div');
    102     var shadowRoot = host.attachShadow({mode: 'closed'});
    103     shadowRoot.appendChild(instance);
    104 
    105     calls = [];
    106     shadowRoot.removeChild(instance);
    107     assert_array_equals(calls, []);
    108 }, 'Removing a custom element from a detached shadow tree must not enqueue and invoke disconnectedCallback');
    109 
     85            calls = [];
     86            shadowRoot.removeChild(instance);
     87            assert_array_equals(calls, []);
     88        });
     89    }, 'Removing a custom element from a detached shadow tree that belongs to a ' + documentName + ' must not enqueue and invoke disconnectedCallback');
     90});
    11091
    11192</script>
  • trunk/Source/WebCore/ChangeLog

    r205056 r205060  
     12016-08-23  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Adopted custom element's callbacks should continue to work
     4        https://bugs.webkit.org/show_bug.cgi?id=161065
     5
     6        Reviewed by Andreas Kling.
     7
     8        When a custom element is adopted into another document, its reaction callbacks need to continue to work.
     9        Because a different document may have its own global object, each custom element needs to remember its
     10        original global object or JSCustomElementInterface. This patch adds the latter to the element rare data.
     11
     12        Tests: fast/custom-elements/connected-callbacks.html
     13               fast/custom-elements/disconnected-callbacks.html
     14
     15        * bindings/js/JSCustomElementInterface.cpp:
     16        (WebCore::JSCustomElementInterface::constructElement):
     17        (WebCore::JSCustomElementInterface::upgradeElement):
     18        * dom/CustomElementReactionQueue.cpp:
     19        (WebCore::findInterfaceForCustomElement): Deleted.
     20        (WebCore::CustomElementReactionQueue::enqueueConnectedCallbackIfNeeded):
     21        (WebCore::CustomElementReactionQueue::enqueueDisconnectedCallbackIfNeeded):
     22        (WebCore::CustomElementReactionQueue::enqueueAttributeChangedCallbackIfNeeded):
     23        * dom/Element.cpp:
     24        (WebCore::Element::insertedInto): Invoke callbacks even when the current document is not a HTML document.
     25        (WebCore::Element::removedFrom): Ditto.
     26        (WebCore::Element::setCustomElementIsResolved): Moved from Node. Add the element interface to the rare data.
     27        (WebCore::Element::customElementInterface): Added.
     28        * dom/Element.h:
     29        * dom/ElementRareData.cpp:
     30        * dom/ElementRareData.h:
     31        (WebCore::ElementRareData::customElementInterface): Added.
     32        (WebCore::ElementRareData::setCustomElementInterface): Added.
     33        * dom/Node.h:
     34        ((WebCore::Node::setCustomElementIsResolved): Deleted.
     35
    1362016-08-26  Zalan Bujtas  <zalan@apple.com>
    237
  • trunk/Source/WebCore/bindings/js/JSCustomElementInterface.cpp

    r204619 r205060  
    9999    if (!wrappedElement)
    100100        return nullptr;
    101     wrappedElement->setCustomElementIsResolved();
     101    wrappedElement->setCustomElementIsResolved(*this);
    102102    return wrappedElement;
    103103}
     
    148148        return;
    149149    }
    150     wrappedElement->setCustomElementIsResolved();
    151     ASSERT(wrappedElement->isCustomElement());
     150    wrappedElement->setCustomElementIsResolved(*this);
    152151}
    153152
  • trunk/Source/WebCore/dom/CustomElementReactionQueue.cpp

    r204732 r205060  
    107107}
    108108
    109 static JSCustomElementInterface* findInterfaceForCustomElement(Element& element)
    110 {
    111     ASSERT(element.isCustomElement());
    112     auto* window = element.document().domWindow();
    113     if (!window)
    114         return nullptr;
    115 
    116     auto* registry = window->customElementRegistry();
    117     if (!registry)
    118         return nullptr;
    119 
    120     return registry->findInterface(element.tagQName());
    121 }
    122 
    123109void CustomElementReactionQueue::enqueueConnectedCallbackIfNeeded(Element& element)
    124110{
    125     auto* elementInterface = findInterfaceForCustomElement(element);
     111    auto* elementInterface = element.customElementInterface();
    126112    if (!elementInterface)
    127113        return;
     
    133119void CustomElementReactionQueue::enqueueDisconnectedCallbackIfNeeded(Element& element)
    134120{
    135     auto* elementInterface = findInterfaceForCustomElement(element);
     121    auto* elementInterface = element.customElementInterface();
    136122    if (!elementInterface)
    137123        return;
     
    143129void CustomElementReactionQueue::enqueueAttributeChangedCallbackIfNeeded(Element& element, const QualifiedName& attributeName, const AtomicString& oldValue, const AtomicString& newValue)
    144130{
    145     auto* elementInterface = findInterfaceForCustomElement(element);
     131    auto* elementInterface = element.customElementInterface();
    146132    if (!elementInterface || !elementInterface->observesAttribute(attributeName.localName()))
    147133        return;
  • trunk/Source/WebCore/dom/Element.cpp

    r204732 r205060  
    15751575    // or its ancestor is inserted belongs to the same tree scope as this element's.
    15761576    TreeScope* newScope = &insertionPoint.treeScope();
    1577     HTMLDocument* newDocument = !wasInDocument && inDocument() && is<HTMLDocument>(newScope->documentScope()) ? &downcast<HTMLDocument>(newScope->documentScope()) : nullptr;
     1577    bool becomeConnected = !wasInDocument && inDocument();
     1578    HTMLDocument* newDocument = becomeConnected && is<HTMLDocument>(newScope->documentScope()) ? &downcast<HTMLDocument>(newScope->documentScope()) : nullptr;
    15781579    if (newScope != &treeScope())
    15791580        newScope = nullptr;
     
    16011602
    16021603#if ENABLE(CUSTOM_ELEMENTS)
    1603     if (newDocument && UNLIKELY(isCustomElement()))
     1604    if (becomeConnected && UNLIKELY(isCustomElement()))
    16041605        CustomElementReactionQueue::enqueueConnectedCallbackIfNeeded(*this);
    16051606#endif
     
    16231624    if (insertionPoint.isInTreeScope()) {
    16241625        TreeScope* oldScope = &insertionPoint.treeScope();
    1625         HTMLDocument* oldDocument = inDocument() && is<HTMLDocument>(oldScope->documentScope()) ? &downcast<HTMLDocument>(oldScope->documentScope()) : nullptr;
     1626        bool becomeDisconnected = inDocument();
     1627        HTMLDocument* oldDocument = becomeDisconnected && is<HTMLDocument>(oldScope->documentScope()) ? &downcast<HTMLDocument>(oldScope->documentScope()) : nullptr;
    16261628
    16271629        // ContainerNode::removeBetween always sets the removed chid's tree scope to Document's but InTreeScope flag is unset in Node::removedFrom.
     
    16521654
    16531655#if ENABLE(CUSTOM_ELEMENTS)
    1654         if (oldDocument && UNLIKELY(isCustomElement()))
     1656        if (becomeDisconnected && UNLIKELY(isCustomElement()))
    16551657            CustomElementReactionQueue::enqueueDisconnectedCallbackIfNeeded(*this);
    16561658#endif
     
    18211823    return *shadowRoot;
    18221824}
     1825
     1826   
     1827#if ENABLE(CUSTOM_ELEMENTS)
     1828
     1829void Element::setCustomElementIsResolved(JSCustomElementInterface& elementInterface)
     1830{
     1831    clearFlag(IsEditingTextOrUnresolvedCustomElementFlag);
     1832    setFlag(IsCustomElement);
     1833    ensureElementRareData().setCustomElementInterface(elementInterface);
     1834}
     1835
     1836JSCustomElementInterface* Element::customElementInterface() const
     1837{
     1838    ASSERT(isCustomElement());
     1839    if (!hasRareData())
     1840        return nullptr;
     1841    return elementRareData()->customElementInterface();
     1842}
     1843
     1844#endif
     1845
    18231846
    18241847const AtomicString& Element::shadowPseudoId() const
  • trunk/Source/WebCore/dom/Element.h

    r204717 r205060  
    4545class HTMLDocument;
    4646class IntSize;
     47class JSCustomElementInterface;
    4748class KeyboardEvent;
    4849class Locale;
     
    272273    ShadowRoot* userAgentShadowRoot() const;
    273274    WEBCORE_EXPORT ShadowRoot& ensureUserAgentShadowRoot();
     275
     276#if ENABLE(CUSTOM_ELEMENTS)
     277    void setCustomElementIsResolved(JSCustomElementInterface&);
     278    JSCustomElementInterface* customElementInterface() const;
     279#endif
    274280
    275281    // FIXME: this should not be virtual, do not override this.
  • trunk/Source/WebCore/dom/ElementRareData.cpp

    r197777 r205060  
    4545    LayoutSize sizeForResizing;
    4646    IntPoint savedLayerScrollPosition;
     47#if ENABLE(CUSTOM_ELEMENTS)
     48    void* pointers[8];
     49#else
    4750    void* pointers[7];
     51#endif
    4852};
    4953
  • trunk/Source/WebCore/dom/ElementRareData.h

    r202607 r205060  
    2525#include "DOMTokenList.h"
    2626#include "DatasetDOMStringMap.h"
     27#include "JSCustomElementInterface.h"
    2728#include "NamedNodeMap.h"
    2829#include "NodeRareData.h"
     
    9394    ShadowRoot* shadowRoot() const { return m_shadowRoot.get(); }
    9495    void setShadowRoot(RefPtr<ShadowRoot>&& shadowRoot) { m_shadowRoot = WTFMove(shadowRoot); }
     96
     97#if ENABLE(CUSTOM_ELEMENTS)
     98    JSCustomElementInterface* customElementInterface() { return m_customElementInterface.get(); }
     99    void setCustomElementInterface(JSCustomElementInterface& customElementInterface) { m_customElementInterface = &customElementInterface; }
     100#endif
    95101
    96102    NamedNodeMap* attributeMap() const { return m_attributeMap.get(); }
     
    150156    std::unique_ptr<DOMTokenList> m_classList;
    151157    RefPtr<ShadowRoot> m_shadowRoot;
     158#if ENABLE(CUSTOM_ELEMENTS)
     159    RefPtr<JSCustomElementInterface> m_customElementInterface;
     160#endif
    152161    std::unique_ptr<NamedNodeMap> m_attributeMap;
    153162
  • trunk/Source/WebCore/dom/Node.h

    r204717 r205060  
    268268    bool isUnresolvedCustomElement() const { return isElementNode() && getFlag(IsEditingTextOrUnresolvedCustomElementFlag); }
    269269    void setIsUnresolvedCustomElement() { setFlag(IsEditingTextOrUnresolvedCustomElementFlag); }
    270     void setCustomElementIsResolved();
    271270#endif
    272271
     
    770769}
    771770
    772 #if ENABLE(CUSTOM_ELEMENTS)
    773 
    774 inline void Node::setCustomElementIsResolved()
    775 {
    776     clearFlag(IsEditingTextOrUnresolvedCustomElementFlag);
    777     setFlag(IsCustomElement);
    778 }
    779 
    780 #endif
    781 
    782771} // namespace WebCore
    783772
Note: See TracChangeset for help on using the changeset viewer.