Title: [205416] trunk
Revision
205416
Author
[email protected]
Date
2016-09-03 22:09:28 -0700 (Sat, 03 Sep 2016)

Log Message

Update the semantics of defined-ness of custom elements per spec changes
https://bugs.webkit.org/show_bug.cgi?id=161570

Reviewed by Darin Adler.

Source/WebCore:

This patch adds the notion of a custom element that failed to construct or upgrade so that :defined
doesn't apply to such an element. We also set the defined flag inside the HTMLElement constructor in
the case of synchronous construction instead of waiting for the custom element constructor to finish.
https://dom.spec.whatwg.org/#concept-create-element

Conceptually, there are four distinct states for an element:
1. The element is a built-in element
2. The element is a custom element yet to be defined (an upgrade candidate).
3. The element is a well-defined custom element (constructed or upgraded).
4. The element has failed to construct or upgrade as a custom element (because the custom element
constructor threw an exception or returned an unexpected object).

In the latest DOM/HTML specifications, these states are called as 1. "uncustomized", 2. "undefined",
3. "custom", and 4. "failed": https://dom.spec.whatwg.org/#concept-element-defined

This patch refactors Node flags to introduce these distinct states as the following:
1. Neither IsCustomElement nor IsEditingTextOrUnresolvedCustomElementFlag is set.
2. IsCustomElement and IsEditingTextOrUnresolvedCustomElementFlag are set.
isCustomElementUpgradeCandidate() and isUndefinedCustomElement() return true.
3. IsCustomElement is set and IsEditingTextOrUnresolvedCustomElementFlag is unset.
isDefinedCustomElement() returns true.
4. IsCustomElement is unset and IsEditingTextOrUnresolvedCustomElementFlag is set.
isFailedCustomElement() and isUndefinedCustomElement() return true.

Per a spec change, this patch also makes :defined applied to a synchronously constructed custom element
immediately after super() call in the constructor. When the constructor throws an exception or fails to
return the right element, the HTML parser marks the fallback element with setIsUndefinedCustomElement.

Tests: fast/custom-elements/defined-pseudo-class.html
       fast/custom-elements/defined-rule.html
       fast/custom-elements/upgrading/Node-cloneNode.html

* bindings/js/JSCustomElementInterface.cpp:
(WebCore::JSCustomElementInterface::constructElement): Don't set :defined flag here since that's done
in the HTMLElement constructor now.
(WebCore::JSCustomElementInterface::upgradeElement): Mark the element as failed-to-upgrade as needed.
* bindings/js/JSElementCustom.cpp:
(WebCore::toJSNewlyCreated):
* bindings/js/JSHTMLElementCustom.cpp:
(WebCore::constructJSHTMLElement):
* css/SelectorCheckerTestFunctions.h:
(WebCore::isDefinedElement):
* dom/CustomElementReactionQueue.cpp:
(WebCore::CustomElementReactionQueue::enqueueElementUpgradeIfDefined): Enqueue custom element reactions
only if the element is well defined (successfully constructed or upgraded).
(WebCore::CustomElementReactionQueue::enqueueConnectedCallbackIfNeeded): Ditto.
(WebCore::CustomElementReactionQueue::enqueueDisconnectedCallbackIfNeeded): Ditto.
(WebCore::CustomElementReactionQueue::enqueueAdoptedCallbackIfNeeded): Ditto.
(WebCore::CustomElementReactionQueue::enqueueAttributeChangedCallbackIfNeeded): Ditto.
* dom/CustomElementRegistry.cpp:
(WebCore::enqueueUpgradeInShadowIncludingTreeOrder):
* dom/Document.cpp:
(WebCore::createUpgradeCandidateElement):
(WebCore::createFallbackHTMLElement):
* dom/Element.cpp:
(WebCore::Element::attributeChanged):
(WebCore::Element::didMoveToNewDocument):
(WebCore::Element::insertedInto):
(WebCore::Element::removedFrom):
(WebCore::Element::setCustomElementIsResolved): Deleted.
(WebCore::Element::setIsDefinedCustomElement): Renamed from setCustomElementIsResolved.
(WebCore::Element::setIsFailedCustomElement): Added.
(WebCore::Element::setIsCustomElementUpgradeCandidate): Added.
(WebCore::Element::customElementInterface):
* dom/Element.h:
* dom/Node.h:
(WebCore::Node::setIsCustomElement): Deleted.
(WebCore::Node::isUndefinedCustomElement): Renamed from isUnresolvedCustomElement.
(WebCore::Node::setIsUnresolvedCustomElement): Deleted.
(WebCore::Node::isCustomElementUpgradeCandidate): Added.
(WebCore::Node::isDefinedCustomElement): Renamed from isCustomElement.
(WebCore::Node::isFailedCustomElement): Added.
* dom/make_names.pl:
(printWrapperFactoryCppFile): Use the HTMLElement wrapper on upgrade candidates. When a custom element
failed to upgrade, the HTMLElement constructor would have created the wrapper so we never run this code.
* html/parser/HTMLConstructionSite.cpp:
(WebCore::HTMLConstructionSite::createHTMLElementOrFindCustomElementInterface):
* html/parser/HTMLDocumentParser.cpp:
(WebCore::HTMLDocumentParser::runScriptsForPausedTreeBuilder): Mark the HTMLUnknownElement created when
the custom element constructor failed to run successfully as a failed custom element so that :define
wouldn't apply to this element.

LayoutTests:

Added a new test cases to defined-pseudo-class.html, defined-rule.html, and Node-cloneNode.html
and rebaselined the tests.

* fast/custom-elements/defined-pseudo-class-expected.txt:
* fast/custom-elements/defined-pseudo-class.html:
(MyElement): Made matchInsideConstructor an instance variable so that there won't be inter-test dependency.
Added test cases for :defined not being not applying to a failed-to-upgrade custom element. Finally, updated
test expectation to reflect the fact :defined now applies inside custom element constructors immediately after
super() call.
* fast/custom-elements/defined-rule.html: Added a test case for :defined not applying to a failed-to-upgrade
custom element. Also adjusted the height of the last box so that the green box is still 100px by 100px.
* fast/custom-elements/upgrading/Node-cloneNode-expected.txt:
* fast/custom-elements/upgrading/Node-cloneNode.html: Added a test to make sure we don't try to upgrade
a custom element for the second time when the first attempt resulted in the constructor throwing an exception.

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (205415 => 205416)


--- trunk/LayoutTests/ChangeLog	2016-09-04 04:34:57 UTC (rev 205415)
+++ trunk/LayoutTests/ChangeLog	2016-09-04 05:09:28 UTC (rev 205416)
@@ -1,5 +1,27 @@
 2016-09-03  Ryosuke Niwa  <[email protected]>
 
+        Update the semantics of defined-ness of custom elements per spec changes
+        https://bugs.webkit.org/show_bug.cgi?id=161570
+
+        Reviewed by Darin Adler.
+
+        Added a new test cases to defined-pseudo-class.html, defined-rule.html, and Node-cloneNode.html
+        and rebaselined the tests.
+
+        * fast/custom-elements/defined-pseudo-class-expected.txt:
+        * fast/custom-elements/defined-pseudo-class.html:
+        (MyElement): Made matchInsideConstructor an instance variable so that there won't be inter-test dependency.
+        Added test cases for :defined not being not applying to a failed-to-upgrade custom element. Finally, updated
+        test expectation to reflect the fact :defined now applies inside custom element constructors immediately after
+        super() call.
+        * fast/custom-elements/defined-rule.html: Added a test case for :defined not applying to a failed-to-upgrade
+        custom element. Also adjusted the height of the last box so that the green box is still 100px by 100px.
+        * fast/custom-elements/upgrading/Node-cloneNode-expected.txt:
+        * fast/custom-elements/upgrading/Node-cloneNode.html: Added a test to make sure we don't try to upgrade
+        a custom element for the second time when the first attempt resulted in the constructor throwing an exception.
+
+2016-09-03  Ryosuke Niwa  <[email protected]>
+
         Unbreak customElements.whenDefined after r205383 with a crash fix
         https://bugs.webkit.org/show_bug.cgi?id=161562
 

Modified: trunk/LayoutTests/fast/custom-elements/defined-pseudo-class-expected.txt (205415 => 205416)


--- trunk/LayoutTests/fast/custom-elements/defined-pseudo-class-expected.txt	2016-09-04 04:34:57 UTC (rev 205415)
+++ trunk/LayoutTests/fast/custom-elements/defined-pseudo-class-expected.txt	2016-09-04 05:09:28 UTC (rev 205416)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 75: TypeError: The result of constructing a custom element must be a HTMLElement
+CONSOLE MESSAGE: line 79: TypeError: The result of constructing a custom element must be a HTMLElement
 
 Harness Error (FAIL), message = TypeError: The result of constructing a custom element must be a HTMLElement
 
@@ -5,10 +5,12 @@
 PASS The defined flag of a custom element must not be set if a custom element has not been upgraded yet 
 PASS The defined flag of a custom element must not be set if a custom element has not been upgraded yet even if the element has been defined 
 PASS The defined flag of a custom element must be set when a custom element is successfully upgraded 
-PASS The defined flag of a custom element must be set if there is a matching definition 
+PASS The defined flag of a custom element must be set inside the HTMLElement constructor 
 PASS The defined flag of an upgraded custom element must be set 
 PASS The defined flag of a custom element created by HTML parser must be unset if there is no matching definition 
 PASS The defined flag of a custom element created by HTML parser must be set if there is a matching definition 
-PASS The defined flag of a custom element created by HTML parser must be set after checking the returned result is an instance of HTMLElement 
+PASS The element inserted by HTML parser must not have the defined flag set if the constructor returns a Text node 
 PASS The defined flag of a custom element must be set after checking the returned result is an instance of HTMLElement when upgrading a custom element 
+PASS The defined flag of a custom element must be set inside a constructor when constructing a custom element synchronously even if the constructor threw an exception later 
+PASS The defined flag of a custom element must not be set when an upgrade of a custom element fails 
 

Modified: trunk/LayoutTests/fast/custom-elements/defined-pseudo-class.html (205415 => 205416)


--- trunk/LayoutTests/fast/custom-elements/defined-pseudo-class.html	2016-09-04 04:34:57 UTC (rev 205415)
+++ trunk/LayoutTests/fast/custom-elements/defined-pseudo-class.html	2016-09-04 05:09:28 UTC (rev 205416)
@@ -18,13 +18,13 @@
     assert_false(upgradeCandidate.matches(':defined'));
 }, 'The defined flag of a custom element must not be set if a custom element has not been upgraded yet');
 
-var matchInsideConstructor;
 class MyElement extends HTMLElement {
     constructor() {
         super();
-        matchInsideConstructor = this.matches(':defined');
+        this.matchInsideConstructor = this.matches(':defined');
     }
 }
+
 customElements.define('my-element', MyElement);
 
 test(function () {
@@ -34,19 +34,19 @@
 test(function () {
     document.body.appendChild(upgradeCandidate);
     assert_true(upgradeCandidate.matches(':defined'));
-    assert_false(matchInsideConstructor, 'Upgrading a custom element must set defined flag after invoking the constructor');
+    assert_false(!!upgradeCandidate.matchInsideConstructor, 'Upgrading a custom element must set defined flag after invoking the constructor');
 }, 'The defined flag of a custom element must be set when a custom element is successfully upgraded');
 
 test(function () {
     var definedElement = document.createElement('my-element');
     assert_true(definedElement.matches(':defined'));
-    assert_false(matchInsideConstructor, 'Creating a custom element must set defined flag after invoking the constructor');
-}, 'The defined flag of a custom element must be set if there is a matching definition');
+    assert_true(!!definedElement.matchInsideConstructor);
+}, 'The defined flag of a custom element must be set inside the HTMLElement constructor');
 
 test(function () {
     var upgradedElement = document.createElement('my-element').cloneNode(true);
     assert_true(upgradedElement.matches(':defined'));
-    assert_false(matchInsideConstructor, 'Creating a custom element must set defined flag after invoking the constructor');
+    assert_false(!!upgradedElement.matchInsideConstructor, 'Upgrading a custom element must set defined flag after invoking the constructor');
 }, 'The defined flag of an upgraded custom element must be set');
 
 document.write('<my-other-element></my-other-element>');
@@ -54,19 +54,23 @@
 test(function () {
     var parserCreatedUnfefinedElement = document.querySelector('my-other-element');
     assert_false(parserCreatedUnfefinedElement.matches(':defined'));
+    assert_false(!!parserCreatedUnfefinedElement.matchInsideConstructor);
 }, 'The defined flag of a custom element created by HTML parser must be unset if there is no matching definition');
 
-document.write('<my-element></my-element>');
+document.write('<my-element id="parser-created-defined-element"></my-element>');
 
 test(function () {
-    var parserCreatedDefinedElement = document.querySelector('my-element');
+    var parserCreatedDefinedElement = document.getElementById('parser-created-defined-element');
     assert_true(parserCreatedDefinedElement.matches(':defined'));
+    assert_true(!!parserCreatedDefinedElement.matchInsideConstructor,
+        'The defined flag must be set inside HTMLElement constructor when HTMLParser creates a custom element synchronously');
 }, 'The defined flag of a custom element created by HTML parser must be set if there is a matching definition');
 
 class ReturnsAnotherNode extends HTMLElement {
     constructor() {
         super();
-        matchInsideConstructor = this.matches(':defined');
+        this.matchInsideConstructor = this.matches(':defined');
+        ReturnsAnotherNode.lastInstance = this;
         return document.createTextNode('');
     }
 }
@@ -75,10 +79,14 @@
 document.write('<returns-another-node></returns-another-node>');
 
 test(function () {
-    assert_true(document.querySelector('returns-another-node').matches(':defined'));
-    assert_false(matchInsideConstructor,
-        'HTML parser must create a custom element with the defined flag initially unset');
-}, 'The defined flag of a custom element created by HTML parser must be set after checking the returned result is an instance of HTMLElement');
+    var instance = document.querySelector('returns-another-node');
+    assert_not_equals(instance, ReturnsAnotherNode.lastInstance, 'The element inserted by HTML parser must not be the one returned by super() call');
+    assert_true(instance instanceof HTMLElement, 'The element inserted by HTML parser must be a HTMLElement');
+    assert_false(instance instanceof ReturnsAnotherNode, 'The element inserted by HTML parser must be a custom element');
+    assert_false(instance.matches(':defined'), 'The defined flag must not be set on the element inserted by HTML parser');
+    assert_true(!!ReturnsAnotherNode.lastInstance.matchInsideConstructor,
+        'The defined flag must be set inside HTMLElement constructor when HTMLParser creates a custom element synchronously');
+}, 'The element inserted by HTML parser must not have the defined flag set if the constructor returns a Text node');
 
 test(function () {
     var instance = document.createElement('returns-another-node-2');
@@ -86,10 +94,38 @@
         customElements.define('returns-another-node-2', class extends ReturnsAnotherNode {});
     } catch (e) { }
     assert_false(instance.matches(':defined'));
-    assert_false(matchInsideConstructor,
+    assert_false(!!instance.matchInsideConstructor,
         'Creating a custom element must leave the defined flag unset when synchronous custom elements flag is not set');
 }, 'The defined flag of a custom element must be set after checking the returned result is an instance of HTMLElement when upgrading a custom element');
 
+test(function () {
+    var matchInsideConstructor = false;
+    customElements.define('throws-exception', class extends HTMLElement {
+        constructor() {
+            super();
+            matchInsideConstructor = this.matches(':defined');
+            throw {name: 'bad'};
+        }
+    });
+    var instance;
+    assert_throws({name: 'bad'}, function () { instance = document.createElement('throws-exception'); });
+    assert_true(matchInsideConstructor);
+}, 'The defined flag of a custom element must be set inside a constructor when constructing a custom element synchronously'
+    + ' even if the constructor threw an exception later');
+
+test(function () {
+    var instance = document.createElement('throws-exception-2');
+    document.body.appendChild(instance);
+    assert_throws({name: 'bad'}, function () {
+        customElements.define('throws-exception-2', class extends HTMLElement {
+            constructor() {
+                throw {name: 'bad'};
+            }
+        });
+    });
+    assert_false(instance.matches(':defined'));
+}, 'The defined flag of a custom element must not be set when an upgrade of a custom element fails');
+
 </script>
 </body>
 </html>

Modified: trunk/LayoutTests/fast/custom-elements/defined-rule.html (205415 => 205416)


--- trunk/LayoutTests/fast/custom-elements/defined-rule.html	2016-09-04 04:34:57 UTC (rev 205415)
+++ trunk/LayoutTests/fast/custom-elements/defined-rule.html	2016-09-04 05:09:28 UTC (rev 205416)
@@ -21,7 +21,11 @@
         my-undefined-element:defined { background: red; }
         my-undefined-element:not(:defined) { color: green; }
 
-        div.box { background: green; color: red; height: 50px; }
+        failed-element { background: green; color: red; }
+        failed-element:defined { background: red; }
+        failed-element:not(:defined) { color: green; }
+
+        div.box { background: green; color: red; }
         div:defined { color: green; }
         div:not(:defined) { background: red; }
     </style>
@@ -28,10 +32,14 @@
     <p>Test passes if you see a single 100px by 100px green box below.</p>
     <my-defined-element class="box">FAIL</my-defined-element>
     <my-undefined-element class="box">FAIL</my-undefined-element>
+    <failed-element class="box">FAIL</failed-element>
     <div class="box"></div>
     <script>
 
         customElements.define('my-defined-element', class extends HTMLElement {});
+        customElements.define('failed-element', class extends HTMLElement {
+            constructor() { throw 'bad'; }
+        });
 
     </script>
 </body>

Modified: trunk/LayoutTests/fast/custom-elements/upgrading/Node-cloneNode-expected.txt (205415 => 205416)


--- trunk/LayoutTests/fast/custom-elements/upgrading/Node-cloneNode-expected.txt	2016-09-04 04:34:57 UTC (rev 205415)
+++ trunk/LayoutTests/fast/custom-elements/upgrading/Node-cloneNode-expected.txt	2016-09-04 05:09:28 UTC (rev 205416)
@@ -6,4 +6,5 @@
 PASS HTMLElement constructor must throw an InvalidStateError when the top of the construction stack is marked AlreadyConstructed due to a custom element constructor constructing itself after super() call 
 PASS HTMLElement constructor must throw an InvalidStateError when the top of the construction stack is marked AlreadyConstructed due to a custom element constructor constructing itself before super() call 
 PASS Upgrading a custom element must throw InvalidStateError when the custom element's constructor returns another element 
+PASS Inserting an element must not try to upgrade a custom element when it had already failed to upgrade once 
 

Modified: trunk/LayoutTests/fast/custom-elements/upgrading/Node-cloneNode.html (205415 => 205416)


--- trunk/LayoutTests/fast/custom-elements/upgrading/Node-cloneNode.html	2016-09-04 04:34:57 UTC (rev 205415)
+++ trunk/LayoutTests/fast/custom-elements/upgrading/Node-cloneNode.html	2016-09-04 05:09:28 UTC (rev 205416)
@@ -164,6 +164,33 @@
     });
 }, 'Upgrading a custom element must throw InvalidStateError when the custom element\'s constructor returns another element');
 
+test(function () {
+    withNewDocumentWithABrowsingContext(function (contentWindow, contentDocument) {
+
+        var instance = contentDocument.createElement('my-custom-element');
+        contentDocument.body.appendChild(instance);
+
+        var calls = [];
+        class MyCustomElement extends contentWindow.HTMLElement {
+            constructor() {
+                super();
+                calls.push(this);
+                throw 'bad';
+            }
+        }
+
+        try {
+            contentWindow.customElements.define('my-custom-element', MyCustomElement);
+        } catch (e) { }
+
+        assert_array_equals(calls, [instance]);
+        contentDocument.body.removeChild(instance);
+        contentDocument.body.appendChild(instance);
+        assert_array_equals(calls, [instance]);
+
+    });
+}, 'Inserting an element must not try to upgrade a custom element when it had already failed to upgrade once');
+
 </script>
 </body>
 </html>

Modified: trunk/Source/WebCore/ChangeLog (205415 => 205416)


--- trunk/Source/WebCore/ChangeLog	2016-09-04 04:34:57 UTC (rev 205415)
+++ trunk/Source/WebCore/ChangeLog	2016-09-04 05:09:28 UTC (rev 205416)
@@ -1,3 +1,92 @@
+2016-09-03  Ryosuke Niwa  <[email protected]>
+
+        Update the semantics of defined-ness of custom elements per spec changes
+        https://bugs.webkit.org/show_bug.cgi?id=161570
+
+        Reviewed by Darin Adler.
+
+        This patch adds the notion of a custom element that failed to construct or upgrade so that :defined
+        doesn't apply to such an element. We also set the defined flag inside the HTMLElement constructor in
+        the case of synchronous construction instead of waiting for the custom element constructor to finish.
+        https://dom.spec.whatwg.org/#concept-create-element
+
+        Conceptually, there are four distinct states for an element:
+        1. The element is a built-in element
+        2. The element is a custom element yet to be defined (an upgrade candidate).
+        3. The element is a well-defined custom element (constructed or upgraded).
+        4. The element has failed to construct or upgrade as a custom element (because the custom element
+        constructor threw an exception or returned an unexpected object).
+
+        In the latest DOM/HTML specifications, these states are called as 1. "uncustomized", 2. "undefined",
+        3. "custom", and 4. "failed": https://dom.spec.whatwg.org/#concept-element-defined
+
+        This patch refactors Node flags to introduce these distinct states as the following:
+        1. Neither IsCustomElement nor IsEditingTextOrUnresolvedCustomElementFlag is set.
+        2. IsCustomElement and IsEditingTextOrUnresolvedCustomElementFlag are set.
+        isCustomElementUpgradeCandidate() and isUndefinedCustomElement() return true.
+        3. IsCustomElement is set and IsEditingTextOrUnresolvedCustomElementFlag is unset.
+        isDefinedCustomElement() returns true.
+        4. IsCustomElement is unset and IsEditingTextOrUnresolvedCustomElementFlag is set.
+        isFailedCustomElement() and isUndefinedCustomElement() return true.
+
+        Per a spec change, this patch also makes :defined applied to a synchronously constructed custom element
+        immediately after super() call in the constructor. When the constructor throws an exception or fails to
+        return the right element, the HTML parser marks the fallback element with setIsUndefinedCustomElement.
+
+        Tests: fast/custom-elements/defined-pseudo-class.html
+               fast/custom-elements/defined-rule.html
+               fast/custom-elements/upgrading/Node-cloneNode.html
+
+        * bindings/js/JSCustomElementInterface.cpp:
+        (WebCore::JSCustomElementInterface::constructElement): Don't set :defined flag here since that's done
+        in the HTMLElement constructor now.
+        (WebCore::JSCustomElementInterface::upgradeElement): Mark the element as failed-to-upgrade as needed.
+        * bindings/js/JSElementCustom.cpp:
+        (WebCore::toJSNewlyCreated):
+        * bindings/js/JSHTMLElementCustom.cpp:
+        (WebCore::constructJSHTMLElement):
+        * css/SelectorCheckerTestFunctions.h:
+        (WebCore::isDefinedElement):
+        * dom/CustomElementReactionQueue.cpp:
+        (WebCore::CustomElementReactionQueue::enqueueElementUpgradeIfDefined): Enqueue custom element reactions
+        only if the element is well defined (successfully constructed or upgraded).
+        (WebCore::CustomElementReactionQueue::enqueueConnectedCallbackIfNeeded): Ditto.
+        (WebCore::CustomElementReactionQueue::enqueueDisconnectedCallbackIfNeeded): Ditto.
+        (WebCore::CustomElementReactionQueue::enqueueAdoptedCallbackIfNeeded): Ditto.
+        (WebCore::CustomElementReactionQueue::enqueueAttributeChangedCallbackIfNeeded): Ditto.
+        * dom/CustomElementRegistry.cpp:
+        (WebCore::enqueueUpgradeInShadowIncludingTreeOrder):
+        * dom/Document.cpp:
+        (WebCore::createUpgradeCandidateElement):
+        (WebCore::createFallbackHTMLElement):
+        * dom/Element.cpp:
+        (WebCore::Element::attributeChanged):
+        (WebCore::Element::didMoveToNewDocument):
+        (WebCore::Element::insertedInto):
+        (WebCore::Element::removedFrom):
+        (WebCore::Element::setCustomElementIsResolved): Deleted.
+        (WebCore::Element::setIsDefinedCustomElement): Renamed from setCustomElementIsResolved.
+        (WebCore::Element::setIsFailedCustomElement): Added.
+        (WebCore::Element::setIsCustomElementUpgradeCandidate): Added.
+        (WebCore::Element::customElementInterface):
+        * dom/Element.h:
+        * dom/Node.h:
+        (WebCore::Node::setIsCustomElement): Deleted.
+        (WebCore::Node::isUndefinedCustomElement): Renamed from isUnresolvedCustomElement.
+        (WebCore::Node::setIsUnresolvedCustomElement): Deleted.
+        (WebCore::Node::isCustomElementUpgradeCandidate): Added.
+        (WebCore::Node::isDefinedCustomElement): Renamed from isCustomElement.
+        (WebCore::Node::isFailedCustomElement): Added.
+        * dom/make_names.pl:
+        (printWrapperFactoryCppFile): Use the HTMLElement wrapper on upgrade candidates. When a custom element
+        failed to upgrade, the HTMLElement constructor would have created the wrapper so we never run this code.
+        * html/parser/HTMLConstructionSite.cpp:
+        (WebCore::HTMLConstructionSite::createHTMLElementOrFindCustomElementInterface): 
+        * html/parser/HTMLDocumentParser.cpp:
+        (WebCore::HTMLDocumentParser::runScriptsForPausedTreeBuilder): Mark the HTMLUnknownElement created when
+        the custom element constructor failed to run successfully as a failed custom element so that :define
+        wouldn't apply to this element.
+
 2016-09-03  Wenson Hsieh  <[email protected]>
 
         Refactor the heuristic for showing media controls to take all media sessions into account

Modified: trunk/Source/WebCore/bindings/js/JSCustomElementInterface.cpp (205415 => 205416)


--- trunk/Source/WebCore/bindings/js/JSCustomElementInterface.cpp	2016-09-04 04:34:57 UTC (rev 205415)
+++ trunk/Source/WebCore/bindings/js/JSCustomElementInterface.cpp	2016-09-04 05:09:28 UTC (rev 205416)
@@ -89,7 +89,6 @@
         return nullptr;
     }
 
-    element->setCustomElementIsResolved(*this);
     return element;
 }
 
@@ -149,7 +148,7 @@
 void JSCustomElementInterface::upgradeElement(Element& element)
 {
     ASSERT(element.tagQName() == name());
-    ASSERT(element.isUnresolvedCustomElement());
+    ASSERT(element.isCustomElementUpgradeCandidate());
     if (!canInvokeCallback())
         return;
 
@@ -186,15 +185,18 @@
 
     m_constructionStack.removeLast();
 
-    if (state->hadException())
+    if (state->hadException()) {
+        element.setIsFailedCustomElement(*this);
         return;
+    }
 
     Element* wrappedElement = JSElement::toWrapped(returnedElement);
     if (!wrappedElement || wrappedElement != &element) {
+        element.setIsFailedCustomElement(*this);
         throwInvalidStateError(*state, scope, "Custom element constructor failed to upgrade an element");
         return;
     }
-    wrappedElement->setCustomElementIsResolved(*this);
+    element.setIsDefinedCustomElement(*this);
 }
 
 void JSCustomElementInterface::invokeCallback(Element& element, JSObject* callback, const WTF::Function<void(ExecState*, JSDOMGlobalObject*, MarkedArgumentBuffer&)>& addArguments)

Modified: trunk/Source/WebCore/bindings/js/JSElementCustom.cpp (205415 => 205416)


