/* | |
* Copyright (C) 2006 Lars Knoll <lars@trolltech.com> | |
* Copyright (C) 2007-2009 Torch Mobile, Inc. | |
* | |
* This library is free software; you can redistribute it and/or | |
* modify it under the terms of the GNU Library General Public | |
* License as published by the Free Software Foundation; either | |
* version 2 of the License, or (at your option) any later version. | |
* | |
* This library is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
* Library General Public License for more details. | |
* | |
* You should have received a copy of the GNU Library General Public License | |
* along with this library; see the file COPYING.LIB. If not, write to | |
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
* Boston, MA 02111-1307, USA. | |
* | |
*/ | |
#include "config.h" | |
#include "TextBreakIterator.h" | |
#include "PlatformString.h" | |
#include <wtf/StdLibExtras.h> | |
#include <wtf/unicode/Unicode.h> | |
using namespace WTF::Unicode; | |
namespace WebCore { | |
// Hack, not entirely correct | |
static inline bool isCharStop(UChar c) | |
{ | |
CharCategory charCategory = category(c); | |
return charCategory != Mark_NonSpacing && (charCategory != Other_Surrogate || (c < 0xd800 || c >= 0xdc00)); | |
} | |
static inline bool isLineStop(UChar c) | |
{ | |
return category(c) != Separator_Line; | |
} | |
static inline bool isSentenceStop(UChar c) | |
{ | |
return isPunct(c); | |
} | |
class TextBreakIterator { | |
public: | |
void reset(const UChar* str, int len) | |
{ | |
string = str; | |
length = len; | |
currentPos = 0; | |
} | |
virtual int first() = 0; | |
virtual int next() = 0; | |
virtual int previous() = 0; | |
int following(int position) | |
{ | |
currentPos = position; | |
return next(); | |
} | |
int preceding(int position) | |
{ | |
currentPos = position; | |
return previous(); | |
} | |
int currentPos; | |
const UChar* string; | |
int length; | |
}; | |
struct WordBreakIterator: TextBreakIterator { | |
virtual int first(); | |
virtual int next(); | |
virtual int previous(); | |
}; | |
struct CharBreakIterator: TextBreakIterator { | |
virtual int first(); | |
virtual int next(); | |
virtual int previous(); | |
}; | |
struct LineBreakIterator: TextBreakIterator { | |
virtual int first(); | |
virtual int next(); | |
virtual int previous(); | |
}; | |
struct SentenceBreakIterator : TextBreakIterator { | |
virtual int first(); | |
virtual int next(); | |
virtual int previous(); | |
}; | |
int WordBreakIterator::first() | |
{ | |
currentPos = 0; | |
return currentPos; | |
} | |
int WordBreakIterator::next() | |
{ | |
if (currentPos == length) { | |
currentPos = -1; | |
return currentPos; | |
} | |
bool haveSpace = false; | |
while (currentPos < length) { | |
if (haveSpace && !isSpace(string[currentPos])) | |
break; | |
if (isSpace(string[currentPos])) | |
haveSpace = true; | |
++currentPos; | |
} | |
return currentPos; | |
} | |
int WordBreakIterator::previous() | |
{ | |
if (!currentPos) { | |
currentPos = -1; | |
return currentPos; | |
} | |
bool haveSpace = false; | |
while (currentPos > 0) { | |
if (haveSpace && !isSpace(string[currentPos])) | |
break; | |
if (isSpace(string[currentPos])) | |
haveSpace = true; | |
--currentPos; | |
} | |
return currentPos; | |
} | |
int CharBreakIterator::first() | |
{ | |
currentPos = 0; | |
return currentPos; | |
} | |
int CharBreakIterator::next() | |
{ | |
if (currentPos >= length) | |
return -1; | |
++currentPos; | |
while (currentPos < length && !isCharStop(string[currentPos])) | |
++currentPos; | |
return currentPos; | |
} | |
int CharBreakIterator::previous() | |
{ | |
if (currentPos <= 0) | |
return -1; | |
if (currentPos > length) | |
currentPos = length; | |
--currentPos; | |
while (currentPos > 0 && !isCharStop(string[currentPos])) | |
--currentPos; | |
return currentPos; | |
} | |
int LineBreakIterator::first() | |
{ | |
currentPos = 0; | |
return currentPos; | |
} | |
int LineBreakIterator::next() | |
{ | |
if (currentPos == length) { | |
currentPos = -1; | |
return currentPos; | |
} | |
bool haveSpace = false; | |
while (currentPos < length) { | |
if (haveSpace && !isLineStop(string[currentPos])) | |
break; | |
if (isLineStop(string[currentPos])) | |
haveSpace = true; | |
++currentPos; | |
} | |
return currentPos; | |
} | |
int LineBreakIterator::previous() | |
{ | |
if (!currentPos) { | |
currentPos = -1; | |
return currentPos; | |
} | |
bool haveSpace = false; | |
while (currentPos > 0) { | |
if (haveSpace && !isLineStop(string[currentPos])) | |
break; | |
if (isLineStop(string[currentPos])) | |
haveSpace = true; | |
--currentPos; | |
} | |
return currentPos; | |
} | |
int SentenceBreakIterator::first() | |
{ | |
currentPos = 0; | |
return currentPos; | |
} | |
int SentenceBreakIterator::next() | |
{ | |
if (currentPos == length) { | |
currentPos = -1; | |
return currentPos; | |
} | |
bool haveSpace = false; | |
while (currentPos < length) { | |
if (haveSpace && !isSentenceStop(string[currentPos])) | |
break; | |
if (isSentenceStop(string[currentPos])) | |
haveSpace = true; | |
++currentPos; | |
} | |
return currentPos; | |
} | |
int SentenceBreakIterator::previous() | |
{ | |
if (!currentPos) { | |
currentPos = -1; | |
return currentPos; | |
} | |
bool haveSpace = false; | |
while (currentPos > 0) { | |
if (haveSpace && !isSentenceStop(string[currentPos])) | |
break; | |
if (isSentenceStop(string[currentPos])) | |
haveSpace = true; | |
--currentPos; | |
} | |
return currentPos; | |
} | |
TextBreakIterator* wordBreakIterator(const UChar* string, int length) | |
{ | |
DEFINE_STATIC_LOCAL(WordBreakIterator, iterator, ()); | |
iterator.reset(string, length); | |
return &iterator; | |
} | |
TextBreakIterator* characterBreakIterator(const UChar* string, int length) | |
{ | |
DEFINE_STATIC_LOCAL(CharBreakIterator, iterator, ()); | |
iterator.reset(string, length); | |
return &iterator; | |
} | |
TextBreakIterator* lineBreakIterator(const UChar* string, int length) | |
{ | |
DEFINE_STATIC_LOCAL(LineBreakIterator , iterator, ()); | |
iterator.reset(string, length); | |
return &iterator; | |
} | |
TextBreakIterator* sentenceBreakIterator(const UChar* string, int length) | |
{ | |
DEFINE_STATIC_LOCAL(SentenceBreakIterator, iterator, ()); | |
iterator.reset(string, length); | |
return &iterator; | |
} | |
int textBreakFirst(TextBreakIterator* breakIterator) | |
{ | |
return breakIterator->first(); | |
} | |
int textBreakNext(TextBreakIterator* breakIterator) | |
{ | |
return breakIterator->next(); | |
} | |
int textBreakPreceding(TextBreakIterator* breakIterator, int position) | |
{ | |
return breakIterator->preceding(position); | |
} | |
int textBreakFollowing(TextBreakIterator* breakIterator, int position) | |
{ | |
return breakIterator->following(position); | |
} | |
int textBreakCurrent(TextBreakIterator* breakIterator) | |
{ | |
return breakIterator->currentPos; | |
} | |
bool isTextBreak(TextBreakIterator*, int) | |
{ | |
return true; | |
} | |
TextBreakIterator* cursorMovementIterator(const UChar* string, int length) | |
{ | |
return characterBreakIterator(string, length); | |
} | |
} // namespace WebCore |