Bug 1462703 - Set returned CustomElementDefinition again after script runner is set draft
authorTimothy Guan-tin Chien <timdream@gmail.com>
Tue, 22 May 2018 07:30:07 +0800
changeset 799797 9140f8fa9e9727ce7b65c68d235bcb1a61c6382e
parent 798564 9055d9d89a4bca5cf48dda789299559aefca4e54
child 799798 1c28bb5247f2dfa9396ceb887f53a6a4510f0d46
child 800172 0c6d2b62c0237bfeb5e9d98c73b97dd611ff29a8
push id111165
push usertimdream@gmail.com
push dateFri, 25 May 2018 10:43:19 +0000
bugs1462703
milestone62.0a1
Bug 1462703 - Set returned CustomElementDefinition again after script runner is set This would help in the case where it is safe to run script in-place and the CustomElementDefinition is available before the function exits. This fixes the tests changed. MozReview-Commit-ID: Ays91W94WZm
dom/base/CustomElementRegistry.cpp
dom/base/nsContentUtils.cpp
dom/tests/mochitest/webcomponents/test_custom_element_set_element_creation_callback.html
dom/tests/mochitest/webcomponents/test_xul_custom_element.xul
--- a/dom/base/CustomElementRegistry.cpp
+++ b/dom/base/CustomElementRegistry.cpp
@@ -325,20 +325,21 @@ CustomElementRegistry::LookupCustomEleme
                                                      nsAtom* aTypeAtom)
 {
   CustomElementDefinition* data = mCustomDefinitions.GetWeak(aTypeAtom);
 
   if (!data) {
     RefPtr<CustomElementCreationCallback> callback;
     mElementCreationCallbacks.Get(aTypeAtom, getter_AddRefs(callback));
     if (callback) {
+      mElementCreationCallbacks.Remove(aTypeAtom);
       RefPtr<Runnable> runnable =
         new RunCustomElementCreationCallback(this, aTypeAtom, callback);
       nsContentUtils::AddScriptRunner(runnable);
-      mElementCreationCallbacks.Remove(aTypeAtom);
+      data = mCustomDefinitions.GetWeak(aTypeAtom);
     }
   }
 
   if (data && data->mLocalName == aNameAtom) {
     return data;
   }
 
   return nullptr;
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -10058,17 +10058,17 @@ nsContentUtils::LookupCustomElementDefin
     return nullptr;
   }
 
   nsPIDOMWindowInner* window = aDoc->GetInnerWindow();
   if (!window) {
     return nullptr;
   }
 
-  CustomElementRegistry* registry = window->CustomElements();
+  RefPtr<CustomElementRegistry> registry(window->CustomElements());
   if (!registry) {
     return nullptr;
   }
 
   return registry->LookupCustomElementDefinition(aNameAtom, aTypeAtom);
 }
 
 /* static */ void
--- a/dom/tests/mochitest/webcomponents/test_custom_element_set_element_creation_callback.html
+++ b/dom/tests/mochitest/webcomponents/test_custom_element_set_element_creation_callback.html
@@ -26,18 +26,16 @@ function simpleTest() {
     }
     callbackCalled = true;
     is(type, "x-html-obj-elem", "Type is passed to the callback.");
     customElements.define("x-html-obj-elem", XObjElement);
   });
   ok(!callbackCalled, "Callback should not be called.");
   let el = document.createElement("x-html-obj-elem");
   ok(callbackCalled, "Callback should be called.");
-  isnot(Object.getPrototypeOf(el), XObjElement.prototype, "Created element is not upgraded.");
-  document.body.appendChild(el);
   is(Object.getPrototypeOf(el), XObjElement.prototype, "Created element should have the prototype of the custom type.");
 }
 
 function multipleDefinitionTest() {
   let callbackCalled = false;
   class XObjElement1 extends HTMLElement {};
   class XObjElement2 extends HTMLElement {};
   let callback = (type) => {
@@ -49,18 +47,16 @@ function multipleDefinitionTest() {
     customElements.define("x-html-obj-elem1", XObjElement1);
     customElements.define("x-html-obj-elem2", XObjElement2);
   };
   registry.setElementCreationCallback("x-html-obj-elem1", callback);
   registry.setElementCreationCallback("x-html-obj-elem2", callback);
   ok(!callbackCalled, "Callback should not be called.");
   let el1 = document.createElement("x-html-obj-elem1");
   ok(callbackCalled, "Callback should be called.");
-  isnot(Object.getPrototypeOf(el1), XObjElement1.prototype, "Created element is not upgraded.");
-  document.body.appendChild(el1);
   is(Object.getPrototypeOf(el1), XObjElement1.prototype, "Created element should have the prototype of the custom type.");
   let el2 = document.createElement("x-html-obj-elem2");
   is(Object.getPrototypeOf(el2), XObjElement2.prototype, "Created element should have the prototype of the custom type.");
 }
 
 function throwIfDefined() {
   let callbackCalled = false;
   class XObjElement3 extends HTMLElement {};
@@ -96,18 +92,16 @@ function simpleExtendedTest() {
     }
     callbackCalled = true;
     customElements.define("x-extended-button", ExtendButton, { extends: "button" });
     is(type, "x-extended-button", "Type is passed to the callback.");
   });
   ok(!callbackCalled, "Callback should not be called.");
   let el = document.createElement("button", { is: "x-extended-button"});
   ok(callbackCalled, "Callback should be called.");
-  isnot(Object.getPrototypeOf(el), ExtendButton.prototype, "Created element is not upgraded.");
-  document.body.appendChild(el);
   is(Object.getPrototypeOf(el), ExtendButton.prototype, "Created element should have the prototype of the extended type.");
   is(el.getAttribute("is"), "x-extended-button", "The |is| attribute of the created element should be the extended type.");
 }
 
 function simpleInnerHTMLTest() {
   let callbackCalled = false;
   class XObjElement4 extends HTMLElement {};
   registry.setElementCreationCallback("x-html-obj-elem5", (type) => {
--- a/dom/tests/mochitest/webcomponents/test_xul_custom_element.xul
+++ b/dom/tests/mochitest/webcomponents/test_xul_custom_element.xul
@@ -307,16 +307,25 @@
         document.createElementNS(XUL_NS, "test-built-in-element-1")];
 
       for (let element of elements) {
         is(Object.getPrototypeOf(element), XULElement.prototype,
           `<${element.localName} is="${element.getAttribute("is")}" /> should not be a custom element.`);
       }
     }
 
+    function setElementCreationCallbackCreate() {
+      class TestCustomElement4 extends XULElement {}
+      customElements.setElementCreationCallback(
+        "test-custom-element-4", () => customElements.define("test-custom-element-4", TestCustomElement4));
+
+      let element = document.createElementNS(XUL_NS, "test-custom-element-4");
+      ok(element instanceof TestCustomElement4, "Should be an instance of TestCustomElement4");
+    }
+
     function runTest() {
       basicCustomElementCreate();
       parserBasicElementUpgrade();
 
       tagNameWithoutDash();
       upgradeAfterDefine();
 
       basicElementCreateBuiltIn();
@@ -327,16 +336,18 @@
 
       upgradeAfterDefineBuiltIn();
 
       throwForInvalidBuiltInName();
       extendingWithoutDashCustomElement();
 
       nonCustomElementCreate();
 
+      setElementCreationCallbackCreate();
+
       SimpleTest.finish();
     }
   ]]>
   </script>
 
   <body xmlns="http://www.w3.org/1999/xhtml">
     <p id="display"></p>
     <div id="content" style="display: none">