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)

Reply via email to