b652a2929bde2d6def13c34c5ed05cd3e9d36bbc
[WebKit-https.git] / WebCore / khtml / editing / visible_text.h
1 /*
2  * Copyright (C) 2004 Apple Computer, 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 COMPUTER, 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 COMPUTER, 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 KHTML_EDITING_VISIBLE_TEXT_H
27 #define KHTML_EDITING_VISIBLE_TEXT_H
28
29 #include "dom/dom2_range.h"
30
31 namespace khtml {
32
33 class InlineTextBox;
34
35 // FIXME: Can't really answer this question without knowing the white-space mode.
36 // FIXME: Move this along with the white-space position functions above
37 // somewhere in the editing directory. It doesn't belong here.
38 inline bool isCollapsibleWhitespace(const QChar &c)
39 {
40     switch (c.unicode()) {
41         case ' ':
42         case '\n':
43             return true;
44         default:
45             return false;
46     }
47 }
48
49 QString plainText(const DOM::Range &);
50 DOM::Range findPlainText(const DOM::Range &, const QString &, bool forward, bool caseSensitive);
51
52 // Iterates through the DOM range, returning all the text, and 0-length boundaries
53 // at points where replaced elements break up the text flow.  The text comes back in
54 // chunks so as to optimize for performance of the iteration.
55
56 enum IteratorKind { CONTENT = 0, RUNFINDER = 1 };
57
58 class TextIterator
59 {
60 public:
61     TextIterator();
62     explicit TextIterator(const DOM::Range &, IteratorKind kind = CONTENT );
63     
64     bool atEnd() const { return !m_positionNode; }
65     void advance();
66     
67     long length() const { return m_textLength; }
68     const QChar *characters() const { return m_textCharacters; }
69     
70     DOM::Range range() const;
71         
72 private:
73     void exitNode();
74     bool handleTextNode();
75     bool handleReplacedElement();
76     bool handleNonTextNode();
77     void handleTextBox();
78     void emitCharacter(QChar, DOM::NodeImpl *textNode, DOM::NodeImpl *offsetBaseNode, long textStartOffset, long textEndOffset);
79     
80     // Current position, not necessarily of the text being returned, but position
81     // as we walk through the DOM tree.
82     DOM::NodeImpl *m_node;
83     long m_offset;
84     bool m_handledNode;
85     bool m_handledChildren;
86     
87     // End of the range.
88     DOM::NodeImpl *m_endContainer;
89     long m_endOffset;
90     DOM::NodeImpl *m_pastEndNode;
91     
92     // The current text and its position, in the form to be returned from the iterator.
93     DOM::NodeImpl *m_positionNode;
94     mutable DOM::NodeImpl *m_positionOffsetBaseNode;
95     mutable long m_positionStartOffset;
96     mutable long m_positionEndOffset;
97     const QChar *m_textCharacters;
98     long m_textLength;
99     
100     // Used when there is still some pending text from the current node; when these
101     // are false and 0, we go back to normal iterating.
102     bool m_needAnotherNewline;
103     InlineTextBox *m_textBox;
104     
105     // Used to do the whitespace collapsing logic.
106     DOM::NodeImpl *m_lastTextNode;    
107     bool m_lastTextNodeEndedWithCollapsedSpace;
108     QChar m_lastCharacter;
109     
110     // Used for whitespace characters that aren't in the DOM, so we can point at them.
111     QChar m_singleCharacterBuffer;
112 };
113
114 // Iterates through the DOM range, returning all the text, and 0-length boundaries
115 // at points where replaced elements break up the text flow.  The text comes back in
116 // chunks so as to optimize for performance of the iteration.
117 class SimplifiedBackwardsTextIterator
118 {
119 public:
120     SimplifiedBackwardsTextIterator();
121     explicit SimplifiedBackwardsTextIterator(const DOM::Range &);
122     
123     bool atEnd() const { return !m_positionNode; }
124     void advance();
125     
126     long length() const { return m_textLength; }
127     const QChar *characters() const { return m_textCharacters; }
128     
129     DOM::Range range() const;
130         
131 private:
132     void exitNode();
133     bool handleTextNode();
134     bool handleReplacedElement();
135     bool handleNonTextNode();
136     void emitCharacter(QChar, DOM::NodeImpl *Node, long startOffset, long endOffset);
137     void emitNewlineForBROrText();
138     
139     // Current position, not necessarily of the text being returned, but position
140     // as we walk through the DOM tree.
141     DOM::NodeImpl *m_node;
142     long m_offset;
143     bool m_handledNode;
144     bool m_handledChildren;
145     
146     // End of the range.
147     DOM::NodeImpl *m_startNode;
148     long m_startOffset;
149     
150     // The current text and its position, in the form to be returned from the iterator.
151     DOM::NodeImpl *m_positionNode;
152     long m_positionStartOffset;
153     long m_positionEndOffset;
154     const QChar *m_textCharacters;
155     long m_textLength;
156
157     // Used to do the whitespace logic.
158     DOM::NodeImpl *m_lastTextNode;    
159     QChar m_lastCharacter;
160     
161     // Used for whitespace characters that aren't in the DOM, so we can point at them.
162     QChar m_singleCharacterBuffer;
163 };
164
165 // Builds on the text iterator, adding a character position so we can walk one
166 // character at a time, or faster, as needed. Useful for searching.
167 class CharacterIterator {
168 public:
169     CharacterIterator();
170     explicit CharacterIterator(const DOM::Range &r);
171     
172     void advance(long numCharacters);
173     
174     bool atBreak() const { return m_atBreak; }
175     bool atEnd() const { return m_textIterator.atEnd(); }
176     
177     long length() const { return m_textIterator.length() - m_runOffset; }
178     const QChar *characters() const { return m_textIterator.characters() + m_runOffset; }
179     QString string(long numChars);
180     
181     long characterOffset() const { return m_offset; }
182     DOM::Range range() const;
183         
184 private:
185     long m_offset;
186     long m_runOffset;
187     bool m_atBreak;
188     
189     TextIterator m_textIterator;
190 };
191     
192 // Very similar to the TextIterator, except that the chunks of text returned are "well behaved",
193 // meaning they never end split up a word.  This is useful for spellcheck or (perhaps one day) searching.
194 class WordAwareIterator {
195 public:
196     WordAwareIterator();
197     explicit WordAwareIterator(const DOM::Range &r);
198
199     bool atEnd() const { return !m_didLookAhead && m_textIterator.atEnd(); }
200     void advance();
201     
202     long length() const;
203     const QChar *characters() const;
204     
205     // Range of the text we're currently returning
206     DOM::Range range() const { return m_range; }
207
208 private:
209     // text from the previous chunk from the textIterator
210     const QChar *m_previousText;
211     long m_previousLength;
212
213     // many chunks from textIterator concatenated
214     QString m_buffer;
215     
216     // Did we have to look ahead in the textIterator to confirm the current chunk?
217     bool m_didLookAhead;
218
219     DOM::Range m_range;
220
221     TextIterator m_textIterator;
222 };
223
224 }
225
226 #endif