sw/source/filter/ww8/wrtw8nds.cxx | 37 ++++--------------------------------- 1 file changed, 4 insertions(+), 33 deletions(-)
New commits: commit d96164ec47b4a3716bf171fe81bdb3db8778beb1 Author: Justin Luth <[email protected]> AuthorDate: Mon Feb 2 11:19:38 2026 -0500 Commit: Justin Luth <[email protected]> CommitDate: Thu Feb 5 14:51:01 2026 +0100 tdf#170516 docx export: (almost) always write flies in separate w:r I don't see any reason why flies should not be written in their own run - separate from whatever follows. That seems to be what Microsoft does. This was practically the case earlier, so I'm not really changing much. It just means that a few edge cases aren't slipping through the cracks anymore. This should allow cleanup of hard-to-understand hackery. I'll attempt that in follow-up patches. This unit test makes sure my run-split is after bookmarks/annotations make CppunitTest_sw_ooxmlexport13 \ CPPUNIT_TEST_NAME=testImageCommentAtChar Change-Id: If2c73b92d68a3a70502726417d62917be148f7d0 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198380 Tested-by: Jenkins Reviewed-by: Justin Luth <[email protected]> diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx index cda69bc6d464..c5568fe220af 100644 --- a/sw/source/filter/ww8/wrtw8nds.cxx +++ b/sw/source/filter/ww8/wrtw8nds.cxx @@ -2508,11 +2508,9 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) // Don't redline content-controls--Word doesn't do them. SwTextAttr* pAttr = rNode.GetTextAttrAt(nCurrentPos, RES_TXTATR_CONTENTCONTROL, sw::GetTextAttrMode::Default); - bool bIsStartOfContentControl = false; if (pAttr && pAttr->GetStart() == nCurrentPos) { pRedlineData = nullptr; - bIsStartOfContentControl = true; } sal_Int32 nNextAttr = GetNextPos( &aAttrIter, rNode, nCurrentPos ); @@ -2542,20 +2540,6 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) } } - /* - 1) If there is a text node and an overlapping anchor, then write them in two different - runs and not as part of the same run. - 2) Ensure that it is a text node and not in a fly. - 3) If the anchor is associated with a text node with empty text then we ignore. - */ - if (GetExportFormat() == MSWordExportBase::ExportFormat::DOCX - && aStr != OUStringChar(CH_TXTATR_BREAKWORD) && !aStr.isEmpty() - && !rNode.GetFlyFormat() - && aAttrIter.IsAnchorLinkedToThisNode(rNode.GetIndex()) ) - { - bPostponeWritingText = true ; - } - FlyProcessingState nStateOfFlyFrame = aAttrIter.OutFlys( nCurrentPos ); AttrOutput().SetStateOfFlyFrame( nStateOfFlyFrame ); AttrOutput().SetAnchorIsLinkedToNode( bPostponeWritingText && (FLY_POSTPONED != nStateOfFlyFrame) ); @@ -2577,16 +2561,13 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) OUString aSymbolFont; sal_Int32 nLen = nNextAttr - nCurrentPos; - if (!bPostponeWritingText && bIsStartOfContentControl - && nStateOfFlyFrame == FLY_PROCESSED + // DOCX: Put the flies in their own run. + // This is critical for plainText content controls and fields. + if (nStateOfFlyFrame == FLY_PROCESSED && !aStr.isEmpty() + && aStr != OUStringChar(CH_TXTATR_BREAKWORD) && GetExportFormat() == MSWordExportBase::ExportFormat::DOCX) { // FLY_PROCESSED: there is at least 1 fly already written - - // assurance: this will not duplicate what is done for fields below... - assert(bTextAtr); // because SwTextContentControl always SetHasDummyChar(true) - - // write flys in a separate run before Sdt content control AttrOutput().EndRun(&rNode, nCurrentPos, /*nLen=*/-1, /*bLastRun=*/false); AttrOutput().StartRun(pRedlineData, nCurrentPos, bSingleEmptyRun); } @@ -2600,16 +2581,6 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) || ch == CH_TXT_ATR_FIELDEND || ch == CH_TXT_ATR_FORMELEMENT) ? 1 : 0; - if (ofs == 1 - && GetExportFormat() == MSWordExportBase::ExportFormat::DOCX - // FLY_PROCESSED: there's at least 1 fly already written - && nStateOfFlyFrame == FLY_PROCESSED) - { - // write flys in a separate run before field character - AttrOutput().EndRun(&rNode, nCurrentPos, -1, nNextAttr == nEnd); - AttrOutput().StartRun(pRedlineData, nCurrentPos, bSingleEmptyRun); - } - IDocumentMarkAccess* const pMarkAccess = m_rDoc.getIDocumentMarkAccess(); if ( ch == CH_TXT_ATR_FIELDSTART ) {
