b0dc3d3ddf4664a880077772270d608e9ccf0661
[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 namespace WebCore {
24
25 SegmentedString::SegmentedString(const SegmentedString& other)
26     : m_pushedChar1(other.m_pushedChar1)
27     , m_pushedChar2(other.m_pushedChar2)
28     , m_currentString(other.m_currentString)
29     , m_numberOfCharactersConsumedPriorToCurrentString(other.m_numberOfCharactersConsumedPriorToCurrentString)
30     , m_numberOfCharactersConsumedPriorToCurrentLine(other.m_numberOfCharactersConsumedPriorToCurrentLine)
31     , m_currentLine(other.m_currentLine)
32     , m_substrings(other.m_substrings)
33     , m_closed(other.m_closed)
34     , m_empty(other.m_empty)
35     , m_fastPathFlags(other.m_fastPathFlags)
36     , m_advanceFunc(other.m_advanceFunc)
37     , m_advanceAndUpdateLineNumberFunc(other.m_advanceAndUpdateLineNumberFunc)
38 {
39     if (m_pushedChar2)
40         m_currentChar = m_pushedChar2;
41     else if (m_pushedChar1)
42         m_currentChar = m_pushedChar1;
43     else
44         m_currentChar = m_currentString.m_length ? m_currentString.getCurrentChar() : 0;
45 }
46
47 const SegmentedString& SegmentedString::operator=(const SegmentedString& other)
48 {
49     m_pushedChar1 = other.m_pushedChar1;
50     m_pushedChar2 = other.m_pushedChar2;
51     m_currentString = other.m_currentString;
52     m_substrings = other.m_substrings;
53     if (m_pushedChar2)
54         m_currentChar = m_pushedChar2;
55     else if (m_pushedChar1)
56         m_currentChar = m_pushedChar1;
57     else
58         m_currentChar = m_currentString.m_length ? m_currentString.getCurrentChar() : 0;
59
60     m_closed = other.m_closed;
61     m_empty = other.m_empty;
62     m_fastPathFlags = other.m_fastPathFlags;
63     m_numberOfCharactersConsumedPriorToCurrentString = other.m_numberOfCharactersConsumedPriorToCurrentString;
64     m_numberOfCharactersConsumedPriorToCurrentLine = other.m_numberOfCharactersConsumedPriorToCurrentLine;
65     m_currentLine = other.m_currentLine;
66
67     m_advanceFunc = other.m_advanceFunc;
68     m_advanceAndUpdateLineNumberFunc = other.m_advanceAndUpdateLineNumberFunc;
69
70     return *this;
71 }
72
73 unsigned SegmentedString::length() const
74 {
75     unsigned length = m_currentString.m_length;
76     if (m_pushedChar1) {
77         ++length;
78         if (m_pushedChar2)
79             ++length;
80     }
81     if (isComposite()) {
82         Deque<SegmentedSubstring>::const_iterator it = m_substrings.begin();
83         Deque<SegmentedSubstring>::const_iterator e = m_substrings.end();
84         for (; it != e; ++it)
85             length += it->m_length;
86     }
87     return length;
88 }
89
90 void SegmentedString::setExcludeLineNumbers()
91 {
92     m_currentString.setExcludeLineNumbers();
93     if (isComposite()) {
94         Deque<SegmentedSubstring>::iterator it = m_substrings.begin();
95         Deque<SegmentedSubstring>::iterator e = m_substrings.end();
96         for (; it != e; ++it)
97             it->setExcludeLineNumbers();
98     }
99 }
100
101 void SegmentedString::clear()
102 {
103     m_pushedChar1 = 0;
104     m_pushedChar2 = 0;
105     m_currentChar = 0;
106     m_currentString.clear();
107     m_numberOfCharactersConsumedPriorToCurrentString = 0;
108     m_numberOfCharactersConsumedPriorToCurrentLine = 0;
109     m_currentLine = 0;
110     m_substrings.clear();
111     m_closed = false;
112     m_empty = true;
113     m_fastPathFlags = NoFastPath;
114     m_advanceFunc = &SegmentedString::advanceEmpty;
115     m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
116 }
117
118 void SegmentedString::append(const SegmentedSubstring& s)
119 {
120     ASSERT(!m_closed);
121     if (!s.m_length)
122         return;
123
124     if (!m_currentString.m_length) {
125         m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
126         m_currentString = s;
127         updateAdvanceFunctionPointers();
128     } else
129         m_substrings.append(s);
130     m_empty = false;
131 }
132
133 void SegmentedString::prepend(const SegmentedSubstring& s)
134 {
135     ASSERT(!escaped());
136     ASSERT(!s.numberOfCharactersConsumed());
137     if (!s.m_length)
138         return;
139
140     // FIXME: We're assuming that the prepend were originally consumed by
141     //        this SegmentedString.  We're also ASSERTing that s is a fresh
142     //        SegmentedSubstring.  These assumptions are sufficient for our
143     //        current use, but we might need to handle the more elaborate
144     //        cases in the future.
145     m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
146     m_numberOfCharactersConsumedPriorToCurrentString -= s.m_length;
147     if (!m_currentString.m_length) {
148         m_currentString = s;
149         updateAdvanceFunctionPointers();
150     } else {
151         // Shift our m_currentString into our list.
152         m_substrings.prepend(m_currentString);
153         m_currentString = s;
154         updateAdvanceFunctionPointers();
155     }
156     m_empty = false;
157 }
158
159 void SegmentedString::close()
160 {
161     // Closing a stream twice is likely a coding mistake.
162     ASSERT(!m_closed);
163     m_closed = true;
164 }
165
166 void SegmentedString::append(const SegmentedString& s)
167 {
168     ASSERT(!m_closed);
169     ASSERT(!s.escaped());
170     append(s.m_currentString);
171     if (s.isComposite()) {
172         Deque<SegmentedSubstring>::const_iterator it = s.m_substrings.begin();
173         Deque<SegmentedSubstring>::const_iterator e = s.m_substrings.end();
174         for (; it != e; ++it)
175             append(*it);
176     }
177     m_currentChar = m_pushedChar1 ? m_pushedChar1 : (m_currentString.m_length ? m_currentString.getCurrentChar() : 0);
178 }
179
180 void SegmentedString::prepend(const SegmentedString& s)
181 {
182     ASSERT(!escaped());
183     ASSERT(!s.escaped());
184     if (s.isComposite()) {
185         Deque<SegmentedSubstring>::const_reverse_iterator it = s.m_substrings.rbegin();
186         Deque<SegmentedSubstring>::const_reverse_iterator e = s.m_substrings.rend();
187         for (; it != e; ++it)
188             prepend(*it);
189     }
190     prepend(s.m_currentString);
191     m_currentChar = m_pushedChar1 ? m_pushedChar1 : (m_currentString.m_length ? m_currentString.getCurrentChar() : 0);
192 }
193
194 void SegmentedString::advanceSubstring()
195 {
196     if (isComposite()) {
197         m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
198         m_currentString = m_substrings.takeFirst();
199         // If we've previously consumed some characters of the non-current
200         // string, we now account for those characters as part of the current
201         // string, not as part of "prior to current string."
202         m_numberOfCharactersConsumedPriorToCurrentString -= m_currentString.numberOfCharactersConsumed();
203         updateAdvanceFunctionPointers();
204     } else {
205         m_currentString.clear();
206         m_empty = true;
207         m_fastPathFlags = NoFastPath;
208         m_advanceFunc = &SegmentedString::advanceEmpty;
209         m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
210     }
211 }
212
213 String SegmentedString::toString() const
214 {
215     StringBuilder result;
216     if (m_pushedChar1) {
217         result.append(m_pushedChar1);
218         if (m_pushedChar2)
219             result.append(m_pushedChar2);
220     }
221     m_currentString.appendTo(result);
222     if (isComposite()) {
223         Deque<SegmentedSubstring>::const_iterator it = m_substrings.begin();
224         Deque<SegmentedSubstring>::const_iterator e = m_substrings.end();
225         for (; it != e; ++it)
226             it->appendTo(result);
227     }
228     return result.toString();
229 }
230
231 void SegmentedString::advance(unsigned count, UChar* consumedCharacters)
232 {
233     ASSERT_WITH_SECURITY_IMPLICATION(count <= length());
234     for (unsigned i = 0; i < count; ++i) {
235         consumedCharacters[i] = currentChar();
236         advance();
237     }
238 }
239
240 void SegmentedString::advance8()
241 {
242     ASSERT(!m_pushedChar1);
243     decrementAndCheckLength();
244     m_currentChar = m_currentString.incrementAndGetCurrentChar8();
245 }
246
247 void SegmentedString::advance16()
248 {
249     ASSERT(!m_pushedChar1);
250     decrementAndCheckLength();
251     m_currentChar = m_currentString.incrementAndGetCurrentChar16();
252 }
253
254 void SegmentedString::advanceAndUpdateLineNumber8()
255 {
256     ASSERT(!m_pushedChar1);
257     ASSERT(m_currentString.getCurrentChar() == m_currentChar);
258     if (m_currentChar == '\n') {
259         ++m_currentLine;
260         m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1;
261     }
262     decrementAndCheckLength();
263     m_currentChar = m_currentString.incrementAndGetCurrentChar8();
264 }
265
266 void SegmentedString::advanceAndUpdateLineNumber16()
267 {
268     ASSERT(!m_pushedChar1);
269     ASSERT(m_currentString.getCurrentChar() == m_currentChar);
270     if (m_currentChar == '\n') {
271         ++m_currentLine;
272         m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1;
273     }
274     decrementAndCheckLength();
275     m_currentChar = m_currentString.incrementAndGetCurrentChar16();
276 }
277
278 void SegmentedString::advanceSlowCase()
279 {
280     if (m_pushedChar1) {
281         m_pushedChar1 = m_pushedChar2;
282         m_pushedChar2 = 0;
283
284         if (m_pushedChar1) {
285             m_currentChar = m_pushedChar1;
286             return;
287         }
288
289         updateAdvanceFunctionPointers();
290     } else if (m_currentString.m_length) {
291         if (--m_currentString.m_length == 0)
292             advanceSubstring();
293     } else if (!isComposite()) {
294         m_currentString.clear();
295         m_empty = true;
296         m_fastPathFlags = NoFastPath;
297         m_advanceFunc = &SegmentedString::advanceEmpty;
298         m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
299     }
300     m_currentChar = m_currentString.m_length ? m_currentString.getCurrentChar() : 0;
301 }
302
303 void SegmentedString::advanceAndUpdateLineNumberSlowCase()
304 {
305     if (m_pushedChar1) {
306         m_pushedChar1 = m_pushedChar2;
307         m_pushedChar2 = 0;
308
309         if (m_pushedChar1) {
310             m_currentChar = m_pushedChar1;
311             return;
312         }
313
314         updateAdvanceFunctionPointers();
315     } else if (m_currentString.m_length) {
316         if (m_currentString.getCurrentChar() == '\n' && m_currentString.doNotExcludeLineNumbers()) {
317             ++m_currentLine;
318             // Plus 1 because numberOfCharactersConsumed value hasn't incremented yet; it does with m_length decrement below.
319             m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1;
320         }
321         if (--m_currentString.m_length == 0)
322             advanceSubstring();
323         else
324             m_currentString.incrementAndGetCurrentChar(); // Only need the ++
325     } else if (!isComposite()) {
326         m_currentString.clear();
327         m_empty = true;
328         m_fastPathFlags = NoFastPath;
329         m_advanceFunc = &SegmentedString::advanceEmpty;
330         m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty;
331     }
332
333     m_currentChar = m_currentString.m_length ? m_currentString.getCurrentChar() : 0;
334 }
335
336 void SegmentedString::advanceEmpty()
337 {
338     ASSERT(!m_currentString.m_length && !isComposite());
339     m_currentChar = 0;
340 }
341
342 void SegmentedString::updateSlowCaseFunctionPointers()
343 {
344     m_fastPathFlags = NoFastPath;
345     m_advanceFunc = &SegmentedString::advanceSlowCase;
346     m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceAndUpdateLineNumberSlowCase;
347 }
348
349 OrdinalNumber SegmentedString::currentLine() const
350 {
351     return OrdinalNumber::fromZeroBasedInt(m_currentLine);
352 }
353
354 OrdinalNumber SegmentedString::currentColumn() const
355 {
356     int zeroBasedColumn = numberOfCharactersConsumed() - m_numberOfCharactersConsumedPriorToCurrentLine;
357     return OrdinalNumber::fromZeroBasedInt(zeroBasedColumn);
358 }
359
360 void SegmentedString::setCurrentPosition(OrdinalNumber line, OrdinalNumber columnAftreProlog, int prologLength)
361 {
362     m_currentLine = line.zeroBasedInt();
363     m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + prologLength - columnAftreProlog.zeroBasedInt();
364 }
365
366 }