Modernize and streamline HTMLTokenizer
[WebKit-https.git] / Source / WebCore / platform / text / SegmentedString.cpp
1 /*
2     Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
3
4     This library is free software; you can redistribute it and/or
5     modify it under the terms of the GNU Library General Public
6     License as published by the Free Software Foundation; either
7     version 2 of the License, or (at your option) any later version.
8
9     This library is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12     Library General Public License for more details.
13
14     You should have received a copy of the GNU Library General Public License
15     along with this library; see the file COPYING.LIB.  If not, write to
16     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17     Boston, MA 02110-1301, USA.
18 */
19
20 #include "config.h"
21 #include "SegmentedString.h"
22
23 #include <wtf/text/TextPosition.h>
24
25 namespace WebCore {
26
27 SegmentedString::SegmentedString(const SegmentedString& other)
28     : m_pushedChar1(other.m_pushedChar1)
29     , m_pushedChar2(other.m_pushedChar2)
30     , m_currentString(other.m_currentString)
31     , m_numberOfCharactersConsumedPriorToCurrentString(other.m_numberOfCharactersConsumedPriorToCurrentString)
32     , m_numberOfCharactersConsumedPriorToCurrentLine(other.m_numberOfCharactersConsumedPriorToCurrentLine)
33     , m_currentLine(other.m_currentLine)
34     , m_substrings(other.m_substrings)
35     , m_closed(other.m_closed)
36     , m_empty(other.m_empty)
37     , m_fastPathFlags(other.m_fastPathFlags)
38     , m_advanceFunc(other.m_advanceFunc)
39     , m_advanceAndUpdateLineNumberFunc(other.m_advanceAndUpdateLineNumberFunc)
40 {
41     if (m_pushedChar2)
42         m_currentChar = m_pushedChar2;
43     else if (m_pushedChar1)
44         m_currentChar = m_pushedChar1;
45     else
46         m_currentChar = m_currentString.m_length ? m_currentString.getCurrentChar() : 0;
47 }
48
49 SegmentedString& SegmentedString::operator=(const SegmentedString& other)
50 {
51     m_pushedChar1 = other.m_pushedChar1;
52     m_pushedChar2 = other.m_pushedChar2;
53     m_currentString = other.m_currentString;
54     m_substrings = other.m_substrings;
55     if (m_pushedChar2)
56         m_currentChar = m_pushedChar2;
57     else if (m_pushedChar1)
58         m_currentChar = m_pushedChar1;
59     else
60         m_currentChar = m_currentString.m_length ? m_currentString.getCurrentChar() : 0;
61
62     m_closed = other.m_closed;
63     m_empty = other.m_empty;
64     m_fastPathFlags = other.m_fastPathFlags;
65     m_numberOfCharactersConsumedPriorToCurrentString = other.m_numberOfCharactersConsumedPriorToCurrentString;
66     m_numberOfCharactersConsumedPriorToCurrentLine = other.m_numberOfCharactersConsumedPriorToCurrentLine;
67     m_currentLine = other.m_currentLine;
68
69     m_advanceFunc = other.m_advanceFunc;
70     m_advanceAndUpdateLineNumberFunc = other.m_advanceAndUpdateLineNumberFunc;
71
72     return *this;
73 }
74
75 unsigned SegmentedString::length() const
76 {
77     unsigned length = m_currentString.m_length;
78     if (m_pushedChar1) {
79         ++length;
80         if (m_pushedChar2)
81             ++length;
82     }
83     if (isComposite()) {
84         Deque<SegmentedSubstring>::const_iterator it = m_substrings.begin();
85         Deque<SegmentedSubstring>::const_iterator e = m_substrings.end();
86         for (; it != e; ++it)
87             length += it->m_length;
88     }
89     return length;
90 }
91
92 void SegmentedString::setExcludeLineNumbers()
93 {
94     m_currentString.setExcludeLineNumbers();
95     if (isComposite()) {
96         Deque<SegmentedSubstring>::iterator it = m_substrings.begin();
97         Deque<SegmentedSubstring>::iterator e = m_substrings.end();
98         for (; it != e; ++it)
99             it->setExcludeLineNumbers();
100     }
101 }
102
103 void SegmentedString::clear()
104 {
105     m_pushedChar1 = 0;
106     m_pushedChar2 = 0;
107     m_currentChar = 0;
108     m_currentString.clear();
109     m_numberOfCharactersConsumedPriorToCurrentString = 0;
110     m_numberOfCharactersConsumedPriorToCurrentLine = 0;
111     m_currentLine = 0;
112     m_substrings.clear();
113     m_closed = false;
114     m_empty = true;
115     m_fastPathFlags = NoFastPath;
116     m_advanceFunc = &SegmentedString::advanceEmpty;
117     m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
118 }
119
120 void SegmentedString::append(const SegmentedSubstring& s)
121 {
122     ASSERT(!m_closed);
123     if (!s.m_length)
124         return;
125
126     if (!m_currentString.m_length) {
127         m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
128         m_currentString = s;
129         updateAdvanceFunctionPointers();
130     } else
131         m_substrings.append(s);
132     m_empty = false;
133 }
134
135 void SegmentedString::pushBack(const SegmentedSubstring& s)
136 {
137     ASSERT(!m_pushedChar1);
138     ASSERT(!s.numberOfCharactersConsumed());
139     if (!s.m_length)
140         return;
141
142     // FIXME: We're assuming that the characters were originally consumed by
143     //        this SegmentedString.  We're also ASSERTing that s is a fresh
144     //        SegmentedSubstring.  These assumptions are sufficient for our
145     //        current use, but we might need to handle the more elaborate
146     //        cases in the future.
147     m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
148     m_numberOfCharactersConsumedPriorToCurrentString -= s.m_length;
149     if (!m_currentString.m_length) {
150         m_currentString = s;
151         updateAdvanceFunctionPointers();
152     } else {
153         // Shift our m_currentString into our list.
154         m_substrings.prepend(m_currentString);
155         m_currentString = s;
156         updateAdvanceFunctionPointers();
157     }
158     m_empty = false;
159 }
160
161 void SegmentedString::close()
162 {
163     // Closing a stream twice is likely a coding mistake.
164     ASSERT(!m_closed);
165     m_closed = true;
166 }
167
168 void SegmentedString::append(const SegmentedString& s)
169 {
170     ASSERT(!m_closed);
171     ASSERT(!s.m_pushedChar1);
172     append(s.m_currentString);
173     if (s.isComposite()) {
174         Deque<SegmentedSubstring>::const_iterator it = s.m_substrings.begin();
175         Deque<SegmentedSubstring>::const_iterator e = s.m_substrings.end();
176         for (; it != e; ++it)
177             append(*it);
178     }
179     m_currentChar = m_pushedChar1 ? m_pushedChar1 : (m_currentString.m_length ? m_currentString.getCurrentChar() : 0);
180 }
181
182 void SegmentedString::pushBack(const SegmentedString& s)
183 {
184     ASSERT(!m_pushedChar1);
185     ASSERT(!s.m_pushedChar1);
186     if (s.isComposite()) {
187         Deque<SegmentedSubstring>::const_reverse_iterator it = s.m_substrings.rbegin();
188         Deque<SegmentedSubstring>::const_reverse_iterator e = s.m_substrings.rend();
189         for (; it != e; ++it)
190             pushBack(*it);
191     }
192     pushBack(s.m_currentString);
193     m_currentChar = m_pushedChar1 ? m_pushedChar1 : (m_currentString.m_length ? m_currentString.getCurrentChar() : 0);
194 }
195
196 void SegmentedString::advanceSubstring()
197 {
198     if (isComposite()) {
199         m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
200         m_currentString = m_substrings.takeFirst();
201         // If we've previously consumed some characters of the non-current
202         // string, we now account for those characters as part of the current
203         // string, not as part of "prior to current string."
204         m_numberOfCharactersConsumedPriorToCurrentString -= m_currentString.numberOfCharactersConsumed();
205         updateAdvanceFunctionPointers();
206     } else {
207         m_currentString.clear();
208         m_empty = true;
209         m_fastPathFlags = NoFastPath;
210         m_advanceFunc = &SegmentedString::advanceEmpty;
211         m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
212     }
213 }
214
215 String SegmentedString::toString() const
216 {
217     StringBuilder result;
218     if (m_pushedChar1) {
219         result.append(m_pushedChar1);
220         if (m_pushedChar2)
221             result.append(m_pushedChar2);
222     }
223     m_currentString.appendTo(result);
224     if (isComposite()) {
225         Deque<SegmentedSubstring>::const_iterator it = m_substrings.begin();
226         Deque<SegmentedSubstring>::const_iterator e = m_substrings.end();
227         for (; it != e; ++it)
228             it->appendTo(result);
229     }
230     return result.toString();
231 }
232
233 void SegmentedString::advancePastNonNewlines(unsigned count, UChar* consumedCharacters)
234 {
235     ASSERT_WITH_SECURITY_IMPLICATION(count <= length());
236     for (unsigned i = 0; i < count; ++i) {
237         consumedCharacters[i] = currentChar();
238         advancePastNonNewline();
239     }
240 }
241
242 void SegmentedString::advance8()
243 {
244     ASSERT(!m_pushedChar1);
245     decrementAndCheckLength();
246     m_currentChar = m_currentString.incrementAndGetCurrentChar8();
247 }
248
249 void SegmentedString::advance16()
250 {
251     ASSERT(!m_pushedChar1);
252     decrementAndCheckLength();
253     m_currentChar = m_currentString.incrementAndGetCurrentChar16();
254 }
255
256 void SegmentedString::advanceAndUpdateLineNumber8()
257 {
258     ASSERT(!m_pushedChar1);
259     ASSERT(m_currentString.getCurrentChar() == m_currentChar);
260     if (m_currentChar == '\n') {
261         ++m_currentLine;
262         m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1;
263     }
264     decrementAndCheckLength();
265     m_currentChar = m_currentString.incrementAndGetCurrentChar8();
266 }
267
268 void SegmentedString::advanceAndUpdateLineNumber16()
269 {
270     ASSERT(!m_pushedChar1);
271     ASSERT(m_currentString.getCurrentChar() == m_currentChar);
272     if (m_currentChar == '\n') {
273         ++m_currentLine;
274         m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1;
275     }
276     decrementAndCheckLength();
277     m_currentChar = m_currentString.incrementAndGetCurrentChar16();
278 }
279
280 void SegmentedString::advanceSlowCase()
281 {
282     if (m_pushedChar1) {
283         m_pushedChar1 = m_pushedChar2;
284         m_pushedChar2 = 0;
285
286         if (m_pushedChar1) {
287             m_currentChar = m_pushedChar1;
288             return;
289         }
290
291         updateAdvanceFunctionPointers();
292     } else if (m_currentString.m_length) {
293         if (--m_currentString.m_length == 0)
294             advanceSubstring();
295     } else if (!isComposite()) {
296         m_currentString.clear();
297         m_empty = true;
298         m_fastPathFlags = NoFastPath;
299         m_advanceFunc = &SegmentedString::advanceEmpty;
300         m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
301     }
302     m_currentChar = m_currentString.m_length ? m_currentString.getCurrentChar() : 0;
303 }
304
305 void SegmentedString::advanceAndUpdateLineNumberSlowCase()
306 {
307     if (m_pushedChar1) {
308         m_pushedChar1 = m_pushedChar2;
309         m_pushedChar2 = 0;
310
311         if (m_pushedChar1) {
312             m_currentChar = m_pushedChar1;
313             return;
314         }
315
316         updateAdvanceFunctionPointers();
317     } else if (m_currentString.m_length) {
318         if (m_currentString.getCurrentChar() == '\n' && m_currentString.doNotExcludeLineNumbers()) {
319             ++m_currentLine;
320             // Plus 1 because numberOfCharactersConsumed value hasn't incremented yet; it does with m_length decrement below.
321             m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1;
322         }
323         if (--m_currentString.m_length == 0)
324             advanceSubstring();
325         else
326             m_currentString.incrementAndGetCurrentChar(); // Only need the ++
327     } else if (!isComposite()) {
328         m_currentString.clear();
329         m_empty = true;
330         m_fastPathFlags = NoFastPath;
331         m_advanceFunc = &SegmentedString::advanceEmpty;
332         m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
333     }
334
335     m_currentChar = m_currentString.m_length ? m_currentString.getCurrentChar() : 0;
336 }
337
338 void SegmentedString::advanceEmpty()
339 {
340     ASSERT(!m_currentString.m_length && !isComposite());
341     m_currentChar = 0;
342 }
343
344 void SegmentedString::updateSlowCaseFunctionPointers()
345 {
346     m_fastPathFlags = NoFastPath;
347     m_advanceFunc = &SegmentedString::advanceSlowCase;
348     m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceAndUpdateLineNumberSlowCase;
349 }
350
351 OrdinalNumber SegmentedString::currentLine() const
352 {
353     return OrdinalNumber::fromZeroBasedInt(m_currentLine);
354 }
355
356 OrdinalNumber SegmentedString::currentColumn() const
357 {
358     return OrdinalNumber::fromZeroBasedInt(numberOfCharactersConsumed() - m_numberOfCharactersConsumedPriorToCurrentLine);
359 }
360
361 void SegmentedString::setCurrentPosition(OrdinalNumber line, OrdinalNumber columnAftreProlog, int prologLength)
362 {
363     m_currentLine = line.zeroBasedInt();
364     m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + prologLength - columnAftreProlog.zeroBasedInt();
365 }
366
367 SegmentedString::AdvancePastResult SegmentedString::advancePastSlowCase(const char* literal, bool caseSensitive)
368 {
369     unsigned length = strlen(literal);
370     if (length > this->length())
371         return NotEnoughCharacters;
372     UChar* consumedCharacters;
373     String consumedString = String::createUninitialized(length, consumedCharacters);
374     advancePastNonNewlines(length, consumedCharacters);
375     if (consumedString.startsWith(literal, caseSensitive))
376         return DidMatch;
377     pushBack(SegmentedString(consumedString));
378     return DidNotMatch;
379 }
380
381 }