diff options
-rw-r--r-- | dom/base/CustomElementRegistry.cpp | 12 | ||||
-rw-r--r-- | dom/base/CustomElementRegistry.h | 2 | ||||
-rw-r--r-- | dom/base/nsContentUtils.cpp | 22 | ||||
-rw-r--r-- | dom/base/nsContentUtils.h | 3 | ||||
-rw-r--r-- | dom/html/nsHTMLContentSink.cpp | 95 |
5 files changed, 129 insertions, 5 deletions
diff --git a/dom/base/CustomElementRegistry.cpp b/dom/base/CustomElementRegistry.cpp index 897f7df12..27e92a56a 100644 --- a/dom/base/CustomElementRegistry.cpp +++ b/dom/base/CustomElementRegistry.cpp @@ -931,7 +931,7 @@ DoUpgrade(Element* aElement, } // anonymous namespace // https://html.spec.whatwg.org/multipage/scripting.html#upgrades -void +/* static */ void CustomElementRegistry::Upgrade(Element* aElement, CustomElementDefinition* aDefinition, ErrorResult& aRv) @@ -969,8 +969,10 @@ CustomElementRegistry::Upgrade(Element* aElement, (attrValue.IsEmpty() ? NullString() : attrValue), (namespaceURI.IsEmpty() ? NullString() : namespaceURI) }; - EnqueueLifecycleCallback(nsIDocument::eAttributeChanged, aElement, - &args, aDefinition); + nsContentUtils::EnqueueLifecycleCallback(aElement->OwnerDoc(), + nsIDocument::eAttributeChanged, + aElement, + &args, aDefinition); } } } @@ -995,7 +997,9 @@ CustomElementRegistry::Upgrade(Element* aElement, data->mState = CustomElementData::State::eCustom; // This is for old spec. - EnqueueLifecycleCallback(nsIDocument::eCreated, aElement, nullptr, aDefinition); + nsContentUtils::EnqueueLifecycleCallback(aElement->OwnerDoc(), + nsIDocument::eCreated, + aElement, nullptr, aDefinition); } //----------------------------------------------------- diff --git a/dom/base/CustomElementRegistry.h b/dom/base/CustomElementRegistry.h index b85d089f9..b731a1858 100644 --- a/dom/base/CustomElementRegistry.h +++ b/dom/base/CustomElementRegistry.h @@ -357,7 +357,7 @@ public: * Upgrade an element. * https://html.spec.whatwg.org/multipage/scripting.html#upgrades */ - void Upgrade(Element* aElement, CustomElementDefinition* aDefinition, ErrorResult& aRv); + static void Upgrade(Element* aElement, CustomElementDefinition* aDefinition, ErrorResult& aRv); private: ~CustomElementRegistry(); diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 570065dba..f8964d198 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -9660,6 +9660,28 @@ nsContentUtils::GetElementDefinitionIfObservingAttr(Element* aCustomElement, } /* static */ void +nsContentUtils::EnqueueUpgradeReaction(Element* aElement, + CustomElementDefinition* aDefinition) +{ + MOZ_ASSERT(aElement); + + nsIDocument* doc = aElement->OwnerDoc(); + nsPIDOMWindowInner* window(doc->GetInnerWindow()); + if (!window) { + return; + } + + RefPtr<CustomElementRegistry> registry(window->CustomElements()); + if (!registry) { + return; + } + + CustomElementReactionsStack* stack = + doc->GetDocGroup()->CustomElementReactionsStack(); + stack->EnqueueUpgradeReaction(registry, aElement, aDefinition); +} + +/* static */ void nsContentUtils::EnqueueLifecycleCallback(nsIDocument* aDoc, nsIDocument::ElementCallbackType aType, Element* aCustomElement, diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 96c920394..1828d8b21 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -2728,6 +2728,9 @@ public: nsIAtom* aExtensionType, nsIAtom* aAttrName); + static void EnqueueUpgradeReaction(Element* aElement, + mozilla::dom::CustomElementDefinition* aDefinition); + static void EnqueueLifecycleCallback(nsIDocument* aDoc, nsIDocument::ElementCallbackType aType, Element* aCustomElement, diff --git a/dom/html/nsHTMLContentSink.cpp b/dom/html/nsHTMLContentSink.cpp index bba5d38ab..ef160cf21 100644 --- a/dom/html/nsHTMLContentSink.cpp +++ b/dom/html/nsHTMLContentSink.cpp @@ -232,6 +232,26 @@ public: int32_t mStackPos; }; +static void +DoCustomElementCreate(Element** aElement, nsIDocument* aDoc, + CustomElementConstructor* aConstructor, ErrorResult& aRv) +{ + RefPtr<Element> element = + aConstructor->Construct("Custom Element Create", aRv); + if (aRv.Failed() || !element->IsHTMLElement()) { + aRv.ThrowTypeError<MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE>(NS_LITERAL_STRING("HTMLElement")); + return; + } + + if (aDoc != element->OwnerDoc() || element->GetParentNode() || + element->HasChildren() || element->GetAttrCount()) { + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return; + } + + element.forget(aElement); +} + nsresult NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo, FromParser aFromParser, const nsAString* aIs) @@ -251,6 +271,81 @@ NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& int32_t tag = parserService->HTMLCaseSensitiveAtomTagToId(name); + // https://dom.spec.whatwg.org/#concept-create-element + // We only handle the "synchronous custom elements flag is set" now. + // For the unset case (e.g. cloning a node), see bug 1319342 for that. + // Step 4. + CustomElementDefinition* definition = nullptr; + if (CustomElementRegistry::IsCustomElementEnabled()) { + definition = + nsContentUtils::LookupCustomElementDefinition(nodeInfo->GetDocument(), + nodeInfo->LocalName(), + nodeInfo->NamespaceID(), + aIs); + } + + // It might be a problem that parser synchronously calls constructor, so filed + // bug 1378079 to figure out what we should do for parser case. + if (definition) { + /* + * Synchronous custom elements flag is determined by 3 places in spec, + * 1) create an element for a token, the flag is determined by + * "will execute script" which is not originally created + * for the HTML fragment parsing algorithm. + * 2) createElement and createElementNS, the flag is the same as + * NOT_FROM_PARSER. + * 3) clone a node, our implementation will not go into this function. + * For the unset case which is non-synchronous only applied for + * inner/outerHTML. + */ + bool synchronousCustomElements = aFromParser != dom::FROM_PARSER_FRAGMENT || + aFromParser == dom::NOT_FROM_PARSER; + // Per discussion in https://github.com/w3c/webcomponents/issues/635, + // use entry global in those places that are called from JS APIs. + nsIGlobalObject* global = GetEntryGlobal(); + MOZ_ASSERT(global); + AutoEntryScript aes(global, "create custom elements"); + JSContext* cx = aes.cx(); + ErrorResult rv; + + // Step 5. + if (definition->IsCustomBuiltIn()) { + // SetupCustomElement() should be called with an element that don't have + // CustomElementData setup, if not we will hit the assertion in + // SetCustomElementData(). + nsCOMPtr<nsIAtom> tagAtom = nodeInfo->NameAtom(); + nsCOMPtr<nsIAtom> typeAtom = aIs ? NS_Atomize(*aIs) : tagAtom; + // Built-in element + *aResult = CreateHTMLElement(tag, nodeInfo.forget(), aFromParser).take(); + (*aResult)->SetCustomElementData(new CustomElementData(typeAtom)); + if (synchronousCustomElements) { + CustomElementRegistry::Upgrade(*aResult, definition, rv); + } else { + nsContentUtils::EnqueueUpgradeReaction(*aResult, definition); + } + + if (rv.MaybeSetPendingException(cx)) { + aes.ReportException(); + } + return NS_OK; + } + + // Step 6.1. + if (synchronousCustomElements) { + DoCustomElementCreate(aResult, nodeInfo->GetDocument(), + definition->mConstructor, rv); + if (rv.MaybeSetPendingException(cx)) { + NS_IF_ADDREF(*aResult = NS_NewHTMLUnknownElement(nodeInfo.forget(), aFromParser)); + } + return NS_OK; + } + + // Step 6.2. + NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser)); + nsContentUtils::EnqueueUpgradeReaction(*aResult, definition); + return NS_OK; + } + // Per the Custom Element specification, unknown tags that are valid custom // element names should be HTMLElement instead of HTMLUnknownElement. bool isCustomElementName = (tag == eHTMLTag_userdefined && |