Bug 1301024 - Part 2: Implement create an element steps. r=smaug

This commit is contained in:
John Dai 2017-09-25 01:33:00 -04:00
Родитель ca4066029e
Коммит cc16112226
5 изменённых файлов: 158 добавлений и 8 удалений

Просмотреть файл

@ -939,7 +939,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)
@ -977,8 +977,10 @@ CustomElementRegistry::Upgrade(Element* aElement,
(attrValue.IsEmpty() ? VoidString() : attrValue),
(namespaceURI.IsEmpty() ? VoidString() : namespaceURI)
};
EnqueueLifecycleCallback(nsIDocument::eAttributeChanged, aElement,
&args, aDefinition);
nsContentUtils::EnqueueLifecycleCallback(aElement->OwnerDoc(),
nsIDocument::eAttributeChanged,
aElement,
&args, aDefinition);
}
}
}
@ -1003,7 +1005,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);
}
//-----------------------------------------------------

Просмотреть файл

@ -362,11 +362,15 @@ public:
void GetCustomPrototype(nsIAtom* aAtom,
JS::MutableHandle<JSObject*> aPrototype);
void SyncInvokeReactions(nsIDocument::ElementCallbackType aType,
Element* aCustomElement,
CustomElementDefinition* aDefinition);
/**
* 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();
@ -375,9 +379,6 @@ private:
nsIDocument::ElementCallbackType aType, Element* aCustomElement,
LifecycleCallbackArgs* aArgs, CustomElementDefinition* aDefinition);
void SyncInvokeReactions(nsIDocument::ElementCallbackType aType,
Element* aCustomElement,
CustomElementDefinition* aDefinition);
/**
* Registers an unresolved custom element that is a candidate for
* upgrade when the definition is registered via registerElement.

Просмотреть файл

@ -10154,6 +10154,49 @@ nsContentUtils::GetElementDefinitionIfObservingAttr(Element* aCustomElement,
return definition;
}
/* static */ void
nsContentUtils::SyncInvokeReactions(nsIDocument::ElementCallbackType aType,
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;
}
registry->SyncInvokeReactions(aType, aElement, aDefinition);
}
/* 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,

Просмотреть файл

@ -2998,6 +2998,13 @@ public:
nsIAtom* aExtensionType,
nsIAtom* aAttrName);
static void SyncInvokeReactions(nsIDocument::ElementCallbackType aType,
Element* aCustomElement,
mozilla::dom::CustomElementDefinition* aDefinition);
static void EnqueueUpgradeReaction(Element* aElement,
mozilla::dom::CustomElementDefinition* aDefinition);
static void EnqueueLifecycleCallback(nsIDocument* aDoc,
nsIDocument::ElementCallbackType aType,
Element* aCustomElement,

Просмотреть файл

@ -223,6 +223,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)
@ -238,6 +258,81 @@ NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&&
int32_t tag = nsHTMLTags::CaseSensitiveAtomTagToId(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 &&