editeng/qa/unit/core-test.cxx       |   85 ++++++++++++++++++++++++++
 editeng/source/editeng/impedit4.cxx |    7 ++
 sw/qa/extras/uiwriter/uiwriter4.cxx |  116 ++++++++++++++++++++++++++++++++++++
 sw/source/core/txtnode/txtedt.cxx   |    6 +
 4 files changed, 214 insertions(+)

New commits:
commit 49ddbc94a088344bf69444445a0300342ea3f184
Author:     Michael Warner <michael.warner.ut+libreoff...@gmail.com>
AuthorDate: Mon Apr 11 00:18:25 2022 -0400
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Wed May 11 22:59:59 2022 +0200

    tdf#148148: Applying Title Case when selection contains only spaces
    
    Previously, if the user's selection does not contain any word
    characters, but the node does contain characters outside of
    the user's selection, then searching for the word boundaries
    when applying title case could result in start and end points
    that were incorrect. In Writer this results in title case
    being applied to non-selected characters. In Calc this results
    in a debug assertion being hit.
    
    This commit prevents those issues by skipping transliteration
    on the node in this case.
    
    Change-Id: I20c5ef44793741c5863f838c13ba222452346a97
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132801
    Tested-by: Jenkins
    Tested-by: Julien Nabet <serval2...@yahoo.fr>
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/editeng/qa/unit/core-test.cxx b/editeng/qa/unit/core-test.cxx
index 8965b8c21ba6..2836c6ba81d6 100644
--- a/editeng/qa/unit/core-test.cxx
+++ b/editeng/qa/unit/core-test.cxx
@@ -99,6 +99,8 @@ public:
 
     void testTdf147196();
 
+    void testTdf148148();
+
     DECL_STATIC_LINK( Test, CalcFieldValueHdl, EditFieldInfo*, void );
 
     CPPUNIT_TEST_SUITE(Test);
@@ -122,6 +124,7 @@ public:
     CPPUNIT_TEST(testLargeParaCopyPaste);
     CPPUNIT_TEST(testTransliterate);
     CPPUNIT_TEST(testTdf147196);
