tdf#135451 - Change the skipSpace implementation of the break iterator

Change the ICU whitespace function of the break iterator from u_isWhitespace to u_isUWhiteSpace to include no-break spaces.

u_isWhitespace includes Java isWhitespace; Z + whitespace ISO controls but excludes no-break spaces
u_isUWhiteSpace includes all code points with the Unicode White_Space property; most of general categories "Z" (separators) + most whitespace ISO controls (including no-break spaces, but excluding IS1..IS4)

See https://unicode-org.github.io/icu-docs/apidoc/dev/icu4c/uchar_8h.html for further details.

Change-Id: I21fddefaf2149096824908f644310a59d6e2f38d
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137582
Tested-by: Jenkins
Reviewed-by: Andreas Heinisch <andreas.heinisch@yahoo.de>
This commit is contained in:
Andreas Heinisch
2022-07-29 09:29:33 +02:00
parent 6c0b8669e1
commit 70c99eef16
3 changed files with 30 additions and 8 deletions

View File

@@ -82,7 +82,7 @@ static sal_Int32 skipSpace(const OUString& Text, sal_Int32 nPos, sal_Int32 len,
while (nPos < len)
{
ch = Text.iterateCodePoints(&pos);
if (!u_isWhitespace(ch) && !isZWSP(ch))
if (!u_isUWhiteSpace(ch) && !isZWSP(ch))
break;
nPos = pos;
}
@@ -90,7 +90,7 @@ static sal_Int32 skipSpace(const OUString& Text, sal_Int32 nPos, sal_Int32 len,
while (nPos > 0)
{
ch = Text.iterateCodePoints(&pos, -1);
if (!u_isWhitespace(ch) && !isZWSP(ch))
if (!u_isUWhiteSpace(ch) && !isZWSP(ch))
break;
nPos = pos;
}

View File

@@ -379,9 +379,10 @@ Boundary SAL_CALL BreakIterator_Unicode::nextWord( const OUString& Text, sal_Int
if( rv.startPos >= Text.getLength() || rv.startPos == icu::BreakIterator::DONE )
rv.endPos = result.startPos;
else {
if ( (rWordType == WordType::ANYWORD_IGNOREWHITESPACES ||
rWordType == WordType::DICTIONARY_WORD ) &&
u_isWhitespace(Text.iterateCodePoints(&rv.startPos, 0)) )
if ((rWordType == WordType::ANYWORD_IGNOREWHITESPACES
&& u_isUWhiteSpace(Text.iterateCodePoints(&rv.startPos, 0)))
|| (rWordType == WordType::DICTIONARY_WORD
&& u_isWhitespace(Text.iterateCodePoints(&rv.startPos, 0))))
rv.startPos = icuBI->mpValue->mpBreakIterator->following(rv.startPos);
rv.endPos = icuBI->mpValue->mpBreakIterator->following(rv.startPos);
@@ -402,9 +403,11 @@ Boundary SAL_CALL BreakIterator_Unicode::previousWord(const OUString& Text, sal_
if( rv.startPos < 0)
rv.endPos = rv.startPos;
else {
if ( (rWordType == WordType::ANYWORD_IGNOREWHITESPACES ||
rWordType == WordType::DICTIONARY_WORD) &&
u_isWhitespace(Text.iterateCodePoints(&rv.startPos, 0)) )
if ((rWordType == WordType::ANYWORD_IGNOREWHITESPACES
&& u_isUWhiteSpace(Text.iterateCodePoints(&rv.startPos, 0)))
|| (rWordType == WordType::DICTIONARY_WORD
&& u_isWhitespace(Text.iterateCodePoints(&rv.startPos, 0))))
rv.startPos = icuBI->mpValue->mpBreakIterator->preceding(rv.startPos);
rv.endPos = icuBI->mpValue->mpBreakIterator->following(rv.startPos);

View File

@@ -164,6 +164,25 @@ CPPUNIT_TEST_FIXTURE(SwCoreCrsrTest, testContentControlReadOnly)
CPPUNIT_ASSERT(pWrtShell->HasReadonlySel());
}
CPPUNIT_TEST_FIXTURE(SwCoreCrsrTest, testTdf135451)
{
SwDoc* pDoc = createSwDoc();
SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
// Insert narrow no-break space and move the cursor right before it
pWrtShell->Insert(u"a" + OUStringChar(CHAR_NNBSP) + "b");
pWrtShell->EndPara(/*bSelect=*/false);
pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
pWrtShell->GoPrevWord();
pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/true, 1, /*bBasicCall=*/false);
// Without the accompanying fix in place, this test would have failed with:
// - Expected: a
// - Actual : CHAR_NNBSP
// i.e., the cursor did not move over the narrow no-break space (CHAR_NNBSP)
CPPUNIT_ASSERT_EQUAL(OUString("a"), pWrtShell->GetSelText());
}
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */