initial import
[vuplus_webkit] / 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_substrings(other.m_substrings)
30     , m_closed(other.m_closed)
31 {
32     if (other.m_currentChar == &other.m_pushedChar1)
33         m_currentChar = &m_pushedChar1;
34     else if (other.m_currentChar == &other.m_pushedChar2)
35         m_currentChar = &m_pushedChar2;
36     else
37         m_currentChar = other.m_currentChar;
38 }
39
40 const SegmentedString& SegmentedString::operator=(const SegmentedString& other)
41 {
42     m_pushedChar1 = other.m_pushedChar1;
43     m_pushedChar2 = other.m_pushedChar2;
44     m_currentString = other.m_currentString;
45     m_substrings = other.m_substrings;
46     if (other.m_currentChar == &other.m_pushedChar1)
47         m_currentChar = &m_pushedChar1;
48     else if (other.m_currentChar == &other.m_pushedChar2)
49         m_currentChar = &m_pushedChar2;
50     else
51         m_currentChar = other.m_currentChar;
52     m_closed = other.m_closed;
53     m_numberOfCharactersConsumedPriorToCurrentString = other.m_numberOfCharactersConsumedPriorToCurrentString;
54     m_numberOfCharactersConsumedPriorToCurrentLine = other.m_numberOfCharactersConsumedPriorToCurrentLine;
55     m_currentLine = other.m_currentLine;
56
57     return *this;
58 }
59
60 unsigned SegmentedString::length() const
61 {
62     unsigned length = m_currentString.m_length;
63     if (m_pushedChar1) {
64         ++length;
65         if (m_pushedChar2)
66             ++length;
67     }
68     if (isComposite()) {
69         Deque<SegmentedSubstring>::const_iterator it = m_substrings.begin();
70         Deque<SegmentedSubstring>::const_iterator e = m_substrings.end();
71         for (; it != e; ++it)
72             length += it->m_length;
73     }
74     return length;
75 }
76
77 void SegmentedString::setExcludeLineNumbers()
78 {
79     m_currentString.setExcludeLineNumbers();
80     if (isComposite()) {
81         Deque<SegmentedSubstring>::iterator it = m_substrings.begin();
82         Deque<SegmentedSubstring>::iterator e = m_substrings.end();
83         for (; it != e; ++it)
84             it->setExcludeLineNumbers();
85     }
86 }
87
88 void SegmentedString::clear()
89 {
90     m_pushedChar1 = 0;
91     m_pushedChar2 = 0;
92     m_currentChar = 0;
93     m_currentString.clear();
94     m_substrings.clear();
95     m_closed = false;
96 }
97
98 void SegmentedString::append(const SegmentedSubstring& s)
99 {
100     ASSERT(!m_closed);
101     if (!s.m_length)
102         return;
103
104     if (!m_currentString.m_length) {
105         m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
106         m_currentString = s;
107     } else
108         m_substrings.append(s);
109 }
110
111 void SegmentedString::prepend(const SegmentedSubstring& s)
112 {
113     ASSERT(!escaped());
114     ASSERT(!s.numberOfCharactersConsumed());
115     if (!s.m_length)
116         return;
117
118     // FIXME: We're assuming that the prepend were originally consumed by
119     //        this SegmentedString.  We're also ASSERTing that s is a fresh
120     //        SegmentedSubstring.  These assumptions are sufficient for our
121     //        current use, but we might need to handle the more elaborate
122     //        cases in the future.
123     m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
124     m_numberOfCharactersConsumedPriorToCurrentString -= s.m_length;
125     if (!m_currentString.m_length)
126         m_currentString = s;
127     else {
128         // Shift our m_currentString into our list.
129         m_substrings.prepend(m_currentString);
130         m_currentString = s;
131     }
132 }
133
134 void SegmentedString::close()
135 {
136     // Closing a stream twice is likely a coding mistake.
137     ASSERT(!m_closed);
138     m_closed = true;
139 }
140
141 void SegmentedString::append(const SegmentedString& s)
142 {
143     ASSERT(!m_closed);
144     ASSERT(!s.escaped());
145     append(s.m_currentString);
146     if (s.isComposite()) {
147         Deque<SegmentedSubstring>::const_iterator it = s.m_substrings.begin();
148         Deque<SegmentedSubstring>::const_iterator e = s.m_substrings.end();
149         for (; it != e; ++it)
150             append(*it);
151     }
152     m_currentChar = m_pushedChar1 ? &m_pushedChar1 : m_currentString.m_current;
153 }
154
155 void SegmentedString::prepend(const SegmentedString& s)
156 {
157     ASSERT(!escaped());
158     ASSERT(!s.escaped());
159     if (s.isComposite()) {
160         Deque<SegmentedSubstring>::const_reverse_iterator it = s.m_substrings.rbegin();
161         Deque<SegmentedSubstring>::const_reverse_iterator e = s.m_substrings.rend();
162         for (; it != e; ++it)
163             prepend(*it);
164     }
165     prepend(s.m_currentString);
166     m_currentChar = m_pushedChar1 ? &m_pushedChar1 : m_currentString.m_current;
167 }
168
169 void SegmentedString::advanceSubstring()
170 {
171     if (isComposite()) {
172         m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed();
173         m_currentString = m_substrings.takeFirst();
174         // If we've previously consumed some characters of the non-current
175         // string, we now account for those characters as part of the current
176         // string, not as part of "prior to current string."
177         m_numberOfCharactersConsumedPriorToCurrentString -= m_currentString.numberOfCharactersConsumed();
178     } else
179         m_currentString.clear();
180 }
181
182 String SegmentedString::toString() const
183 {
184     String result;
185     if (m_pushedChar1) {
186         result.append(m_pushedChar1);
187         if (m_pushedChar2)
188             result.append(m_pushedChar2);
189     }
190     m_currentString.appendTo(result);
191     if (isComposite()) {
192         Deque<SegmentedSubstring>::const_iterator it = m_substrings.begin();
193         Deque<SegmentedSubstring>::const_iterator e = m_substrings.end();
194         for (; it != e; ++it)
195             it->appendTo(result);
196     }
197     return result;
198 }
199
200 void SegmentedString::advance(unsigned count, UChar* consumedCharacters)
201 {
202     ASSERT(count <= length());
203     for (unsigned i = 0; i < count; ++i) {
204         consumedCharacters[i] = *current();
205         advance();
206     }
207 }
208
209 void SegmentedString::advanceSlowCase()
210 {
211     if (m_pushedChar1) {
212         m_pushedChar1 = m_pushedChar2;
213         m_pushedChar2 = 0;
214     } else if (m_currentString.m_current) {
215         ++m_currentString.m_current;
216         if (--m_currentString.m_length == 0)
217             advanceSubstring();
218     }
219     m_currentChar = m_pushedChar1 ? &m_pushedChar1 : m_currentString.m_current;
220 }
221
222 void SegmentedString::advanceSlowCase(int& lineNumber)
223 {
224     if (m_pushedChar1) {
225         m_pushedChar1 = m_pushedChar2;
226         m_pushedChar2 = 0;
227     } else if (m_currentString.m_current) {
228         if (*m_currentString.m_current++ == '\n' && m_currentString.doNotExcludeLineNumbers()) {
229             ++lineNumber;
230             ++m_currentLine;
231             // Plus 1 because numberOfCharactersConsumed value hasn't incremented yet; it does with m_length decrement below.
232             m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1;
233         }
234         if (--m_currentString.m_length == 0)
235             advanceSubstring();
236     }
237     m_currentChar = m_pushedChar1 ? &m_pushedChar1 : m_currentString.m_current;
238 }
239
240 WTF::ZeroBasedNumber SegmentedString::currentLine() const
241 {
242     return WTF::ZeroBasedNumber::fromZeroBasedInt(m_currentLine);
243 }
244
245 WTF::ZeroBasedNumber SegmentedString::currentColumn() const
246 {
247     int zeroBasedColumn = numberOfCharactersConsumed() - m_numberOfCharactersConsumedPriorToCurrentLine;
248     return WTF::ZeroBasedNumber::fromZeroBasedInt(zeroBasedColumn);
249 }
250
251 void SegmentedString::setCurrentPosition(WTF::ZeroBasedNumber line, WTF::ZeroBasedNumber columnAftreProlog, int prologLength)
252 {
253     m_currentLine = line.zeroBasedInt();
254     m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + prologLength - columnAftreProlog.zeroBasedInt();
255 }
256
257 }