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 DOM Core's nsIDOMComment, nsIDOMDocumentType, nsIDOMText, michael@0: * nsIDOMCDATASection, and nsIDOMProcessingInstruction nodes. michael@0: */ michael@0: michael@0: #ifndef nsGenericDOMDataNode_h___ michael@0: #define nsGenericDOMDataNode_h___ michael@0: michael@0: #include "mozilla/Attributes.h" michael@0: #include "nsIContent.h" michael@0: michael@0: #include "nsTextFragment.h" michael@0: #include "nsError.h" michael@0: #include "mozilla/dom/Element.h" michael@0: #include "nsCycleCollectionParticipant.h" michael@0: michael@0: #include "nsISMILAttr.h" michael@0: #include "nsIDocument.h" michael@0: michael@0: class nsIDOMAttr; michael@0: class nsIDOMEventListener; michael@0: class nsIDOMNodeList; michael@0: class nsIFrame; michael@0: class nsIDOMText; michael@0: class nsINodeInfo; michael@0: class nsURI; michael@0: michael@0: #define DATA_NODE_FLAG_BIT(n_) NODE_FLAG_BIT(NODE_TYPE_SPECIFIC_BITS_OFFSET + (n_)) michael@0: michael@0: // Data node specific flags michael@0: enum { michael@0: // This bit is set to indicate that if the text node changes to michael@0: // non-whitespace, we may need to create a frame for it. This bit must michael@0: // not be set on nodes that already have a frame. michael@0: NS_CREATE_FRAME_IF_NON_WHITESPACE = DATA_NODE_FLAG_BIT(0), michael@0: michael@0: // This bit is set to indicate that if the text node changes to michael@0: // whitespace, we may need to reframe it (or its ancestors). michael@0: NS_REFRAME_IF_WHITESPACE = DATA_NODE_FLAG_BIT(1), michael@0: michael@0: // This bit is set to indicate that we have a cached michael@0: // TextIsOnlyWhitespace value michael@0: NS_CACHED_TEXT_IS_ONLY_WHITESPACE = DATA_NODE_FLAG_BIT(2), michael@0: michael@0: // This bit is only meaningful if the NS_CACHED_TEXT_IS_ONLY_WHITESPACE michael@0: // bit is set, and if so it indicates whether we're only whitespace or michael@0: // not. michael@0: NS_TEXT_IS_ONLY_WHITESPACE = DATA_NODE_FLAG_BIT(3), michael@0: }; michael@0: michael@0: // Make sure we have enough space for those bits michael@0: ASSERT_NODE_FLAGS_SPACE(NODE_TYPE_SPECIFIC_BITS_OFFSET + 4); michael@0: michael@0: #undef DATA_NODE_FLAG_BIT michael@0: michael@0: class nsGenericDOMDataNode : public nsIContent michael@0: { michael@0: public: michael@0: NS_DECL_CYCLE_COLLECTING_ISUPPORTS michael@0: michael@0: NS_DECL_SIZEOF_EXCLUDING_THIS michael@0: michael@0: nsGenericDOMDataNode(already_AddRefed& aNodeInfo); michael@0: nsGenericDOMDataNode(already_AddRefed&& aNodeInfo); michael@0: virtual ~nsGenericDOMDataNode(); michael@0: michael@0: virtual void GetNodeValueInternal(nsAString& aNodeValue) MOZ_OVERRIDE; michael@0: virtual void SetNodeValueInternal(const nsAString& aNodeValue, michael@0: mozilla::ErrorResult& aError) MOZ_OVERRIDE; michael@0: michael@0: // Implementation for nsIDOMCharacterData michael@0: nsresult GetData(nsAString& aData) const; michael@0: nsresult SetData(const nsAString& aData); michael@0: nsresult GetLength(uint32_t* aLength); michael@0: nsresult SubstringData(uint32_t aOffset, uint32_t aCount, michael@0: nsAString& aReturn); michael@0: nsresult AppendData(const nsAString& aArg); michael@0: nsresult InsertData(uint32_t aOffset, const nsAString& aArg); michael@0: nsresult DeleteData(uint32_t aOffset, uint32_t aCount); michael@0: nsresult ReplaceData(uint32_t aOffset, uint32_t aCount, michael@0: const nsAString& aArg); michael@0: NS_IMETHOD MozRemove(); michael@0: michael@0: // nsINode 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: { michael@0: GetNodeValue(aTextContent); michael@0: } michael@0: virtual void SetTextContentInternal(const nsAString& aTextContent, michael@0: mozilla::ErrorResult& aError) MOZ_OVERRIDE michael@0: { michael@0: // Batch possible DOMSubtreeModified events. michael@0: mozAutoSubtreeModified subtree(OwnerDoc(), nullptr); michael@0: return SetNodeValue(aTextContent, aError); michael@0: } michael@0: michael@0: // Implementation for nsIContent michael@0: virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, michael@0: nsIContent* aBindingParent, michael@0: bool aCompileEventHandlers) MOZ_OVERRIDE; michael@0: virtual void UnbindFromTree(bool aDeep = true, michael@0: bool aNullParent = true) MOZ_OVERRIDE; michael@0: michael@0: virtual already_AddRefed GetChildren(uint32_t aFilter) MOZ_OVERRIDE; michael@0: michael@0: virtual nsIAtom *GetIDAttributeName() const MOZ_OVERRIDE; michael@0: michael@0: nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName, michael@0: const nsAString& aValue, bool aNotify) michael@0: { michael@0: return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify); michael@0: } michael@0: virtual nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute, michael@0: nsIAtom* aPrefix, const nsAString& aValue, michael@0: bool aNotify) MOZ_OVERRIDE; michael@0: virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute, michael@0: bool aNotify) MOZ_OVERRIDE; michael@0: virtual const nsAttrName* GetAttrNameAt(uint32_t aIndex) const MOZ_OVERRIDE; michael@0: virtual uint32_t GetAttrCount() const 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 void DestroyContent() MOZ_OVERRIDE; michael@0: virtual void SaveSubtreeState() MOZ_OVERRIDE; michael@0: michael@0: #ifdef DEBUG michael@0: virtual void List(FILE* out, int32_t aIndent) const MOZ_OVERRIDE; michael@0: virtual void DumpContent(FILE* out, int32_t aIndent, bool aDumpAll) const MOZ_OVERRIDE; michael@0: #endif michael@0: 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 mozilla::dom::ShadowRoot *GetContainingShadow() const MOZ_OVERRIDE; michael@0: virtual mozilla::dom::ShadowRoot *GetShadowRoot() const MOZ_OVERRIDE; michael@0: virtual void SetShadowRoot(mozilla::dom::ShadowRoot* aShadowRoot) MOZ_OVERRIDE; michael@0: virtual nsIContent *GetXBLInsertionParent() const MOZ_OVERRIDE; michael@0: virtual void SetXBLInsertionParent(nsIContent* aContent) MOZ_OVERRIDE; michael@0: virtual bool IsNodeOfType(uint32_t aFlags) const MOZ_OVERRIDE; michael@0: virtual bool IsLink(nsIURI** aURI) const MOZ_OVERRIDE; michael@0: michael@0: virtual mozilla::dom::CustomElementData* GetCustomElementData() const MOZ_OVERRIDE; michael@0: virtual void SetCustomElementData(mozilla::dom::CustomElementData* aData) MOZ_OVERRIDE; michael@0: michael@0: virtual nsIAtom* DoGetID() const MOZ_OVERRIDE; michael@0: virtual const nsAttrValue* DoGetClasses() const MOZ_OVERRIDE; michael@0: NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) MOZ_OVERRIDE; michael@0: NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const; michael@0: virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute, michael@0: int32_t aModType) const; michael@0: virtual nsIAtom *GetClassAttributeName() const; michael@0: michael@0: virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE michael@0: { michael@0: *aResult = CloneDataNode(aNodeInfo, true); michael@0: if (!*aResult) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: NS_ADDREF(*aResult); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult SplitData(uint32_t aOffset, nsIContent** aReturn, michael@0: bool aCloneAfterOriginal = true); michael@0: michael@0: // WebIDL API michael@0: // Our XPCOM GetData is just fine for WebIDL michael@0: virtual void SetData(const nsAString& aData, mozilla::ErrorResult& rv) michael@0: { michael@0: rv = SetData(aData); michael@0: } michael@0: // nsINode::Length() returns the right thing for our length attribute michael@0: void SubstringData(uint32_t aStart, uint32_t aCount, nsAString& aReturn, michael@0: mozilla::ErrorResult& rv); michael@0: void AppendData(const nsAString& aData, mozilla::ErrorResult& rv) michael@0: { michael@0: rv = AppendData(aData); michael@0: } michael@0: void InsertData(uint32_t aOffset, const nsAString& aData, michael@0: mozilla::ErrorResult& rv) michael@0: { michael@0: rv = InsertData(aOffset, aData); michael@0: } michael@0: void DeleteData(uint32_t aOffset, uint32_t aCount, mozilla::ErrorResult& rv) michael@0: { michael@0: rv = DeleteData(aOffset, aCount); michael@0: } michael@0: void ReplaceData(uint32_t aOffset, uint32_t aCount, const nsAString& aData, michael@0: mozilla::ErrorResult& rv) michael@0: { michael@0: rv = ReplaceData(aOffset, aCount, aData); michael@0: } michael@0: michael@0: //---------------------------------------- michael@0: michael@0: #ifdef DEBUG michael@0: void ToCString(nsAString& aBuf, int32_t aOffset, int32_t aLen) const; michael@0: #endif michael@0: michael@0: NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(nsGenericDOMDataNode) michael@0: michael@0: protected: michael@0: virtual mozilla::dom::Element* GetNameSpaceElement() michael@0: { michael@0: nsINode *parent = GetParentNode(); michael@0: michael@0: return parent && parent->IsElement() ? parent->AsElement() : nullptr; michael@0: } michael@0: 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 nsDataSlots : public nsINode::nsSlots michael@0: { michael@0: public: michael@0: nsDataSlots(); michael@0: michael@0: void Traverse(nsCycleCollectionTraversalCallback &cb); michael@0: void Unlink(); michael@0: michael@0: /** michael@0: * The nearest enclosing content node with a binding that created us. michael@0: * @see nsIContent::GetBindingParent michael@0: */ michael@0: nsIContent* mBindingParent; // [Weak] michael@0: michael@0: /** michael@0: * @see nsIContent::GetXBLInsertionParent michael@0: */ michael@0: nsCOMPtr mXBLInsertionParent; michael@0: michael@0: /** michael@0: * @see nsIContent::GetContainingShadow michael@0: */ michael@0: nsRefPtr mContainingShadow; michael@0: }; michael@0: michael@0: // Override from nsINode michael@0: virtual nsINode::nsSlots* CreateSlots() MOZ_OVERRIDE; michael@0: michael@0: nsDataSlots* DataSlots() michael@0: { michael@0: return static_cast(Slots()); michael@0: } michael@0: michael@0: nsDataSlots *GetExistingDataSlots() const michael@0: { michael@0: return static_cast(GetExistingSlots()); michael@0: } michael@0: michael@0: nsresult SplitText(uint32_t aOffset, nsIDOMText** aReturn); michael@0: michael@0: nsresult GetWholeText(nsAString& aWholeText); michael@0: michael@0: static int32_t FirstLogicallyAdjacentTextNode(nsIContent* aParent, michael@0: int32_t aIndex); michael@0: michael@0: static int32_t LastLogicallyAdjacentTextNode(nsIContent* aParent, michael@0: int32_t aIndex, michael@0: uint32_t aCount); michael@0: michael@0: nsresult SetTextInternal(uint32_t aOffset, uint32_t aCount, michael@0: const char16_t* aBuffer, uint32_t aLength, michael@0: bool aNotify, michael@0: CharacterDataChangeInfo::Details* aDetails = nullptr); michael@0: michael@0: /** michael@0: * Method to clone this node. This needs to be overriden by all derived michael@0: * classes. If aCloneText is true the text content will be cloned too. michael@0: * michael@0: * @param aOwnerDocument the ownerDocument of the clone michael@0: * @param aCloneText if true the text content will be cloned too michael@0: * @return the clone michael@0: */ michael@0: virtual nsGenericDOMDataNode *CloneDataNode(nsINodeInfo *aNodeInfo, michael@0: bool aCloneText) const = 0; michael@0: michael@0: nsTextFragment mText; michael@0: michael@0: public: michael@0: virtual bool OwnedOnlyByTheDOMTree() MOZ_OVERRIDE michael@0: { michael@0: return GetParent() && mRefCnt.get() == 1; michael@0: } michael@0: michael@0: virtual bool IsPurple() MOZ_OVERRIDE michael@0: { michael@0: return mRefCnt.IsPurple(); michael@0: } michael@0: virtual void RemovePurple() MOZ_OVERRIDE michael@0: { michael@0: mRefCnt.RemovePurple(); michael@0: } michael@0: michael@0: private: michael@0: already_AddRefed GetCurrentValueAtom(); michael@0: }; michael@0: michael@0: #endif /* nsGenericDOMDataNode_h___ */