sw/qa/extras/unowriter/unowriter.cxx | 21 +++++++++++++++++++++ sw/source/core/unocore/unoobj.cxx | 12 +++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-)
New commits: commit 41586f2f417a2d55d6baa07d3885d2d117a16d1d Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Wed Mar 20 16:24:07 2024 +0500 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Fri Mar 22 08:35:46 2024 +0100 tdf#160278: restore cursor bounds properly The passed string length is not a correct measure of how many steps should the selection expand in the resulting text: the cursor goes over glyphs, not over UTF-16 code units. Thus, it's easier to store the position prior to insertion, and restore it from the indexes. Change-Id: I1d592ff30199007ba3a99d7e1a6d2db2da35f1cb Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165056 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165145 diff --git a/sw/qa/extras/unowriter/unowriter.cxx b/sw/qa/extras/unowriter/unowriter.cxx index 8bcadbaf4227..80b9e556f73b 100644 --- a/sw/qa/extras/unowriter/unowriter.cxx +++ b/sw/qa/extras/unowriter/unowriter.cxx @@ -1201,6 +1201,27 @@ CPPUNIT_TEST_FIXTURE(SwUnoWriter, testTdf129841) CPPUNIT_ASSERT_EQUAL(aRefColor, aColor); } +CPPUNIT_TEST_FIXTURE(SwUnoWriter, testTdf160278) +{ + createSwDoc(); + auto xTextDocument(mxComponent.queryThrow<css::text::XTextDocument>()); + auto xText(xTextDocument->getText()); + xText->setString(u"123"_ustr); + CPPUNIT_ASSERT_EQUAL(u"123"_ustr, xText->getString()); + auto xCursor = xText->createTextCursorByRange(xText->getEnd()); + xCursor->goLeft(1, true); + CPPUNIT_ASSERT_EQUAL(u"3"_ustr, xCursor->getString()); + // Insert an SMP character U+1f702 (so it's two UTF-16 code units, 0xd83d 0xdf02): + xCursor->setString(u"🜂"_ustr); + // Without the fix, the replacement would expand the cursor one too many characters to the left, + // and the cursor text would become "2🜂", failing the next test: + CPPUNIT_ASSERT_EQUAL(u"🜂"_ustr, xCursor->getString()); + xCursor->setString(u"test"_ustr); + CPPUNIT_ASSERT_EQUAL(u"test"_ustr, xCursor->getString()); + // This test would fail, too; the text would be "1test": + CPPUNIT_ASSERT_EQUAL(u"12test"_ustr, xText->getString()); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unoobj.cxx b/sw/source/core/unocore/unoobj.cxx index 49562c1d0284..df02c4773a15 100644 --- a/sw/source/core/unocore/unoobj.cxx +++ b/sw/source/core/unocore/unoobj.cxx @@ -752,13 +752,19 @@ void SwXTextCursor::DeleteAndInsert(std::u16string_view aText, } if(nTextLen) { + // Store node and content indexes prior to insertion: to select the inserted text, + // we need to account for possible surrogate pairs, combining characters, etc.; it + // is easier to just restore the correct position from the indexes. + const auto start = pCurrent->Start(); + const auto nodeIndex = start->GetNodeIndex(); + const auto contentIndex = start->GetContentIndex(); const bool bSuccess( SwUnoCursorHelper::DocInsertStringSplitCR( - rDoc, *pCurrent, aText, bool(eMode & ::sw::DeleteAndInsertMode::ForceExpandHints))); + rDoc, SwPaM(*start, pCurrent), aText, bool(eMode & ::sw::DeleteAndInsertMode::ForceExpandHints))); OSL_ENSURE( bSuccess, "Doc->Insert(Str) failed." ); - SwUnoCursorHelper::SelectPam(*pUnoCursor, true); - pCurrent->Left(aText.size()); + pCurrent->SetMark(); + pCurrent->GetPoint()->Assign(nodeIndex, contentIndex); } pCurrent = pCurrent->GetNext(); } while (pCurrent != pUnoCursor);