mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-05 15:28:39 +09:00
Bug 1315885 - Part 4: Implement callback reaction for custom element reactions.
Note: Skipped SyncInvokeReactions since it is removed in CE v1, waste of time. Tag UXP Issue #1344
This commit is contained in:
parent
931b14f847
commit
34dd7065f5
5 changed files with 101 additions and 138 deletions
|
|
@ -92,26 +92,12 @@ CustomElementData::CustomElementData(nsIAtom* aType)
|
|||
|
||||
CustomElementData::CustomElementData(nsIAtom* aType, State aState)
|
||||
: mType(aType)
|
||||
, mCurrentCallback(-1)
|
||||
, mElementIsBeingCreated(false)
|
||||
, mCreatedCallbackInvoked(true)
|
||||
, mAssociatedMicroTask(-1)
|
||||
, mState(aState)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CustomElementData::RunCallbackQueue()
|
||||
{
|
||||
// Note: It's possible to re-enter this method.
|
||||
while (static_cast<uint32_t>(++mCurrentCallback) < mCallbackQueue.Length()) {
|
||||
mCallbackQueue[mCurrentCallback]->Call();
|
||||
}
|
||||
|
||||
mCallbackQueue.Clear();
|
||||
mCurrentCallback = -1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------
|
||||
// CustomElementRegistry
|
||||
|
||||
|
|
@ -128,7 +114,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CustomElementRegistry)
|
||||
for (auto iter = tmp->mCustomDefinitions.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsAutoPtr<LifecycleCallbacks>& callbacks = iter.UserData()->mCallbacks;
|
||||
auto& callbacks = iter.UserData()->mCallbacks;
|
||||
|
||||
if (callbacks->mAttributeChangedCallback.WasPassed()) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
|
||||
|
|
@ -191,43 +177,6 @@ CustomElementRegistry::IsCustomElementEnabled(JSContext* aCx, JSObject* aObject)
|
|||
nsContentUtils::IsWebComponentsEnabled();
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
CustomElementRegistry::ProcessTopElementQueue()
|
||||
{
|
||||
MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
|
||||
|
||||
nsTArray<RefPtr<CustomElementData>>& stack = *sProcessingStack;
|
||||
uint32_t firstQueue = stack.LastIndexOf((CustomElementData*) nullptr);
|
||||
|
||||
for (uint32_t i = firstQueue + 1; i < stack.Length(); ++i) {
|
||||
// Callback queue may have already been processed in an earlier
|
||||
// element queue or in an element queue that was popped
|
||||
// off more recently.
|
||||
if (stack[i]->mAssociatedMicroTask != -1) {
|
||||
stack[i]->RunCallbackQueue();
|
||||
stack[i]->mAssociatedMicroTask = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// If this was actually the base element queue, don't bother trying to pop
|
||||
// the first "queue" marker (sentinel).
|
||||
if (firstQueue != 0) {
|
||||
stack.SetLength(firstQueue);
|
||||
} else {
|
||||
// Don't pop sentinel for base element queue.
|
||||
stack.SetLength(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
CustomElementRegistry::XPCOMShutdown()
|
||||
{
|
||||
sProcessingStack.reset();
|
||||
}
|
||||
|
||||
/* static */ Maybe<nsTArray<RefPtr<CustomElementData>>>
|
||||
CustomElementRegistry::sProcessingStack;
|
||||
|
||||
CustomElementRegistry::CustomElementRegistry(nsPIDOMWindowInner* aWindow)
|
||||
: mWindow(aWindow)
|
||||
, mIsCustomDefinitionRunning(false)
|
||||
|
|
@ -237,12 +186,6 @@ CustomElementRegistry::CustomElementRegistry(nsPIDOMWindowInner* aWindow)
|
|||
MOZ_ALWAYS_TRUE(mConstructors.init());
|
||||
|
||||
mozilla::HoldJSObjects(this);
|
||||
|
||||
if (!sProcessingStack) {
|
||||
sProcessingStack.emplace();
|
||||
// Add the base queue sentinel to the processing stack.
|
||||
sProcessingStack->AppendElement((CustomElementData*) nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
CustomElementRegistry::~CustomElementRegistry()
|
||||
|
|
@ -346,14 +289,15 @@ 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, definition);
|
||||
// We make it synchronously for createElement/createElementNS in order to
|
||||
// pass tests. It'll be removed when we deprecate custom elements v0.
|
||||
// SyncInvokeReactions(nsIDocument::eCreated, aElement, definition);
|
||||
}
|
||||
|
||||
void
|
||||
CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
|
||||
Element* aCustomElement,
|
||||
LifecycleCallbackArgs* aArgs,
|
||||
CustomElementDefinition* aDefinition)
|
||||
UniquePtr<CustomElementCallback>
|
||||
CustomElementRegistry::CreateCustomElementCallback(
|
||||
nsIDocument::ElementCallbackType aType, Element* aCustomElement,
|
||||
LifecycleCallbackArgs* aArgs, CustomElementDefinition* aDefinition)
|
||||
{
|
||||
RefPtr<CustomElementData> elementData = aCustomElement->GetCustomElementData();
|
||||
MOZ_ASSERT(elementData, "CustomElementData should exist");
|
||||
|
|
@ -372,7 +316,7 @@ CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType
|
|||
if (!definition || definition->mLocalName != info->NameAtom()) {
|
||||
// Trying to enqueue a callback for an element that is not
|
||||
// a custom element. We are done, nothing to do.
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -406,7 +350,7 @@ CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType
|
|||
|
||||
// If there is no such callback, stop.
|
||||
if (!func) {
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aType == nsIDocument::eCreated) {
|
||||
|
|
@ -414,54 +358,41 @@ CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType
|
|||
} else if (!elementData->mCreatedCallbackInvoked) {
|
||||
// Callbacks other than created callback must not be enqueued
|
||||
// until after the created callback has been invoked.
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Add CALLBACK to ELEMENT's callback queue.
|
||||
CustomElementCallback* callback = new CustomElementCallback(aCustomElement,
|
||||
aType,
|
||||
func,
|
||||
elementData);
|
||||
// Ownership of callback is taken by mCallbackQueue.
|
||||
elementData->mCallbackQueue.AppendElement(callback);
|
||||
auto callback =
|
||||
MakeUnique<CustomElementCallback>(aCustomElement, aType, func, elementData);
|
||||
|
||||
if (aArgs) {
|
||||
callback->SetArgs(*aArgs);
|
||||
}
|
||||
|
||||
if (!elementData->mElementIsBeingCreated) {
|
||||
CustomElementData* lastData =
|
||||
sProcessingStack->SafeLastElement(nullptr);
|
||||
return Move(callback);
|
||||
}
|
||||
|
||||
// A new element queue needs to be pushed if the queue at the
|
||||
// top of the stack is associated with another microtask level.
|
||||
bool shouldPushElementQueue =
|
||||
(!lastData || lastData->mAssociatedMicroTask <
|
||||
static_cast<int32_t>(nsContentUtils::MicroTaskLevel()));
|
||||
|
||||
// Push a new element queue onto the processing stack when appropriate
|
||||
// (when we enter a new microtask).
|
||||
if (shouldPushElementQueue) {
|
||||
// Push a sentinel value on the processing stack to mark the
|
||||
// boundary between the element queues.
|
||||
sProcessingStack->AppendElement((CustomElementData*) nullptr);
|
||||
}
|
||||
|
||||
sProcessingStack->AppendElement(elementData);
|
||||
elementData->mAssociatedMicroTask =
|
||||
static_cast<int32_t>(nsContentUtils::MicroTaskLevel());
|
||||
|
||||
// Add a script runner to pop and process the element queue at
|
||||
// the top of the processing stack.
|
||||
if (shouldPushElementQueue) {
|
||||
// Lifecycle callbacks enqueued by user agent implementation
|
||||
// should be invoked prior to returning control back to script.
|
||||
// Create a script runner to process the top of the processing
|
||||
// stack as soon as it is safe to run script.
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableFunction(&CustomElementRegistry::ProcessTopElementQueue);
|
||||
nsContentUtils::AddScriptRunner(runnable);
|
||||
}
|
||||
void
|
||||
CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
|
||||
Element* aCustomElement,
|
||||
LifecycleCallbackArgs* aArgs,
|
||||
CustomElementDefinition* aDefinition)
|
||||
{
|
||||
auto callback =
|
||||
CreateCustomElementCallback(aType, aCustomElement, aArgs, aDefinition);
|
||||
if (!callback) {
|
||||
return;
|
||||
}
|
||||
|
||||
DocGroup* docGroup = mWindow->GetDocGroup();
|
||||
if (!docGroup) {
|
||||
return;
|
||||
}
|
||||
|
||||
CustomElementReactionsStack* reactionsStack =
|
||||
docGroup->CustomElementReactionsStack();
|
||||
reactionsStack->EnqueueCallbackReaction(this, aCustomElement, aDefinition,
|
||||
Move(callback));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -933,6 +864,16 @@ CustomElementReactionsStack::EnqueueUpgradeReaction(CustomElementRegistry* aRegi
|
|||
Enqueue(aElement, new CustomElementUpgradeReaction(aRegistry, aDefinition));
|
||||
}
|
||||
|
||||
void
|
||||
CustomElementReactionsStack::EnqueueCallbackReaction(CustomElementRegistry* aRegistry,
|
||||
Element* aElement,
|
||||
CustomElementDefinition* aDefinition,
|
||||
UniquePtr<CustomElementCallback> aCustomElementCallback)
|
||||
{
|
||||
Enqueue(aElement, new CustomElementCallbackReaction(aRegistry, aDefinition,
|
||||
Move(aCustomElementCallback)));
|
||||
}
|
||||
|
||||
void
|
||||
CustomElementReactionsStack::Enqueue(Element* aElement,
|
||||
CustomElementReaction* aReaction)
|
||||
|
|
@ -1026,5 +967,14 @@ CustomElementUpgradeReaction::Invoke(Element* aElement)
|
|||
mRegistry->Upgrade(aElement, mDefinition);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------
|
||||
// CustomElementCallbackReaction
|
||||
|
||||
/* virtual */ void
|
||||
CustomElementCallbackReaction::Invoke(Element* aElement)
|
||||
{
|
||||
mCustomElementCallback->Call();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue