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
23namespace blink {
24
25unsigned 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
42void 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
53void 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
70void 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
86void 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
112void SegmentedString::close()
113{
114    // Closing a stream twice is likely a coding mistake.
115    ASSERT(!m_closed);
116    m_closed = true;
117}
118
119void 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
140void 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
154void 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
173String 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
191void 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
200void SegmentedString::advance8()
201{
202    ASSERT(!m_pushedChar1);
203    decrementAndCheckLength();
204    m_currentChar = m_currentString.incrementAndGetCurrentChar8();
205}
206
207void SegmentedString::advance16()
208{
209    ASSERT(!m_pushedChar1);
210    decrementAndCheckLength();
211    m_currentChar = m_currentString.incrementAndGetCurrentChar16();
212}
213
214void 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
226void 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
238void 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
263void 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
296void SegmentedString::advanceEmpty()
297{
298    ASSERT(!m_currentString.m_length && !isComposite());
299    m_currentChar = 0;
300}
301
302void SegmentedString::updateSlowCaseFunctionPointers()
303{
304    m_fastPathFlags = NoFastPath;
305    m_advanceFunc = &SegmentedString::advanceSlowCase;
306    m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceAndUpdateLineNumberSlowCase;
307}
308
309OrdinalNumber SegmentedString::currentLine() const
310{
311    return OrdinalNumber::fromZeroBasedInt(m_currentLine);
312}
313
314OrdinalNumber SegmentedString::currentColumn() const
315{
316    int zeroBasedColumn = numberOfCharactersConsumed() - m_numberOfCharactersConsumedPriorToCurrentLine;
317    return OrdinalNumber::fromZeroBasedInt(zeroBasedColumn);
318}
319
320void 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