Simple line layout(regression): Calling innerText on RenderFlow with multiple childre...
[WebKit-https.git] / Source / WebCore / editing / TextIterator.h
1 /*
2  * Copyright (C) 2004, 2006, 2009, 2014 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 #ifndef TextIterator_h
27 #define TextIterator_h
28
29 // FIXME: Move each iterator class into a separate header file.
30
31 #include "FindOptions.h"
32 #include "Range.h"
33 #include "TextIteratorBehavior.h"
34 #include <wtf/Vector.h>
35 #include <wtf/text/StringView.h>
36
37 namespace WebCore {
38
39 class InlineTextBox;
40 class RenderText;
41 class RenderTextFragment;
42 namespace SimpleLineLayout {
43 class RunResolver;
44 }
45
46 WEBCORE_EXPORT String plainText(const Range*, TextIteratorBehavior = TextIteratorDefaultBehavior, bool isDisplayString = false);
47 WEBCORE_EXPORT String plainTextReplacingNoBreakSpace(const Range*, TextIteratorBehavior = TextIteratorDefaultBehavior, bool isDisplayString = false);
48 Ref<Range> findPlainText(const Range&, const String&, FindOptions);
49
50 // FIXME: Move this somewhere else in the editing directory. It doesn't belong here.
51 bool isRendererReplacedElement(RenderObject*);
52
53 class BitStack {
54 public:
55     BitStack();
56     ~BitStack();
57
58     void push(bool);
59     void pop();
60
61     bool top() const;
62     unsigned size() const;
63
64 private:
65     unsigned m_size;
66     Vector<unsigned, 1> m_words;
67 };
68
69 class TextIteratorCopyableText {
70 public:
71     TextIteratorCopyableText()
72         : m_singleCharacter(0)
73         , m_offset(0)
74         , m_length(0)
75     {
76     }
77
78     StringView text() const { return m_singleCharacter ? StringView(&m_singleCharacter, 1) : StringView(m_string).substring(m_offset, m_length); }
79     void appendToStringBuilder(StringBuilder&) const;
80
81     void reset();
82     void set(String&&);
83     void set(String&&, unsigned offset, unsigned length);
84     void set(UChar);
85
86 private:
87     UChar m_singleCharacter;
88     String m_string;
89     unsigned m_offset;
90     unsigned m_length;
91 };
92
93 // Iterates through the DOM range, returning all the text, and 0-length boundaries
94 // at points where replaced elements break up the text flow. The text is delivered in
95 // the chunks it's already stored in, to avoid copying any text.
96
97 class TextIterator {
98 public:
99     WEBCORE_EXPORT explicit TextIterator(const Range*, TextIteratorBehavior = TextIteratorDefaultBehavior);
100     WEBCORE_EXPORT ~TextIterator();
101
102     bool atEnd() const { return !m_positionNode; }
103     WEBCORE_EXPORT void advance();
104
105     StringView text() const { ASSERT(!atEnd()); return m_text; }
106     WEBCORE_EXPORT Ref<Range> range() const;
107     WEBCORE_EXPORT Node* node() const;
108
109     const TextIteratorCopyableText& copyableText() const { ASSERT(!atEnd()); return m_copyableText; }
110     void appendTextToStringBuilder(StringBuilder& builder) const { copyableText().appendToStringBuilder(builder); }
111
112     WEBCORE_EXPORT static int rangeLength(const Range*, bool spacesForReplacedElements = false);
113     WEBCORE_EXPORT static RefPtr<Range> rangeFromLocationAndLength(ContainerNode* scope, int rangeLocation, int rangeLength, bool spacesForReplacedElements = false);
114     WEBCORE_EXPORT static bool getLocationAndLengthFromRange(Node* scope, const Range*, size_t& location, size_t& length);
115     WEBCORE_EXPORT static Ref<Range> subrange(Range* entireRange, int characterOffset, int characterCount);
116
117 private:
118     void exitNode();
119     bool shouldRepresentNodeOffsetZero();
120     bool shouldEmitSpaceBeforeAndAfterNode(Node&);
121     void representNodeOffsetZero();
122     bool handleTextNode();
123     bool handleReplacedElement();
124     bool handleNonTextNode();
125     void handleTextBox();
126     void handleTextNodeFirstLetter(RenderTextFragment&);
127     void emitCharacter(UChar, Node& characterNode, Node* offsetBaseNode, int textStartOffset, int textEndOffset);
128     void emitText(Text& textNode, RenderText&, int textStartOffset, int textEndOffset);
129
130     const TextIteratorBehavior m_behavior;
131
132     // Current position, not necessarily of the text being returned, but position as we walk through the DOM tree.
133     Node* m_node;
134     int m_offset;
135     bool m_handledNode;
136     bool m_handledChildren;
137     BitStack m_fullyClippedStack;
138
139     // The range.
140     Node* m_startContainer;
141     int m_startOffset;
142     Node* m_endContainer;
143     int m_endOffset;
144     Node* m_pastEndNode;
145
146     // The current text and its position, in the form to be returned from the iterator.
147     Node* m_positionNode;
148     mutable Node* m_positionOffsetBaseNode;
149     mutable int m_positionStartOffset;
150     mutable int m_positionEndOffset;
151     TextIteratorCopyableText m_copyableText;
152     StringView m_text;
153
154     // Used when there is still some pending text from the current node; when these are false and null, we go back to normal iterating.
155     bool m_needsAnotherNewline;
156     InlineTextBox* m_textBox;
157
158     // Used when iterating over :first-letter text to save pointer to remaining text box.
159     InlineTextBox* m_remainingTextBox;
160
161     // Used to point to RenderText object for :first-letter.
162     RenderText* m_firstLetterText;
163
164     // Used to do the whitespace collapsing logic.
165     Text* m_lastTextNode;
166     bool m_lastTextNodeEndedWithCollapsedSpace;
167     UChar m_lastCharacter;
168
169     // Used to do simple line layout run logic.
170     bool m_nextRunNeedsWhitespace { false };
171     unsigned m_previousTextLengthInFlow { 0 };
172     std::unique_ptr<SimpleLineLayout::RunResolver> m_flowRunResolverCache;
173
174     // Used when text boxes are out of order (Hebrew/Arabic with embedded LTR text)
175     Vector<InlineTextBox*> m_sortedTextBoxes;
176     size_t m_sortedTextBoxesPosition;
177
178     // Used when deciding whether to emit a "positioning" (e.g. newline) before any other content
179     bool m_hasEmitted;
180
181     // Used when deciding text fragment created by :first-letter should be looked into.
182     bool m_handledFirstLetter;
183 };
184
185 // Iterates through the DOM range, returning all the text, and 0-length boundaries
186 // at points where replaced elements break up the text flow. The text comes back in
187 // chunks so as to optimize for performance of the iteration.
188 class SimplifiedBackwardsTextIterator {
189 public:
190     explicit SimplifiedBackwardsTextIterator(const Range&, TextIteratorBehavior = TextIteratorDefaultBehavior);
191
192     bool atEnd() const { return !m_positionNode; }
193     void advance();
194
195     StringView text() const { ASSERT(!atEnd()); return m_text; }
196     WEBCORE_EXPORT Ref<Range> range() const;
197     Node* node() const { ASSERT(!atEnd()); return m_node; }
198
199 private:
200     void exitNode();
201     bool handleTextNode();
202     RenderText* handleFirstLetter(int& startOffset, int& offsetInNode);
203     bool handleReplacedElement();
204     bool handleNonTextNode();
205     void emitCharacter(UChar, Node&, int startOffset, int endOffset);
206     bool advanceRespectingRange(Node*);
207
208     const TextIteratorBehavior m_behavior;
209
210     // Current position, not necessarily of the text being returned, but position as we walk through the DOM tree.
211     Node* m_node;
212     int m_offset;
213     bool m_handledNode;
214     bool m_handledChildren;
215     BitStack m_fullyClippedStack;
216
217     // The range.
218     Node* m_startContainer;
219     int m_startOffset;
220     Node* m_endContainer;
221     int m_endOffset;
222     
223     // The current text and its position, in the form to be returned from the iterator.
224     Node* m_positionNode;
225     int m_positionStartOffset;
226     int m_positionEndOffset;
227     TextIteratorCopyableText m_copyableText;
228     StringView m_text;
229
230     // Used to do the whitespace logic.
231     Text* m_lastTextNode;
232     UChar m_lastCharacter;
233
234     // Whether m_node has advanced beyond the iteration range (i.e. m_startContainer).
235     bool m_havePassedStartContainer;
236
237     // Should handle first-letter renderer in the next call to handleTextNode.
238     bool m_shouldHandleFirstLetter;
239 };
240
241 // Builds on the text iterator, adding a character position so we can walk one
242 // character at a time, or faster, as needed. Useful for searching.
243 class CharacterIterator {
244 public:
245     explicit CharacterIterator(const Range&, TextIteratorBehavior = TextIteratorDefaultBehavior);
246     
247     bool atEnd() const { return m_underlyingIterator.atEnd(); }
248     void advance(int numCharacters);
249     
250     StringView text() const { return m_underlyingIterator.text().substring(m_runOffset); }
251     Ref<Range> range() const;
252
253     bool atBreak() const { return m_atBreak; }
254     int characterOffset() const { return m_offset; }
255
256 private:
257     TextIterator m_underlyingIterator;
258
259     int m_offset;
260     int m_runOffset;
261     bool m_atBreak;
262 };
263     
264 class BackwardsCharacterIterator {
265 public:
266     explicit BackwardsCharacterIterator(const Range&);
267
268     bool atEnd() const { return m_underlyingIterator.atEnd(); }
269     void advance(int numCharacters);
270
271     Ref<Range> range() const;
272
273 private:
274     SimplifiedBackwardsTextIterator m_underlyingIterator;
275
276     int m_offset;
277     int m_runOffset;
278     bool m_atBreak;
279 };
280
281 // Similar to the TextIterator, except that the chunks of text returned are "well behaved", meaning
282 // they never split up a word. This is useful for spell checking and perhaps one day for searching as well.
283 class WordAwareIterator {
284 public:
285     explicit WordAwareIterator(const Range&);
286
287     bool atEnd() const { return !m_didLookAhead && m_underlyingIterator.atEnd(); }
288     void advance();
289
290     StringView text() const;
291
292 private:
293     TextIterator m_underlyingIterator;
294
295     // Text from the previous chunk from the text iterator.
296     TextIteratorCopyableText m_previousText;
297
298     // Many chunks from text iterator concatenated.
299     Vector<UChar> m_buffer;
300     
301     // Did we have to look ahead in the text iterator to confirm the current chunk?
302     bool m_didLookAhead;
303 };
304
305 }
306
307 #endif