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