+    CPPUNIT_TEST(testTdf148148);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -1889,6 +1892,88 @@ void Test::testTdf147196()
     CPPUNIT_ASSERT_EQUAL(OUString("2.2 Publication Of Information - 
Caa\nSection 4.2 Of A Ca\'s Certificate Policy And/Or Certification Practice 
Statement Shall State The Ca\'s Policy Or Practice On Processing Caa Records 
For Fully Qualified Domain Names; That Policy Shall Be Consistent With These 
Requirements. \n\nIt Shall Clearly Specify The Set Of Issuer Domain Names That 
The Ca Recognises In Caa \"Issue\" Or \"Issuewild\" Records As Permitting It To 
Issue. The Ca Shall Log All Actions Taken, If Any, Consistent With Its 
Processing Practice."), editEng.GetText());
 }
 
+void Test::testTdf148148()
+{
+    using TF = TransliterationFlags;
+    EditEngine editEng( mpItemPool.get() );
+
+    /* Test what happens when node contains text but selection does not 
contain any text */
+    int selStart = 0;
+    int selEnd = 3;
+    ESelection esel(0, selStart, 0, selEnd);
+    const OUString sText1("   text");
+    editEng.SetText(sText1);
+    CPPUNIT_ASSERT_EQUAL(OUString("   "), editEng.GetText(esel));
+
+    CPPUNIT_ASSERT_EQUAL(OUString("   text"), lcl_translitTest(editEng, 
sText1, esel, TF::SENTENCE_CASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("   text"), lcl_translitTest(editEng, 
sText1, esel, TF::TITLE_CASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("   text"), lcl_translitTest(editEng, 
sText1, esel, TF::LOWERCASE_UPPERCASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("   text"), lcl_translitTest(editEng, 
sText1, esel, TF::UPPERCASE_LOWERCASE));
+
+    selStart = 4;
+    selEnd = 8;
+    esel = ESelection(0, selStart, 0, selEnd);
+    const OUString sText2("text    ");
+    editEng.SetText(sText2);
+    CPPUNIT_ASSERT_EQUAL(OUString("    "), editEng.GetText(esel));
+
+    CPPUNIT_ASSERT_EQUAL(OUString("text    "), lcl_translitTest(editEng, 
sText2, esel, TF::SENTENCE_CASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("text    "), lcl_translitTest(editEng, 
sText2, esel, TF::TITLE_CASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("text    "), lcl_translitTest(editEng, 
sText2, esel, TF::LOWERCASE_UPPERCASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("text    "), lcl_translitTest(editEng, 
sText2, esel, TF::UPPERCASE_LOWERCASE));
+
+    /* Test what happens when node contains only non-word text but selection 
does not contain any text */
+    selStart = 0;
+    selEnd = 3;
+    esel = ESelection(0, selStart, 0, selEnd);
+    const OUString sText3("   -1");
+    editEng.SetText(sText3);
+    CPPUNIT_ASSERT_EQUAL(OUString("   "), editEng.GetText(esel));
+
+    CPPUNIT_ASSERT_EQUAL(OUString("   -1"), lcl_translitTest(editEng, sText3, 
esel, TF::SENTENCE_CASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("   -1"), lcl_translitTest(editEng, sText3, 
esel, TF::TITLE_CASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("   -1"), lcl_translitTest(editEng, sText3, 
esel, TF::LOWERCASE_UPPERCASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("   -1"), lcl_translitTest(editEng, sText3, 
esel, TF::UPPERCASE_LOWERCASE));
+
+    selStart = 2;
+    selEnd = 6;
+    esel = ESelection(0, selStart, 0, selEnd);
+    const OUString sText4("-1    ");
+    editEng.SetText(sText4);
+    CPPUNIT_ASSERT_EQUAL(OUString("    "), editEng.GetText(esel));
+
+    CPPUNIT_ASSERT_EQUAL(OUString("-1    "), lcl_translitTest(editEng, sText4, 
esel, TF::SENTENCE_CASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("-1    "), lcl_translitTest(editEng, sText4, 
esel, TF::TITLE_CASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("-1    "), lcl_translitTest(editEng, sText4, 
esel, TF::LOWERCASE_UPPERCASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("-1    "), lcl_translitTest(editEng, sText4, 
esel, TF::UPPERCASE_LOWERCASE));
+
+    /* Test what happens when node and selection contains only non-word text */
+    selStart = 0;
+    selEnd = 5;
+    esel = ESelection(0, selStart, 0, selEnd);
+    const OUString sText5("   -1");
+    editEng.SetText(sText3);
+    CPPUNIT_ASSERT_EQUAL(OUString("   -1"), editEng.GetText(esel));
+
+    CPPUNIT_ASSERT_EQUAL(OUString("   -1"), lcl_translitTest(editEng, sText5, 
esel, TF::SENTENCE_CASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("   -1"), lcl_translitTest(editEng, sText5, 
esel, TF::TITLE_CASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("   -1"), lcl_translitTest(editEng, sText5, 
esel, TF::LOWERCASE_UPPERCASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("   -1"), lcl_translitTest(editEng, sText5, 
esel, TF::UPPERCASE_LOWERCASE));
+
+    selStart = 0;
+    selEnd = 5;
+    esel = ESelection(0, selStart, 0, selEnd);
+    const OUString sText6("-1   ");
+    editEng.SetText(sText4);
+    CPPUNIT_ASSERT_EQUAL(OUString("-1   "), editEng.GetText(esel));
+
+    CPPUNIT_ASSERT_EQUAL(OUString("-1   "), lcl_translitTest(editEng, sText6, 
esel, TF::SENTENCE_CASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("-1   "), lcl_translitTest(editEng, sText6, 
esel, TF::TITLE_CASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("-1   "), lcl_translitTest(editEng, sText6, 
esel, TF::LOWERCASE_UPPERCASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("-1   "), lcl_translitTest(editEng, sText6, 
esel, TF::UPPERCASE_LOWERCASE));
+
+
+}
 
 CPPUNIT_TEST_SUITE_REGISTRATION(Test);
 
diff --git a/editeng/source/editeng/impedit4.cxx 
b/editeng/source/editeng/impedit4.cxx
index 03b8d511e5c3..35b6f6291687 100644
--- a/editeng/source/editeng/impedit4.cxx
+++ b/editeng/source/editeng/impedit4.cxx
@@ -2750,6 +2750,12 @@ EditSelection ImpEditEngine::TransliterateText( const 
EditSelection& rSelection,
                         nWordType);
             }
 
+            /* Nothing to do if user selection lies entirely outside of word 
start and end boundary computed above.
+             * Skip this node, because otherwise the below logic for 
constraining to the selection will fail */
+            if (aSttBndry.startPos >= aSel.Max().GetIndex() || 
aEndBndry.endPos <= aSel.Min().GetIndex()) {
+                continue;
+            }
+
             // prevent going outside of the user's selection, which may
             // start or end in the middle of a word
             if (nNode == nStartNode) {
@@ -2758,6 +2764,7 @@ EditSelection ImpEditEngine::TransliterateText( const 
EditSelection& rSelection,
                 aEndBndry.startPos = std::max(aEndBndry.startPos, 
aSttBndry.startPos);
                 aEndBndry.endPos   = std::min(aEndBndry.endPos,   
aSel.Max().GetIndex());
             }
+
             i18n::Boundary aCurWordBndry( aSttBndry );
             while (aCurWordBndry.endPos && aCurWordBndry.startPos <= 
aEndBndry.startPos)
             {
diff --git a/sw/qa/extras/uiwriter/uiwriter4.cxx 
b/sw/qa/extras/uiwriter/uiwriter4.cxx
index f6791e4ebb02..e3a625be7b30 100644
--- a/sw/qa/extras/uiwriter/uiwriter4.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter4.cxx
@@ -356,6 +356,122 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf147196)
         lcl_translitTest(*pDoc, *pCursor, TF::TITLE_CASE));
 }
 
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf148148)
+{
+    using TF = TransliterationFlags;
+    SwDoc* pDoc = createSwDoc();
+    SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+
+    pWrtShell->SttEndDoc(/*bStt=*/false);
+    pWrtShell->Insert("   text");
+
+    /* Test what happens when node contains text but selection does not 
contain any text */
+    pWrtShell->StartOfSection();
+    SwShellCursor* pCursor = pWrtShell->getShellCursor(false);
+    pCursor->SetMark();
+    for (int i = 0; i < 3; i++)
+    {
+        pCursor->Move(fnMoveForward);
+    }
+    CPPUNIT_ASSERT_EQUAL(OUString("   text"), lcl_translitTest(*pDoc, 
*pCursor, TF::TITLE_CASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("   text"), lcl_translitTest(*pDoc, 
*pCursor, TF::SENTENCE_CASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("   text"),
+                         lcl_translitTest(*pDoc, *pCursor, 
TF::LOWERCASE_UPPERCASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("   text"),
+                         lcl_translitTest(*pDoc, *pCursor, 
TF::UPPERCASE_LOWERCASE));
+
+    /* Test what happens when node contains text but selection does not 
contain any text */
+    pDoc = createSwDoc();
+    pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+    pWrtShell->SttEndDoc(/*bStt=*/false);
+    pWrtShell->Insert("text   ");
+
+    pWrtShell->StartOfSection();
+    pCursor = pWrtShell->getShellCursor(false);
+    for (int i = 0; i < 4; i++)
+    {
+        pCursor->Move(fnMoveForward);
+    }
+    pCursor->SetMark();
+    for (int i = 0; i < 2; i++)
+    {
+        pCursor->Move(fnMoveForward);
+    }
+
+    CPPUNIT_ASSERT_EQUAL(OUString("text   "), lcl_translitTest(*pDoc, 
*pCursor, TF::SENTENCE_CASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("text   "), lcl_translitTest(*pDoc, 
*pCursor, TF::TITLE_CASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("text   "),
+                         lcl_translitTest(*pDoc, *pCursor, 
TF::LOWERCASE_UPPERCASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("text   "),
+                         lcl_translitTest(*pDoc, *pCursor, 
TF::UPPERCASE_LOWERCASE));
+
+    /* Test what happens when node contains only non-word text but selection 
does not contain any text */
+    pDoc = createSwDoc();
+    pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+    pWrtShell->SttEndDoc(/*bStt=*/false);
+    pWrtShell->Insert("-1   ");
+
+    pWrtShell->StartOfSection();
+    pCursor = pWrtShell->getShellCursor(false);
+    for (int i = 0; i < 2; i++)
+    {
+        pCursor->Move(fnMoveForward);
+    }
+    pCursor->SetMark();
+    for (int i = 0; i < 2; i++)
+    {
+        pCursor->Move(fnMoveForward);
+    }
+
+    CPPUNIT_ASSERT_EQUAL(OUString("-1   "), lcl_translitTest(*pDoc, *pCursor, 
TF::SENTENCE_CASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("-1   "), lcl_translitTest(*pDoc, *pCursor, 
TF::TITLE_CASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("-1   "),
+                         lcl_translitTest(*pDoc, *pCursor, 
TF::LOWERCASE_UPPERCASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("-1   "),
+                         lcl_translitTest(*pDoc, *pCursor, 
TF::UPPERCASE_LOWERCASE));
+
+    pDoc = createSwDoc();
+    pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+    pWrtShell->SttEndDoc(/*bStt=*/false);
+    pWrtShell->Insert("   -1");
+
+    pWrtShell->StartOfSection();
+    pCursor = pWrtShell->getShellCursor(false);
+    pCursor->SetMark();
+    for (int i = 0; i < 2; i++)
+    {
+        pCursor->Move(fnMoveForward);
+    }
+
+    CPPUNIT_ASSERT_EQUAL(OUString("   -1"), lcl_translitTest(*pDoc, *pCursor, 
TF::SENTENCE_CASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("   -1"), lcl_translitTest(*pDoc, *pCursor, 
TF::TITLE_CASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("   -1"),
+                         lcl_translitTest(*pDoc, *pCursor, 
TF::LOWERCASE_UPPERCASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("   -1"),
+                         lcl_translitTest(*pDoc, *pCursor, 
TF::UPPERCASE_LOWERCASE));
+
+    /* Test what happens when node and selection contains only non-word text */
+    pDoc = createSwDoc();
+    pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+    pWrtShell->SttEndDoc(/*bStt=*/false);
+    pWrtShell->Insert("   -1");
+
+    pWrtShell->StartOfSection();
+    pCursor = pWrtShell->getShellCursor(false);
+    pCursor->SetMark();
+    for (int i = 0; i < 5; i++)
+    {
+        pCursor->Move(fnMoveForward);
+    }
+
+    CPPUNIT_ASSERT_EQUAL(OUString("   -1"), lcl_translitTest(*pDoc, *pCursor, 
TF::SENTENCE_CASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("   -1"), lcl_translitTest(*pDoc, *pCursor, 
TF::TITLE_CASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("   -1"),
+                         lcl_translitTest(*pDoc, *pCursor, 
TF::LOWERCASE_UPPERCASE));
+    CPPUNIT_ASSERT_EQUAL(OUString("   -1"),
+                         lcl_translitTest(*pDoc, *pCursor, 
TF::UPPERCASE_LOWERCASE));
+}
+
 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf96943)
 {
     // Enable hide whitespace mode.
diff --git a/sw/source/core/txtnode/txtedt.cxx 
b/sw/source/core/txtnode/txtedt.cxx
index 28b633755a7d..1188daef9821 100644
--- a/sw/source/core/txtnode/txtedt.cxx
+++ b/sw/source/core/txtnode/txtedt.cxx
@@ -1756,6 +1756,12 @@ void SwTextNode::TransliterateText(
                     nWordType);
         }
 
+        /* Nothing to do if user selection lies entirely outside of word start 
and end boundary computed above.
+         * Skip this node, because otherwise the below logic for constraining 
to the selection will fail */
+        if (aSttBndry.startPos >= selEnd || aEndBndry.endPos <= selStart) {
+            return;
+        }
+
         // prevent going outside of the user's selection, which may
         // start in the middle of a word
         aSttBndry.startPos = std::max(aSttBndry.startPos, selStart);

Reply via email to