diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index f097c643887e..b555cb0bce5d 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -4402,6 +4402,15 @@ Element::SetCustomElementData(CustomElementData* aData) { nsExtendedDOMSlots *slots = ExtendedDOMSlots(); MOZ_ASSERT(!slots->mCustomElementData, "Custom element data may not be changed once set."); + #if DEBUG + nsAtom* name = NodeInfo()->NameAtom(); + nsAtom* type = aData->GetCustomElementType(); + if (nsContentUtils::IsCustomElementName(name)) { + MOZ_ASSERT(type == name); + } else { + MOZ_ASSERT(type != name); + } + #endif slots->mCustomElementData = aData; } diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 81b49afea03c..437cba722ada 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -9989,9 +9989,6 @@ nsContentUtils::NewXULOrHTMLElement(Element** aResult, mozilla::dom::NodeInfo* a "Can only create XUL or XHTML elements."); nsAtom *name = nodeInfo->NameAtom(); - RefPtr tagAtom = nodeInfo->NameAtom(); - RefPtr typeAtom = aIs ? NS_Atomize(*aIs) : tagAtom; - int32_t tag = eHTMLTag_unknown; bool isCustomElementName = false; if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) { @@ -10001,7 +9998,14 @@ nsContentUtils::NewXULOrHTMLElement(Element** aResult, mozilla::dom::NodeInfo* a } else { isCustomElementName = nsContentUtils::IsCustomElementName(name); } + + RefPtr tagAtom = nodeInfo->NameAtom(); + RefPtr typeAtom; bool isCustomElement = isCustomElementName || aIs; + if (isCustomElement) { + typeAtom = isCustomElementName ? tagAtom : NS_Atomize(*aIs); + } + MOZ_ASSERT_IF(aDefinition, isCustomElement); // https://dom.spec.whatwg.org/#concept-create-element diff --git a/dom/base/nsNodeUtils.cpp b/dom/base/nsNodeUtils.cpp index 86e31172e748..8dfa76ae0a36 100644 --- a/dom/base/nsNodeUtils.cpp +++ b/dom/base/nsNodeUtils.cpp @@ -504,7 +504,13 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, bool aClone, bool aDeep, cloneElem->GetAttr(kNameSpaceID_None, nsGkAtoms::is, extension); } - if (data || !extension.IsEmpty()) { + if ((data && data->GetCustomElementType() == tagAtom) || + !extension.IsEmpty()) { + // The typeAtom can be determined by extension, because we only need to + // consider two cases: 1) Original node is a autonomous custom element + // which has CustomElementData. 2) Original node is a built-in custom + // element or normal element, but it has `is` attribute when it is being + // cloned. RefPtr typeAtom = extension.IsEmpty() ? tagAtom : NS_Atomize(extension); cloneElem->SetCustomElementData(new CustomElementData(typeAtom)); CustomElementDefinition* definition = diff --git a/parser/html/nsHtml5TreeOperation.cpp b/parser/html/nsHtml5TreeOperation.cpp index 0444590f6c28..770d785a6922 100644 --- a/parser/html/nsHtml5TreeOperation.cpp +++ b/parser/html/nsHtml5TreeOperation.cpp @@ -409,7 +409,7 @@ nsHtml5TreeOperation::CreateHTMLElement( if (isCustomElement && aFromParser != dom::FROM_PARSER_FRAGMENT) { RefPtr tagAtom = nodeInfo->NameAtom(); RefPtr typeAtom = - isValue.IsEmpty() ? tagAtom : NS_Atomize(isValue); + (aCreator == NS_NewCustomElement) ? tagAtom : NS_Atomize(isValue); definition = nsContentUtils::LookupCustomElementDefinition(document, nodeInfo->LocalName(), nodeInfo->NamespaceID(), typeAtom); diff --git a/testing/web-platform/meta/MANIFEST.json b/testing/web-platform/meta/MANIFEST.json index 82d5f7d42551..eb420a486330 100644 --- a/testing/web-platform/meta/MANIFEST.json +++ b/testing/web-platform/meta/MANIFEST.json @@ -305751,6 +305751,12 @@ {} ] ], + "custom-elements/parser/parser-constructs-custom-elements-with-is.html": [ + [ + "/custom-elements/parser/parser-constructs-custom-elements-with-is.html", + {} + ] + ], "custom-elements/parser/parser-constructs-custom-elements.html": [ [ "/custom-elements/parser/parser-constructs-custom-elements.html", @@ -523823,7 +523829,7 @@ "testharness" ], "custom-elements/Document-createElement.html": [ - "074c9f703cc7feb1dfc3d07aedd08460bd591d42", + "fb10e851deb193aed700c8ab6790c216766cc362", "testharness" ], "custom-elements/HTMLElement-constructor.html": [ @@ -523882,6 +523888,10 @@ "dc0ca4a066d9a05362a81b263594965763919e46", "testharness" ], + "custom-elements/parser/parser-constructs-custom-elements-with-is.html": [ + "7a7df7aab092906b5a753c0d122b971aff01517a", + "testharness" + ], "custom-elements/parser/parser-constructs-custom-elements.html": [ "228d4a90d57dc942692becc6f126ec9130b3a4e0", "testharness" @@ -524027,7 +524037,7 @@ "testharness" ], "custom-elements/upgrading/Node-cloneNode.html": [ - "cc121ea56de1b8e1074062b5dda69f57e2add665", + "264a2631a79370bce8392657ba52c8b0c949b7e1", "testharness" ], "custom-elements/upgrading/upgrading-enqueue-reactions.html": [ diff --git a/testing/web-platform/tests/custom-elements/Document-createElement.html b/testing/web-platform/tests/custom-elements/Document-createElement.html index e446c507ca86..52a68e8e1789 100644 --- a/testing/web-platform/tests/custom-elements/Document-createElement.html +++ b/testing/web-platform/tests/custom-elements/Document-createElement.html @@ -29,6 +29,21 @@ test(function () { }, 'document.createElement must create an instance of custom elements'); +test(function () { + class AutonomousCustomElement extends HTMLElement {}; + class IsCustomElement extends HTMLElement {}; + + customElements.define('autonomous-custom-element', AutonomousCustomElement); + customElements.define('is-custom-element', IsCustomElement); + + var instance = document.createElement('autonomous-custom-element', { is: "is-custom-element"}); + + assert_true(instance instanceof AutonomousCustomElement); + assert_equals(instance.localName, 'autonomous-custom-element'); + assert_equals(instance.namespaceURI, 'http://www.w3.org/1999/xhtml', 'A custom element HTML must use HTML namespace'); + +}, 'document.createElement must create an instance of autonomous custom elements when it has is attribute'); + function assert_reports(expected, testFunction, message) { var uncaughtError = null; window.onerror = function (message, url, lineNumber, columnNumber, error) { uncaughtError = error; return true; } diff --git a/testing/web-platform/tests/custom-elements/parser/parser-constructs-custom-elements-with-is.html b/testing/web-platform/tests/custom-elements/parser/parser-constructs-custom-elements-with-is.html new file mode 100644 index 000000000000..96c00278a3d7 --- /dev/null +++ b/testing/web-platform/tests/custom-elements/parser/parser-constructs-custom-elements-with-is.html @@ -0,0 +1,51 @@ + + + +Custom Elements: Changes to the HTML parser + + + + + + + + +
+ + + + + + diff --git a/testing/web-platform/tests/custom-elements/upgrading/Node-cloneNode.html b/testing/web-platform/tests/custom-elements/upgrading/Node-cloneNode.html index 0d158fd59e48..0492e1f39a13 100644 --- a/testing/web-platform/tests/custom-elements/upgrading/Node-cloneNode.html +++ b/testing/web-platform/tests/custom-elements/upgrading/Node-cloneNode.html @@ -30,6 +30,25 @@ test(function () { 'A cloned custom element must be an instance of the custom element'); }, 'Node.prototype.cloneNode(false) must be able to clone a custom element'); +test(function () { + class AutonomousCustomElement extends HTMLElement {}; + class IsCustomElement extends HTMLElement {}; + + customElements.define('autonomous-custom-element', AutonomousCustomElement); + customElements.define('is-custom-element', IsCustomElement); + + var instance = document.createElement('autonomous-custom-element', { is: "is-custom-element"}); + assert_true(instance instanceof HTMLElement); + assert_true(instance instanceof AutonomousCustomElement); + + var clone = instance.cloneNode(false); + assert_not_equals(instance, clone); + assert_true(clone instanceof HTMLElement, + 'A cloned custom element must be an instance of HTMLElement'); + assert_true(clone instanceof AutonomousCustomElement, + 'A cloned custom element must be an instance of the custom element'); +}, 'Node.prototype.cloneNode(false) must be able to clone as a autonomous custom element when it contains is attribute'); + test_with_window(function (contentWindow) { var contentDocument = contentWindow.document; class MyCustomElement extends contentWindow.HTMLElement {}