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);