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 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 } 131 m_empty = false; 132 } 133 134 void SegmentedString::prepend(const SegmentedSubstring& s) 135 { 136 ASSERT(!escaped()); 137 ASSERT(!s.numberOfCharactersConsumed()); 138 if (!s.m_length) 139 return; 140 141 // FIXME: We're assuming that the prepend were originally consumed by 142 // this SegmentedString. We're also ASSERTing that s is a fresh 143 // SegmentedSubstring. These assumptions are sufficient for our 144 // current use, but we might need to handle the more elaborate 145 // cases in the future. 146 m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed(); 147 m_numberOfCharactersConsumedPriorToCurrentString -= s.m_length; 148 if (!m_currentString.m_length) { 149 m_currentString = s; 150 updateAdvanceFunctionPointers(); 151 } else { 152 // Shift our m_currentString into our list. 153 m_substrings.prepend(m_currentString); 154 m_currentString = s; 155 updateAdvanceFunctionPointers(); 156 } 157 m_empty = false; 158 } 159 160 void SegmentedString::close() 161 { 162 // Closing a stream twice is likely a coding mistake. 163 ASSERT(!m_closed); 164 m_closed = true; 165 } 166 167 void SegmentedString::append(const SegmentedString& s) 168 { 169 ASSERT(!m_closed); 170 ASSERT(!s.escaped()); 171 append(s.m_currentString); 172 if (s.isComposite()) { 173 Deque<SegmentedSubstring>::const_iterator it = s.m_substrings.begin(); 174 Deque<SegmentedSubstring>::const_iterator e = s.m_substrings.end(); 175 for (; it != e; ++it) 176 append(*it); 177 } 178 m_currentChar = m_pushedChar1 ? m_pushedChar1 : (m_currentString.m_length ? m_currentString.getCurrentChar() : 0); 179 } 180 181 void SegmentedString::prepend(const SegmentedString& s) 182 { 183 ASSERT(!escaped()); 184 ASSERT(!s.escaped()); 185 if (s.isComposite()) { 186 Deque<SegmentedSubstring>::const_reverse_iterator it = s.m_substrings.rbegin(); 187 Deque<SegmentedSubstring>::const_reverse_iterator e = s.m_substrings.rend(); 188 for (; it != e; ++it) 189 prepend(*it); 190 } 191 prepend(s.m_currentString); 192 m_currentChar = m_pushedChar1 ? m_pushedChar1 : (m_currentString.m_length ? m_currentString.getCurrentChar() : 0); 193 } 194 195 void SegmentedString::advanceSubstring() 196 { 197 if (isComposite()) { 198 m_numberOfCharactersConsumedPriorToCurrentString += m_currentString.numberOfCharactersConsumed(); 199 m_currentString = m_substrings.takeFirst(); 200 // If we've previously consumed some characters of the non-current 201 // string, we now account for those characters as part of the current 202 // string, not as part of "prior to current string." 203 m_numberOfCharactersConsumedPriorToCurrentString -= m_currentString.numberOfCharactersConsumed(); 204 updateAdvanceFunctionPointers(); 205 } else { 206 m_currentString.clear(); 207 m_empty = true; 208 m_fastPathFlags = NoFastPath; 209 m_advanceFunc = &SegmentedString::advanceEmpty; 210 m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty; 211 } 212 } 213 214 String SegmentedString::toString() const 215 { 216 StringBuilder result; 217 if (m_pushedChar1) { 218 result.append(m_pushedChar1); 219 if (m_pushedChar2) 220 result.append(m_pushedChar2); 221 } 222 m_currentString.appendTo(result); 223 if (isComposite()) { 224 Deque<SegmentedSubstring>::const_iterator it = m_substrings.begin(); 225 Deque<SegmentedSubstring>::const_iterator e = m_substrings.end(); 226 for (; it != e; ++it) 227 it->appendTo(result); 228 } 229 return result.toString(); 230 } 231 232 void SegmentedString::advance(unsigned count, UChar* consumedCharacters) 233 { 234 ASSERT_WITH_SECURITY_IMPLICATION(count <= length()); 235 for (unsigned i = 0; i < count; ++i) { 236 consumedCharacters[i] = currentChar(); 237 advance(); 238 } 239 } 240 241 void SegmentedString::advance8() 242 { 243 ASSERT(!m_pushedChar1); 244 decrementAndCheckLength(); 245 m_currentChar = m_currentString.incrementAndGetCurrentChar8(); 246 } 247 248 void SegmentedString::advance16() 249 { 250 ASSERT(!m_pushedChar1); 251 decrementAndCheckLength(); 252 m_currentChar = m_currentString.incrementAndGetCurrentChar16(); 253 } 254 255 void SegmentedString::advanceAndUpdateLineNumber8() 256 { 257 ASSERT(!m_pushedChar1); 258 ASSERT(m_currentString.getCurrentChar() == m_currentChar); 259 if (m_currentChar == '\n') { 260 ++m_currentLine; 261 m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1; 262 } 263 decrementAndCheckLength(); 264 m_currentChar = m_currentString.incrementAndGetCurrentChar8(); 265 } 266 267 void SegmentedString::advanceAndUpdateLineNumber16() 268 { 269 ASSERT(!m_pushedChar1); 270 ASSERT(m_currentString.getCurrentChar() == m_currentChar); 271 if (m_currentChar == '\n') { 272 ++m_currentLine; 273 m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1; 274 } 275 decrementAndCheckLength(); 276 m_currentChar = m_currentString.incrementAndGetCurrentChar16(); 277 } 278 279 void SegmentedString::advanceSlowCase() 280 { 281 if (m_pushedChar1) { 282 m_pushedChar1 = m_pushedChar2; 283 m_pushedChar2 = 0; 284 285 if (m_pushedChar1) { 286 m_currentChar = m_pushedChar1; 287 return; 288 } 289 290 updateAdvanceFunctionPointers(); 291 } else if (m_currentString.m_length) { 292 if (!--m_currentString.m_length) 293 advanceSubstring(); 294 } else if (!isComposite()) { 295 m_currentString.clear(); 296 m_empty = true; 297 m_fastPathFlags = NoFastPath; 298 m_advanceFunc = &SegmentedString::advanceEmpty; 299 m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty; 300 } 301 m_currentChar = m_currentString.m_length ? m_currentString.getCurrentChar() : 0; 302 } 303 304 void SegmentedString::advanceAndUpdateLineNumberSlowCase() 305 { 306 if (m_pushedChar1) { 307 m_pushedChar1 = m_pushedChar2; 308 m_pushedChar2 = 0; 309 310 if (m_pushedChar1) { 311 m_currentChar = m_pushedChar1; 312 return; 313 } 314 315 updateAdvanceFunctionPointers(); 316 } else if (m_currentString.m_length) { 317 if (m_currentString.getCurrentChar() == '\n' && m_currentString.doNotExcludeLineNumbers()) { 318 ++m_currentLine; 319 // Plus 1 because numberOfCharactersConsumed value hasn't incremented yet; it does with m_length decrement below. 320 m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + 1; 321 } 322 if (!--m_currentString.m_length) 323 advanceSubstring(); 324 else 325 m_currentString.incrementAndGetCurrentChar(); // Only need the ++ 326 } else if (!isComposite()) { 327 m_currentString.clear(); 328 m_empty = true; 329 m_fastPathFlags = NoFastPath; 330 m_advanceFunc = &SegmentedString::advanceEmpty; 331 m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceEmpty; 332 } 333 334 m_currentChar = m_currentString.m_length ? m_currentString.getCurrentChar() : 0; 335 } 336 337 void SegmentedString::advanceEmpty() 338 { 339 ASSERT(!m_currentString.m_length && !isComposite()); 340 m_currentChar = 0; 341 } 342 343 void SegmentedString::updateSlowCaseFunctionPointers() 344 { 345 m_fastPathFlags = NoFastPath; 346 m_advanceFunc = &SegmentedString::advanceSlowCase; 347 m_advanceAndUpdateLineNumberFunc = &SegmentedString::advanceAndUpdateLineNumberSlowCase; 348 } 349 350 OrdinalNumber SegmentedString::currentLine() const 351 { 352 return OrdinalNumber::fromZeroBasedInt(m_currentLine); 353 } 354 355 OrdinalNumber SegmentedString::currentColumn() const 356 { 357 int zeroBasedColumn = numberOfCharactersConsumed() - m_numberOfCharactersConsumedPriorToCurrentLine; 358 return OrdinalNumber::fromZeroBasedInt(zeroBasedColumn); 359 } 360 361 void SegmentedString::setCurrentPosition(OrdinalNumber line, OrdinalNumber columnAftreProlog, int prologLength) 362 { 363 m_currentLine = line.zeroBasedInt(); 364 m_numberOfCharactersConsumedPriorToCurrentLine = numberOfCharactersConsumed() + prologLength - columnAftreProlog.zeroBasedInt(); 365 } 366 367 } 368