--- trunk/Source/WebCore/bindings/js/JSElementCustom.cpp	2016-09-04 04:34:57 UTC (rev 205415)
+++ trunk/Source/WebCore/bindings/js/JSElementCustom.cpp	2016-09-04 05:09:28 UTC (rev 205416)
@@ -68,7 +68,7 @@
 JSValue toJSNewlyCreated(ExecState*, JSDOMGlobalObject* globalObject, Ref<Element>&& element)
 {
 #if ENABLE(CUSTOM_ELEMENTS)
-    if (element->isCustomElement())
+    if (element->isDefinedCustomElement())
         return getCachedWrapper(globalObject->world(), element);
 #endif
     ASSERT(!getCachedWrapper(globalObject->world(), element));

Modified: trunk/Source/WebCore/bindings/js/JSHTMLElementCustom.cpp (205415 => 205416)


--- trunk/Source/WebCore/bindings/js/JSHTMLElementCustom.cpp	2016-09-04 04:34:57 UTC (rev 205415)
+++ trunk/Source/WebCore/bindings/js/JSHTMLElementCustom.cpp	2016-09-04 05:09:28 UTC (rev 205416)
@@ -82,7 +82,7 @@
             return JSValue::encode(jsUndefined());
 
         Ref<HTMLElement> element = HTMLElement::create(elementInterface->name(), document);
-        element->setIsUnresolvedCustomElement();
+        element->setIsDefinedCustomElement(*elementInterface);
         auto* jsElement = JSHTMLElement::create(newElementStructure, globalObject, element.get());
         cacheWrapper(globalObject->world(), element.ptr(), jsElement);
         return JSValue::encode(jsElement);

Modified: trunk/Source/WebCore/css/SelectorCheckerTestFunctions.h (205415 => 205416)


--- trunk/Source/WebCore/css/SelectorCheckerTestFunctions.h	2016-09-04 04:34:57 UTC (rev 205415)
+++ trunk/Source/WebCore/css/SelectorCheckerTestFunctions.h	2016-09-04 05:09:28 UTC (rev 205416)
@@ -66,7 +66,7 @@
 #if ENABLE(CUSTOM_ELEMENTS)
 ALWAYS_INLINE bool isDefinedElement(const Element& element)
 {
-    return !element.isUnresolvedCustomElement();
+    return !element.isUndefinedCustomElement();
 }
 #endif
 

Modified: trunk/Source/WebCore/dom/CustomElementReactionQueue.cpp (205415 => 205416)


--- trunk/Source/WebCore/dom/CustomElementReactionQueue.cpp	2016-09-04 04:34:57 UTC (rev 205415)
+++ trunk/Source/WebCore/dom/CustomElementReactionQueue.cpp	2016-09-04 05:09:28 UTC (rev 205416)
@@ -124,7 +124,7 @@
 void CustomElementReactionQueue::enqueueElementUpgradeIfDefined(Element& element)
 {
     ASSERT(element.inDocument());
-    ASSERT(element.isUnresolvedCustomElement());
+    ASSERT(element.isCustomElementUpgradeCandidate());
     auto* window = element.document().domWindow();
     if (!window)
         return;
@@ -142,7 +142,7 @@
 
 void CustomElementReactionQueue::enqueueConnectedCallbackIfNeeded(Element& element)
 {
-    ASSERT(element.isCustomElement());
+    ASSERT(element.isDefinedCustomElement());
     auto* elementInterface = element.customElementInterface();
     ASSERT(elementInterface);
     if (!elementInterface->hasConnectedCallback())
@@ -154,7 +154,7 @@
 
 void CustomElementReactionQueue::enqueueDisconnectedCallbackIfNeeded(Element& element)
 {
-    ASSERT(element.isCustomElement());
+    ASSERT(element.isDefinedCustomElement());
     auto* elementInterface = element.customElementInterface();
     ASSERT(elementInterface);
     if (!elementInterface->hasDisconnectedCallback())
@@ -166,7 +166,7 @@
 
 void CustomElementReactionQueue::enqueueAdoptedCallbackIfNeeded(Element& element, Document& oldDocument, Document& newDocument)
 {
-    ASSERT(element.isCustomElement());
+    ASSERT(element.isDefinedCustomElement());
     auto* elementInterface = element.customElementInterface();
     ASSERT(elementInterface);
     if (!elementInterface->hasAdoptedCallback())
@@ -178,7 +178,7 @@
 
 void CustomElementReactionQueue::enqueueAttributeChangedCallbackIfNeeded(Element& element, const QualifiedName& attributeName, const AtomicString& oldValue, const AtomicString& newValue)
 {
-    ASSERT(element.isCustomElement());
+    ASSERT(element.isDefinedCustomElement());
     auto* elementInterface = element.customElementInterface();
     ASSERT(elementInterface);
     if (!elementInterface->observesAttribute(attributeName.localName()))

Modified: trunk/Source/WebCore/dom/CustomElementRegistry.cpp (205415 => 205416)


--- trunk/Source/WebCore/dom/CustomElementRegistry.cpp	2016-09-04 04:34:57 UTC (rev 205415)
+++ trunk/Source/WebCore/dom/CustomElementRegistry.cpp	2016-09-04 05:09:28 UTC (rev 205416)
@@ -60,7 +60,7 @@
 static void enqueueUpgradeInShadowIncludingTreeOrder(ContainerNode& node, JSCustomElementInterface& elementInterface)
 {
     for (Element* element = ElementTraversal::firstWithin(node); element; element = ElementTraversal::next(*element)) {
-        if (element->isUnresolvedCustomElement() && element->tagQName() == elementInterface.name())
+        if (element->isCustomElementUpgradeCandidate() && element->tagQName() == elementInterface.name())
             CustomElementReactionQueue::enqueueElementUpgrade(*element, elementInterface);
         if (auto* shadowRoot = element->shadowRoot()) {
             if (shadowRoot->mode() != ShadowRoot::Mode::UserAgent)

Modified: trunk/Source/WebCore/dom/Document.cpp (205415 => 205416)


--- trunk/Source/WebCore/dom/Document.cpp	2016-09-04 04:34:57 UTC (rev 205415)
+++ trunk/Source/WebCore/dom/Document.cpp	2016-09-04 05:09:28 UTC (rev 205416)
@@ -890,7 +890,7 @@
         return nullptr;
 
     auto element = HTMLElement::create(name, document);
-    element->setIsUnresolvedCustomElement();
+    element->setIsCustomElementUpgradeCandidate();
     return WTFMove(element);
 }
 #endif
@@ -1091,7 +1091,7 @@
         if (UNLIKELY(registry)) {
             if (auto* elementInterface = registry->findInterface(name)) {
                 auto element = HTMLElement::create(name, document);
-                element->setIsUnresolvedCustomElement();
+                element->setIsCustomElementUpgradeCandidate();
                 CustomElementReactionQueue::enqueueElementUpgrade(element.get(), *elementInterface);
                 return element;
             }

Modified: trunk/Source/WebCore/dom/Element.cpp (205415 => 205416)


--- trunk/Source/WebCore/dom/Element.cpp	2016-09-04 04:34:57 UTC (rev 205415)
+++ trunk/Source/WebCore/dom/Element.cpp	2016-09-04 05:09:28 UTC (rev 205416)
@@ -1295,7 +1295,7 @@
     document().incDOMTreeVersion();
 
 #if ENABLE(CUSTOM_ELEMENTS)
-    if (UNLIKELY(isCustomElement()))
+    if (UNLIKELY(isDefinedCustomElement()))
         CustomElementReactionQueue::enqueueAttributeChangedCallbackIfNeeded(*this, name, oldValue, newValue);
 #endif
 
@@ -1495,7 +1495,7 @@
     }
 
 #if ENABLE(CUSTOM_ELEMENTS)
-    if (UNLIKELY(isCustomElement()))
+    if (UNLIKELY(isDefinedCustomElement()))
         CustomElementReactionQueue::enqueueAdoptedCallbackIfNeeded(*this, *oldDocument, document());
 #endif
 }
@@ -1607,9 +1607,9 @@
 
 #if ENABLE(CUSTOM_ELEMENTS)
     if (becomeConnected) {
-        if (UNLIKELY(isUnresolvedCustomElement()))
+        if (UNLIKELY(isCustomElementUpgradeCandidate()))
             CustomElementReactionQueue::enqueueElementUpgradeIfDefined(*this);
-        if (UNLIKELY(isCustomElement()))
+        if (UNLIKELY(isDefinedCustomElement()))
             CustomElementReactionQueue::enqueueConnectedCallbackIfNeeded(*this);
     }
 
@@ -1663,7 +1663,7 @@
         }
 
 #if ENABLE(CUSTOM_ELEMENTS)
-        if (becomeDisconnected && UNLIKELY(isCustomElement()))
+        if (becomeDisconnected && UNLIKELY(isDefinedCustomElement()))
             CustomElementReactionQueue::enqueueDisconnectedCallbackIfNeeded(*this);
 #endif
     }
@@ -1836,16 +1836,31 @@
     
 #if ENABLE(CUSTOM_ELEMENTS)
 
-void Element::setCustomElementIsResolved(JSCustomElementInterface& elementInterface)
+void Element::setIsDefinedCustomElement(JSCustomElementInterface& elementInterface)
 {
-    clearFlag(IsEditingTextOrUnresolvedCustomElementFlag);
+    clearFlag(IsEditingTextOrUndefinedCustomElementFlag);
     setFlag(IsCustomElement);
     ensureElementRareData().setCustomElementInterface(elementInterface);
 }
 
+void Element::setIsFailedCustomElement(JSCustomElementInterface& elementInterface)
+{
+    ASSERT(isUndefinedCustomElement());
+    ASSERT(getFlag(IsEditingTextOrUndefinedCustomElementFlag));
+    clearFlag(IsCustomElement);
+    ensureElementRareData().setCustomElementInterface(elementInterface);
+}
+
+void Element::setIsCustomElementUpgradeCandidate()
+{
+    ASSERT(!getFlag(IsCustomElement));
+    setFlag(IsCustomElement);
+    setFlag(IsEditingTextOrUndefinedCustomElementFlag);
+}
+
 JSCustomElementInterface* Element::customElementInterface() const
 {
-    ASSERT(isCustomElement());
+    ASSERT(isDefinedCustomElement());
     if (!hasRareData())
         return nullptr;
     return elementRareData()->customElementInterface();

Modified: trunk/Source/WebCore/dom/Element.h (205415 => 205416)


--- trunk/Source/WebCore/dom/Element.h	2016-09-04 04:34:57 UTC (rev 205415)
+++ trunk/Source/WebCore/dom/Element.h	2016-09-04 05:09:28 UTC (rev 205416)
@@ -274,7 +274,9 @@
     WEBCORE_EXPORT ShadowRoot& ensureUserAgentShadowRoot();
 
 #if ENABLE(CUSTOM_ELEMENTS)
-    void setCustomElementIsResolved(JSCustomElementInterface&);
+    void setIsDefinedCustomElement(JSCustomElementInterface&);
+    void setIsFailedCustomElement(JSCustomElementInterface&);
+    void setIsCustomElementUpgradeCandidate();
     JSCustomElementInterface* customElementInterface() const;
 #endif
 

Modified: trunk/Source/WebCore/dom/Node.h (205415 => 205416)


--- trunk/Source/WebCore/dom/Node.h	2016-09-04 04:34:57 UTC (rev 205415)
+++ trunk/Source/WebCore/dom/Node.h	2016-09-04 05:09:28 UTC (rev 205416)
@@ -262,11 +262,10 @@
     HTMLSlotElement* assignedSlotForBindings() const;
 
 #if ENABLE(CUSTOM_ELEMENTS)
-    bool isCustomElement() const { return getFlag(IsCustomElement); }
-    void setIsCustomElement() { setFlag(IsCustomElement); }
-
-    bool isUnresolvedCustomElement() const { return isElementNode() && getFlag(IsEditingTextOrUnresolvedCustomElementFlag); }
-    void setIsUnresolvedCustomElement() { setFlag(IsEditingTextOrUnresolvedCustomElementFlag); }
+    bool isUndefinedCustomElement() const { return isElementNode() && getFlag(IsEditingTextOrUndefinedCustomElementFlag); }
+    bool isCustomElementUpgradeCandidate() const { return getFlag(IsCustomElement) && getFlag(IsEditingTextOrUndefinedCustomElementFlag); }
+    bool isDefinedCustomElement() const { return getFlag(IsCustomElement) && !getFlag(IsEditingTextOrUndefinedCustomElementFlag); }
+    bool isFailedCustomElement() const { return isElementNode() && !getFlag(IsCustomElement) && getFlag(IsEditingTextOrUndefinedCustomElementFlag); }
 #endif
 
     // Returns null, a child of ShadowRoot, or a legacy shadow root.
@@ -321,7 +320,7 @@
     StyleChangeType styleChangeType() const { return static_cast<StyleChangeType>(m_nodeFlags & StyleChangeMask); }
     bool childNeedsStyleRecalc() const { return getFlag(ChildNeedsStyleRecalcFlag); }
     bool styleIsAffectedByPreviousSibling() const { return getFlag(StyleIsAffectedByPreviousSibling); }
-    bool isEditingText() const { return getFlag(IsTextFlag) && getFlag(IsEditingTextOrUnresolvedCustomElementFlag); }
+    bool isEditingText() const { return getFlag(IsTextFlag) && getFlag(IsEditingTextOrUndefinedCustomElementFlag); }
 
     void setChildNeedsStyleRecalc() { setFlag(ChildNeedsStyleRecalcFlag); }
     void clearChildNeedsStyleRecalc() { m_nodeFlags &= ~(ChildNeedsStyleRecalcFlag | DirectChildNeedsStyleRecalcFlag); }
@@ -594,7 +593,7 @@
         IsParsingChildrenFinishedFlag = 1 << 13, // Element
 
         StyleChangeMask = 1 << nodeStyleChangeShift | 1 << (nodeStyleChangeShift + 1) | 1 << (nodeStyleChangeShift + 2),
-        IsEditingTextOrUnresolvedCustomElementFlag = 1 << 17,
+        IsEditingTextOrUndefinedCustomElementFlag = 1 << 17,
         HasFocusWithin = 1 << 18,
         HasSyntheticAttrChildNodesFlag = 1 << 19,
         HasCustomStyleResolveCallbacksFlag = 1 << 20,
@@ -633,7 +632,7 @@
         CreateHTMLElement = CreateStyledElement | IsHTMLFlag,
         CreateSVGElement = CreateStyledElement | IsSVGFlag | HasCustomStyleResolveCallbacksFlag,
         CreateDocument = CreateContainer | InDocumentFlag,
-        CreateEditingText = CreateText | IsEditingTextOrUnresolvedCustomElementFlag,
+        CreateEditingText = CreateText | IsEditingTextOrUndefinedCustomElementFlag,
         CreateMathMLElement = CreateStyledElement | IsMathMLFlag
     };
     Node(Document&, ConstructionType);

Modified: trunk/Source/WebCore/dom/make_names.pl (205415 => 205416)


--- trunk/Source/WebCore/dom/make_names.pl	2016-09-04 04:34:57 UTC (rev 205415)
+++ trunk/Source/WebCore/dom/make_names.pl	2016-09-04 05:09:28 UTC (rev 205416)
@@ -1323,7 +1323,7 @@
     if ($parameters{customElementInterfaceName}) {
         print F <<END
 #if ENABLE(CUSTOM_ELEMENTS)
-    if (element->isUnresolvedCustomElement())
+    if (element->isCustomElementUpgradeCandidate())
         return CREATE_DOM_WRAPPER(globalObject, $parameters{customElementInterfaceName}, WTFMove(element));
 #endif
 END

Modified: trunk/Source/WebCore/html/parser/HTMLConstructionSite.cpp (205415 => 205416)


--- trunk/Source/WebCore/html/parser/HTMLConstructionSite.cpp	2016-09-04 04:34:57 UTC (rev 205415)
+++ trunk/Source/WebCore/html/parser/HTMLConstructionSite.cpp	2016-09-04 05:09:28 UTC (rev 205416)
@@ -677,7 +677,7 @@
 #if ENABLE(CUSTOM_ELEMENTS)
         if (window && Document::validateCustomElementName(localName) == CustomElementNameValidationStatus::Valid) {
             element = HTMLElement::create(qualifiedName, ownerDocument);
-            element->setIsUnresolvedCustomElement();
+            element->setIsCustomElementUpgradeCandidate();
         } else
 #endif
             element = HTMLUnknownElement::create(qualifiedName, ownerDocument);

Modified: trunk/Source/WebCore/html/parser/HTMLDocumentParser.cpp (205415 => 205416)


--- trunk/Source/WebCore/html/parser/HTMLDocumentParser.cpp	2016-09-04 04:34:57 UTC (rev 205415)
+++ trunk/Source/WebCore/html/parser/HTMLDocumentParser.cpp	2016-09-04 05:09:28 UTC (rev 205416)
@@ -195,10 +195,14 @@
     if (std::unique_ptr<CustomElementConstructionData> constructionData = m_treeBuilder->takeCustomElementConstructionData()) {
         ASSERT(!m_treeBuilder->hasParserBlockingScriptWork());
 
-        RefPtr<Element> newElement = constructionData->elementInterface->constructElement(constructionData->name, JSCustomElementInterface::ShouldClearException::Clear);
+        // https://html.spec.whatwg.org/#create-an-element-for-the-token
+        auto& elementInterface = constructionData->elementInterface.get();
+        RefPtr<Element> newElement = elementInterface.constructElement(constructionData->name, JSCustomElementInterface::ShouldClearException::Clear);
         if (!newElement) {
             ASSERT(!m_treeBuilder->isParsingTemplateContents());
             newElement = HTMLUnknownElement::create(QualifiedName(nullAtom, constructionData->name, xhtmlNamespaceURI), *document());
+            newElement->setIsCustomElementUpgradeCandidate();
+            newElement->setIsFailedCustomElement(elementInterface);
         }
 
         m_treeBuilder->didCreateCustomOrCallbackElement(newElement.releaseNonNull(), *constructionData);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to