diff options
Diffstat (limited to 'dom/base/nsStubMutationObserver.cpp')
-rw-r--r-- | dom/base/nsStubMutationObserver.cpp | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/dom/base/nsStubMutationObserver.cpp b/dom/base/nsStubMutationObserver.cpp new file mode 100644 index 0000000000..fcd8a8fdc5 --- /dev/null +++ b/dom/base/nsStubMutationObserver.cpp @@ -0,0 +1,201 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * nsStubMutationObserver is an implementation of the nsIMutationObserver + * interface (except for the methods on nsISupports) that is intended to be + * used as a base class within the content/layout library. All methods do + * nothing. + */ + +#include "nsStubMutationObserver.h" +#include "mozilla/RefCountType.h" +#include "nsISupports.h" +#include "nsINode.h" + +/****************************************************************************** + * nsStubMutationObserver + *****************************************************************************/ + +NS_IMPL_NSIMUTATIONOBSERVER_CORE_STUB(nsStubMutationObserver) +NS_IMPL_NSIMUTATIONOBSERVER_CONTENT(nsStubMutationObserver) + +/****************************************************************************** + * MutationObserverWrapper + *****************************************************************************/ + +/** + * @brief Wrapper class for a mutation observer that observes multiple nodes. + * + * This wrapper implements all methods of the nsIMutationObserver interface + * and forwards all calls to its owner, which is an instance of + * nsMultiMutationObserver. + * + * This class holds a reference to the owner and AddRefs/Releases its owner + * as well to ensure lifetime. + */ +class MutationObserverWrapper final : public nsIMutationObserver { + public: + NS_DECL_ISUPPORTS + + explicit MutationObserverWrapper(nsMultiMutationObserver* aOwner) + : mOwner(aOwner) {} + + void CharacterDataWillChange(nsIContent* aContent, + const CharacterDataChangeInfo& aInfo) override { + MOZ_ASSERT(mOwner); + mOwner->CharacterDataWillChange(aContent, aInfo); + } + + void CharacterDataChanged(nsIContent* aContent, + const CharacterDataChangeInfo& aInfo) override { + MOZ_ASSERT(mOwner); + mOwner->CharacterDataChanged(aContent, aInfo); + } + + void AttributeWillChange(mozilla::dom::Element* aElement, + int32_t aNameSpaceID, nsAtom* aAttribute, + int32_t aModType) override { + MOZ_ASSERT(mOwner); + mOwner->AttributeWillChange(aElement, aNameSpaceID, aAttribute, aModType); + } + + void AttributeChanged(mozilla::dom::Element* aElement, int32_t aNameSpaceID, + nsAtom* aAttribute, int32_t aModType, + const nsAttrValue* aOldValue) override { + MOZ_ASSERT(mOwner); + mOwner->AttributeChanged(aElement, aNameSpaceID, aAttribute, aModType, + aOldValue); + } + + void AttributeSetToCurrentValue(mozilla::dom::Element* aElement, + int32_t aNameSpaceID, + nsAtom* aAttribute) override { + MOZ_ASSERT(mOwner); + mOwner->AttributeSetToCurrentValue(aElement, aNameSpaceID, aAttribute); + } + + void ContentAppended(nsIContent* aFirstNewContent) override { + MOZ_ASSERT(mOwner); + mOwner->ContentAppended(aFirstNewContent); + } + + void ContentInserted(nsIContent* aChild) override { + MOZ_ASSERT(mOwner); + mOwner->ContentInserted(aChild); + } + + void ContentRemoved(nsIContent* aChild, + nsIContent* aPreviousSibling) override { + MOZ_ASSERT(mOwner); + mOwner->ContentRemoved(aChild, aPreviousSibling); + } + + void NodeWillBeDestroyed(nsINode* aNode) override { + MOZ_ASSERT(mOwner); + AddRefWrapper(); + RefPtr<nsMultiMutationObserver> owner = mOwner; + owner->NodeWillBeDestroyed(aNode); + owner->RemoveMutationObserverFromNode(aNode); + mOwner = nullptr; + ReleaseWrapper(); + } + + void ParentChainChanged(nsIContent* aContent) override { + MOZ_ASSERT(mOwner); + mOwner->ParentChainChanged(aContent); + } + + void ARIAAttributeDefaultWillChange(mozilla::dom::Element* aElement, + nsAtom* aAttribute, + int32_t aModType) override { + MOZ_ASSERT(mOwner); + mOwner->ARIAAttributeDefaultWillChange(aElement, aAttribute, aModType); + } + + void ARIAAttributeDefaultChanged(mozilla::dom::Element* aElement, + nsAtom* aAttribute, + int32_t aModType) override { + MOZ_ASSERT(mOwner); + mOwner->ARIAAttributeDefaultChanged(aElement, aAttribute, aModType); + } + + MozExternalRefCountType AddRefWrapper() { + nsrefcnt count = ++mRefCnt; + NS_LOG_ADDREF(this, count, "MutationObserverWrapper", sizeof(*this)); + return count; + } + + MozExternalRefCountType ReleaseWrapper() { + --mRefCnt; + NS_LOG_RELEASE(this, mRefCnt, "MutationObserverWrapper"); + if (mRefCnt == 0) { + mRefCnt = 1; + delete this; + return MozExternalRefCountType(0); + } + return mRefCnt; + } + + private: + ~MutationObserverWrapper() = default; + nsMultiMutationObserver* mOwner{nullptr}; +}; + +NS_IMPL_QUERY_INTERFACE(MutationObserverWrapper, nsIMutationObserver); + +MozExternalRefCountType MutationObserverWrapper::AddRef() { + MOZ_ASSERT(mOwner); + AddRefWrapper(); + mOwner->AddRef(); + return mRefCnt; +} + +MozExternalRefCountType MutationObserverWrapper::Release() { + MOZ_ASSERT(mOwner); + mOwner->Release(); + return ReleaseWrapper(); +} + +/****************************************************************************** + * nsMultiMutationObserver + *****************************************************************************/ + +void nsMultiMutationObserver::AddMutationObserverToNode(nsINode* aNode) { + if (!aNode) { + return; + } + if (mWrapperForNode.Contains(aNode)) { + return; + } + auto* newWrapper = new MutationObserverWrapper{this}; + newWrapper->AddRefWrapper(); + mWrapperForNode.InsertOrUpdate(aNode, newWrapper); + aNode->AddMutationObserver(newWrapper); +} + +void nsMultiMutationObserver::RemoveMutationObserverFromNode(nsINode* aNode) { + if (!aNode) { + return; + } + + if (auto obs = mWrapperForNode.MaybeGet(aNode); obs.isSome()) { + aNode->RemoveMutationObserver(*obs); + mWrapperForNode.Remove(aNode); + (*obs)->ReleaseWrapper(); + } +} + +bool nsMultiMutationObserver::ContainsNode(const nsINode* aNode) const { + return mWrapperForNode.Contains(const_cast<nsINode*>(aNode)); +} + +/****************************************************************************** + * nsStubMultiMutationObserver + *****************************************************************************/ + +NS_IMPL_NSIMUTATIONOBSERVER_CORE_STUB(nsStubMultiMutationObserver) +NS_IMPL_NSIMUTATIONOBSERVER_CONTENT(nsStubMultiMutationObserver) |