Move most of TextIterator off of live ranges
[WebKit-https.git] / Source / WebCore / editing / TextIterator.h
1 /*
2  * Copyright (C) 2004-2020 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #pragma once
27
28 #include "FindOptions.h"
29 #include "LineLayoutTraversal.h"
30 #include "SimpleRange.h"
31 #include "TextIteratorBehavior.h"
32 #include <wtf/Vector.h>
33
34 namespace WebCore {
35
36 class Range;
37 class RenderTextFragment;
38
39 WEBCORE_EXPORT String plainText(const Range*, TextIteratorBehavior = TextIteratorDefaultBehavior, bool isDisplayString = false);
40 WEBCORE_EXPORT String plainText(const SimpleRange&, TextIteratorBehavior = TextIteratorDefaultBehavior, bool isDisplayString = false);
41 WEBCORE_EXPORT String plainTextReplacingNoBreakSpace(const SimpleRange&, TextIteratorBehavior = TextIteratorDefaultBehavior, bool isDisplayString = false);
42 WEBCORE_EXPORT String plainTextUsingBackwardsTextIteratorForTesting(const SimpleRange&);
43
44 SimpleRange findPlainText(const SimpleRange&, const String&, FindOptions);
45 WEBCORE_EXPORT SimpleRange findClosestPlainText(const SimpleRange&, const String&, FindOptions, unsigned);
46 WEBCORE_EXPORT bool hasAnyPlainText(const SimpleRange&, TextIteratorBehavior = TextIteratorDefaultBehavior);
47 bool containsPlainText(const String& document, const String&, FindOptions); // Lets us use the search algorithm on a string.
48 WEBCORE_EXPORT String foldQuoteMarks(const String&);
49
50 // FIXME: Move this somewhere else in the editing directory. It doesn't belong here.
51 bool isRendererReplacedElement(RenderObject*);
52
53 // FIXME: Move each iterator class into a separate header file.
54
55 class BitStack {
56 public:
57     void push(bool);
58     void pop();
59     bool top() const;
60
61 private:
62     unsigned m_size { 0 };
63     Vector<unsigned, 1> m_words;
64 };
65
66 class TextIteratorCopyableText {
67 public:
68     StringView text() const { return m_singleCharacter ? StringView(&m_singleCharacter, 1) : StringView(m_string).substring(m_offset, m_length); }
69     void appendToStringBuilder(StringBuilder&) const;
70
71     void reset();
72     void set(String&&);
73     void set(String&&, unsigned offset, unsigned length);
74     void set(UChar);
75
76 private:
77     UChar m_singleCharacter { 0 };
78     String m_string;
79     unsigned m_offset { 0 };
80     unsigned m_length { 0 };
81 };
82
83 // Iterates through the DOM range, returning all the text, and 0-length boundaries
84 // at points where replaced elements break up the text flow. The text is delivered in
85 // the chunks it's already stored in, to avoid copying any text.
86
87 class TextIterator {
88     WTF_MAKE_FAST_ALLOCATED;
89 public:
90     WEBCORE_EXPORT explicit TextIterator(const SimpleRange&, TextIteratorBehavior = TextIteratorDefaultBehavior);
91     WEBCORE_EXPORT ~TextIterator();
92
93     bool atEnd() const { return !m_positionNode; }
94     WEBCORE_EXPORT void advance();
95
96     StringView text() const { ASSERT(!atEnd()); return m_text; }
97     WEBCORE_EXPORT SimpleRange range() const;
98     WEBCORE_EXPORT Node* node() const;
99
100     const TextIteratorCopyableText& copyableText() const { ASSERT(!atEnd()); return m_copyableText; }
101     void appendTextToStringBuilder(StringBuilder& builder) const { copyableText().appendToStringBuilder(builder); }
102
103     WEBCORE_EXPORT static int rangeLength(const Range*, bool spacesForReplacedElements = false);
104     WEBCORE_EXPORT static RefPtr<Range> rangeFromLocationAndLength(ContainerNode* scope, int rangeLocation, int rangeLength, bool spacesForReplacedElements = false);
105     WEBCORE_EXPORT static bool getLocationAndLengthFromRange(Node* scope, const Range*, size_t& location, size_t& length);
106     WEBCORE_EXPORT static Ref<Range> subrange(Range& entireRange, int characterOffset, int characterCount);
107
108 private:
109     void init();
110     void exitNode(Node*);
111     bool shouldRepresentNodeOffsetZero();
112     bool shouldEmitSpaceBeforeAndAfterNode(Node&);
113     void representNodeOffsetZero();
114     bool handleTextNode();
115     bool handleReplacedElement();
116     bool handleNonTextNode();
117     void handleTextBox();
118     void handleTextNodeFirstLetter(RenderTextFragment&);
119     void emitCharacter(UChar, Node& characterNode, Node* offsetBaseNode, int textStartOffset, int textEndOffset);
120     void emitText(Text& textNode, RenderText&, int textStartOffset, int textEndOffset);
121
122     Node* baseNodeForEmittingNewLine() const;
123
124     const TextIteratorBehavior m_behavior { TextIteratorDefaultBehavior };
125
126     // Current position, not necessarily of the text being returned, but position as we walk through the DOM tree.
127     Node* m_node { nullptr };
128     int m_offset { 0 };
129     bool m_handledNode { false };
130     bool m_handledChildren { false };
131     BitStack m_fullyClippedStack;
132
133     // The range.
134     Node* m_startContainer { nullptr };
135     int m_startOffset { 0 };
136     Node* m_endContainer { nullptr };
137     int m_endOffset { 0 };
138     Node* m_pastEndNode { nullptr };
139
140     // The current text and its position, in the form to be returned from the iterator.
141     Node* m_positionNode { nullptr };
142     mutable Node* m_positionOffsetBaseNode { nullptr };
143     mutable int m_positionStartOffset { 0 };
144     mutable int m_positionEndOffset { 0 };
145     TextIteratorCopyableText m_copyableText;
146     StringView m_text;
147
148     // Used when there is still some pending text from the current node; when these are false and null, we go back to normal iterating.
149     Node* m_nodeForAdditionalNewline { nullptr };
150     LineLayoutTraversal::TextBoxIterator m_textBox;
151
152     // Used when iterating over :first-letter text to save pointer to remaining text box.
153     LineLayoutTraversal::TextBoxIterator m_remainingTextBox;
154
155     // Used to point to RenderText object for :first-letter.
156     RenderText* m_firstLetterText { nullptr };
157
158     // Used to do the whitespace collapsing logic.
159     Text* m_lastTextNode { nullptr };
160     bool m_lastTextNodeEndedWithCollapsedSpace { false };
161     UChar m_lastCharacter { 0 };
162
163     // Used when deciding whether to emit a "positioning" (e.g. newline) before any other content
164     bool m_hasEmitted { false };
165
166     // Used when deciding text fragment created by :first-letter should be looked into.
167     bool m_handledFirstLetter { false };
168 };
169
170 // Iterates through the DOM range, returning all the text, and 0-length boundaries
171 // at points where replaced elements break up the text flow. The text comes back in
172 // chunks so as to optimize for performance of the iteration.
173 class SimplifiedBackwardsTextIterator {
174 public:
175     explicit SimplifiedBackwardsTextIterator(const SimpleRange&);
176
177     bool atEnd() const { return !m_positionNode; }
178     void advance();
179
180     StringView text() const { ASSERT(!atEnd()); return m_text; }
181     WEBCORE_EXPORT SimpleRange range() const;
182     Node* node() const { ASSERT(!atEnd()); return m_node; }
183
184 private:
185     void exitNode();
186     bool handleTextNode();
187     RenderText* handleFirstLetter(int& startOffset, int& offsetInNode);
188     bool handleReplacedElement();
189     bool handleNonTextNode();
190     void emitCharacter(UChar, Node&, int startOffset, int endOffset);
191     bool advanceRespectingRange(Node*);
192
193     const TextIteratorBehavior m_behavior { TextIteratorDefaultBehavior };
194
195     // Current position, not necessarily of the text being returned, but position as we walk through the DOM tree.
196     Node* m_node { nullptr };
197     int m_offset { 0 };
198     bool m_handledNode { false };
199     bool m_handledChildren { false };
200     BitStack m_fullyClippedStack;
201
202     // The range.
203     Node* m_startContainer { nullptr };
204     int m_startOffset { 0 };
205     Node* m_endContainer { nullptr };
206     int m_endOffset { 0 };
207     
208     // The current text and its position, in the form to be returned from the iterator.
209     Node* m_positionNode { nullptr };
210     int m_positionStartOffset { 0 };
211     int m_positionEndOffset { 0 };
212     TextIteratorCopyableText m_copyableText;
213     StringView m_text;
214
215     // Used to do the whitespace logic.
216     Text* m_lastTextNode { nullptr };
217     UChar m_lastCharacter { 0 };
218
219     // Whether m_node has advanced beyond the iteration range (i.e. m_startContainer).
220     bool m_havePassedStartContainer { false };
221
222     // Should handle first-letter renderer in the next call to handleTextNode.
223     bool m_shouldHandleFirstLetter { false };
224 };
225
226 // Builds on the text iterator, adding a character position so we can walk one
227 // character at a time, or faster, as needed. Useful for searching.
228 class CharacterIterator {
229 public:
230     WEBCORE_EXPORT explicit CharacterIterator(const SimpleRange&, TextIteratorBehavior = TextIteratorDefaultBehavior);
231     
232     bool atEnd() const { return m_underlyingIterator.atEnd(); }
233     WEBCORE_EXPORT void advance(int numCharacters);
234     
235     StringView text() const { return m_underlyingIterator.text().substring(m_runOffset); }
236     WEBCORE_EXPORT SimpleRange range() const;
237
238     bool atBreak() const { return m_atBreak; }
239     unsigned characterOffset() const { return m_offset; }
240
241 private:
242     TextIterator m_underlyingIterator;
243
244     unsigned m_offset { 0 };
245     unsigned m_runOffset { 0 };
246     bool m_atBreak { true };
247 };
248     
249 class BackwardsCharacterIterator {
250 public:
251     explicit BackwardsCharacterIterator(const SimpleRange&);
252
253     bool atEnd() const { return m_underlyingIterator.atEnd(); }
254     void advance(int numCharacters);
255
256     SimpleRange range() const;
257
258 private:
259     SimplifiedBackwardsTextIterator m_underlyingIterator;
260
261     unsigned m_offset { 0 };
262     unsigned m_runOffset { 0 };
263     bool m_atBreak { true };
264 };
265
266 // Similar to the TextIterator, except that the chunks of text returned are "well behaved", meaning
267 // they never split up a word. This is useful for spell checking and perhaps one day for searching as well.
268 class WordAwareIterator {
269 public:
270     explicit WordAwareIterator(const SimpleRange&);
271
272     bool atEnd() const { return !m_didLookAhead && m_underlyingIterator.atEnd(); }
273     void advance();
274
275     StringView text() const;
276
277 private:
278     TextIterator m_underlyingIterator;
279
280     // Text from the previous chunk from the text iterator.
281     TextIteratorCopyableText m_previousText;
282
283     // Many chunks from text iterator concatenated.
284     Vector<UChar> m_buffer;
285
286     // Did we have to look ahead in the text iterator to confirm the current chunk?
287     bool m_didLookAhead { true };
288 };
289
290 } // namespace WebCore