sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx | 6 ++++++ sw/source/filter/ww8/wrtw8nds.cxx | 16 +++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-)
New commits: commit e606e8f75a9297af67177d4b97f27a550ce2b6cf Author: Justin Luth <[email protected]> AuthorDate: Tue Feb 10 12:13:59 2026 -0500 Commit: Justin Luth <[email protected]> CommitDate: Wed Feb 11 13:45:05 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]> 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 e1c036339a92..64118f6aa51a 100644 --- a/sw/source/filter/ww8/wrtw8nds.cxx +++ b/sw/source/filter/ww8/wrtw8nds.cxx @@ -2492,9 +2492,9 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) const SwRedlineData* pRedlineData = aAttrIter.GetRunLevelRedline( nCurrentPos ); // 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; } @@ -2772,6 +2772,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); + } aAttrIter.OutFlys(nEnd); // insert final bookmarks if any before CR and after flys AppendBookmarks( rNode, nEnd, 1 );
