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 #ifndef nsNodeUtils_h___ 8 #define nsNodeUtils_h___ 9 10 #include "mozilla/Maybe.h" 11 #include "nsIContent.h" // for use in inline function (ParentChainChanged) 12 #include "nsIMutationObserver.h" // for use in inline function (ParentChainChanged) 13 #include "js/TypeDecls.h" 14 #include "nsCOMArray.h" 15 16 struct CharacterDataChangeInfo; 17 template <class E> 18 class nsCOMArray; 19 class nsCycleCollectionTraversalCallback; 20 namespace mozilla { 21 struct NonOwningAnimationTarget; 22 class ErrorResult; 23 namespace dom { 24 class Animation; 25 } // namespace dom 26 } // namespace mozilla 27 28 class nsNodeUtils { 29 public: 30 /** 31 * Send CharacterDataWillChange notifications to nsIMutationObservers. 32 * @param aContent Node whose data changed 33 * @param aInfo Struct with information details about the change 34 * @see nsIMutationObserver::CharacterDataWillChange 35 */ 36 static void CharacterDataWillChange(nsIContent* aContent, 37 const CharacterDataChangeInfo&); 38 39 /** 40 * Send CharacterDataChanged notifications to nsIMutationObservers. 41 * @param aContent Node whose data changed 42 * @param aInfo Struct with information details about the change 43 * @see nsIMutationObserver::CharacterDataChanged 44 */ 45 static void CharacterDataChanged(nsIContent* aContent, 46 const CharacterDataChangeInfo&); 47 48 /** 49 * Send AttributeWillChange notifications to nsIMutationObservers. 50 * @param aElement Element whose data will change 51 * @param aNameSpaceID Namespace of changing attribute 52 * @param aAttribute Local-name of changing attribute 53 * @param aModType Type of change (add/change/removal) 54 * @param aNewValue The parsed new value, but only if BeforeSetAttr 55 * preparsed it!!! 56 * @see nsIMutationObserver::AttributeWillChange 57 */ 58 static void AttributeWillChange(mozilla::dom::Element* aElement, 59 int32_t aNameSpaceID, nsAtom* aAttribute, 60 int32_t aModType, 61 const nsAttrValue* aNewValue); 62 63 /** 64 * Send AttributeChanged notifications to nsIMutationObservers. 65 * @param aElement Element whose data changed 66 * @param aNameSpaceID Namespace of changed attribute 67 * @param aAttribute Local-name of changed attribute 68 * @param aModType Type of change (add/change/removal) 69 * @param aOldValue If the old value was StoresOwnData() (or absent), 70 * that value, otherwise null 71 * @see nsIMutationObserver::AttributeChanged 72 */ 73 static void AttributeChanged(mozilla::dom::Element* aElement, 74 int32_t aNameSpaceID, nsAtom* aAttribute, 75 int32_t aModType, const nsAttrValue* aOldValue); 76 77 /** 78 * Send AttributeSetToCurrentValue notifications to nsIMutationObservers. 79 * @param aElement Element whose data changed 80 * @param aNameSpaceID Namespace of the attribute 81 * @param aAttribute Local-name of the attribute 82 * @see nsIMutationObserver::AttributeSetToCurrentValue 83 */ 84 static void AttributeSetToCurrentValue(mozilla::dom::Element* aElement, 85 int32_t aNameSpaceID, 86 nsAtom* aAttribute); 87 88 /** 89 * Send ContentAppended notifications to nsIMutationObservers 90 * @param aContainer Node into which new child/children were added 91 * @param aFirstNewContent First new child 92 * @see nsIMutationObserver::ContentAppended 93 */ 94 static void ContentAppended(nsIContent* aContainer, 95 nsIContent* aFirstNewContent); 96 97 /** 98 * Send NativeAnonymousChildList notifications to nsIMutationObservers 99 * @param aContent Anonymous node that's been added or removed 100 * @param aIsRemove True if it's a removal, false if an addition 101 * @see nsIMutationObserver::NativeAnonymousChildListChange 102 */ 103 static void NativeAnonymousChildListChange(nsIContent* aContent, 104 bool aIsRemove); 105 106 /** 107 * Send ContentInserted notifications to nsIMutationObservers 108 * @param aContainer Node into which new child was inserted 109 * @param aChild Newly inserted child 110 * @see nsIMutationObserver::ContentInserted 111 */ 112 static void ContentInserted(nsINode* aContainer, nsIContent* aChild); 113 /** 114 * Send ContentRemoved notifications to nsIMutationObservers 115 * @param aContainer Node from which child was removed 116 * @param aChild Removed child 117 * @param aPreviousSibling Previous sibling of the removed child 118 * @see nsIMutationObserver::ContentRemoved 119 */ 120 static void ContentRemoved(nsINode* aContainer, nsIContent* aChild, 121 nsIContent* aPreviousSibling); 122 /** 123 * Send ParentChainChanged notifications to nsIMutationObservers 124 * @param aContent The piece of content that had its parent changed. 125 * @see nsIMutationObserver::ParentChainChanged 126 */ ParentChainChanged(nsIContent * aContent)127 static inline void ParentChainChanged(nsIContent* aContent) { 128 nsINode::nsSlots* slots = aContent->GetExistingSlots(); 129 if (slots && !slots->mMutationObservers.IsEmpty()) { 130 NS_OBSERVER_AUTO_ARRAY_NOTIFY_OBSERVERS(slots->mMutationObservers, 131 nsIMutationObserver, 1, 132 ParentChainChanged, (aContent)); 133 } 134 } 135 136 /** 137 * Utility function to get the target (pseudo-)element associated with an 138 * animation. 139 * @param aAnimation The animation whose target is what we want. 140 */ 141 static mozilla::Maybe<mozilla::NonOwningAnimationTarget> 142 GetTargetForAnimation(const mozilla::dom::Animation* aAnimation); 143 144 /** 145 * Notify that an animation is added/changed/removed. 146 * @param aAnimation The animation we added/changed/removed. 147 */ 148 static void AnimationAdded(mozilla::dom::Animation* aAnimation); 149 static void AnimationChanged(mozilla::dom::Animation* aAnimation); 150 static void AnimationRemoved(mozilla::dom::Animation* aAnimation); 151 152 /** 153 * To be called when reference count of aNode drops to zero. 154 * @param aNode The node which is going to be deleted. 155 */ 156 static void LastRelease(nsINode* aNode); 157 158 /** 159 * Clones aNode, its attributes and, if aDeep is true, its descendant nodes 160 * If aNewNodeInfoManager is not null, it is used to create new nodeinfos for 161 * the clones. aNodesWithProperties will be filled with all the nodes that 162 * have properties, and every node in it will be followed by its clone. 163 * 164 * @param aNode Node to clone. 165 * @param aDeep If true the function will be called recursively on 166 * descendants of the node 167 * @param aNewNodeInfoManager The nodeinfo manager to use to create new 168 * nodeinfos for aNode and its attributes and 169 * descendants. May be null if the nodeinfos 170 * shouldn't be changed. 171 * @param aNodesWithProperties All nodes (from amongst aNode and its 172 * descendants) with properties. Every node will 173 * be followed by its clone. Null can be passed to 174 * prevent this from being used. 175 * @param aError The error, if any. 176 * 177 * @return The newly created node. Null in error conditions. 178 */ Clone(nsINode * aNode,bool aDeep,nsNodeInfoManager * aNewNodeInfoManager,nsCOMArray<nsINode> * aNodesWithProperties,mozilla::ErrorResult & aError)179 static already_AddRefed<nsINode> Clone( 180 nsINode* aNode, bool aDeep, nsNodeInfoManager* aNewNodeInfoManager, 181 nsCOMArray<nsINode>* aNodesWithProperties, mozilla::ErrorResult& aError) { 182 return CloneAndAdopt(aNode, true, aDeep, aNewNodeInfoManager, nullptr, 183 aNodesWithProperties, nullptr, aError); 184 } 185 186 /** 187 * Walks aNode, its attributes and descendant nodes. If aNewNodeInfoManager is 188 * not null, it is used to create new nodeinfos for the nodes. Also reparents 189 * the XPConnect wrappers for the nodes into aReparentScope if non-null. 190 * aNodesWithProperties will be filled with all the nodes that have 191 * properties. 192 * 193 * @param aNode Node to adopt. 194 * @param aNewNodeInfoManager The nodeinfo manager to use to create new 195 * nodeinfos for aNode and its attributes and 196 * descendants. May be null if the nodeinfos 197 * shouldn't be changed. 198 * @param aReparentScope New scope for the wrappers, or null if no reparenting 199 * should be done. 200 * @param aNodesWithProperties All nodes (from amongst aNode and its 201 * descendants) with properties. 202 * @param aError The error, if any. 203 */ Adopt(nsINode * aNode,nsNodeInfoManager * aNewNodeInfoManager,JS::Handle<JSObject * > aReparentScope,nsCOMArray<nsINode> & aNodesWithProperties,mozilla::ErrorResult & aError)204 static void Adopt(nsINode* aNode, nsNodeInfoManager* aNewNodeInfoManager, 205 JS::Handle<JSObject*> aReparentScope, 206 nsCOMArray<nsINode>& aNodesWithProperties, 207 mozilla::ErrorResult& aError) { 208 // Just need to store the return value of CloneAndAdopt in a 209 // temporary nsCOMPtr to make sure we release it. 210 nsCOMPtr<nsINode> node = 211 CloneAndAdopt(aNode, false, true, aNewNodeInfoManager, aReparentScope, 212 &aNodesWithProperties, nullptr, aError); 213 214 nsMutationGuard::DidMutate(); 215 } 216 217 /** 218 * Helper for the cycle collector to traverse the DOM UserData for aNode. 219 * 220 * @param aNode the node to traverse UserData for 221 * @param aCb the cycle collection callback 222 */ 223 static void TraverseUserData(nsINode* aNode, 224 nsCycleCollectionTraversalCallback& aCb); 225 226 /** 227 * A basic implementation of the DOM cloneNode method. Calls nsINode::Clone to 228 * do the actual cloning of the node. 229 * 230 * @param aNode the node to clone 231 * @param aDeep if true all descendants will be cloned too 232 * @param aError the error, if any. 233 * 234 * @return the clone, or null if an error occurs. 235 */ 236 static already_AddRefed<nsINode> CloneNodeImpl(nsINode* aNode, bool aDeep, 237 mozilla::ErrorResult& aError); 238 239 /** 240 * Release the UserData for aNode. 241 * 242 * @param aNode the node to release the UserData for 243 */ 244 static void UnlinkUserData(nsINode* aNode); 245 246 /** 247 * Returns a true if the node is a HTMLTemplate element. 248 * 249 * @param aNode a node to test for HTMLTemplate elementness. 250 */ 251 static bool IsTemplateElement(const nsINode* aNode); 252 253 /** 254 * Returns the first child of a node or the first child of 255 * a template element's content if the provided node is a 256 * template element. 257 * 258 * @param aNode A node from which to retrieve the first child. 259 */ 260 static nsIContent* GetFirstChildOfTemplateOrNode(nsINode* aNode); 261 262 private: 263 /** 264 * Walks aNode, its attributes and, if aDeep is true, its descendant nodes. 265 * If aClone is true the nodes will be cloned. If aNewNodeInfoManager is 266 * not null, it is used to create new nodeinfos for the nodes. Also reparents 267 * the XPConnect wrappers for the nodes into aReparentScope if non-null. 268 * aNodesWithProperties will be filled with all the nodes that have 269 * properties. 270 * 271 * @param aNode Node to adopt/clone. 272 * @param aClone If true the node will be cloned and the cloned node will 273 * be returned. 274 * @param aDeep If true the function will be called recursively on 275 * descendants of the node 276 * @param aNewNodeInfoManager The nodeinfo manager to use to create new 277 * nodeinfos for aNode and its attributes and 278 * descendants. May be null if the nodeinfos 279 * shouldn't be changed. 280 * @param aReparentScope Scope into which wrappers should be reparented, or 281 * null if no reparenting should be done. 282 * @param aNodesWithProperties All nodes (from amongst aNode and its 283 * descendants) with properties. If aClone is 284 * true every node will be followed by its 285 * clone. Null can be passed to prevent this from 286 * being populated. 287 * @param aParent If aClone is true the cloned node will be appended to 288 * aParent's children. May be null. If not null then aNode 289 * must be an nsIContent. 290 * @param aError The error, if any. 291 * 292 * @return If aClone is true then the cloned node will be returned, 293 * unless an error occurred. In error conditions, null 294 * will be returned. 295 */ 296 static already_AddRefed<nsINode> CloneAndAdopt( 297 nsINode* aNode, bool aClone, bool aDeep, 298 nsNodeInfoManager* aNewNodeInfoManager, 299 JS::Handle<JSObject*> aReparentScope, 300 nsCOMArray<nsINode>* aNodesWithProperties, nsINode* aParent, 301 mozilla::ErrorResult& aError); 302 303 enum class AnimationMutationType { Added, Changed, Removed }; 304 /** 305 * Notify the observers of the target of an animation 306 * @param aAnimation The mutated animation. 307 * @param aMutationType The mutation type of this animation. It could be 308 * Added, Changed, or Removed. 309 */ 310 static void AnimationMutated(mozilla::dom::Animation* aAnimation, 311 AnimationMutationType aMutatedType); 312 }; 313 314 #endif // nsNodeUtils_h___ 315