Text.cpp (5009B)
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 #include "mozilla/dom/Text.h" 8 9 #include "mozAutoDocUpdate.h" 10 #include "nsTextNode.h" 11 12 namespace mozilla::dom { 13 14 already_AddRefed<Text> Text::SplitText(uint32_t aOffset, ErrorResult& aRv) { 15 nsAutoString cutText; 16 const uint32_t length = TextLength(); 17 18 if (aOffset > length) { 19 aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); 20 return nullptr; 21 } 22 23 const uint32_t cutStartOffset = aOffset; 24 const uint32_t cutLength = length - aOffset; 25 SubstringData(cutStartOffset, cutLength, cutText, aRv); 26 if (aRv.Failed()) { 27 return nullptr; 28 } 29 30 Document* document = GetComposedDoc(); 31 mozAutoDocUpdate updateBatch(document, true); 32 33 // Use Clone for creating the new node so that the new node is of same class 34 // as this node! 35 RefPtr<CharacterData> clone = CloneDataNode(mNodeInfo, false); 36 MOZ_ASSERT(clone && clone->IsText()); 37 RefPtr<Text> newContent = static_cast<Text*>(clone.get()); 38 39 // nsRange expects the CharacterDataChanged notification is followed 40 // by an insertion of |newContent|. If you change this code, 41 // make sure you make the appropriate changes in nsRange. 42 newContent->SetText(cutText, true); // XXX should be false? 43 44 CharacterDataChangeInfo::Details details = { 45 CharacterDataChangeInfo::Details::eSplit, newContent}; 46 nsresult rv = 47 SetTextInternal(cutStartOffset, cutLength, nullptr, 0, true, 48 MutationEffectOnScript::KeepTrustWorthiness, &details); 49 if (NS_FAILED(rv)) { 50 aRv.Throw(rv); 51 return nullptr; 52 } 53 54 nsCOMPtr<nsINode> parent = GetParentNode(); 55 if (parent) { 56 nsCOMPtr<nsIContent> beforeNode = GetNextSibling(); 57 parent->InsertChildBefore(newContent, beforeNode, true, IgnoreErrors(), 58 nullptr, 59 MutationEffectOnScript::KeepTrustWorthiness); 60 } 61 62 return newContent.forget(); 63 } 64 65 static Text* FirstLogicallyAdjacentTextNode(Text* aNode) { 66 do { 67 nsIContent* sibling = aNode->GetPreviousSibling(); 68 if (!sibling || !sibling->IsText()) { 69 return aNode; 70 } 71 aNode = static_cast<Text*>(sibling); 72 } while (1); // Must run out of previous siblings eventually! 73 } 74 75 static Text* LastLogicallyAdjacentTextNode(Text* aNode) { 76 do { 77 nsIContent* sibling = aNode->GetNextSibling(); 78 if (!sibling || !sibling->IsText()) { 79 return aNode; 80 } 81 82 aNode = static_cast<Text*>(sibling); 83 } while (1); // Must run out of next siblings eventually! 84 } 85 86 void Text::GetWholeText(nsAString& aWholeText) { 87 nsIContent* parent = GetParent(); 88 89 // Handle parent-less nodes 90 if (!parent) { 91 GetData(aWholeText); 92 return; 93 } 94 95 Text* first = FirstLogicallyAdjacentTextNode(this); 96 Text* last = LastLogicallyAdjacentTextNode(this); 97 98 aWholeText.Truncate(); 99 100 nsAutoString tmp; 101 102 while (true) { 103 first->GetData(tmp); 104 aWholeText.Append(tmp); 105 106 if (first == last) { 107 break; 108 } 109 110 nsIContent* next = first->GetNextSibling(); 111 MOZ_ASSERT(next && next->IsText(), 112 "How did we run out of text before hitting `last`?"); 113 first = static_cast<Text*>(next); 114 } 115 } 116 117 /* static */ 118 already_AddRefed<Text> Text::Constructor(const GlobalObject& aGlobal, 119 const nsAString& aData, 120 ErrorResult& aRv) { 121 nsCOMPtr<nsPIDOMWindowInner> window = 122 do_QueryInterface(aGlobal.GetAsSupports()); 123 if (!window || !window->GetDoc()) { 124 aRv.Throw(NS_ERROR_FAILURE); 125 return nullptr; 126 } 127 128 return window->GetDoc()->CreateTextNode(aData); 129 } 130 131 nsresult Text::BindToTree(BindContext& aContext, nsINode& aParent) { 132 nsresult rv = CharacterData::BindToTree(aContext, aParent); 133 NS_ENSURE_SUCCESS(rv, rv); 134 135 SetDirectionFromNewTextNode(this); 136 137 return NS_OK; 138 } 139 140 void Text::UnbindFromTree(UnbindContext& aContext) { 141 CharacterData::UnbindFromTree(aContext); 142 ResetDirectionSetByTextNode(this, aContext); 143 } 144 145 bool Text::HasTextForTranslation() { 146 if (mBuffer.Is2b()) { 147 // The fragment contains non-8bit characters which means there 148 // was at least one "interesting" character to trigger non-8bit. 149 return true; 150 } 151 152 if (HasFlag(NS_CACHED_TEXT_IS_ONLY_WHITESPACE) && 153 HasFlag(NS_TEXT_IS_ONLY_WHITESPACE)) { 154 return false; 155 } 156 157 const char* cp = mBuffer.Get1b(); 158 const char* end = cp + mBuffer.GetLength(); 159 160 unsigned char ch; 161 for (; cp < end; cp++) { 162 ch = *cp; 163 164 // These are the characters that are letters 165 // in the first 256 UTF-8 codepoints. 166 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || 167 (ch >= 192 && ch <= 214) || (ch >= 216 && ch <= 246) || (ch >= 248)) { 168 return true; 169 } 170 } 171 172 return false; 173 } 174 175 } // namespace mozilla::dom