Bug 1347446 - Move custom element reactions stack to DocGroup.

Tag UXP Issue #1344
This commit is contained in:
Gaming4JC 2020-01-03 22:18:55 -05:00 • committed by Roy Tam
commit bde53294f8
4 changed files with 136 additions and 90 deletions

View file

@ -9,6 +9,7 @@
#include "mozilla/dom/CustomElementRegistryBinding.h" #include "mozilla/dom/CustomElementRegistryBinding.h"
#include "mozilla/dom/HTMLElementBinding.h" #include "mozilla/dom/HTMLElementBinding.h"
#include "mozilla/dom/WebComponentsBinding.h" #include "mozilla/dom/WebComponentsBinding.h"
#include "mozilla/dom/DocGroup.h"
#include "nsIParserService.h" #include "nsIParserService.h"
#include "jsapi.h" #include "jsapi.h"
@ -214,7 +215,6 @@ CustomElementRegistry::sProcessingStack;
CustomElementRegistry::CustomElementRegistry(nsPIDOMWindowInner* aWindow) CustomElementRegistry::CustomElementRegistry(nsPIDOMWindowInner* aWindow)
: mWindow(aWindow) : mWindow(aWindow)
, mIsCustomDefinitionRunning(false) , mIsCustomDefinitionRunning(false)
, mIsBackupQueueProcessing(false)
{ {
MOZ_ASSERT(aWindow); MOZ_ASSERT(aWindow);
MOZ_ASSERT(aWindow->IsInnerWindow()); MOZ_ASSERT(aWindow->IsInnerWindow());
@ -467,18 +467,27 @@ CustomElementRegistry::GetCustomPrototype(nsIAtom* aAtom,
void void
CustomElementRegistry::UpgradeCandidates(JSContext* aCx, CustomElementRegistry::UpgradeCandidates(JSContext* aCx,
nsIAtom* aKey, nsIAtom* aKey,
CustomElementDefinition* aDefinition) CustomElementDefinition* aDefinition,
ErrorResult& aRv)
{ {
DocGroup* docGroup = mWindow->GetDocGroup();
if (!docGroup) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return;
}
nsAutoPtr<nsTArray<nsWeakPtr>> candidates; nsAutoPtr<nsTArray<nsWeakPtr>> candidates;
mCandidatesMap.RemoveAndForget(aKey, candidates); mCandidatesMap.RemoveAndForget(aKey, candidates);
if (candidates) { if (candidates) {
CustomElementReactionsStack* reactionsStack =
docGroup->CustomElementReactionsStack();
for (size_t i = 0; i < candidates->Length(); ++i) { for (size_t i = 0; i < candidates->Length(); ++i) {
nsCOMPtr<Element> elem = do_QueryReferent(candidates->ElementAt(i)); nsCOMPtr<Element> elem = do_QueryReferent(candidates->ElementAt(i));
if (!elem) { if (!elem) {
continue; continue;
} }
EnqueueUpgradeReaction(elem, aDefinition); reactionsStack->EnqueueUpgradeReaction(this, elem, aDefinition);
} }
} }
} }
@ -540,7 +549,13 @@ CustomElementRegistry::Define(const nsAString& aName,
{ {
// We do this for [CEReaction] temporarily and it will be removed // We do this for [CEReaction] temporarily and it will be removed
// after webidl supports [CEReaction] annotation in bug 1309147. // after webidl supports [CEReaction] annotation in bug 1309147.
AutoCEReaction ceReaction(this); DocGroup* docGroup = mWindow->GetDocGroup();
if (!docGroup) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return;
}
AutoCEReaction ceReaction(docGroup->CustomElementReactionsStack());
aRv.MightThrowJSException(); aRv.MightThrowJSException();
AutoJSAPI jsapi; AutoJSAPI jsapi;
@ -770,7 +785,7 @@ CustomElementRegistry::Define(const nsAString& aName,
* 13. 14. 15. Upgrade candidates * 13. 14. 15. Upgrade candidates
*/ */
// TODO: Bug 1299363 - Implement custom element v1 upgrade algorithm // TODO: Bug 1299363 - Implement custom element v1 upgrade algorithm
UpgradeCandidates(cx, nameAtom, definition); UpgradeCandidates(cx, nameAtom, definition, aRv);
/** /**
* 16. If this CustomElementRegistry's when-defined promise map contains an * 16. If this CustomElementRegistry's when-defined promise map contains an
@ -834,13 +849,6 @@ CustomElementRegistry::WhenDefined(const nsAString& aName, ErrorResult& aRv)
return promise.forget(); return promise.forget();
} }
void
CustomElementRegistry::EnqueueUpgradeReaction(Element* aElement,
CustomElementDefinition* aDefinition)
{
Enqueue(aElement, new CustomElementUpgradeReaction(this, aDefinition));
}
void void
CustomElementRegistry::Upgrade(Element* aElement, CustomElementRegistry::Upgrade(Element* aElement,
CustomElementDefinition* aDefinition) CustomElementDefinition* aDefinition)
@ -887,16 +895,18 @@ CustomElementRegistry::Upgrade(Element* aElement,
EnqueueLifecycleCallback(nsIDocument::eCreated, aElement, nullptr, aDefinition); EnqueueLifecycleCallback(nsIDocument::eCreated, aElement, nullptr, aDefinition);
} }
//-----------------------------------------------------
// CustomElementReactionsStack
void void
CustomElementRegistry::CreateAndPushElementQueue() CustomElementReactionsStack::CreateAndPushElementQueue()
{ {
// Push a new element queue onto the custom element reactions stack. // Push a new element queue onto the custom element reactions stack.
mReactionsStack.AppendElement(); mReactionsStack.AppendElement();
} }
void void
CustomElementRegistry::PopAndInvokeElementQueue() CustomElementReactionsStack::PopAndInvokeElementQueue()
{ {
// Pop the element queue from the custom element reactions stack, // Pop the element queue from the custom element reactions stack,
// and invoke custom element reactions in that queue. // and invoke custom element reactions in that queue.
@ -904,15 +914,23 @@ CustomElementRegistry::PopAndInvokeElementQueue()
"Reaction stack shouldn't be empty"); "Reaction stack shouldn't be empty");
ElementQueue& elementQueue = mReactionsStack.LastElement(); ElementQueue& elementQueue = mReactionsStack.LastElement();
CustomElementRegistry::InvokeReactions(elementQueue); InvokeReactions(elementQueue);
DebugOnly<bool> isRemovedElement = mReactionsStack.RemoveElement(elementQueue); DebugOnly<bool> isRemovedElement = mReactionsStack.RemoveElement(elementQueue);
MOZ_ASSERT(isRemovedElement, MOZ_ASSERT(isRemovedElement,
"Reaction stack should have an element queue to remove"); "Reaction stack should have an element queue to remove");
} }
void void
CustomElementRegistry::Enqueue(Element* aElement, CustomElementReactionsStack::EnqueueUpgradeReaction(CustomElementRegistry* aRegistry,
CustomElementReaction* aReaction) Element* aElement,
CustomElementDefinition* aDefinition)
{
Enqueue(aElement, new CustomElementUpgradeReaction(aRegistry, aDefinition));
}
void
CustomElementReactionsStack::Enqueue(Element* aElement,
CustomElementReaction* aReaction)
{ {
// Add element to the current element queue. // Add element to the current element queue.
if (!mReactionsStack.IsEmpty()) { if (!mReactionsStack.IsEmpty()) {
@ -943,13 +961,13 @@ CustomElementRegistry::Enqueue(Element* aElement,
} }
void void
CustomElementRegistry::InvokeBackupQueue() CustomElementReactionsStack::InvokeBackupQueue()
{ {
CustomElementRegistry::InvokeReactions(mBackupQueue); InvokeReactions(mBackupQueue);
} }
void void
CustomElementRegistry::InvokeReactions(ElementQueue& aElementQueue) CustomElementReactionsStack::InvokeReactions(ElementQueue& aElementQueue)
{ {
for (uint32_t i = 0; i < aElementQueue.Length(); ++i) { for (uint32_t i = 0; i < aElementQueue.Length(); ++i) {
nsCOMPtr<Element> element = do_QueryReferent(aElementQueue[i]); nsCOMPtr<Element> element = do_QueryReferent(aElementQueue[i]);

View file

@ -165,6 +165,86 @@ private:
virtual void Invoke(Element* aElement) override; virtual void Invoke(Element* aElement) override;
}; };
// https://html.spec.whatwg.org/multipage/scripting.html#custom-element-reactions-stack
class CustomElementReactionsStack
{
public:
NS_INLINE_DECL_REFCOUNTING(CustomElementReactionsStack)
CustomElementReactionsStack()
: mIsBackupQueueProcessing(false)
{
}
// nsWeakPtr is a weak pointer of Element
// The element reaction queues are stored in ElementReactionQueueMap.
// We need to lookup ElementReactionQueueMap again to get relevant reaction queue.
typedef nsTArray<nsWeakPtr> ElementQueue;
/**
* Enqueue a custom element upgrade reaction
* https://html.spec.whatwg.org/multipage/scripting.html#enqueue-a-custom-element-upgrade-reaction
*/
void EnqueueUpgradeReaction(CustomElementRegistry* aRegistry,
Element* aElement,
CustomElementDefinition* aDefinition);
// [CEReactions] Before executing the algorithm's steps
// Push a new element queue onto the custom element reactions stack.
void CreateAndPushElementQueue();
// [CEReactions] After executing the algorithm's steps
// Pop the element queue from the custom element reactions stack,
// and invoke custom element reactions in that queue.
void PopAndInvokeElementQueue();
private:
~CustomElementReactionsStack() {};
typedef nsTArray<nsAutoPtr<CustomElementReaction>> ReactionQueue;
typedef nsClassHashtable<nsISupportsHashKey, ReactionQueue>
ElementReactionQueueMap;
ElementReactionQueueMap mElementReactionQueueMap;
nsTArray<ElementQueue> mReactionsStack;
ElementQueue mBackupQueue;
// https://html.spec.whatwg.org/#enqueue-an-element-on-the-appropriate-element-queue
bool mIsBackupQueueProcessing;
void InvokeBackupQueue();
/**
* Invoke custom element reactions
* https://html.spec.whatwg.org/multipage/scripting.html#invoke-custom-element-reactions
*/
void InvokeReactions(ElementQueue& aElementQueue);
void Enqueue(Element* aElement, CustomElementReaction* aReaction);
private:
class ProcessBackupQueueRunnable : public mozilla::Runnable {
public:
explicit ProcessBackupQueueRunnable(CustomElementReactionsStack* aReactionStack)
: mReactionStack(aReactionStack)
{
MOZ_ASSERT(!mReactionStack->mIsBackupQueueProcessing,
"mIsBackupQueueProcessing should be initially false");
mReactionStack->mIsBackupQueueProcessing = true;
}
NS_IMETHOD Run() override
{
mReactionStack->InvokeBackupQueue();
mReactionStack->mIsBackupQueueProcessing = false;
return NS_OK;
}
private:
RefPtr<CustomElementReactionsStack> mReactionStack;
};
};
class CustomElementRegistry final : public nsISupports, class CustomElementRegistry final : public nsISupports,
public nsWrapperCache public nsWrapperCache
{ {
@ -210,24 +290,8 @@ public:
void GetCustomPrototype(nsIAtom* aAtom, void GetCustomPrototype(nsIAtom* aAtom,
JS::MutableHandle<JSObject*> aPrototype); JS::MutableHandle<JSObject*> aPrototype);
/**
* Enqueue a custom element upgrade reaction
* https://html.spec.whatwg.org/multipage/scripting.html#enqueue-a-custom-element-upgrade-reaction
*/
void EnqueueUpgradeReaction(Element* aElement,
CustomElementDefinition* aDefinition);
void Upgrade(Element* aElement, CustomElementDefinition* aDefinition); void Upgrade(Element* aElement, CustomElementDefinition* aDefinition);
// [CEReactions] Before executing the algorithm's steps
// Push a new element queue onto the custom element reactions stack.
void CreateAndPushElementQueue();
// [CEReactions] After executing the algorithm's steps
// Pop the element queue from the custom element reactions stack,
// and invoke custom element reactions in that queue.
void PopAndInvokeElementQueue();
private: private:
~CustomElementRegistry(); ~CustomElementRegistry();
@ -244,22 +308,8 @@ private:
void UpgradeCandidates(JSContext* aCx, void UpgradeCandidates(JSContext* aCx,
nsIAtom* aKey, nsIAtom* aKey,
CustomElementDefinition* aDefinition); CustomElementDefinition* aDefinition,
ErrorResult& aRv);
void InvokeBackupQueue();
void Enqueue(Element* aElement, CustomElementReaction* aReaction);
// nsWeakPtr is a weak pointer of Element
// The element reaction queues are stored in ElementReactionQueueMap.
// We need to lookup ElementReactionQueueMap again to get relevant reaction queue.
typedef nsTArray<nsWeakPtr> ElementQueue;
/**
* Invoke custom element reactions
* https://html.spec.whatwg.org/multipage/scripting.html#invoke-custom-element-reactions
*/
void InvokeReactions(ElementQueue& aElementQueue);
typedef nsClassHashtable<nsISupportsHashKey, CustomElementDefinition> typedef nsClassHashtable<nsISupportsHashKey, CustomElementDefinition>
DefinitionMap; DefinitionMap;
@ -301,17 +351,6 @@ private:
// It is used to prevent reentrant invocations of element definition. // It is used to prevent reentrant invocations of element definition.
bool mIsCustomDefinitionRunning; bool mIsCustomDefinitionRunning;
// https://html.spec.whatwg.org/#enqueue-an-element-on-the-appropriate-element-queue
bool mIsBackupQueueProcessing;
typedef nsTArray<nsAutoPtr<CustomElementReaction>> ReactionQueue;
typedef nsClassHashtable<nsISupportsHashKey, ReactionQueue>
ElementReactionQueueMap;
ElementReactionQueueMap mElementReactionQueueMap;
nsTArray<ElementQueue> mReactionsStack;
ElementQueue mBackupQueue;
private: private:
class MOZ_RAII AutoSetRunningFlag final { class MOZ_RAII AutoSetRunningFlag final {
@ -332,28 +371,6 @@ private:
CustomElementRegistry* mRegistry; CustomElementRegistry* mRegistry;
}; };
private:
class ProcessBackupQueueRunnable : public mozilla::Runnable {
public:
explicit ProcessBackupQueueRunnable(CustomElementRegistry* aRegistry)
: mRegistry(aRegistry)
{
MOZ_ASSERT(!mRegistry->mIsBackupQueueProcessing,
"mIsBackupQueueProcessing should be initially false");
mRegistry->mIsBackupQueueProcessing = true;
}
NS_IMETHOD Run() override
{
mRegistry->InvokeBackupQueue();
mRegistry->mIsBackupQueueProcessing = false;
return NS_OK;
}
private:
RefPtr<CustomElementRegistry> mRegistry;
};
public: public:
nsISupports* GetParentObject() const; nsISupports* GetParentObject() const;
@ -370,15 +387,15 @@ public:
class MOZ_RAII AutoCEReaction final { class MOZ_RAII AutoCEReaction final {
public: public:
explicit AutoCEReaction(CustomElementRegistry* aRegistry) explicit AutoCEReaction(CustomElementReactionsStack* aReactionsStack)
: mRegistry(aRegistry) { : mReactionsStack(aReactionsStack) {
mRegistry->CreateAndPushElementQueue(); mReactionsStack->CreateAndPushElementQueue();
} }
~AutoCEReaction() { ~AutoCEReaction() {
mRegistry->PopAndInvokeElementQueue(); mReactionsStack->PopAndInvokeElementQueue();
} }
private: private:
RefPtr<CustomElementRegistry> mRegistry; RefPtr<CustomElementReactionsStack> mReactionsStack;
}; };
} // namespace dom } // namespace dom

View file

@ -14,6 +14,7 @@
#include "nsString.h" #include "nsString.h"
#include "mozilla/RefPtr.h" #include "mozilla/RefPtr.h"
#include "mozilla/dom/CustomElementRegistry.h"
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
@ -52,6 +53,14 @@ public:
{ {
return mTabGroup; return mTabGroup;
} }
mozilla::dom::CustomElementReactionsStack* CustomElementReactionsStack()
{
if (!mReactionsStack) {
mReactionsStack = new mozilla::dom::CustomElementReactionsStack();
}
return mReactionsStack;
}
void RemoveDocument(nsIDocument* aWindow); void RemoveDocument(nsIDocument* aWindow);
// Iterators for iterating over every document within the DocGroup // Iterators for iterating over every document within the DocGroup
@ -71,6 +80,7 @@ private:
nsCString mKey; nsCString mKey;
RefPtr<TabGroup> mTabGroup; RefPtr<TabGroup> mTabGroup;
nsTArray<nsIDocument*> mDocuments; nsTArray<nsIDocument*> mDocuments;
RefPtr<mozilla::dom::CustomElementReactionsStack> mReactionsStack;
}; };
} // namespace dom } // namespace dom

View file

@ -16,6 +16,7 @@
#include "mozilla/dom/FlyWebDiscoveryManager.h" #include "mozilla/dom/FlyWebDiscoveryManager.h"
#include "mozilla/dom/FlyWebDiscoveryManagerBinding.h" #include "mozilla/dom/FlyWebDiscoveryManagerBinding.h"
#include "mozilla/dom/Element.h"
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {