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

Reply via email to