Bug 1446247 - Pass namespace into IsCustomElementName to allow for non-dashed XUL elements;r=e7358d9c+590837,smaug
authorBrian Grinstead <bgrinstead@mozilla.com>
Thu, 29 Mar 2018 09:34:56 -0700
changeset 412931 13faaffe1c4f3019171eed2fbbc4940e8f84075e
parent 412930 1fe53fae0f8d5429bea94dced05cc43f2616c8f9
child 412932 1ec9d664832286a8544d725c8dd053b3242a6dd1
push id102036
push userebalazs@mozilla.com
push dateThu, 12 Apr 2018 09:47:53 +0000
treeherdermozilla-inbound@2655ff95e4ff [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerse7358d9c
bugs1446247, 590837
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1446247 - Pass namespace into IsCustomElementName to allow for non-dashed XUL elements;r=e7358d9c+590837,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
dom/base/CustomElementRegistry.cpp
dom/base/Element.cpp
dom/base/nsContentUtils.cpp
dom/base/nsContentUtils.h
dom/tests/mochitest/webcomponents/test_xul_custom_element.xul
--- a/dom/base/CustomElementRegistry.cpp
+++ b/dom/base/CustomElementRegistry.cpp
@@ -691,18 +691,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.
    */
@@ -734,17 +736,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 ||
@@ -974,17 +976,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 ||
@@ -4294,17 +4294,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
@@ -3189,18 +3189,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') {
@@ -9949,19 +9954,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>