sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx |    6 ++++++
 sw/source/filter/ww8/wrtw8nds.cxx             |   16 +++++++++++++---
 2 files changed, 19 insertions(+), 3 deletions(-)

New commits:
commit ab7e8ef92630cce4438ceb418c6e6796e7c672a0
Author:     Justin Luth <[email protected]>
AuthorDate: Tue Feb 10 12:13:59 2026 -0500
Commit:     Xisco Fauli <[email protected]>
CommitDate: Thu Feb 12 16:53:30 2026 +0100

    tdf#170686 docx export: end SDT before writing final flies
    
    A plainText-y content control is reported as corrupt
    by Microsoft Word if it contains a floating frame.
    
    When a runSdt was at the end of the paragraph,
    the export was dumping any flies at the end
    into the Sdt run.
    
    Instead, the Sdt should first be closed,
    and then the remaining flies
    should be placed into their own separate run.
    
    Possibly, this should happen for fields as well?
    Or even for any paragraph, like we did in bug tdf#170516?
    It probably also belongs in the other 'if nNextAttr == nEnd'
    but I couldn't find any example unit tests to confirm.
    
    make CppunitTest_sw_ooxmlfieldexport \
        CPPUNIT_TEST_NAME=testContentControlShape
    
    Change-Id: Ic1c160ed9c9985d4fcc308a271ee168fe00ea82b
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199092
    Tested-by: Jenkins
    Reviewed-by: Justin Luth <[email protected]>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199284
    Reviewed-by: Xisco Fauli <[email protected]>

diff --git a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
index 4b65fe4b8fc8..f8d806e8a041 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
@@ -1096,6 +1096,12 @@ CPPUNIT_TEST_FIXTURE(Test, testContentControlShape)
     // Then make sure that completes without an assertion failure, which would 
mean not-well-formed
     // output was produced, since the <w:sdt> was conditional but the </w:sdt> 
was unconditional:
     save(TestFilter::DOCX);
+
+    // tdf#170686: floating shapes are not allowed inside plainText date 
controls
+    xmlDocUniquePtr pXmlDoc = parseExport(u"word/document.xml"_ustr);
+    assertXPath(pXmlDoc, "//w:sdt", 1); // only one sdt
+    assertXPath(pXmlDoc, "//mc:AlternateContent", 1); // only one drawing
+    assertXPath(pXmlDoc, "//w:body/w:p/w:r/mc:AlternateContent", 1); // and it 
is not inside the sdt
 }
 
 CPPUNIT_TEST_FIXTURE(Test, testTdf104823)
diff --git a/sw/source/filter/ww8/wrtw8nds.cxx 
b/sw/source/filter/ww8/wrtw8nds.cxx
index 2f7c6882d746..ccbaf678958c 100644
--- a/sw/source/filter/ww8/wrtw8nds.cxx
+++ b/sw/source/filter/ww8/wrtw8nds.cxx
@@ -2510,9 +2510,9 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
             OUString aSavedSnippet ;
 
             // Don't redline content-controls--Word doesn't do them.
-            SwTextAttr* pAttr = rNode.GetTextAttrAt(nCurrentPos, 
RES_TXTATR_CONTENTCONTROL,
-                                                    
sw::GetTextAttrMode::Default);
-            if (pAttr && pAttr->GetStart() == nCurrentPos)
+            const SwTextAttr* pSdt = rNode.GetTextAttrAt(nCurrentPos, 
RES_TXTATR_CONTENTCONTROL,
+                                                         
sw::GetTextAttrMode::Default);
+            if (pSdt && pSdt->GetStart() == nCurrentPos)
             {
                 pRedlineData = nullptr;
             }
@@ -2816,6 +2816,16 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode 
)
                     else
                     {
                         // insert final graphic anchors if any before CR
+                        if (pSdt && *pSdt->GetEnd() == nEnd && 
aAttrIter.HasFlysAt(nEnd))
+                        {
+                            // Close the content control run before exporting 
final flies,
+                            // otherwise the flies will be moved into the Sdt 
run,
+                            // which (for a non-richText Sdt) will be 
considered corrupt in MS Word.
+                            AttrOutput().EndRun(&rNode, nCurrentPos, nLen, 
/*bLastRun=*/false);
+                            nLen = 0;
+                            nCurrentPos = nEnd;
+                            AttrOutput().StartRun(pRedlineData, nCurrentPos, 
bSingleEmptyRun);
+                        }
                         nStateOfFlyFrame = aAttrIter.OutFlys( nEnd );
                         // insert final bookmarks if any before CR and after 
flys
                         AppendBookmarks( rNode, nEnd, 1 );

Reply via email to