From 8573c572fbf5fa68defb3228e7f1450ec234d59b Mon Sep 17 00:00:00 2001 From: Gaming4JC Date: Sun, 5 Jan 2020 15:31:44 -0500 Subject: Bug 1392970 - Part 1: Make CustomElementDefinition ref-counted and put it in CustomElementData. Tag UXP Issue #1344 --- dom/base/CustomElementRegistry.cpp | 109 +++++++++++++++++++++---------------- dom/base/CustomElementRegistry.h | 27 ++++++++- dom/base/Element.cpp | 20 +++++++ dom/base/Element.h | 16 ++++++ dom/base/FragmentOrElement.cpp | 14 ++++- dom/base/nsDocument.cpp | 3 +- 6 files changed, 139 insertions(+), 50 deletions(-) (limited to 'dom/base') diff --git a/dom/base/CustomElementRegistry.cpp b/dom/base/CustomElementRegistry.cpp index 27e92a56a..b752fdda7 100644 --- a/dom/base/CustomElementRegistry.cpp +++ b/dom/base/CustomElementRegistry.cpp @@ -160,46 +160,15 @@ private: NS_IMPL_CYCLE_COLLECTION_CLASS(CustomElementRegistry) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CustomElementRegistry) - tmp->mCustomDefinitions.Clear(); tmp->mConstructors.clear(); + NS_IMPL_CYCLE_COLLECTION_UNLINK(mCustomDefinitions) NS_IMPL_CYCLE_COLLECTION_UNLINK(mWhenDefinedPromiseMap) NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow) NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CustomElementRegistry) - for (auto iter = tmp->mCustomDefinitions.Iter(); !iter.Done(); iter.Next()) { - auto& callbacks = iter.UserData()->mCallbacks; - - if (callbacks->mAttributeChangedCallback.WasPassed()) { - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, - "mCustomDefinitions->mCallbacks->mAttributeChangedCallback"); - cb.NoteXPCOMChild(callbacks->mAttributeChangedCallback.Value()); - } - - if (callbacks->mCreatedCallback.WasPassed()) { - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, - "mCustomDefinitions->mCallbacks->mCreatedCallback"); - cb.NoteXPCOMChild(callbacks->mCreatedCallback.Value()); - } - - if (callbacks->mAttachedCallback.WasPassed()) { - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, - "mCustomDefinitions->mCallbacks->mAttachedCallback"); - cb.NoteXPCOMChild(callbacks->mAttachedCallback.Value()); - } - - if (callbacks->mDetachedCallback.WasPassed()) { - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, - "mCustomDefinitions->mCallbacks->mDetachedCallback"); - cb.NoteXPCOMChild(callbacks->mDetachedCallback.Value()); - } - - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, - "mCustomDefinitions->mConstructor"); - cb.NoteXPCOMChild(iter.UserData()->mConstructor); - } - + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCustomDefinitions) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWhenDefinedPromiseMap) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END @@ -256,7 +225,7 @@ CustomElementRegistry::LookupCustomElementDefinition(const nsAString& aLocalName nsCOMPtr localNameAtom = NS_Atomize(aLocalName); nsCOMPtr typeAtom = aIs ? NS_Atomize(*aIs) : localNameAtom; - CustomElementDefinition* data = mCustomDefinitions.Get(typeAtom); + CustomElementDefinition* data = mCustomDefinitions.GetWeak(typeAtom); if (data && data->mLocalName == localNameAtom) { return data; } @@ -275,7 +244,7 @@ CustomElementRegistry::LookupCustomElementDefinition(JSContext* aCx, return nullptr; } - CustomElementDefinition* definition = mCustomDefinitions.Get(ptr->value()); + CustomElementDefinition* definition = mCustomDefinitions.GetWeak(ptr->value()); MOZ_ASSERT(definition, "Definition must be found in mCustomDefinitions"); return definition; @@ -294,7 +263,7 @@ CustomElementRegistry::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTy typeName = info->NameAtom(); } - if (mCustomDefinitions.Get(typeName)) { + if (mCustomDefinitions.GetWeak(typeName)) { return; } @@ -368,7 +337,7 @@ CustomElementRegistry::CreateCustomElementCallback( nsCOMPtr typeAtom = elementData ? elementData->mType.get() : info->NameAtom(); - definition = mCustomDefinitions.Get(typeAtom); + definition = mCustomDefinitions.GetWeak(typeAtom); 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. @@ -447,7 +416,7 @@ CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType nsCOMPtr typeAtom = elementData ? elementData->mType.get() : info->NameAtom(); - definition = mCustomDefinitions.Get(typeAtom); + definition = mCustomDefinitions.GetWeak(typeAtom); if (!definition || definition->mLocalName != info->NameAtom()) { return; } @@ -482,7 +451,8 @@ void CustomElementRegistry::GetCustomPrototype(nsIAtom* aAtom, JS::MutableHandle aPrototype) { - mozilla::dom::CustomElementDefinition* definition = mCustomDefinitions.Get(aAtom); + mozilla::dom::CustomElementDefinition* definition = + mCustomDefinitions.GetWeak(aAtom); if (definition) { aPrototype.set(definition->mPrototype); } else { @@ -617,7 +587,7 @@ CustomElementRegistry::Define(const nsAString& aName, * 3. If this CustomElementRegistry contains an entry with name name, then * throw a "NotSupportedError" DOMException and abort these steps. */ - if (mCustomDefinitions.Get(nameAtom)) { + if (mCustomDefinitions.GetWeak(nameAtom)) { aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return; } @@ -628,7 +598,7 @@ CustomElementRegistry::Define(const nsAString& aName, */ const auto& ptr = mConstructors.lookup(constructorUnwrapped); if (ptr) { - MOZ_ASSERT(mCustomDefinitions.Get(ptr->value()), + MOZ_ASSERT(mCustomDefinitions.GetWeak(ptr->value()), "Definition must be found in mCustomDefinitions"); aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return; @@ -826,7 +796,7 @@ CustomElementRegistry::Define(const nsAString& aName, return; } - CustomElementDefinition* definition = + RefPtr definition = new CustomElementDefinition(nameAtom, localNameAtom, &aFunctionConstructor, @@ -835,7 +805,8 @@ CustomElementRegistry::Define(const nsAString& aName, callbacks, 0 /* TODO dependent on HTML imports. Bug 877072 */); - mCustomDefinitions.Put(nameAtom, definition); + CustomElementDefinition* def = definition.get(); + mCustomDefinitions.Put(nameAtom, definition.forget()); MOZ_ASSERT(mCustomDefinitions.Count() == mConstructors.count(), "Number of entries should be the same"); @@ -843,7 +814,7 @@ CustomElementRegistry::Define(const nsAString& aName, /** * 13. 14. 15. Upgrade candidates */ - UpgradeCandidates(nameAtom, definition, aRv); + UpgradeCandidates(nameAtom, def, aRv); /** * 16. If this CustomElementRegistry's when-defined promise map contains an @@ -866,7 +837,7 @@ CustomElementRegistry::Get(JSContext* aCx, const nsAString& aName, JS::MutableHandle aRetVal) { nsCOMPtr nameAtom(NS_Atomize(aName)); - CustomElementDefinition* data = mCustomDefinitions.Get(nameAtom); + CustomElementDefinition* data = mCustomDefinitions.GetWeak(nameAtom); if (!data) { aRetVal.setUndefined(); @@ -893,7 +864,7 @@ CustomElementRegistry::WhenDefined(const nsAString& aName, ErrorResult& aRv) return promise.forget(); } - if (mCustomDefinitions.Get(nameAtom)) { + if (mCustomDefinitions.GetWeak(nameAtom)) { promise->MaybeResolve(JS::UndefinedHandleValue); return promise.forget(); } @@ -996,6 +967,9 @@ CustomElementRegistry::Upgrade(Element* aElement, // Step 8. data->mState = CustomElementData::State::eCustom; + // Step 9. + aElement->SetCustomElementDefinition(aDefinition); + // This is for old spec. nsContentUtils::EnqueueLifecycleCallback(aElement->OwnerDoc(), nsIDocument::eCreated, @@ -1148,6 +1122,49 @@ CustomElementReactionsStack::InvokeReactions(ElementQueue* aElementQueue, //----------------------------------------------------- // CustomElementDefinition +NS_IMPL_CYCLE_COLLECTION_CLASS(CustomElementDefinition) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CustomElementDefinition) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mConstructor) + tmp->mPrototype = nullptr; + tmp->mCallbacks = nullptr; +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CustomElementDefinition) + mozilla::dom::LifecycleCallbacks* callbacks = tmp->mCallbacks.get(); + + if (callbacks->mAttributeChangedCallback.WasPassed()) { + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, + "mCallbacks->mAttributeChangedCallback"); + cb.NoteXPCOMChild(callbacks->mAttributeChangedCallback.Value()); + } + + if (callbacks->mCreatedCallback.WasPassed()) { + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCallbacks->mCreatedCallback"); + cb.NoteXPCOMChild(callbacks->mCreatedCallback.Value()); + } + + if (callbacks->mAttachedCallback.WasPassed()) { + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCallbacks->mAttachedCallback"); + cb.NoteXPCOMChild(callbacks->mAttachedCallback.Value()); + } + + if (callbacks->mDetachedCallback.WasPassed()) { + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCallbacks->mDetachedCallback"); + cb.NoteXPCOMChild(callbacks->mDetachedCallback.Value()); + } + + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mConstructor"); + cb.NoteXPCOMChild(tmp->mConstructor); +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CustomElementDefinition) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mPrototype) +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(CustomElementDefinition, AddRef) +NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(CustomElementDefinition, Release) + CustomElementDefinition::CustomElementDefinition(nsIAtom* aType, nsIAtom* aLocalName, Function* aConstructor, diff --git a/dom/base/CustomElementRegistry.h b/dom/base/CustomElementRegistry.h index b731a1858..89e754365 100644 --- a/dom/base/CustomElementRegistry.h +++ b/dom/base/CustomElementRegistry.h @@ -13,7 +13,9 @@ #include "mozilla/ErrorResult.h" #include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/FunctionBinding.h" +#include "mozilla/dom/WebComponentsBinding.h" #include "nsCycleCollectionParticipant.h" +#include "nsGenericHTMLElement.h" #include "nsWrapperCache.h" class nsDocument; @@ -23,7 +25,6 @@ namespace dom { struct CustomElementData; struct ElementDefinitionOptions; -struct LifecycleCallbacks; class CallbackFunction; class CustomElementReaction; class Function; @@ -115,6 +116,22 @@ struct CustomElementData // e.g., create an element, insert a node. AutoTArray, 3> mReactionQueue; + RefPtr mCustomElementDefinition; + + void + SetCustomElementDefinition(CustomElementDefinition* aDefinition) + { + MOZ_ASSERT(!mCustomElementDefinition); + + mCustomElementDefinition = aDefinition; + } + + CustomElementDefinition* + GetCustomElementDefinition() + { + return mCustomElementDefinition; + } + private: virtual ~CustomElementData() {} }; @@ -125,6 +142,9 @@ private: // https://html.spec.whatwg.org/multipage/scripting.html#custom-element-definition struct CustomElementDefinition { + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(CustomElementDefinition) + NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(CustomElementDefinition) + CustomElementDefinition(nsIAtom* aType, nsIAtom* aLocalName, Function* aConstructor, @@ -170,6 +190,9 @@ struct CustomElementDefinition return mObservedAttributes.Contains(aName); } + +private: + ~CustomElementDefinition() {} }; class CustomElementReaction @@ -381,7 +404,7 @@ private: CustomElementDefinition* aDefinition, ErrorResult& aRv); - typedef nsClassHashtable + typedef nsRefPtrHashtable DefinitionMap; typedef nsClassHashtable> CandidateMap; diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index 5719b423d..e90d44476 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -4065,3 +4065,23 @@ Element::SetCustomElementData(CustomElementData* aData) MOZ_ASSERT(!slots->mCustomElementData, "Custom element data may not be changed once set."); slots->mCustomElementData = aData; } + +CustomElementDefinition* +Element::GetCustomElementDefinition() const +{ + CustomElementData* data = GetCustomElementData(); + if (!data) { + return nullptr; + } + + return data->GetCustomElementDefinition(); +} + +void +Element::SetCustomElementDefinition(CustomElementDefinition* aDefinition) +{ + CustomElementData* data = GetCustomElementData(); + MOZ_ASSERT(data); + + data->SetCustomElementDefinition(aDefinition); +} diff --git a/dom/base/Element.h b/dom/base/Element.h index e7218ee93..782004703 100644 --- a/dom/base/Element.h +++ b/dom/base/Element.h @@ -413,6 +413,22 @@ public: */ void SetCustomElementData(CustomElementData* aData); + /** + * Gets the custom element definition used by web components custom element. + * + * @return The custom element definition or null if element is not a custom + * element or custom element is not defined yet. + */ + CustomElementDefinition* GetCustomElementDefinition() const; + + /** + * Sets the custom element definition, called when custom element is created + * or upgraded. + * + * @param aDefinition The custom element definition. + */ + void SetCustomElementDefinition(CustomElementDefinition* aDefinition); + protected: /** * Method to get the _intrinsic_ content state of this element. This is the diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp index e341ae315..a851190ff 100644 --- a/dom/base/FragmentOrElement.cpp +++ b/dom/base/FragmentOrElement.cpp @@ -589,6 +589,13 @@ FragmentOrElement::nsDOMSlots::Traverse(nsCycleCollectionTraversalCallback &cb) mExtendedSlots->mCustomElementData->mReactionQueue[i]->Traverse(cb); } } + + if (mExtendedSlots->mCustomElementData->mCustomElementDefinition) { + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, + "mExtendedSlots->mCustomElementData->mCustomElementDefinition"); + cb.NoteNativeChild(mExtendedSlots->mCustomElementData->mCustomElementDefinition, + NS_CYCLE_COLLECTION_PARTICIPANT(CustomElementDefinition)); + } } for (auto iter = mExtendedSlots->mRegisteredIntersectionObservers.Iter(); @@ -625,7 +632,12 @@ FragmentOrElement::nsDOMSlots::Unlink() mExtendedSlots->mContainingShadow = nullptr; MOZ_ASSERT(!(mExtendedSlots->mXBLBinding)); mExtendedSlots->mXBLInsertionParent = nullptr; - mExtendedSlots->mCustomElementData = nullptr; + if (mExtendedSlots->mCustomElementData) { + if (mExtendedSlots->mCustomElementData->mCustomElementDefinition) { + mExtendedSlots->mCustomElementData->mCustomElementDefinition = nullptr; + } + mExtendedSlots->mCustomElementData = nullptr; + } mExtendedSlots->mRegisteredIntersectionObservers.Clear(); nsCOMPtr frameLoader = do_QueryInterface(mExtendedSlots->mFrameLoaderOrOpener); diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 99f922c98..6c97750b9 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -5673,7 +5673,8 @@ nsDocument::CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* } nsCOMPtr typeAtom(NS_Atomize(elemName)); - CustomElementDefinition* definition = registry->mCustomDefinitions.Get(typeAtom); + CustomElementDefinition* definition = + registry->mCustomDefinitions.GetWeak(typeAtom); if (!definition) { return true; } -- cgit v1.2.3