michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef nsNodeUtils_h___ michael@0: #define nsNodeUtils_h___ michael@0: michael@0: #include "nsIContent.h" // for use in inline function (ParentChainChanged) michael@0: #include "nsIMutationObserver.h" // for use in inline function (ParentChainChanged) michael@0: #include "js/TypeDecls.h" michael@0: #include "nsCOMArray.h" michael@0: michael@0: struct CharacterDataChangeInfo; michael@0: class nsIVariant; michael@0: class nsIDOMNode; michael@0: class nsIDOMUserDataHandler; michael@0: template class nsCOMArray; michael@0: class nsCycleCollectionTraversalCallback; michael@0: michael@0: class nsNodeUtils michael@0: { michael@0: public: michael@0: /** michael@0: * Send CharacterDataWillChange notifications to nsIMutationObservers. michael@0: * @param aContent Node whose data changed michael@0: * @param aInfo Struct with information details about the change michael@0: * @see nsIMutationObserver::CharacterDataWillChange michael@0: */ michael@0: static void CharacterDataWillChange(nsIContent* aContent, michael@0: CharacterDataChangeInfo* aInfo); michael@0: michael@0: /** michael@0: * Send CharacterDataChanged notifications to nsIMutationObservers. michael@0: * @param aContent Node whose data changed michael@0: * @param aInfo Struct with information details about the change michael@0: * @see nsIMutationObserver::CharacterDataChanged michael@0: */ michael@0: static void CharacterDataChanged(nsIContent* aContent, michael@0: CharacterDataChangeInfo* aInfo); michael@0: michael@0: /** michael@0: * Send AttributeWillChange notifications to nsIMutationObservers. michael@0: * @param aElement Element whose data will change michael@0: * @param aNameSpaceID Namespace of changing attribute michael@0: * @param aAttribute Local-name of changing attribute michael@0: * @param aModType Type of change (add/change/removal) michael@0: * @see nsIMutationObserver::AttributeWillChange michael@0: */ michael@0: static void AttributeWillChange(mozilla::dom::Element* aElement, michael@0: int32_t aNameSpaceID, michael@0: nsIAtom* aAttribute, michael@0: int32_t aModType); michael@0: michael@0: /** michael@0: * Send AttributeChanged notifications to nsIMutationObservers. michael@0: * @param aElement Element whose data changed michael@0: * @param aNameSpaceID Namespace of changed attribute michael@0: * @param aAttribute Local-name of changed attribute michael@0: * @param aModType Type of change (add/change/removal) michael@0: * @see nsIMutationObserver::AttributeChanged michael@0: */ michael@0: static void AttributeChanged(mozilla::dom::Element* aElement, michael@0: int32_t aNameSpaceID, michael@0: nsIAtom* aAttribute, michael@0: int32_t aModType); michael@0: /** michael@0: * Send AttributeSetToCurrentValue notifications to nsIMutationObservers. michael@0: * @param aElement Element whose data changed michael@0: * @param aNameSpaceID Namespace of the attribute michael@0: * @param aAttribute Local-name of the attribute michael@0: * @see nsIMutationObserver::AttributeSetToCurrentValue michael@0: */ michael@0: static void AttributeSetToCurrentValue(mozilla::dom::Element* aElement, michael@0: int32_t aNameSpaceID, michael@0: nsIAtom* aAttribute); michael@0: michael@0: /** michael@0: * Send ContentAppended notifications to nsIMutationObservers michael@0: * @param aContainer Node into which new child/children were added michael@0: * @param aFirstNewContent First new child michael@0: * @param aNewIndexInContainer Index of first new child michael@0: * @see nsIMutationObserver::ContentAppended michael@0: */ michael@0: static void ContentAppended(nsIContent* aContainer, michael@0: nsIContent* aFirstNewContent, michael@0: int32_t aNewIndexInContainer); michael@0: michael@0: /** michael@0: * Send ContentInserted notifications to nsIMutationObservers michael@0: * @param aContainer Node into which new child was inserted michael@0: * @param aChild Newly inserted child michael@0: * @param aIndexInContainer Index of new child michael@0: * @see nsIMutationObserver::ContentInserted michael@0: */ michael@0: static void ContentInserted(nsINode* aContainer, michael@0: nsIContent* aChild, michael@0: int32_t aIndexInContainer); michael@0: /** michael@0: * Send ContentRemoved notifications to nsIMutationObservers michael@0: * @param aContainer Node from which child was removed michael@0: * @param aChild Removed child michael@0: * @param aIndexInContainer Index of removed child michael@0: * @see nsIMutationObserver::ContentRemoved michael@0: */ michael@0: static void ContentRemoved(nsINode* aContainer, michael@0: nsIContent* aChild, michael@0: int32_t aIndexInContainer, michael@0: nsIContent* aPreviousSibling); michael@0: /** michael@0: * Send ParentChainChanged notifications to nsIMutationObservers michael@0: * @param aContent The piece of content that had its parent changed. michael@0: * @see nsIMutationObserver::ParentChainChanged michael@0: */ michael@0: static inline void ParentChainChanged(nsIContent *aContent) michael@0: { michael@0: nsINode::nsSlots* slots = aContent->GetExistingSlots(); michael@0: if (slots && !slots->mMutationObservers.IsEmpty()) { michael@0: NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(slots->mMutationObservers, michael@0: nsIMutationObserver, michael@0: ParentChainChanged, michael@0: (aContent)); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * To be called when reference count of aNode drops to zero. michael@0: * @param aNode The node which is going to be deleted. michael@0: */ michael@0: static void LastRelease(nsINode* aNode); michael@0: michael@0: /** michael@0: * Clones aNode, its attributes and, if aDeep is true, its descendant nodes michael@0: * If aNewNodeInfoManager is not null, it is used to create new nodeinfos for michael@0: * the clones. aNodesWithProperties will be filled with all the nodes that michael@0: * have properties, and every node in it will be followed by its clone. michael@0: * michael@0: * @param aNode Node to clone. michael@0: * @param aDeep If true the function will be called recursively on michael@0: * descendants of the node michael@0: * @param aNewNodeInfoManager The nodeinfo manager to use to create new michael@0: * nodeinfos for aNode and its attributes and michael@0: * descendants. May be null if the nodeinfos michael@0: * shouldn't be changed. michael@0: * @param aNodesWithProperties All nodes (from amongst aNode and its michael@0: * descendants) with properties. Every node will michael@0: * be followed by its clone. michael@0: * @param aResult *aResult will contain the cloned node. michael@0: */ michael@0: static nsresult Clone(nsINode *aNode, bool aDeep, michael@0: nsNodeInfoManager *aNewNodeInfoManager, michael@0: nsCOMArray &aNodesWithProperties, michael@0: nsINode **aResult) michael@0: { michael@0: return CloneAndAdopt(aNode, true, aDeep, aNewNodeInfoManager, michael@0: JS::NullPtr(), aNodesWithProperties, nullptr, aResult); michael@0: } michael@0: michael@0: /** michael@0: * Clones aNode, its attributes and, if aDeep is true, its descendant nodes michael@0: */ michael@0: static nsresult Clone(nsINode *aNode, bool aDeep, nsINode **aResult) michael@0: { michael@0: nsCOMArray dummyNodeWithProperties; michael@0: return CloneAndAdopt(aNode, true, aDeep, nullptr, JS::NullPtr(), michael@0: dummyNodeWithProperties, aNode->GetParent(), aResult); michael@0: } michael@0: michael@0: /** michael@0: * Walks aNode, its attributes and descendant nodes. If aNewNodeInfoManager is michael@0: * not null, it is used to create new nodeinfos for the nodes. Also reparents michael@0: * the XPConnect wrappers for the nodes into aReparentScope if non-null. michael@0: * aNodesWithProperties will be filled with all the nodes that have michael@0: * properties. michael@0: * michael@0: * @param aNode Node to adopt. michael@0: * @param aNewNodeInfoManager The nodeinfo manager to use to create new michael@0: * nodeinfos for aNode and its attributes and michael@0: * descendants. May be null if the nodeinfos michael@0: * shouldn't be changed. michael@0: * @param aReparentScope New scope for the wrappers, or null if no reparenting michael@0: * should be done. michael@0: * @param aNodesWithProperties All nodes (from amongst aNode and its michael@0: * descendants) with properties. michael@0: */ michael@0: static nsresult Adopt(nsINode *aNode, nsNodeInfoManager *aNewNodeInfoManager, michael@0: JS::Handle aReparentScope, michael@0: nsCOMArray &aNodesWithProperties) michael@0: { michael@0: nsCOMPtr node; michael@0: nsresult rv = CloneAndAdopt(aNode, false, true, aNewNodeInfoManager, michael@0: aReparentScope, aNodesWithProperties, michael@0: nullptr, getter_AddRefs(node)); michael@0: michael@0: nsMutationGuard::DidMutate(); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: /** michael@0: * Call registered userdata handlers for operation aOperation for the nodes in michael@0: * aNodesWithProperties. If aCloned is true aNodesWithProperties should michael@0: * contain both the original and the cloned nodes (and only the userdata michael@0: * handlers registered for the original nodes will be called). michael@0: * michael@0: * @param aNodesWithProperties Contains the nodes that might have properties michael@0: * registered on them. If aCloned is true every michael@0: * one of those nodes should be immediately michael@0: * followed in the array by the cloned node. michael@0: * @param aOwnerDocument The ownerDocument of the original nodes. michael@0: * @param aOperation The operation to call a userdata handler for. michael@0: * @param aCloned If true aNodesWithProperties will contain both original michael@0: * and cloned nodes. michael@0: */ michael@0: static nsresult CallUserDataHandlers(nsCOMArray &aNodesWithProperties, michael@0: nsIDocument *aOwnerDocument, michael@0: uint16_t aOperation, bool aCloned); michael@0: michael@0: /** michael@0: * Helper for the cycle collector to traverse the DOM UserData and michael@0: * UserDataHandlers for aNode. michael@0: * michael@0: * @param aNode the node to traverse UserData and UserDataHandlers for michael@0: * @param aCb the cycle collection callback michael@0: */ michael@0: static void TraverseUserData(nsINode* aNode, michael@0: nsCycleCollectionTraversalCallback &aCb); michael@0: michael@0: /** michael@0: * A basic implementation of the DOM cloneNode method. Calls nsINode::Clone to michael@0: * do the actual cloning of the node. michael@0: * michael@0: * @param aNode the node to clone michael@0: * @param aDeep if true all descendants will be cloned too michael@0: * @param aCallUserDataHandlers if true, user data handlers will be called michael@0: * @param aResult the clone michael@0: */ michael@0: static nsresult CloneNodeImpl(nsINode *aNode, bool aDeep, michael@0: bool aCallUserDataHandlers, michael@0: nsINode **aResult); michael@0: michael@0: /** michael@0: * Release the UserData and UserDataHandlers for aNode. michael@0: * michael@0: * @param aNode the node to release the UserData and UserDataHandlers for michael@0: */ michael@0: static void UnlinkUserData(nsINode *aNode); michael@0: michael@0: /** michael@0: * Returns a true if the node is a HTMLTemplate element. michael@0: * michael@0: * @param aNode a node to test for HTMLTemplate elementness. michael@0: */ michael@0: static bool IsTemplateElement(const nsINode *aNode); michael@0: michael@0: /** michael@0: * Returns the first child of a node or the first child of michael@0: * a template element's content if the provided node is a michael@0: * template element. michael@0: * michael@0: * @param aNode A node from which to retrieve the first child. michael@0: */ michael@0: static nsIContent* GetFirstChildOfTemplateOrNode(nsINode* aNode); michael@0: michael@0: private: michael@0: /** michael@0: * Walks aNode, its attributes and, if aDeep is true, its descendant nodes. michael@0: * If aClone is true the nodes will be cloned. If aNewNodeInfoManager is michael@0: * not null, it is used to create new nodeinfos for the nodes. Also reparents michael@0: * the XPConnect wrappers for the nodes into aReparentScope if non-null. michael@0: * aNodesWithProperties will be filled with all the nodes that have michael@0: * properties. michael@0: * michael@0: * @param aNode Node to adopt/clone. michael@0: * @param aClone If true the node will be cloned and the cloned node will michael@0: * be in aResult. michael@0: * @param aDeep If true the function will be called recursively on michael@0: * descendants of the node michael@0: * @param aNewNodeInfoManager The nodeinfo manager to use to create new michael@0: * nodeinfos for aNode and its attributes and michael@0: * descendants. May be null if the nodeinfos michael@0: * shouldn't be changed. michael@0: * @param aReparentScope Scope into which wrappers should be reparented, or michael@0: * null if no reparenting should be done. michael@0: * @param aNodesWithProperties All nodes (from amongst aNode and its michael@0: * descendants) with properties. If aClone is michael@0: * true every node will be followed by its michael@0: * clone. michael@0: * @param aParent If aClone is true the cloned node will be appended to michael@0: * aParent's children. May be null. If not null then aNode michael@0: * must be an nsIContent. michael@0: * @param aResult If aClone is true then *aResult will contain the cloned michael@0: * node. michael@0: */ michael@0: static nsresult CloneAndAdopt(nsINode *aNode, bool aClone, bool aDeep, michael@0: nsNodeInfoManager *aNewNodeInfoManager, michael@0: JS::Handle aReparentScope, michael@0: nsCOMArray &aNodesWithProperties, michael@0: nsINode *aParent, nsINode **aResult); michael@0: }; michael@0: michael@0: #endif // nsNodeUtils_h___