Bug 1446247 - Pass namespace into IsCustomElementName to allow for non-dashed XUL elements;r=smaug
This will make it possible to migrate existing bindings without also needing to
mass-rewrite frontend code at the same time.
MozReview-Commit-ID: IBBqC4eeDDX
--- a/dom/base/CustomElementRegistry.cpp
+++ b/dom/base/CustomElementRegistry.cpp
@@ -677,18 +677,20 @@ CustomElementRegistry::Define(const nsAS
aRv.ThrowTypeError<MSG_NOT_CONSTRUCTOR>(NS_LITERAL_STRING("Argument 2 of CustomElementRegistry.define"));
return;
}
/**
* 2. If name is not a valid custom element name, then throw a "SyntaxError"
* DOMException and abort these steps.
*/
+ nsIDocument* doc = mWindow->GetExtantDoc();
+ uint32_t nameSpaceID = doc ? doc->GetDefaultNamespaceID() : kNameSpaceID_XHTML;
RefPtr<nsAtom> nameAtom(NS_Atomize(aName));
- if (!nsContentUtils::IsCustomElementName(nameAtom)) {
+ if (!nsContentUtils::IsCustomElementName(nameAtom, nameSpaceID)) {
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
return;
}
/**
* 3. If this CustomElementRegistry contains an entry with name name, then
* throw a "NotSupportedError" DOMException and abort these steps.
*/
@@ -720,17 +722,17 @@ CustomElementRegistry::Define(const nsAS
* HTMLUnknownElement (e.g., if extends does not indicate an element
* definition in this specification), then throw a "NotSupportedError"
* DOMException.
* 3. Set localName to extends.
*/
nsAutoString localName(aName);
if (aOptions.mExtends.WasPassed()) {
RefPtr<nsAtom> extendsAtom(NS_Atomize(aOptions.mExtends.Value()));
- if (nsContentUtils::IsCustomElementName(extendsAtom)) {
+ if (nsContentUtils::IsCustomElementName(extendsAtom, nameSpaceID)) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
// bgsound and multicol are unknown html element.
int32_t tag = nsHTMLTags::CaseSensitiveAtomTagToId(extendsAtom);
if (tag == eHTMLTag_userdefined ||
tag == eHTMLTag_bgsound ||
@@ -960,17 +962,19 @@ CustomElementRegistry::WhenDefined(const
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mWindow);
RefPtr<Promise> promise = Promise::Create(global, aRv);
if (aRv.Failed()) {
return nullptr;
}
RefPtr<nsAtom> nameAtom(NS_Atomize(aName));
- if (!nsContentUtils::IsCustomElementName(nameAtom)) {
+ nsIDocument* doc = mWindow->GetExtantDoc();
+ uint32_t nameSpaceID = doc ? doc->GetDefaultNamespaceID() : kNameSpaceID_XHTML;
+ if (!nsContentUtils::IsCustomElementName(nameAtom, nameSpaceID)) {
promise->MaybeReject(NS_ERROR_DOM_SYNTAX_ERR);
return promise.forget();
}
if (mCustomDefinitions.GetWeak(nameAtom)) {
promise->MaybeResolve(JS::UndefinedHandleValue);
return promise.forget();
}
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -1191,17 +1191,17 @@ Element::AttachShadow(const ShadowRootIn
/**
* 2. If context object’s local name is not
* a valid custom element name, "article", "aside", "blockquote",
* "body", "div", "footer", "h1", "h2", "h3", "h4", "h5", "h6",
* "header", "main" "nav", "p", "section", or "span",
* then throw a "NotSupportedError" DOMException.
*/
nsAtom* nameAtom = NodeInfo()->NameAtom();
- if (!(nsContentUtils::IsCustomElementName(nameAtom) ||
+ if (!(nsContentUtils::IsCustomElementName(nameAtom, NodeInfo()->NamespaceID()) ||
nameAtom == nsGkAtoms::article ||
nameAtom == nsGkAtoms::aside ||
nameAtom == nsGkAtoms::blockquote ||
nameAtom == nsGkAtoms::body ||
nameAtom == nsGkAtoms::div ||
nameAtom == nsGkAtoms::footer ||
nameAtom == nsGkAtoms::h1 ||
nameAtom == nsGkAtoms::h2 ||
@@ -4318,17 +4318,17 @@ Element::ClearServoData(nsIDocument* aDo
void
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)) {
+ if (nsContentUtils::IsCustomElementName(name, NodeInfo()->NamespaceID())) {
MOZ_ASSERT(type == name);
} else {
MOZ_ASSERT(type != name);
}
#endif
slots->mCustomElementData = aData;
}
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -3188,18 +3188,23 @@ nsContentUtils::NewURIWithDocumentCharse
aDocument->GetDocumentCharacterSet(),
aBaseURI, sIOService);
}
return NS_NewURI(aResult, aSpec, nullptr, aBaseURI, sIOService);
}
// static
bool
-nsContentUtils::IsCustomElementName(nsAtom* aName)
-{
+nsContentUtils::IsCustomElementName(nsAtom* aName, uint32_t aNameSpaceID)
+{
+ // Allow non-dashed names in XUL for XBL to Custom Element migrations.
+ if (aNameSpaceID == kNameSpaceID_XUL) {
+ return true;
+ }
+
// A valid custom element name is a sequence of characters name which
// must match the PotentialCustomElementName production:
// PotentialCustomElementName ::= [a-z] (PCENChar)* '-' (PCENChar)*
const char16_t* name = aName->GetUTF16String();
uint32_t len = aName->GetLength();
bool hasDash = false;
if (!len || name[0] < 'a' || name[0] > 'z') {
@@ -9978,19 +9983,19 @@ nsContentUtils::NewXULOrHTMLElement(Elem
"Can only create XUL or XHTML elements.");
nsAtom *name = nodeInfo->NameAtom();
int32_t tag = eHTMLTag_unknown;
bool isCustomElementName = false;
if (nodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
tag = nsHTMLTags::CaseSensitiveAtomTagToId(name);
isCustomElementName = (tag == eHTMLTag_userdefined &&
- nsContentUtils::IsCustomElementName(name));
+ nsContentUtils::IsCustomElementName(name, kNameSpaceID_XHTML));
} else {
- isCustomElementName = nsContentUtils::IsCustomElementName(name);
+ isCustomElementName = nsContentUtils::IsCustomElementName(name, kNameSpaceID_XUL);
}
RefPtr<nsAtom> tagAtom = nodeInfo->NameAtom();
RefPtr<nsAtom> typeAtom;
bool isCustomElement = isCustomElementName || aIsAtom;
if (isCustomElement) {
typeAtom = isCustomElementName ? tagAtom.get() : aIsAtom;
}
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -705,17 +705,17 @@ public:
const nsAString& aSpec,
nsIDocument* aDocument,
nsIURI* aBaseURI);
/**
* Returns true if |aName| is a valid name to be registered via
* customElements.define.
*/
- static bool IsCustomElementName(nsAtom* aName);
+ static bool IsCustomElementName(nsAtom* aName, uint32_t aNameSpaceID);
static nsresult CheckQName(const nsAString& aQualifiedName,
bool aNamespaceAware = true,
const char16_t** aColon = nullptr);
static nsresult SplitQName(const nsIContent* aNamespaceResolver,
const nsString& aQName,
int32_t *aNamespace, nsAtom **aLocalName);
--- a/dom/tests/mochitest/webcomponents/test_xul_custom_element.xul
+++ b/dom/tests/mochitest/webcomponents/test_xul_custom_element.xul
@@ -21,16 +21,19 @@
connectedCallback() {
this.textContent = "foo";
}
}
customElements.define("test-custom-element", TestCustomElement);
+ class TestWithoutDash extends XULElement { }
+ customElements.define("testwithoutdash", TestWithoutDash);
+
function runTest() {
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
let element = document.createElementNS(XUL_NS, "test-custom-element");
document.querySelector("#content").appendChild(element);
is(element.textContent, "foo", "Should have set the textContent");
ok(element instanceof TestCustomElement, "Should be an instance of TestCustomElement");
@@ -48,21 +51,25 @@
is(element3.textContent, "foo", "Should have set the textContent");
ok(element3 instanceof TestCustomElement, "Should be an instance of TestCustomElement");
let element4 = document.getElementById("element4");
is(element4.textContent, "foo",
"Parser should have instantiated the custom element.");
ok(element4 instanceof TestCustomElement, "Should be an instance of TestCustomElement");
+ let element5 = document.getElementById("element5");
+ ok(element5 instanceof TestWithoutDash, "Should be an instance of TestWithoutDash");
+
SimpleTest.finish();
}
]]>
</script>
<body xmlns="http://www.w3.org/1999/xhtml">
<p id="display"></p>
<div id="content" style="display: none">
<test-custom-element id="element4" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>
+ <testwithoutdash id="element5" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"/>
</div>
<pre id="test"></pre>
</body>
</window>