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