nsStubMutationObserver.cpp (6879B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* 8 * nsStubMutationObserver is an implementation of the nsIMutationObserver 9 * interface (except for the methods on nsISupports) that is intended to be 10 * used as a base class within the content/layout library. All methods do 11 * nothing. 12 */ 13 14 #include "nsStubMutationObserver.h" 15 16 #include "mozilla/RefCountType.h" 17 #include "nsINode.h" 18 #include "nsISupports.h" 19 20 /****************************************************************************** 21 * nsStubMutationObserver 22 *****************************************************************************/ 23 24 NS_IMPL_NSIMUTATIONOBSERVER_CORE_STUB(nsStubMutationObserver) 25 NS_IMPL_NSIMUTATIONOBSERVER_CONTENT(nsStubMutationObserver) 26 27 /****************************************************************************** 28 * MutationObserverWrapper 29 *****************************************************************************/ 30 31 /** 32 * @brief Wrapper class for a mutation observer that observes multiple nodes. 33 * 34 * This wrapper implements all methods of the nsIMutationObserver interface 35 * and forwards all calls to its owner, which is an instance of 36 * nsMultiMutationObserver. 37 * 38 * This class holds a reference to the owner and AddRefs/Releases its owner 39 * as well to ensure lifetime. 40 */ 41 class MutationObserverWrapper final : public nsIMutationObserver { 42 public: 43 NS_DECL_ISUPPORTS 44 45 explicit MutationObserverWrapper(nsMultiMutationObserver* aOwner) 46 : mOwner(aOwner) {} 47 48 void CharacterDataWillChange(nsIContent* aContent, 49 const CharacterDataChangeInfo& aInfo) override { 50 MOZ_ASSERT(mOwner); 51 mOwner->CharacterDataWillChange(aContent, aInfo); 52 } 53 54 void CharacterDataChanged(nsIContent* aContent, 55 const CharacterDataChangeInfo& aInfo) override { 56 MOZ_ASSERT(mOwner); 57 mOwner->CharacterDataChanged(aContent, aInfo); 58 } 59 60 void AttributeWillChange(mozilla::dom::Element* aElement, 61 int32_t aNameSpaceID, nsAtom* aAttribute, 62 AttrModType aModType) override { 63 MOZ_ASSERT(mOwner); 64 mOwner->AttributeWillChange(aElement, aNameSpaceID, aAttribute, aModType); 65 } 66 67 void AttributeChanged(mozilla::dom::Element* aElement, int32_t aNameSpaceID, 68 nsAtom* aAttribute, AttrModType aModType, 69 const nsAttrValue* aOldValue) override { 70 MOZ_ASSERT(mOwner); 71 mOwner->AttributeChanged(aElement, aNameSpaceID, aAttribute, aModType, 72 aOldValue); 73 } 74 75 void AttributeSetToCurrentValue(mozilla::dom::Element* aElement, 76 int32_t aNameSpaceID, 77 nsAtom* aAttribute) override { 78 MOZ_ASSERT(mOwner); 79 mOwner->AttributeSetToCurrentValue(aElement, aNameSpaceID, aAttribute); 80 } 81 82 void ContentAppended(nsIContent* aFirstNewContent, 83 const ContentAppendInfo& aInfo) override { 84 MOZ_ASSERT(mOwner); 85 mOwner->ContentAppended(aFirstNewContent, aInfo); 86 } 87 88 void ContentInserted(nsIContent* aChild, 89 const ContentInsertInfo& aInfo) override { 90 MOZ_ASSERT(mOwner); 91 mOwner->ContentInserted(aChild, aInfo); 92 } 93 94 void ContentWillBeRemoved(nsIContent* aChild, 95 const ContentRemoveInfo& aInfo) override { 96 MOZ_ASSERT(mOwner); 97 mOwner->ContentWillBeRemoved(aChild, aInfo); 98 } 99 100 void NodeWillBeDestroyed(nsINode* aNode) override { 101 MOZ_ASSERT(mOwner); 102 AddRefWrapper(); 103 RefPtr<nsMultiMutationObserver> owner = mOwner; 104 owner->NodeWillBeDestroyed(aNode); 105 owner->RemoveMutationObserverFromNode(aNode); 106 mOwner = nullptr; 107 ReleaseWrapper(); 108 } 109 110 void ParentChainChanged(nsIContent* aContent) override { 111 MOZ_ASSERT(mOwner); 112 mOwner->ParentChainChanged(aContent); 113 } 114 115 void ARIAAttributeDefaultWillChange(mozilla::dom::Element* aElement, 116 nsAtom* aAttribute, 117 AttrModType aModType) override { 118 MOZ_ASSERT(mOwner); 119 mOwner->ARIAAttributeDefaultWillChange(aElement, aAttribute, aModType); 120 } 121 122 void ARIAAttributeDefaultChanged(mozilla::dom::Element* aElement, 123 nsAtom* aAttribute, 124 AttrModType aModType) override { 125 MOZ_ASSERT(mOwner); 126 mOwner->ARIAAttributeDefaultChanged(aElement, aAttribute, aModType); 127 } 128 129 MozExternalRefCountType AddRefWrapper() { 130 nsrefcnt count = ++mRefCnt; 131 NS_LOG_ADDREF(this, count, "MutationObserverWrapper", sizeof(*this)); 132 return count; 133 } 134 135 MozExternalRefCountType ReleaseWrapper() { 136 --mRefCnt; 137 NS_LOG_RELEASE(this, mRefCnt, "MutationObserverWrapper"); 138 if (mRefCnt == 0) { 139 mRefCnt = 1; 140 delete this; 141 return MozExternalRefCountType(0); 142 } 143 return mRefCnt; 144 } 145 146 private: 147 ~MutationObserverWrapper() = default; 148 nsMultiMutationObserver* mOwner{nullptr}; 149 }; 150 151 NS_IMPL_QUERY_INTERFACE(MutationObserverWrapper, nsIMutationObserver); 152 153 MozExternalRefCountType MutationObserverWrapper::AddRef() { 154 MOZ_ASSERT(mOwner); 155 AddRefWrapper(); 156 mOwner->AddRef(); 157 return mRefCnt; 158 } 159 160 MozExternalRefCountType MutationObserverWrapper::Release() { 161 MOZ_ASSERT(mOwner); 162 mOwner->Release(); 163 return ReleaseWrapper(); 164 } 165 166 /****************************************************************************** 167 * nsMultiMutationObserver 168 *****************************************************************************/ 169 170 void nsMultiMutationObserver::AddMutationObserverToNode(nsINode* aNode) { 171 if (!aNode) { 172 return; 173 } 174 if (mWrapperForNode.Contains(aNode)) { 175 return; 176 } 177 auto* newWrapper = new MutationObserverWrapper{this}; 178 newWrapper->AddRefWrapper(); 179 mWrapperForNode.InsertOrUpdate(aNode, newWrapper); 180 aNode->AddMutationObserver(newWrapper); 181 } 182 183 void nsMultiMutationObserver::RemoveMutationObserverFromNode(nsINode* aNode) { 184 if (!aNode) { 185 return; 186 } 187 188 if (auto obs = mWrapperForNode.MaybeGet(aNode); obs.isSome()) { 189 aNode->RemoveMutationObserver(*obs); 190 mWrapperForNode.Remove(aNode); 191 (*obs)->ReleaseWrapper(); 192 } 193 } 194 195 bool nsMultiMutationObserver::ContainsNode(const nsINode* aNode) const { 196 return mWrapperForNode.Contains(const_cast<nsINode*>(aNode)); 197 } 198 199 /****************************************************************************** 200 * nsStubMultiMutationObserver 201 *****************************************************************************/ 202 203 NS_IMPL_NSIMUTATIONOBSERVER_CORE_STUB(nsStubMultiMutationObserver) 204 NS_IMPL_NSIMUTATIONOBSERVER_CONTENT(nsStubMultiMutationObserver)