WebCore:
[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     static long TextIterator::rangeLength(const DOM::Range &r);
73     static void TextIterator::setRangeFromLocationAndLength (const DOM::Range &range, DOM::Range &resultRange, long rangeLocation, long rangeLength);
74     
75 private:
76     void exitNode();
77     bool handleTextNode();
78     bool handleReplacedElement();
79     bool handleNonTextNode();
80     void handleTextBox();
81     void emitCharacter(QChar, DOM::NodeImpl *textNode, DOM::NodeImpl *offsetBaseNode, long textStartOffset, long textEndOffset);
82     
83     // Current position, not necessarily of the text being returned, but position
84     // as we walk through the DOM tree.
85     DOM::NodeImpl *m_node;
86     long m_offset;
87     bool m_handledNode;
88     bool m_handledChildren;
89     
90     // End of the range.
91     DOM::NodeImpl *m_endContainer;
92     long m_endOffset;
93     DOM::NodeImpl *m_pastEndNode;
94     
95     // The current text and its position, in the form to be returned from the iterator.
96     DOM::NodeImpl *m_positionNode;
97     mutable DOM::NodeImpl *m_positionOffsetBaseNode;
98     mutable long m_positionStartOffset;
99     mutable long m_positionEndOffset;
100     const QChar *m_textCharacters;
101     long m_textLength;
102     
103     // Used when there is still some pending text from the current node; when these
104     // are false and 0, we go back to normal iterating.
105     bool m_needAnotherNewline;
106     InlineTextBox *m_textBox;
107     
108     // Used to do the whitespace collapsing logic.
109     DOM::NodeImpl *m_lastTextNode;    
110     bool m_lastTextNodeEndedWithCollapsedSpace;
111     QChar m_lastCharacter;
112     
113     // Used for whitespace characters that aren't in the DOM, so we can point at them.
114     QChar m_singleCharacterBuffer;
115 };
116
117 // Iterates through the DOM range, returning all the text, and 0-length boundaries
118 // at points where replaced elements break up the text flow.  The text comes back in
119 // chunks so as to optimize for performance of the iteration.
120 class SimplifiedBackwardsTextIterator
121 {
122 public:
123     SimplifiedBackwardsTextIterator();
124     explicit SimplifiedBackwardsTextIterator(const DOM::Range &);
125     
126     bool atEnd() const { return !m_positionNode; }
127     void advance();
128     
129     long length() const { return m_textLength; }
130     const QChar *characters() const { return m_textCharacters; }
131     
132     DOM::Range range() const;
133         
134 private:
135     void exitNode();
136     bool handleTextNode();
137     bool handleReplacedElement();
138     bool handleNonTextNode();
139     void emitCharacter(QChar, DOM::NodeImpl *Node, long startOffset, long endOffset);
140     void emitNewlineForBROrText();
141     
142     // Current position, not necessarily of the text being returned, but position
143     // as we walk through the DOM tree.
144     DOM::NodeImpl *m_node;
145     long m_offset;
146     bool m_handledNode;
147     bool m_handledChildren;
148     
149     // End of the range.
150     DOM::NodeImpl *m_startNode;
151     long m_startOffset;
152     
153     // The current text and its position, in the form to be returned from the iterator.
154     DOM::NodeImpl *m_positionNode;
155     long m_positionStartOffset;
156     long m_positionEndOffset;
157     const QChar *m_textCharacters;
158     long m_textLength;
159
160     // Used to do the whitespace logic.
161     DOM::NodeImpl *m_lastTextNode;    
162     QChar m_lastCharacter;
163     
164     // Used for whitespace characters that aren't in the DOM, so we can point at them.
165     QChar m_singleCharacterBuffer;
166 };
167
168 // Builds on the text iterator, adding a character position so we can walk one
169 // character at a time, or faster, as needed. Useful for searching.
170 class CharacterIterator {
171 public:
172     CharacterIterator();
173     explicit CharacterIterator(const DOM::Range &r);
174     
175     void advance(long numCharacters);
176     
177     bool atBreak() const { return m_atBreak; }
178     bool atEnd() const { return m_textIterator.atEnd(); }
179     
180     long length() const { return m_textIterator.length() - m_runOffset; }
181     const QChar *characters() const { return m_textIterator.characters() + m_runOffset; }
182     QString string(long numChars);
183     
184     long characterOffset() const { return m_offset; }
185     DOM::Range range() const;
186         
187 private:
188     long m_offset;
189     long m_runOffset;
190     bool m_atBreak;
191     
192     TextIterator m_textIterator;
193 };
194     
195 // Very similar to the TextIterator, except that the chunks of text returned are "well behaved",
196 // meaning they never end split up a word.  This is useful for spellcheck or (perhaps one day) searching.
197 class WordAwareIterator {
198 public:
199     WordAwareIterator();
200     explicit WordAwareIterator(const DOM::Range &r);
201
202     bool atEnd() const { return !m_didLookAhead && m_textIterator.atEnd(); }
203     void advance();
204     
205     long length() const;
206     const QChar *characters() const;
207     
208     // Range of the text we're currently returning
209     DOM::Range range() const { return m_range; }
210
211 private:
212     // text from the previous chunk from the textIterator
213     const QChar *m_previousText;
214     long m_previousLength;
215
216     // many chunks from textIterator concatenated
217     QString m_buffer;
218     
219     // Did we have to look ahead in the textIterator to confirm the current chunk?
220     bool m_didLookAhead;
221
222     DOM::Range m_range;
223
224     TextIterator m_textIterator;
225 };
226
227 }
228
229 #endif