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

New commits:
commit d71c92ffe97c11e8a575cca38e36ef6916c4a3cc
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Wed Feb 21 16:20:08 2024 +0600
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Thu Feb 22 11:18:29 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
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163712

diff --git a/sw/qa/extras/uiwriter/uiwriter9.cxx 
b/sw/qa/extras/uiwriter/uiwriter9.cxx
index b6dea5a8e798..9f961b1def60 100644
--- a/sw/qa/extras/uiwriter/uiwriter9.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter9.cxx
@@ -26,8 +26,10 @@
 #include <ndtxt.hxx>
 #include <toxmgr.hxx>
 #include <IDocumentFieldsAccess.hxx>
+#include <IDocumentLayoutAccess.hxx>
 #include <IDocumentRedlineAccess.hxx>
 #include <fmtinfmt.hxx>
+#include <rootfrm.hxx>
 
 namespace
 {
@@ -68,6 +70,45 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf158785)
     CPPUNIT_ASSERT_EQUAL(IsAttrAtPos::NONE, aContentAtPos.eContentAtPos);
 }
 
+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 anonymouse namespace
 CPPUNIT_PLUGIN_IMPLEMENT();
 
diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx 
b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index 6b1404ecbf0b..edfa3e8efcb0 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -3725,11 +3725,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 );
@@ -3738,6 +3743,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);
         }
     }
 
@@ -3747,7 +3756,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())
         {
@@ -3760,7 +3768,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)
@@ -3851,7 +3859,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