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  * Base class for DOM Core's nsIDOMComment, nsIDOMDocumentType, nsIDOMText,
9  * CDATASection, and nsIDOMProcessingInstruction nodes.
10  */
11 
12 #ifndef nsGenericDOMDataNode_h___
13 #define nsGenericDOMDataNode_h___
14 
15 #include "mozilla/Attributes.h"
16 #include "nsIContent.h"
17 
18 #include "nsTextFragment.h"
19 #include "nsError.h"
20 #include "mozilla/dom/Element.h"
21 #include "nsCycleCollectionParticipant.h"
22 
23 #include "nsISMILAttr.h"
24 #include "mozilla/dom/ShadowRoot.h"
25 
26 class nsIDocument;
27 class nsIDOMText;
28 
29 namespace mozilla {
30 namespace dom {
31 class HTMLSlotElement;
32 }  // namespace dom
33 }  // namespace mozilla
34 
35 #define DATA_NODE_FLAG_BIT(n_) \
36   NODE_FLAG_BIT(NODE_TYPE_SPECIFIC_BITS_OFFSET + (n_))
37 
38 // Data node specific flags
39 enum {
40   // This bit is set to indicate that if the text node changes to
41   // non-whitespace, we may need to create a frame for it. This bit must
42   // not be set on nodes that already have a frame.
43   NS_CREATE_FRAME_IF_NON_WHITESPACE = DATA_NODE_FLAG_BIT(0),
44 
45   // This bit is set to indicate that if the text node changes to
46   // whitespace, we may need to reframe it (or its ancestors).
47   NS_REFRAME_IF_WHITESPACE = DATA_NODE_FLAG_BIT(1),
48 
49   // This bit is set to indicate that we have a cached
50   // TextIsOnlyWhitespace value
51   NS_CACHED_TEXT_IS_ONLY_WHITESPACE = DATA_NODE_FLAG_BIT(2),
52 
53   // This bit is only meaningful if the NS_CACHED_TEXT_IS_ONLY_WHITESPACE
54   // bit is set, and if so it indicates whether we're only whitespace or
55   // not.
56   NS_TEXT_IS_ONLY_WHITESPACE = DATA_NODE_FLAG_BIT(3),
57 
58   // This bit is set if there is a NewlineProperty attached to the node
59   // (used by nsTextFrame).
60   NS_HAS_NEWLINE_PROPERTY = DATA_NODE_FLAG_BIT(4),
61 
62   // This bit is set if there is a FlowLengthProperty attached to the node
63   // (used by nsTextFrame).
64   NS_HAS_FLOWLENGTH_PROPERTY = DATA_NODE_FLAG_BIT(5),
65 
66   // This bit is set if the node may be modified frequently.  This is typically
67   // specified if the instance is in <input> or <textarea>.
68   NS_MAYBE_MODIFIED_FREQUENTLY = DATA_NODE_FLAG_BIT(6),
69 };
70 
71 // Make sure we have enough space for those bits
72 ASSERT_NODE_FLAGS_SPACE(NODE_TYPE_SPECIFIC_BITS_OFFSET + 7);
73 
74 #undef DATA_NODE_FLAG_BIT
75 
76 class nsGenericDOMDataNode : public nsIContent {
77  public:
78   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
79 
80   NS_DECL_ADDSIZEOFEXCLUDINGTHIS
81 
82   explicit nsGenericDOMDataNode(
83       already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
84   explicit nsGenericDOMDataNode(
85       already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
86 
MarkAsMaybeModifiedFrequently()87   void MarkAsMaybeModifiedFrequently() {
88     SetFlags(NS_MAYBE_MODIFIED_FREQUENTLY);
89   }
90 
91   virtual void GetNodeValueInternal(nsAString& aNodeValue) override;
92   virtual void SetNodeValueInternal(const nsAString& aNodeValue,
93                                     mozilla::ErrorResult& aError) override;
94 
95   // Implementation for nsIDOMCharacterData
96   nsresult GetData(nsAString& aData) const;
97   nsresult SetData(const nsAString& aData);
98   nsresult GetLength(uint32_t* aLength);
99   nsresult SubstringData(uint32_t aOffset, uint32_t aCount, nsAString& aReturn);
100   nsresult AppendData(const nsAString& aArg);
101   nsresult InsertData(uint32_t aOffset, const nsAString& aArg);
102   nsresult DeleteData(uint32_t aOffset, uint32_t aCount);
103   nsresult ReplaceData(uint32_t aOffset, uint32_t aCount,
104                        const nsAString& aArg);
105 
106   // nsINode methods
107   virtual uint32_t GetChildCount() const override;
108   virtual nsIContent* GetChildAt_Deprecated(uint32_t aIndex) const override;
109   virtual int32_t ComputeIndexOf(const nsINode* aPossibleChild) const override;
110   virtual nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
111                                      bool aNotify) override;
112   virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
113                                             bool aNotify) override;
114   virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
115   virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
GetTextContentInternal(nsAString & aTextContent,mozilla::OOMReporter & aError)116   virtual void GetTextContentInternal(nsAString& aTextContent,
117                                       mozilla::OOMReporter& aError) override {
118     GetNodeValue(aTextContent);
119   }
SetTextContentInternal(const nsAString & aTextContent,nsIPrincipal * aSubjectPrincipal,mozilla::ErrorResult & aError)120   virtual void SetTextContentInternal(const nsAString& aTextContent,
121                                       nsIPrincipal* aSubjectPrincipal,
122                                       mozilla::ErrorResult& aError) override {
123     // Batch possible DOMSubtreeModified events.
124     mozAutoSubtreeModified subtree(OwnerDoc(), nullptr);
125     return SetNodeValue(aTextContent, aError);
126   }
127 
128   // Implementation for nsIContent
129   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
130                               nsIContent* aBindingParent,
131                               bool aCompileEventHandlers) override;
132   virtual void UnbindFromTree(bool aDeep = true,
133                               bool aNullParent = true) override;
134 
135   virtual already_AddRefed<nsINodeList> GetChildren(uint32_t aFilter) override;
136 
137   virtual const nsTextFragment* GetText() override;
138   virtual uint32_t TextLength() const override;
139   virtual nsresult SetText(const char16_t* aBuffer, uint32_t aLength,
140                            bool aNotify) override;
141   // Need to implement this here too to avoid hiding.
SetText(const nsAString & aStr,bool aNotify)142   nsresult SetText(const nsAString& aStr, bool aNotify) {
143     return SetText(aStr.BeginReading(), aStr.Length(), aNotify);
144   }
145   virtual nsresult AppendText(const char16_t* aBuffer, uint32_t aLength,
146                               bool aNotify) override;
147   virtual bool TextIsOnlyWhitespace() override;
148   bool ThreadSafeTextIsOnlyWhitespace() const final;
149   virtual bool HasTextForTranslation() override;
150   virtual void AppendTextTo(nsAString& aResult) override;
151   MOZ_MUST_USE
152   virtual bool AppendTextTo(nsAString& aResult,
153                             const mozilla::fallible_t&) override;
154   virtual void SaveSubtreeState() override;
155 
156 #ifdef DEBUG
157   virtual void List(FILE* out, int32_t aIndent) const override;
158   virtual void DumpContent(FILE* out, int32_t aIndent,
159                            bool aDumpAll) const override;
160 #endif
161 
162   virtual nsXBLBinding* DoGetXBLBinding() const override;
163   virtual bool IsNodeOfType(uint32_t aFlags) const override;
164   virtual bool IsLink(nsIURI** aURI) const override;
165 
Clone(mozilla::dom::NodeInfo * aNodeInfo,nsINode ** aResult,bool aPreallocateChildren)166   virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
167                          bool aPreallocateChildren) const override {
168     nsCOMPtr<nsINode> result = CloneDataNode(aNodeInfo, true);
169     result.forget(aResult);
170 
171     if (!*aResult) {
172       return NS_ERROR_OUT_OF_MEMORY;
173     }
174 
175     return NS_OK;
176   }
177 
178   nsresult SplitData(uint32_t aOffset, nsIContent** aReturn,
179                      bool aCloneAfterOriginal = true);
180 
181   // WebIDL API
182   // Our XPCOM GetData is just fine for WebIDL
SetData(const nsAString & aData,mozilla::ErrorResult & rv)183   virtual void SetData(const nsAString& aData, mozilla::ErrorResult& rv) {
184     rv = SetData(aData);
185   }
186   // nsINode::Length() returns the right thing for our length attribute
187   void SubstringData(uint32_t aStart, uint32_t aCount, nsAString& aReturn,
188                      mozilla::ErrorResult& rv);
AppendData(const nsAString & aData,mozilla::ErrorResult & rv)189   void AppendData(const nsAString& aData, mozilla::ErrorResult& rv) {
190     rv = AppendData(aData);
191   }
InsertData(uint32_t aOffset,const nsAString & aData,mozilla::ErrorResult & rv)192   void InsertData(uint32_t aOffset, const nsAString& aData,
193                   mozilla::ErrorResult& rv) {
194     rv = InsertData(aOffset, aData);
195   }
DeleteData(uint32_t aOffset,uint32_t aCount,mozilla::ErrorResult & rv)196   void DeleteData(uint32_t aOffset, uint32_t aCount, mozilla::ErrorResult& rv) {
197     rv = DeleteData(aOffset, aCount);
198   }
ReplaceData(uint32_t aOffset,uint32_t aCount,const nsAString & aData,mozilla::ErrorResult & rv)199   void ReplaceData(uint32_t aOffset, uint32_t aCount, const nsAString& aData,
200                    mozilla::ErrorResult& rv) {
201     rv = ReplaceData(aOffset, aCount, aData);
202   }
203 
TextDataLength()204   uint32_t TextDataLength() const { return mText.GetLength(); }
205 
206     //----------------------------------------
207 
208 #ifdef DEBUG
209   void ToCString(nsAString& aBuf, int32_t aOffset, int32_t aLen) const;
210 #endif
211 
212   NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(nsGenericDOMDataNode)
213 
214  protected:
215   virtual ~nsGenericDOMDataNode();
216 
GetNameSpaceElement()217   virtual mozilla::dom::Element* GetNameSpaceElement() override {
218     nsINode* parent = GetParentNode();
219 
220     return parent && parent->IsElement() ? parent->AsElement() : nullptr;
221   }
222 
223   nsresult SplitText(uint32_t aOffset, nsIDOMText** aReturn);
224 
225   nsresult GetWholeText(nsAString& aWholeText);
226 
227   nsresult SetTextInternal(
228       uint32_t aOffset, uint32_t aCount, const char16_t* aBuffer,
229       uint32_t aLength, bool aNotify,
230       CharacterDataChangeInfo::Details* aDetails = nullptr);
231 
232   /**
233    * Method to clone this node. This needs to be overriden by all derived
234    * classes. If aCloneText is true the text content will be cloned too.
235    *
236    * @param aOwnerDocument the ownerDocument of the clone
237    * @param aCloneText if true the text content will be cloned too
238    * @return the clone
239    */
240   virtual nsGenericDOMDataNode* CloneDataNode(mozilla::dom::NodeInfo* aNodeInfo,
241                                               bool aCloneText) const = 0;
242 
243   nsTextFragment mText;
244 
245  public:
OwnedOnlyByTheDOMTree()246   virtual bool OwnedOnlyByTheDOMTree() override {
247     return GetParent() && mRefCnt.get() == 1;
248   }
249 
IsPurple()250   virtual bool IsPurple() override { return mRefCnt.IsPurple(); }
RemovePurple()251   virtual void RemovePurple() override { mRefCnt.RemovePurple(); }
252 
253  private:
254   already_AddRefed<nsAtom> GetCurrentValueAtom();
255 };
256 
257 #endif /* nsGenericDOMDataNode_h___ */
258