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 WebCore { 24 25 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 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 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 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 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 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 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 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 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 173 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 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 200 void SegmentedString::advance8() 201 { 202 ASSERT(!m_pushedChar1); 203 decrementAndCheckLength(); 204 m_currentChar = m_currentString.incrementAndGetCurrentChar8(); 205 } 206 207 void SegmentedString::advance16() 208 { 209 ASSERT(!m_pushedChar1); 210 decrementAndCheckLength(); 211 m_currentChar = m_currentString.incrementAndGetCurrentChar16(); 212 } 213 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 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 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 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 296 void SegmentedString::advanceEmpty() 297 { 298 ASSERT(!m_currentString.m_length && !isComposite()); 299 m_currentChar = 0; 300 } 301 302 void SegmentedString::updateSlowCaseFunctionPointers() 303 { 304 m_fastPathFlags = NoFastPath; 305 m_advanceFunc = &SegmentedString::advanceSlowCase; 306 m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceAndUpdateLineNumberSlowCase; 307 } 308 309 OrdinalNumber SegmentedString::currentLine() const 310 { 311 return OrdinalNumber::fromZeroBasedInt(m_currentLine); 312 } 313 314 OrdinalNumber SegmentedString::currentColumn() const 315 { 316 int zeroBasedColumn = numberOfCharactersConsumed() - m_numberOfCharactersConsumedPriorToCurrentLine; 317 return OrdinalNumber::fromZeroBasedInt(zeroBasedColumn); 318 } 319 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