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 )
                 {

Reply via email to