Bug 1359346 - Implement custom element state;

https://dom.spec.whatwg.org/#concept-element-custom-element-state

Tag UXP Issue #1344
This commit is contained in:
Gaming4JC 2020-01-04 13:24:58 -05:00 committed by Roy Tam
commit cb89330bf3
3 changed files with 44 additions and 22 deletions

View file

@ -78,12 +78,21 @@ CustomElementCallback::CustomElementCallback(Element* aThisObject,
{
}
//-----------------------------------------------------
// CustomElementData
CustomElementData::CustomElementData(nsIAtom* aType)
: mType(aType),
mCurrentCallback(-1),
mElementIsBeingCreated(false),
mCreatedCallbackInvoked(true),
mAssociatedMicroTask(-1)
: CustomElementData(aType, CustomElementData::State::eUndefined)
{
}
CustomElementData::CustomElementData(nsIAtom* aType, State aState)
: mType(aType)
, mCurrentCallback(-1)
, mElementIsBeingCreated(false)
, mCreatedCallbackInvoked(true)
, mAssociatedMicroTask(-1)
, mState(aState)
{
}
@ -99,6 +108,9 @@ CustomElementData::RunCallbackQueue()
mCurrentCallback = -1;
}
//-----------------------------------------------------
// CustomElementRegistry
// Only needed for refcounted objects.
NS_IMPL_CYCLE_COLLECTION_CLASS(CustomElementRegistry)
@ -305,10 +317,15 @@ CustomElementRegistry::SetupCustomElement(Element* aElement,
aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *aTypeExtension, true);
}
CustomElementDefinition* data = LookupCustomElementDefinition(
// SetupCustomElement() should be called with an element that don't have
// CustomElementData setup, if not we will hit the assertion in
// SetCustomElementData().
aElement->SetCustomElementData(new CustomElementData(typeAtom));
CustomElementDefinition* definition = LookupCustomElementDefinition(
aElement->NodeInfo()->LocalName(), aTypeExtension);
if (!data) {
if (!definition) {
// The type extension doesn't exist in the registry,
// thus we don't need to enqueue callback or adjust
// the "is" attribute, but it is possibly an upgrade candidate.
@ -316,7 +333,7 @@ CustomElementRegistry::SetupCustomElement(Element* aElement,
return;
}
if (data->mLocalName != tagAtom) {
if (definition->mLocalName != tagAtom) {
// The element doesn't match the local name for the
// definition, thus the element isn't a custom element
// and we don't need to do anything more.
@ -325,7 +342,7 @@ CustomElementRegistry::SetupCustomElement(Element* aElement,
// Enqueuing the created callback will set the CustomElementData on the
// element, causing prototype swizzling to occur in Element::WrapObject.
EnqueueLifecycleCallback(nsIDocument::eCreated, aElement, nullptr, data);
EnqueueLifecycleCallback(nsIDocument::eCreated, aElement, nullptr, definition);
}
void
@ -334,7 +351,8 @@ CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType
LifecycleCallbackArgs* aArgs,
CustomElementDefinition* aDefinition)
{
CustomElementData* elementData = aCustomElement->GetCustomElementData();
RefPtr<CustomElementData> elementData = aCustomElement->GetCustomElementData();
MOZ_ASSERT(elementData, "CustomElementData should exist");
// Let DEFINITION be ELEMENT's definition
CustomElementDefinition* definition = aDefinition;
@ -354,16 +372,6 @@ CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType
}
}
if (!elementData) {
// Create the custom element data the first time
// that we try to enqueue a callback.
elementData = new CustomElementData(definition->mType);
// aCustomElement takes ownership of elementData
aCustomElement->SetCustomElementData(elementData);
MOZ_ASSERT(aType == nsIDocument::eCreated,
"First callback should be the created callback");
}
// Let CALLBACK be the callback associated with the key NAME in CALLBACKS.
CallbackFunction* func = nullptr;
switch (aType) {
@ -881,8 +889,6 @@ CustomElementRegistry::Upgrade(Element* aElement,
}
} // Leave prototype's compartment.
// Enqueuing the created callback will set the CustomElementData on the
// element, causing prototype swizzling to occur in Element::WrapObject.
EnqueueLifecycleCallback(nsIDocument::eCreated, aElement, nullptr, aDefinition);
}

View file

@ -71,7 +71,18 @@ struct CustomElementData
{
NS_INLINE_DECL_REFCOUNTING(CustomElementData)
// https://dom.spec.whatwg.org/#concept-element-custom-element-state
// CustomElementData is only created on the element which is a custom element
// or an upgrade candidate, so the state of an element without
// CustomElementData is "uncustomized".
enum class State {
eUndefined,
eFailed,
eCustom
};
explicit CustomElementData(nsIAtom* aType);
CustomElementData(nsIAtom* aType, State aState);
// Objects in this array are transient and empty after each microtask
// checkpoint.
nsTArray<nsAutoPtr<CustomElementCallback>> mCallbackQueue;
@ -89,6 +100,8 @@ struct CustomElementData
// it is used to determine if a new queue needs to be pushed onto the
// processing stack.
int32_t mAssociatedMicroTask;
// Custom element state as described in the custom element spec.
State mState;
// Empties the callback queue.
void RunCallbackQueue();

View file

@ -3550,6 +3550,9 @@ CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
element = CreateHTMLElement(tag, nodeInfo.forget(), NOT_FROM_PARSER);
}
element->SetCustomElementData(
new CustomElementData(definition->mType, CustomElementData::State::eCustom));
return element.forget();
}