1 /* 2 * Copyright (C) 2006 Lars Knoll <lars (at) trolltech.com> 3 * Copyright (C) 2007-2009 Torch Mobile, Inc. 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Library General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Library General Public License for more details. 14 * 15 * You should have received a copy of the GNU Library General Public License 16 * along with this library; see the file COPYING.LIB. If not, write to 17 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 * Boston, MA 02111-1307, USA. 19 * 20 */ 21 22 #include "config.h" 23 #include "TextBreakIterator.h" 24 25 #include "PlatformString.h" 26 #include <wtf/StdLibExtras.h> 27 #include <wtf/unicode/Unicode.h> 28 29 using namespace std; 30 using namespace WTF::Unicode; 31 32 namespace WebCore { 33 34 // Hack, not entirely correct 35 static inline bool isCharStop(UChar c) 36 { 37 CharCategory charCategory = category(c); 38 return charCategory != Mark_NonSpacing && (charCategory != Other_Surrogate || (c < 0xd800 || c >= 0xdc00)); 39 } 40 41 static inline bool isLineStop(UChar c) 42 { 43 return category(c) != Separator_Line; 44 } 45 46 static inline bool isSentenceStop(UChar c) 47 { 48 return isPunct(c); 49 } 50 51 class TextBreakIterator { 52 public: 53 void reset(const UChar* str, int len) 54 { 55 string = str; 56 length = len; 57 currentPos = 0; 58 } 59 int first() 60 { 61 currentPos = 0; 62 return currentPos; 63 } 64 int last() 65 { 66 currentPos = length; 67 return currentPos; 68 } 69 virtual int next() = 0; 70 virtual int previous() = 0; 71 int following(int position) 72 { 73 currentPos = position; 74 return next(); 75 } 76 int preceding(int position) 77 { 78 currentPos = position; 79 return previous(); 80 } 81 82 int currentPos; 83 const UChar* string; 84 int length; 85 }; 86 87 struct WordBreakIterator: TextBreakIterator { 88 virtual int next(); 89 virtual int previous(); 90 }; 91 92 struct CharBreakIterator: TextBreakIterator { 93 virtual int next(); 94 virtual int previous(); 95 }; 96 97 struct LineBreakIterator: TextBreakIterator { 98 virtual int next(); 99 virtual int previous(); 100 }; 101 102 struct SentenceBreakIterator : TextBreakIterator { 103 virtual int next(); 104 virtual int previous(); 105 }; 106 107 int WordBreakIterator::next() 108 { 109 if (currentPos == length) { 110 currentPos = -1; 111 return currentPos; 112 } 113 bool haveSpace = false; 114 while (currentPos < length) { 115 if (haveSpace && !isSpace(string[currentPos])) 116 break; 117 if (isSpace(string[currentPos])) 118 haveSpace = true; 119 ++currentPos; 120 } 121 return currentPos; 122 } 123 124 int WordBreakIterator::previous() 125 { 126 if (!currentPos) { 127 currentPos = -1; 128 return currentPos; 129 } 130 bool haveSpace = false; 131 while (currentPos > 0) { 132 if (haveSpace && !isSpace(string[currentPos])) 133 break; 134 if (isSpace(string[currentPos])) 135 haveSpace = true; 136 --currentPos; 137 } 138 return currentPos; 139 } 140 141 int CharBreakIterator::next() 142 { 143 if (currentPos >= length) 144 return -1; 145 ++currentPos; 146 while (currentPos < length && !isCharStop(string[currentPos])) 147 ++currentPos; 148 return currentPos; 149 } 150 151 int CharBreakIterator::previous() 152 { 153 if (currentPos <= 0) 154 return -1; 155 if (currentPos > length) 156 currentPos = length; 157 --currentPos; 158 while (currentPos > 0 && !isCharStop(string[currentPos])) 159 --currentPos; 160 return currentPos; 161 } 162 163 int LineBreakIterator::next() 164 { 165 if (currentPos == length) { 166 currentPos = -1; 167 return currentPos; 168 } 169 bool haveSpace = false; 170 while (currentPos < length) { 171 if (haveSpace && !isLineStop(string[currentPos])) 172 break; 173 if (isLineStop(string[currentPos])) 174 haveSpace = true; 175 ++currentPos; 176 } 177 return currentPos; 178 } 179 180 int LineBreakIterator::previous() 181 { 182 if (!currentPos) { 183 currentPos = -1; 184 return currentPos; 185 } 186 bool haveSpace = false; 187 while (currentPos > 0) { 188 if (haveSpace && !isLineStop(string[currentPos])) 189 break; 190 if (isLineStop(string[currentPos])) 191 haveSpace = true; 192 --currentPos; 193 } 194 return currentPos; 195 } 196 197 int SentenceBreakIterator::next() 198 { 199 if (currentPos == length) { 200 currentPos = -1; 201 return currentPos; 202 } 203 bool haveSpace = false; 204 while (currentPos < length) { 205 if (haveSpace && !isSentenceStop(string[currentPos])) 206 break; 207 if (isSentenceStop(string[currentPos])) 208 haveSpace = true; 209 ++currentPos; 210 } 211 return currentPos; 212 } 213 214 int SentenceBreakIterator::previous() 215 { 216 if (!currentPos) { 217 currentPos = -1; 218 return currentPos; 219 } 220 bool haveSpace = false; 221 while (currentPos > 0) { 222 if (haveSpace && !isSentenceStop(string[currentPos])) 223 break; 224 if (isSentenceStop(string[currentPos])) 225 haveSpace = true; 226 --currentPos; 227 } 228 return currentPos; 229 } 230 231 TextBreakIterator* wordBreakIterator(const UChar* string, int length) 232 { 233 DEFINE_STATIC_LOCAL(WordBreakIterator, iterator, ()); 234 iterator.reset(string, length); 235 return &iterator; 236 } 237 238 TextBreakIterator* characterBreakIterator(const UChar* string, int length) 239 { 240 DEFINE_STATIC_LOCAL(CharBreakIterator, iterator, ()); 241 iterator.reset(string, length); 242 return &iterator; 243 } 244 245 static TextBreakIterator* staticLineBreakIterator; 246 247 TextBreakIterator* acquireLineBreakIterator(const UChar* string, int length) 248 { 249 TextBreakIterator* lineBreakIterator = 0; 250 if (staticLineBreakIterator) { 251 staticLineBreakIterator->reset(string, length); 252 swap(staticLineBreakIterator, lineBreakIterator); 253 } 254 255 if (!lineBreakIterator && string && length) { 256 lineBreakIterator = new LineBreakIterator; 257 lineBreakIterator->reset(string, length); 258 } 259 260 return lineBreakIterator; 261 } 262 263 void releaseLineBreakIterator(TextBreakIterator* iterator) 264 { 265 ASSERT(iterator); 266 267 if (!staticLineBreakIterator) 268 staticLineBreakIterator = iterator; 269 else 270 delete iterator; 271 } 272 273 TextBreakIterator* sentenceBreakIterator(const UChar* string, int length) 274 { 275 DEFINE_STATIC_LOCAL(SentenceBreakIterator, iterator, ()); 276 iterator.reset(string, length); 277 return &iterator; 278 } 279 280 int textBreakFirst(TextBreakIterator* breakIterator) 281 { 282 return breakIterator->first(); 283 } 284 285 int textBreakLast(TextBreakIterator* breakIterator) 286 { 287 return breakIterator->last(); 288 } 289 290 int textBreakNext(TextBreakIterator* breakIterator) 291 { 292 return breakIterator->next(); 293 } 294 295 int textBreakPrevious(TextBreakIterator* breakIterator) 296 { 297 return breakIterator->previous(); 298 } 299 300 int textBreakPreceding(TextBreakIterator* breakIterator, int position) 301 { 302 return breakIterator->preceding(position); 303 } 304 305 int textBreakFollowing(TextBreakIterator* breakIterator, int position) 306 { 307 return breakIterator->following(position); 308 } 309 310 int textBreakCurrent(TextBreakIterator* breakIterator) 311 { 312 return breakIterator->currentPos; 313 } 314 315 bool isTextBreak(TextBreakIterator*, int) 316 { 317 return true; 318 } 319 320 TextBreakIterator* cursorMovementIterator(const UChar* string, int length) 321 { 322 return characterBreakIterator(string, length); 323 } 324 325 } // namespace WebCore 326