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