sw/qa/extras/uiwriter/uiwriter9.cxx                     |   41 ++++++++++++++++
 sw/source/core/doc/DocumentContentOperationsManager.cxx |   14 ++++-
 2 files changed, 52 insertions(+), 3 deletions(-)

New commits:
commit 344c18c8e54a4382f7b990b58ed4c083d0568f74
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Wed Feb 21 16:20:08 2024 +0600
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Wed Feb 21 21:16:15 2024 +0100

    tdf#159813, tdf#159816: Use correct copied PaM
    
    This fixes both the assertion in CopyFlyInFlyImpl (tdf#159813) and
    crash in BigPtrArray::operator[] (tdf#159816).
    
    Change-Id: Ia3424e3a58c7d8fb3e1257dcdbf062fb893da8db
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163683
    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/+/163698

diff --git a/sw/qa/extras/uiwriter/uiwriter9.cxx 
b/sw/qa/extras/uiwriter/uiwriter9.cxx
index 58c95f21d03d..3772955dd9c1 100644
--- a/sw/qa/extras/uiwriter/uiwriter9.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter9.cxx
@@ -28,8 +28,10 @@
 #include <ndtxt.hxx>
 #include <toxmgr.hxx>
 #include <IDocumentFieldsAccess.hxx>
+#include <IDocumentLayoutAccess.hxx>
 #include <IDocumentRedlineAccess.hxx>
 #include <fmtinfmt.hxx>
+#include <rootfrm.hxx>
 
 namespace
 {
@@ -159,6 +161,45 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf159565)
                          xSelection->getString());
 }
 
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf159816)
+{
+    createSwDoc();
+
+    SwDoc* pDoc = getSwDoc();
+    CPPUNIT_ASSERT(pDoc);
+    SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+    CPPUNIT_ASSERT(pWrtShell);
+
+    // Add 5 empty paragraphs
+    pWrtShell->SplitNode();
+    pWrtShell->SplitNode();
+    pWrtShell->SplitNode();
+    pWrtShell->SplitNode();
+    pWrtShell->SplitNode();
+
+    // Add a bookmark at the very end
+    IDocumentMarkAccess& rIDMA(*pDoc->getIDocumentMarkAccess());
+    rIDMA.makeMark(*pWrtShell->GetCursor(), "Mark", 
IDocumentMarkAccess::MarkType::BOOKMARK,
+                   sw::mark::InsertMode::New);
+
+    // Get coordinates of the end point in the document
+    SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
+    SwFrame* pPage = pLayout->Lower();
+    SwFrame* pBody = pPage->GetLower();
+    SwFrame* pLastPara = 
pBody->GetLower()->GetNext()->GetNext()->GetNext()->GetNext()->GetNext();
+    Point ptTo = pLastPara->getFrameArea().BottomRight();
+
+    pWrtShell->SelAll();
+
+    // Drag-n-drop to its own end
+    rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);
+    // Without the fix, this would crash: either in CopyFlyInFlyImpl 
(tdf#159813):
+    // Assertion failed: !pCopiedPaM || pCopiedPaM->End()->GetNode() == 
rRg.aEnd.GetNode()
+    // or in BigPtrArray::operator[] (tdf#159816):
+    // Assertion failed: idx < m_nSize
+    xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, 
/*bXSelection=*/true);
+}
+
 } // end of anonymous namespace
 CPPUNIT_PLUGIN_IMPLEMENT();
 
diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx 
b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index 09e0a1233e5d..57b8e58310d9 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -3788,11 +3788,16 @@ void DocumentContentOperationsManager::CopyWithFlyInFly(
     SwDoc& rDest = rInsPos.GetDoc();
     SwNodeIndex aSavePos( rInsPos );
 
+    SwPaM aCopiedPaM(rRg.aStart, rRg.aEnd);
+    if (pCopiedPaM)
+        aCopiedPaM = pCopiedPaM->first;
+
     if (rRg.aStart != rRg.aEnd)
     {
         bool bEndIsEqualEndPos = rInsPos == rRg.aEnd.GetNode();
         --aSavePos;
         SaveRedlEndPosForRestore aRedlRest( rInsPos, 0 );
+        auto savedEndContentIndex = aCopiedPaM.End()->GetContentIndex();
 
         // insert behind the already copied start node
         m_rDoc.GetNodes().CopyNodes( rRg, rInsPos, false, true );
@@ -3801,6 +3806,10 @@ void DocumentContentOperationsManager::CopyWithFlyInFly(
         if (bEndIsEqualEndPos)
         {
             const_cast<SwNodeIndex&>(rRg.aEnd).Assign(aSavePos.GetNode(), +1);
+            // pCopiedPaM->first now spans a range from the start of the 
original selection
+            // to the end of newly added text, and the insertion point is in 
the middle of
+            // that range. Adjust the local copy to cover the original copied 
PaM.
+            aCopiedPaM.End()->Assign(rRg.aEnd, savedEndContentIndex);
         }
     }
 
@@ -3810,7 +3819,6 @@ void DocumentContentOperationsManager::CopyWithFlyInFly(
     // sw_fieldmarkhide: also needs to be done before making frames
     if (m_rDoc.getIDocumentMarkAccess()->getAllMarksCount())
     {
-        SwPaM aRgTmp( rRg.aStart, rRg.aEnd );
         SwPosition targetPos(aSavePos, SwNodeOffset(rRg.aStart != rRg.aEnd ? 
+1 : 0));
         if (pCopiedPaM && rRg.aStart != pCopiedPaM->first.Start()->GetNode())
         {
@@ -3823,7 +3831,7 @@ void DocumentContentOperationsManager::CopyWithFlyInFly(
             targetPos = pCopiedPaM->second;
         }
 
-        sw::CopyBookmarks(pCopiedPaM ? pCopiedPaM->first : aRgTmp, targetPos, 
flags);
+        sw::CopyBookmarks(aCopiedPaM, targetPos, flags);
     }
 
     if (rRg.aStart != rRg.aEnd)
@@ -3914,7 +3922,7 @@ void DocumentContentOperationsManager::CopyWithFlyInFly(
 
     {
         ::sw::UndoGuard const undoGuard(rDest.GetIDocumentUndoRedo());
-        CopyFlyInFlyImpl(rRg, pCopiedPaM ? &pCopiedPaM->first : nullptr,
+        CopyFlyInFlyImpl(rRg, pCopiedPaM ? &aCopiedPaM : nullptr,
             // see comment below regarding use of pCopiedPaM->second
             (pCopiedPaM && rRg.aStart != pCopiedPaM->first.Start()->GetNode())
                 ? pCopiedPaM->second.GetNode()

Reply via email to