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 Comment, DocumentType, Text, 9 * CDATASection, and ProcessingInstruction nodes. 10 */ 11 12 #ifndef mozilla_dom_CharacterData_h 13 #define mozilla_dom_CharacterData_h 14 15 #include "mozilla/Attributes.h" 16 #include "nsIContent.h" 17 18 #include "nsTextFragment.h" 19 #include "nsError.h" 20 #include "nsCycleCollectionParticipant.h" 21 22 #include "mozilla/dom/ShadowRoot.h" 23 24 namespace mozilla { 25 namespace dom { 26 class Element; 27 class HTMLSlotElement; 28 } // namespace dom 29 } // namespace mozilla 30 31 #define CHARACTER_DATA_FLAG_BIT(n_) \ 32 NODE_FLAG_BIT(NODE_TYPE_SPECIFIC_BITS_OFFSET + (n_)) 33 34 // Data node specific flags 35 enum { 36 // This bit is set to indicate that if the text node changes to 37 // non-whitespace, we may need to create a frame for it. This bit must 38 // not be set on nodes that already have a frame. 39 NS_CREATE_FRAME_IF_NON_WHITESPACE = CHARACTER_DATA_FLAG_BIT(0), 40 41 // This bit is set to indicate that if the text node changes to 42 // whitespace, we may need to reframe it (or its ancestors). 43 NS_REFRAME_IF_WHITESPACE = CHARACTER_DATA_FLAG_BIT(1), 44 45 // This bit is set to indicate that we have a cached 46 // TextIsOnlyWhitespace value 47 NS_CACHED_TEXT_IS_ONLY_WHITESPACE = CHARACTER_DATA_FLAG_BIT(2), 48 49 // This bit is only meaningful if the NS_CACHED_TEXT_IS_ONLY_WHITESPACE 50 // bit is set, and if so it indicates whether we're only whitespace or 51 // not. 52 NS_TEXT_IS_ONLY_WHITESPACE = CHARACTER_DATA_FLAG_BIT(3), 53 54 // This bit is set if there is a NewlineProperty attached to the node 55 // (used by nsTextFrame). 56 NS_HAS_NEWLINE_PROPERTY = CHARACTER_DATA_FLAG_BIT(4), 57 58 // This bit is set if there is a FlowLengthProperty attached to the node 59 // (used by nsTextFrame). 60 NS_HAS_FLOWLENGTH_PROPERTY = CHARACTER_DATA_FLAG_BIT(5), 61 62 // This bit is set if the node may be modified frequently. This is typically 63 // specified if the instance is in <input> or <textarea>. 64 NS_MAYBE_MODIFIED_FREQUENTLY = CHARACTER_DATA_FLAG_BIT(6), 65 66 // This bit is set if the node may be masked because of being in a password 67 // field. 68 NS_MAYBE_MASKED = CHARACTER_DATA_FLAG_BIT(7), 69 }; 70 71 // Make sure we have enough space for those bits 72 ASSERT_NODE_FLAGS_SPACE(NODE_TYPE_SPECIFIC_BITS_OFFSET + 8); 73 74 #undef CHARACTER_DATA_FLAG_BIT 75 76 namespace mozilla { 77 namespace dom { 78 79 class CharacterData : public nsIContent { 80 public: 81 // We want to avoid the overhead of extra function calls for 82 // refcounting when we're not doing refcount logging, so we can't 83 // NS_DECL_ISUPPORTS_INHERITED. 84 NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override; 85 NS_INLINE_DECL_REFCOUNTING_INHERITED(CharacterData, nsIContent); 86 87 NS_DECL_ADDSIZEOFEXCLUDINGTHIS 88 89 explicit CharacterData(already_AddRefed<dom::NodeInfo>&& aNodeInfo); 90 MarkAsMaybeModifiedFrequently()91 void MarkAsMaybeModifiedFrequently() { 92 SetFlags(NS_MAYBE_MODIFIED_FREQUENTLY); 93 } MarkAsMaybeMasked()94 void MarkAsMaybeMasked() { SetFlags(NS_MAYBE_MASKED); } 95 96 NS_IMPL_FROMNODE_HELPER(CharacterData, IsCharacterData()) 97 98 virtual void GetNodeValueInternal(nsAString& aNodeValue) override; 99 virtual void SetNodeValueInternal(const nsAString& aNodeValue, 100 ErrorResult& aError) override; 101 GetTextContentInternal(nsAString & aTextContent,OOMReporter &)102 void GetTextContentInternal(nsAString& aTextContent, OOMReporter&) final { 103 GetNodeValue(aTextContent); 104 } 105 106 void SetTextContentInternal(const nsAString& aTextContent, 107 nsIPrincipal* aSubjectPrincipal, 108 ErrorResult& aError) final; 109 110 // Implementation for nsIContent 111 nsresult BindToTree(BindContext&, nsINode& aParent) override; 112 113 void UnbindFromTree(bool aNullParent = true) override; 114 GetChildren(uint32_t aFilter)115 already_AddRefed<nsINodeList> GetChildren(uint32_t aFilter) final { 116 return nullptr; 117 } 118 GetText()119 const nsTextFragment* GetText() override { return &mText; } TextLength()120 uint32_t TextLength() const final { return TextDataLength(); } 121 TextFragment()122 const nsTextFragment& TextFragment() const { return mText; } TextDataLength()123 uint32_t TextDataLength() const { return mText.GetLength(); } 124 125 /** 126 * Set the text to the given value. If aNotify is true then 127 * the document is notified of the content change. 128 */ 129 nsresult SetText(const char16_t* aBuffer, uint32_t aLength, bool aNotify); 130 /** 131 * Append the given value to the current text. If aNotify is true then 132 * the document is notified of the content change. 133 */ SetText(const nsAString & aStr,bool aNotify)134 nsresult SetText(const nsAString& aStr, bool aNotify) { 135 return SetText(aStr.BeginReading(), aStr.Length(), aNotify); 136 } 137 138 /** 139 * Append the given value to the current text. If aNotify is true then 140 * the document is notified of the content change. 141 */ 142 nsresult AppendText(const char16_t* aBuffer, uint32_t aLength, bool aNotify); 143 144 bool TextIsOnlyWhitespace() final; 145 bool ThreadSafeTextIsOnlyWhitespace() const final; 146 147 /** 148 * Append the text content to aResult. 149 */ AppendTextTo(nsAString & aResult)150 void AppendTextTo(nsAString& aResult) const { mText.AppendTo(aResult); } 151 152 /** 153 * Append the text content to aResult. 154 */ AppendTextTo(nsAString & aResult,const fallible_t & aFallible)155 [[nodiscard]] bool AppendTextTo(nsAString& aResult, 156 const fallible_t& aFallible) const { 157 return mText.AppendTo(aResult, aFallible); 158 } 159 SaveSubtreeState()160 void SaveSubtreeState() final {} 161 162 #ifdef MOZ_DOM_LIST 163 void ToCString(nsAString& aBuf, int32_t aOffset, int32_t aLen) const; 164 List(FILE * out,int32_t aIndent)165 void List(FILE* out, int32_t aIndent) const override {} 166 DumpContent(FILE * out,int32_t aIndent,bool aDumpAll)167 void DumpContent(FILE* out, int32_t aIndent, bool aDumpAll) const override {} 168 #endif 169 IsNodeOfType(uint32_t aFlags)170 bool IsNodeOfType(uint32_t aFlags) const override { return false; } 171 IsLink(nsIURI ** aURI)172 bool IsLink(nsIURI** aURI) const final { 173 *aURI = nullptr; 174 return false; 175 } 176 Clone(dom::NodeInfo * aNodeInfo,nsINode ** aResult)177 nsresult Clone(dom::NodeInfo* aNodeInfo, nsINode** aResult) const override { 178 RefPtr<CharacterData> result = CloneDataNode(aNodeInfo, true); 179 result.forget(aResult); 180 181 if (!*aResult) { 182 return NS_ERROR_OUT_OF_MEMORY; 183 } 184 185 return NS_OK; 186 } 187 188 // WebIDL API 189 void GetData(nsAString& aData) const; 190 virtual void SetData(const nsAString& aData, ErrorResult& rv); 191 // nsINode::Length() returns the right thing for our length attribute 192 void SubstringData(uint32_t aStart, uint32_t aCount, nsAString& aReturn, 193 ErrorResult& rv); 194 void AppendData(const nsAString& aData, ErrorResult& rv); 195 void InsertData(uint32_t aOffset, const nsAString& aData, ErrorResult& rv); 196 void DeleteData(uint32_t aOffset, uint32_t aCount, ErrorResult& rv); 197 void ReplaceData(uint32_t aOffset, uint32_t aCount, const nsAString& aData, 198 ErrorResult& rv); 199 200 //---------------------------------------- 201 NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_INHERITED(CharacterData,nsIContent)202 NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_INHERITED( 203 CharacterData, nsIContent) 204 205 /** 206 * Compare two CharacterData nodes for text equality. 207 */ 208 [[nodiscard]] bool TextEquals(const CharacterData* aOther) const { 209 return mText.TextEquals(aOther->mText); 210 } 211 212 protected: 213 virtual ~CharacterData(); 214 215 Element* GetNameSpaceElement() final; 216 217 nsresult SetTextInternal( 218 uint32_t aOffset, uint32_t aCount, const char16_t* aBuffer, 219 uint32_t aLength, bool aNotify, 220 CharacterDataChangeInfo::Details* aDetails = nullptr); 221 222 /** 223 * Method to clone this node. This needs to be overriden by all derived 224 * classes. If aCloneText is true the text content will be cloned too. 225 * 226 * @param aOwnerDocument the ownerDocument of the clone 227 * @param aCloneText if true the text content will be cloned too 228 * @return the clone 229 */ 230 virtual already_AddRefed<CharacterData> CloneDataNode( 231 dom::NodeInfo* aNodeInfo, bool aCloneText) const = 0; 232 233 nsTextFragment mText; 234 235 private: 236 already_AddRefed<nsAtom> GetCurrentValueAtom(); 237 }; 238 239 } // namespace dom 240 } // namespace mozilla 241 242 #endif /* mozilla_dom_CharacterData_h */ 243