mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-07 00:08:39 +09:00
Bug 1309184 - Implement upgrade reaction for custom element reactions.
Tag UXP Issue #1344
This commit is contained in:
parent
d76a336cd0
commit
a91f703945
2 changed files with 267 additions and 29 deletions
|
|
@ -137,6 +137,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CustomElementRegistry)
|
|||
cb.NoteXPCOMChild(callbacks->mDetachedCallback.Value());
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWhenDefinedPromiseMap)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
|
@ -237,6 +238,7 @@ CustomElementRegistry::sProcessingStack;
|
|||
CustomElementRegistry::CustomElementRegistry(nsPIDOMWindowInner* aWindow)
|
||||
: mWindow(aWindow)
|
||||
, mIsCustomDefinitionRunning(false)
|
||||
, mIsBackupQueueProcessing(false)
|
||||
{
|
||||
mozilla::HoldJSObjects(this);
|
||||
|
||||
|
|
@ -502,35 +504,7 @@ CustomElementRegistry::UpgradeCandidates(JSContext* aCx,
|
|||
continue;
|
||||
}
|
||||
|
||||
elem->RemoveStates(NS_EVENT_STATE_UNRESOLVED);
|
||||
|
||||
// Make sure that the element name matches the name in the definition.
|
||||
// (e.g. a definition for x-button extending button should match
|
||||
// <button is="x-button"> but not <x-button>.
|
||||
if (elem->NodeInfo()->NameAtom() != aDefinition->mLocalName) {
|
||||
//Skip over this element because definition does not apply.
|
||||
continue;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(elem->IsHTMLElement(aDefinition->mLocalName));
|
||||
nsWrapperCache* cache;
|
||||
CallQueryInterface(elem, &cache);
|
||||
MOZ_ASSERT(cache, "Element doesn't support wrapper cache?");
|
||||
|
||||
// We want to set the custom prototype in the caller's comparment.
|
||||
// In the case that element is in a different compartment,
|
||||
// this will set the prototype on the element's wrapper and
|
||||
// thus only visible in the wrapper's compartment.
|
||||
JS::RootedObject wrapper(aCx);
|
||||
JS::Rooted<JSObject*> prototype(aCx, aDefinition->mPrototype);
|
||||
if ((wrapper = cache->GetWrapper()) && JS_WrapObject(aCx, &wrapper)) {
|
||||
if (!JS_SetPrototype(aCx, wrapper, prototype)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
nsContentUtils::EnqueueLifecycleCallback(
|
||||
elem->OwnerDoc(), nsIDocument::eCreated, elem, nullptr, aDefinition);
|
||||
EnqueueUpgradeReaction(elem, aDefinition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -590,6 +564,9 @@ CustomElementRegistry::Define(const nsAString& aName,
|
|||
const ElementDefinitionOptions& aOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
// We do this for [CEReaction] temporarily and it will be removed
|
||||
// after webidl supports [CEReaction] annotation in bug 1309147.
|
||||
AutoCEReaction ceReaction(this);
|
||||
aRv.MightThrowJSException();
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
|
|
@ -883,6 +860,148 @@ CustomElementRegistry::WhenDefined(const nsAString& aName, ErrorResult& aRv)
|
|||
return promise.forget();
|
||||
}
|
||||
|
||||
void
|
||||
CustomElementRegistry::EnqueueUpgradeReaction(Element* aElement,
|
||||
CustomElementDefinition* aDefinition)
|
||||
{
|
||||
Enqueue(aElement, new CustomElementUpgradeReaction(this, aDefinition));
|
||||
}
|
||||
|
||||
void
|
||||
CustomElementRegistry::Upgrade(Element* aElement,
|
||||
CustomElementDefinition* aDefinition)
|
||||
{
|
||||
// TODO: This function will be replaced to v1 upgrade in bug 1299363
|
||||
aElement->RemoveStates(NS_EVENT_STATE_UNRESOLVED);
|
||||
|
||||
// Make sure that the element name matches the name in the definition.
|
||||
// (e.g. a definition for x-button extending button should match
|
||||
// <button is="x-button"> but not <x-button>.
|
||||
if (aElement->NodeInfo()->NameAtom() != aDefinition->mLocalName) {
|
||||
//Skip over this element because definition does not apply.
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aElement->IsHTMLElement(aDefinition->mLocalName));
|
||||
nsWrapperCache* cache;
|
||||
CallQueryInterface(aElement, &cache);
|
||||
MOZ_ASSERT(cache, "Element doesn't support wrapper cache?");
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(mWindow))) {
|
||||
return;
|
||||
}
|
||||
|
||||
JSContext *cx = jsapi.cx();
|
||||
// We want to set the custom prototype in the the compartment of define()'s caller.
|
||||
// We store the prototype from define() directly,
|
||||
// hence the prototype's compartment is the caller's compartment.
|
||||
JS::RootedObject wrapper(cx);
|
||||
JS::Rooted<JSObject*> prototype(cx, aDefinition->mPrototype);
|
||||
{ // Enter prototype's compartment.
|
||||
JSAutoCompartment ac(cx, prototype);
|
||||
|
||||
if ((wrapper = cache->GetWrapper()) && JS_WrapObject(cx, &wrapper)) {
|
||||
if (!JS_SetPrototype(cx, wrapper, prototype)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} // 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);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CustomElementRegistry::CreateAndPushElementQueue()
|
||||
{
|
||||
// Push a new element queue onto the custom element reactions stack.
|
||||
mReactionsStack.AppendElement();
|
||||
}
|
||||
|
||||
void
|
||||
CustomElementRegistry::PopAndInvokeElementQueue()
|
||||
{
|
||||
// Pop the element queue from the custom element reactions stack,
|
||||
// and invoke custom element reactions in that queue.
|
||||
MOZ_ASSERT(!mReactionsStack.IsEmpty(),
|
||||
"Reaction stack shouldn't be empty");
|
||||
|
||||
ElementQueue& elementQueue = mReactionsStack.LastElement();
|
||||
CustomElementRegistry::InvokeReactions(elementQueue);
|
||||
DebugOnly<bool> isRemovedElement = mReactionsStack.RemoveElement(elementQueue);
|
||||
MOZ_ASSERT(isRemovedElement,
|
||||
"Reaction stack should have an element queue to remove");
|
||||
}
|
||||
|
||||
void
|
||||
CustomElementRegistry::Enqueue(Element* aElement,
|
||||
CustomElementReaction* aReaction)
|
||||
{
|
||||
// Add element to the current element queue.
|
||||
if (!mReactionsStack.IsEmpty()) {
|
||||
mReactionsStack.LastElement().AppendElement(do_GetWeakReference(aElement));
|
||||
ReactionQueue* reactionQueue =
|
||||
mElementReactionQueueMap.LookupOrAdd(aElement);
|
||||
reactionQueue->AppendElement(aReaction);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If the custom element reactions stack is empty, then:
|
||||
// Add element to the backup element queue.
|
||||
mBackupQueue.AppendElement(do_GetWeakReference(aElement));
|
||||
|
||||
ReactionQueue* reactionQueue =
|
||||
mElementReactionQueueMap.LookupOrAdd(aElement);
|
||||
reactionQueue->AppendElement(aReaction);
|
||||
|
||||
if (mIsBackupQueueProcessing) {
|
||||
return;
|
||||
}
|
||||
|
||||
CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
|
||||
RefPtr<ProcessBackupQueueRunnable> processBackupQueueRunnable =
|
||||
new ProcessBackupQueueRunnable(this);
|
||||
context->DispatchToMicroTask(processBackupQueueRunnable.forget());
|
||||
}
|
||||
|
||||
void
|
||||
CustomElementRegistry::InvokeBackupQueue()
|
||||
{
|
||||
CustomElementRegistry::InvokeReactions(mBackupQueue);
|
||||
}
|
||||
|
||||
void
|
||||
CustomElementRegistry::InvokeReactions(ElementQueue& aElementQueue)
|
||||
{
|
||||
for (uint32_t i = 0; i < aElementQueue.Length(); ++i) {
|
||||
nsCOMPtr<Element> element = do_QueryReferent(aElementQueue[i]);
|
||||
|
||||
if (!element) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsAutoPtr<ReactionQueue> reactions;
|
||||
mElementReactionQueueMap.RemoveAndForget(element, reactions);
|
||||
|
||||
MOZ_ASSERT(reactions,
|
||||
"Associated ReactionQueue must be found in mElementReactionQueueMap");
|
||||
|
||||
for (uint32_t j = 0; j < reactions->Length(); ++j) {
|
||||
nsAutoPtr<CustomElementReaction>& reaction = reactions->ElementAt(j);
|
||||
reaction->Invoke(element);
|
||||
}
|
||||
}
|
||||
aElementQueue.Clear();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------
|
||||
// CustomElementDefinition
|
||||
|
||||
|
||||
CustomElementDefinition::CustomElementDefinition(nsIAtom* aType,
|
||||
nsIAtom* aLocalName,
|
||||
JSObject* aConstructor,
|
||||
|
|
@ -898,5 +1017,14 @@ CustomElementDefinition::CustomElementDefinition(nsIAtom* aType,
|
|||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------
|
||||
// CustomElementUpgradeReaction
|
||||
|
||||
/* virtual */ void
|
||||
CustomElementUpgradeReaction::Invoke(Element* aElement)
|
||||
{
|
||||
mRegistry->Upgrade(aElement, mDefinition);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue