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: /* michael@0: * Base class for all element classes as well as nsDocumentFragment. This michael@0: * provides an implementation of nsIDOMNode, implements nsIContent, provides michael@0: * utility methods for subclasses, and so forth. michael@0: */ michael@0: michael@0: #ifndef FragmentOrElement_h___ michael@0: #define FragmentOrElement_h___ michael@0: michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/MemoryReporting.h" michael@0: #include "nsAttrAndChildArray.h" // member michael@0: #include "nsCycleCollectionParticipant.h" // NS_DECL_CYCLE_* michael@0: #include "nsIContent.h" // base class michael@0: #include "nsIDOMXPathNSResolver.h" // base class michael@0: #include "nsINodeList.h" // base class michael@0: #include "nsIWeakReference.h" // base class michael@0: #include "nsNodeUtils.h" // class member nsNodeUtils::CloneNodeImpl michael@0: #include "nsIHTMLCollection.h" michael@0: michael@0: class ContentUnbinder; michael@0: class nsContentList; michael@0: class nsDOMAttributeMap; michael@0: class nsDOMTokenList; michael@0: class nsIControllers; michael@0: class nsICSSDeclaration; michael@0: class nsIDocument; michael@0: class nsDOMStringMap; michael@0: class nsINodeInfo; michael@0: class nsIURI; michael@0: michael@0: /** michael@0: * Class that implements the nsIDOMNodeList interface (a list of children of michael@0: * the content), by holding a reference to the content and delegating GetLength michael@0: * and Item to its existing child list. michael@0: * @see nsIDOMNodeList michael@0: */ michael@0: class nsChildContentList MOZ_FINAL : public nsINodeList michael@0: { michael@0: public: michael@0: nsChildContentList(nsINode* aNode) michael@0: : mNode(aNode) michael@0: { michael@0: SetIsDOMBinding(); michael@0: } michael@0: michael@0: NS_DECL_CYCLE_COLLECTING_ISUPPORTS michael@0: NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(nsChildContentList) michael@0: michael@0: // nsWrapperCache michael@0: virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE; michael@0: michael@0: // nsIDOMNodeList interface michael@0: NS_DECL_NSIDOMNODELIST michael@0: michael@0: // nsINodeList interface michael@0: virtual int32_t IndexOf(nsIContent* aContent) MOZ_OVERRIDE; michael@0: virtual nsIContent* Item(uint32_t aIndex) MOZ_OVERRIDE; michael@0: michael@0: void DropReference() michael@0: { michael@0: mNode = nullptr; michael@0: } michael@0: michael@0: virtual nsINode* GetParentObject() MOZ_OVERRIDE michael@0: { michael@0: return mNode; michael@0: } michael@0: michael@0: private: michael@0: // The node whose children make up the list (weak reference) michael@0: nsINode* mNode; michael@0: }; michael@0: michael@0: /** michael@0: * A tearoff class for FragmentOrElement to implement additional interfaces michael@0: */ michael@0: class nsNode3Tearoff : public nsIDOMXPathNSResolver michael@0: { michael@0: public: michael@0: NS_DECL_CYCLE_COLLECTING_ISUPPORTS michael@0: michael@0: NS_DECL_CYCLE_COLLECTION_CLASS(nsNode3Tearoff) michael@0: michael@0: NS_DECL_NSIDOMXPATHNSRESOLVER michael@0: michael@0: nsNode3Tearoff(nsINode *aNode) : mNode(aNode) michael@0: { michael@0: } michael@0: michael@0: protected: michael@0: virtual ~nsNode3Tearoff() {} michael@0: michael@0: private: michael@0: nsCOMPtr mNode; michael@0: }; michael@0: michael@0: /** michael@0: * A class that implements nsIWeakReference michael@0: */ michael@0: michael@0: class nsNodeWeakReference MOZ_FINAL : public nsIWeakReference michael@0: { michael@0: public: michael@0: nsNodeWeakReference(nsINode* aNode) michael@0: : mNode(aNode) michael@0: { michael@0: } michael@0: michael@0: ~nsNodeWeakReference(); michael@0: michael@0: // nsISupports michael@0: NS_DECL_ISUPPORTS michael@0: michael@0: // nsIWeakReference michael@0: NS_DECL_NSIWEAKREFERENCE michael@0: michael@0: void NoticeNodeDestruction() michael@0: { michael@0: mNode = nullptr; michael@0: } michael@0: michael@0: private: michael@0: nsINode* mNode; michael@0: }; michael@0: michael@0: /** michael@0: * Tearoff to use for nodes to implement nsISupportsWeakReference michael@0: */ michael@0: class nsNodeSupportsWeakRefTearoff MOZ_FINAL : public nsISupportsWeakReference michael@0: { michael@0: public: michael@0: nsNodeSupportsWeakRefTearoff(nsINode* aNode) michael@0: : mNode(aNode) michael@0: { michael@0: } michael@0: michael@0: // nsISupports michael@0: NS_DECL_CYCLE_COLLECTING_ISUPPORTS michael@0: michael@0: // nsISupportsWeakReference michael@0: NS_DECL_NSISUPPORTSWEAKREFERENCE michael@0: michael@0: NS_DECL_CYCLE_COLLECTION_CLASS(nsNodeSupportsWeakRefTearoff) michael@0: michael@0: private: michael@0: nsCOMPtr mNode; michael@0: }; michael@0: michael@0: /** michael@0: * A generic base class for DOM elements, implementing many nsIContent, michael@0: * nsIDOMNode and nsIDOMElement methods. michael@0: */ michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: class ShadowRoot; michael@0: class UndoManager; michael@0: michael@0: class FragmentOrElement : public nsIContent michael@0: { michael@0: public: michael@0: FragmentOrElement(already_AddRefed& aNodeInfo); michael@0: FragmentOrElement(already_AddRefed&& aNodeInfo); michael@0: virtual ~FragmentOrElement(); michael@0: michael@0: NS_DECL_CYCLE_COLLECTING_ISUPPORTS michael@0: michael@0: NS_DECL_SIZEOF_EXCLUDING_THIS michael@0: michael@0: // nsINode interface methods michael@0: virtual uint32_t GetChildCount() const MOZ_OVERRIDE; michael@0: virtual nsIContent *GetChildAt(uint32_t aIndex) const MOZ_OVERRIDE; michael@0: virtual nsIContent * const * GetChildArray(uint32_t* aChildCount) const MOZ_OVERRIDE; michael@0: virtual int32_t IndexOf(const nsINode* aPossibleChild) const MOZ_OVERRIDE; michael@0: virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex, michael@0: bool aNotify) MOZ_OVERRIDE; michael@0: virtual void RemoveChildAt(uint32_t aIndex, bool aNotify) MOZ_OVERRIDE; michael@0: virtual void GetTextContentInternal(nsAString& aTextContent) MOZ_OVERRIDE; michael@0: virtual void SetTextContentInternal(const nsAString& aTextContent, michael@0: mozilla::ErrorResult& aError) MOZ_OVERRIDE; michael@0: michael@0: // nsIContent interface methods michael@0: virtual already_AddRefed GetChildren(uint32_t aFilter) MOZ_OVERRIDE; michael@0: virtual const nsTextFragment *GetText() MOZ_OVERRIDE; michael@0: virtual uint32_t TextLength() const MOZ_OVERRIDE; michael@0: virtual nsresult SetText(const char16_t* aBuffer, uint32_t aLength, michael@0: bool aNotify) MOZ_OVERRIDE; michael@0: // Need to implement this here too to avoid hiding. michael@0: nsresult SetText(const nsAString& aStr, bool aNotify) michael@0: { michael@0: return SetText(aStr.BeginReading(), aStr.Length(), aNotify); michael@0: } michael@0: virtual nsresult AppendText(const char16_t* aBuffer, uint32_t aLength, michael@0: bool aNotify) MOZ_OVERRIDE; michael@0: virtual bool TextIsOnlyWhitespace() MOZ_OVERRIDE; michael@0: virtual bool HasTextForTranslation() MOZ_OVERRIDE; michael@0: virtual void AppendTextTo(nsAString& aResult) MOZ_OVERRIDE; michael@0: virtual bool AppendTextTo(nsAString& aResult, michael@0: const mozilla::fallible_t&) MOZ_OVERRIDE NS_WARN_UNUSED_RESULT; michael@0: virtual nsIContent *GetBindingParent() const MOZ_OVERRIDE; michael@0: virtual nsXBLBinding *GetXBLBinding() const MOZ_OVERRIDE; michael@0: virtual void SetXBLBinding(nsXBLBinding* aBinding, michael@0: nsBindingManager* aOldBindingManager = nullptr) MOZ_OVERRIDE; michael@0: virtual ShadowRoot *GetShadowRoot() const MOZ_OVERRIDE; michael@0: virtual ShadowRoot *GetContainingShadow() const MOZ_OVERRIDE; michael@0: virtual void SetShadowRoot(ShadowRoot* aBinding) MOZ_OVERRIDE; michael@0: virtual nsIContent *GetXBLInsertionParent() const MOZ_OVERRIDE; michael@0: virtual void SetXBLInsertionParent(nsIContent* aContent) MOZ_OVERRIDE; michael@0: virtual bool IsLink(nsIURI** aURI) const MOZ_OVERRIDE; michael@0: michael@0: virtual CustomElementData *GetCustomElementData() const MOZ_OVERRIDE; michael@0: virtual void SetCustomElementData(CustomElementData* aData) MOZ_OVERRIDE; michael@0: michael@0: virtual void DestroyContent() MOZ_OVERRIDE; michael@0: virtual void SaveSubtreeState() MOZ_OVERRIDE; michael@0: michael@0: virtual const nsAttrValue* DoGetClasses() const MOZ_OVERRIDE; michael@0: NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) MOZ_OVERRIDE; michael@0: michael@0: nsIHTMLCollection* Children(); michael@0: uint32_t ChildElementCount() michael@0: { michael@0: return Children()->Length(); michael@0: } michael@0: michael@0: public: michael@0: /** michael@0: * If there are listeners for DOMNodeInserted event, fires the event on all michael@0: * aNodes michael@0: */ michael@0: static void FireNodeInserted(nsIDocument* aDoc, michael@0: nsINode* aParent, michael@0: nsTArray >& aNodes); michael@0: michael@0: NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(FragmentOrElement) michael@0: michael@0: /** michael@0: * Fire a DOMNodeRemoved mutation event for all children of this node michael@0: */ michael@0: void FireNodeRemovedForChildren(); michael@0: michael@0: virtual bool OwnedOnlyByTheDOMTree() MOZ_OVERRIDE michael@0: { michael@0: uint32_t rc = mRefCnt.get(); michael@0: if (GetParent()) { michael@0: --rc; michael@0: } michael@0: rc -= mAttrsAndChildren.ChildCount(); michael@0: return rc == 0; michael@0: } michael@0: michael@0: virtual bool IsPurple() MOZ_OVERRIDE michael@0: { michael@0: return mRefCnt.IsPurple(); michael@0: } michael@0: michael@0: virtual void RemovePurple() MOZ_OVERRIDE michael@0: { michael@0: mRefCnt.RemovePurple(); michael@0: } michael@0: michael@0: static void ClearContentUnbinder(); michael@0: static bool CanSkip(nsINode* aNode, bool aRemovingAllowed); michael@0: static bool CanSkipInCC(nsINode* aNode); michael@0: static bool CanSkipThis(nsINode* aNode); michael@0: static void RemoveBlackMarkedNode(nsINode* aNode); michael@0: static void MarkNodeChildren(nsINode* aNode); michael@0: static void InitCCCallbacks(); michael@0: static void MarkUserData(void* aObject, nsIAtom* aKey, void* aChild, michael@0: void *aData); michael@0: static void MarkUserDataHandler(void* aObject, nsIAtom* aKey, void* aChild, michael@0: void* aData); michael@0: michael@0: protected: michael@0: /** michael@0: * Copy attributes and state to another element michael@0: * @param aDest the object to copy to michael@0: */ michael@0: nsresult CopyInnerTo(FragmentOrElement* aDest); michael@0: michael@0: public: michael@0: // Because of a bug in MS C++ compiler nsDOMSlots must be declared public, michael@0: // otherwise nsXULElement::nsXULSlots doesn't compile. michael@0: /** michael@0: * There are a set of DOM- and scripting-specific instance variables michael@0: * that may only be instantiated when a content object is accessed michael@0: * through the DOM. Rather than burn actual slots in the content michael@0: * objects for each of these instance variables, we put them off michael@0: * in a side structure that's only allocated when the content is michael@0: * accessed through the DOM. michael@0: */ michael@0: class nsDOMSlots : public nsINode::nsSlots michael@0: { michael@0: public: michael@0: nsDOMSlots(); michael@0: virtual ~nsDOMSlots(); michael@0: michael@0: void Traverse(nsCycleCollectionTraversalCallback &cb, bool aIsXUL); michael@0: void Unlink(bool aIsXUL); michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: /** michael@0: * The .style attribute (an interface that forwards to the actual michael@0: * style rules) michael@0: * @see nsGenericHTMLElement::GetStyle michael@0: */ michael@0: nsCOMPtr mStyle; michael@0: michael@0: /** michael@0: * The .dataset attribute. michael@0: * @see nsGenericHTMLElement::GetDataset michael@0: */ michael@0: nsDOMStringMap* mDataset; // [Weak] michael@0: michael@0: /** michael@0: * The .undoManager property. michael@0: * @see nsGenericHTMLElement::GetUndoManager michael@0: */ michael@0: nsRefPtr mUndoManager; michael@0: michael@0: /** michael@0: * SMIL Overridde style rules (for SMIL animation of CSS properties) michael@0: * @see nsIContent::GetSMILOverrideStyle michael@0: */ michael@0: nsCOMPtr mSMILOverrideStyle; michael@0: michael@0: /** michael@0: * Holds any SMIL override style rules for this element. michael@0: */ michael@0: nsRefPtr mSMILOverrideStyleRule; michael@0: michael@0: /** michael@0: * An object implementing nsIDOMMozNamedAttrMap for this content (attributes) michael@0: * @see FragmentOrElement::GetAttributes michael@0: */ michael@0: nsRefPtr mAttributeMap; michael@0: michael@0: union { michael@0: /** michael@0: * The nearest enclosing content node with a binding that created us. michael@0: * @see FragmentOrElement::GetBindingParent michael@0: */ michael@0: nsIContent* mBindingParent; // [Weak] michael@0: michael@0: /** michael@0: * The controllers of the XUL Element. michael@0: */ michael@0: nsIControllers* mControllers; // [OWNER] michael@0: }; michael@0: michael@0: /** michael@0: * An object implementing the .children property for this element. michael@0: */ michael@0: nsRefPtr mChildrenList; michael@0: michael@0: /** michael@0: * An object implementing the .classList property for this element. michael@0: */ michael@0: nsRefPtr mClassList; michael@0: michael@0: /** michael@0: * ShadowRoot bound to the element. michael@0: */ michael@0: nsRefPtr mShadowRoot; michael@0: michael@0: /** michael@0: * The root ShadowRoot of this element if it is in a shadow tree. michael@0: */ michael@0: nsRefPtr mContainingShadow; michael@0: michael@0: /** michael@0: * XBL binding installed on the element. michael@0: */ michael@0: nsRefPtr mXBLBinding; michael@0: michael@0: /** michael@0: * XBL binding installed on the lement. michael@0: */ michael@0: nsCOMPtr mXBLInsertionParent; michael@0: michael@0: /** michael@0: * Web components custom element data. michael@0: */ michael@0: nsAutoPtr mCustomElementData; michael@0: }; michael@0: michael@0: protected: michael@0: void GetMarkup(bool aIncludeSelf, nsAString& aMarkup); michael@0: void SetInnerHTMLInternal(const nsAString& aInnerHTML, ErrorResult& aError); michael@0: michael@0: // Override from nsINode michael@0: virtual nsINode::nsSlots* CreateSlots() MOZ_OVERRIDE; michael@0: michael@0: nsDOMSlots *DOMSlots() michael@0: { michael@0: return static_cast(Slots()); michael@0: } michael@0: michael@0: nsDOMSlots *GetExistingDOMSlots() const michael@0: { michael@0: return static_cast(GetExistingSlots()); michael@0: } michael@0: michael@0: friend class ::ContentUnbinder; michael@0: /** michael@0: * Array containing all attributes and children for this element michael@0: */ michael@0: nsAttrAndChildArray mAttrsAndChildren; michael@0: }; michael@0: michael@0: } // namespace dom michael@0: } // namespace mozilla michael@0: michael@0: #define NS_ELEMENT_INTERFACE_TABLE_TO_MAP_SEGUE \ michael@0: if (NS_SUCCEEDED(rv)) \ michael@0: return rv; \ michael@0: \ michael@0: rv = FragmentOrElement::QueryInterface(aIID, aInstancePtr); \ michael@0: NS_INTERFACE_TABLE_TO_MAP_SEGUE michael@0: michael@0: #endif /* FragmentOrElement_h___ */