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);