sw/qa/extras/ww8export/data/clearing-break-with-fly.docx |binary sw/qa/extras/ww8export/ww8export3.cxx | 13 +++++++++++++ sw/source/filter/ww8/ww8par.hxx | 9 +++++++++ sw/source/filter/ww8/ww8par2.cxx | 10 +--------- sw/source/filter/ww8/ww8par6.cxx | 6 +----- 5 files changed, 24 insertions(+), 14 deletions(-)
New commits: commit 9c7c9a59a753fd7765b53c4277e413367d6985f3 Author: Caolán McNamara <[email protected]> AuthorDate: Fri Mar 13 20:55:50 2026 +0000 Commit: Caolán McNamara <[email protected]> CommitDate: Sat Mar 14 11:41:41 2026 +0100 crashtesting: SwContentIndexReg::~SwContentIndexReg on reimport of docx->doc seen on converting tdf105261-1.docx to doc and importing. Looks to me that the ww8par6.cxx case is a copy of the ww8par2.cxx case and we could use the bodges added for ofz#38011 save and restore m_pLastAnchorPos via UnoCursor ofz#9858 Bad-cast in ww8par6.cxx too, but lets try replacing the character rather than deleting and inserting a new one, and keep the flyframes anchored to that position and see if can sidestep those issues. Change-Id: Ib5da08558d054c5cae5935e525245a717fc9075c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/201678 Reviewed-by: Caolán McNamara <[email protected]> Tested-by: Jenkins diff --git a/sw/qa/extras/ww8export/data/clearing-break-with-fly.docx b/sw/qa/extras/ww8export/data/clearing-break-with-fly.docx new file mode 100644 index 000000000000..165ca7cffc46 Binary files /dev/null and b/sw/qa/extras/ww8export/data/clearing-break-with-fly.docx differ diff --git a/sw/qa/extras/ww8export/ww8export3.cxx b/sw/qa/extras/ww8export/ww8export3.cxx index 8dbd63fb7dac..269cc7cb2f50 100644 --- a/sw/qa/extras/ww8export/ww8export3.cxx +++ b/sw/qa/extras/ww8export/ww8export3.cxx @@ -1147,6 +1147,19 @@ CPPUNIT_TEST_FIXTURE(Test, testClearingBreak) verify(); } +CPPUNIT_TEST_FIXTURE(Test, testClearingBreakWithFly) +{ + // Given a .docx with clearing breaks and fly frames anchored at the same + // character positions, export to .doc and reimport: + // Without the fix, the .doc import would crash because Read_LineBreakClear + // used DeleteRange to replace the linebreak char, which triggered + // DelFlyInRange and destroyed fly frames whose content nodes still had + // content indices registered. + createSwDoc("clearing-break-with-fly.docx"); + saveAndReload(TestFilter::DOC); + CPPUNIT_ASSERT_EQUAL(3, getShapes()); +} + CPPUNIT_TEST_FIXTURE(Test, testTdf142840) { createSwDoc("tdf142840.odt"); diff --git a/sw/source/filter/ww8/ww8par.hxx b/sw/source/filter/ww8/ww8par.hxx index ddb301b4c02c..9b9b4516395a 100644 --- a/sw/source/filter/ww8/ww8par.hxx +++ b/sw/source/filter/ww8/ww8par.hxx @@ -118,6 +118,15 @@ namespace com::sun::star{ namespace lang{class XMultiServiceFactory;} } +// Replace a character with a text attribute item. Use EraseText rather than +// DeleteRange to avoid DelFlyInRange deleting fly frames that happen to be +// anchored at this character position. +inline SwTextAttr* ReplaceCharWithItem(SwTextNode& rText, sal_Int32 nPos, SfxPoolItem& rItem) +{ + rText.EraseText(SwPosition(rText, nPos), 1); + return rText.InsertItem(rItem, nPos, nPos); +} + // defines only for the WW8-variable of the INI file #define WW8FL_NO_STYLES 2 #define WW8FL_NO_GRAF 0x80 diff --git a/sw/source/filter/ww8/ww8par2.cxx b/sw/source/filter/ww8/ww8par2.cxx index 251e9dcf13f5..078f5c16841d 100644 --- a/sw/source/filter/ww8/ww8par2.cxx +++ b/sw/source/filter/ww8/ww8par2.cxx @@ -222,16 +222,8 @@ sal_uInt16 SwWW8ImplReader::End_Footnote() if (pText && nPos) { sChar += OUStringChar(pText->GetText()[--nPos]); - m_pPaM->SetMark(); - m_pPaM->GetMark()->AdjustContent(-1); - std::shared_ptr<SwUnoCursor> xLastAnchorCursor(m_oLastAnchorPos ? m_rDoc.CreateUnoCursor(*m_oLastAnchorPos) : nullptr); - m_oLastAnchorPos.reset(); - m_rDoc.getIDocumentContentOperations().DeleteRange( *m_pPaM ); - m_pPaM->DeleteMark(); - if (xLastAnchorCursor) - m_oLastAnchorPos.emplace(*xLastAnchorCursor->GetPoint()); SwFormatFootnote aFootnote(rDesc.meType == MAN_EDN); - pFN = static_cast<SwTextFootnote*>(pText->InsertItem(aFootnote, nPos, nPos)); + pFN = static_cast<SwTextFootnote*>(ReplaceCharWithItem(*pText, nPos, aFootnote)); } OSL_ENSURE(pFN, "Problems creating the footnote text"); if (pFN) diff --git a/sw/source/filter/ww8/ww8par6.cxx b/sw/source/filter/ww8/ww8par6.cxx index 51724613a877..e3058c0a94a1 100644 --- a/sw/source/filter/ww8/ww8par6.cxx +++ b/sw/source/filter/ww8/ww8par6.cxx @@ -4732,13 +4732,9 @@ void SwWW8ImplReader::Read_LineBreakClear(sal_uInt16 /*nId*/, const sal_uInt8* p // Replace the linebreak char with a clearing break. --nPos; - m_pPaM->SetMark(); - m_pPaM->GetMark()->AdjustContent(-1); - m_rDoc.getIDocumentContentOperations().DeleteRange(*m_pPaM); - m_pPaM->DeleteMark(); SwFormatLineBreak aLineBreak(*m_oLineBreakClear); m_oLineBreakClear.reset(); - pText->InsertItem(aLineBreak, nPos, nPos); + ReplaceCharWithItem(*pText, nPos, aLineBreak); } if (nLen < 1)
