From 3eced2d52415abeac266804ab682bee022322a19 Mon Sep 17 00:00:00 2001 From: Michael Stahl Date: Wed, 10 Mar 2021 11:26:07 +0100 Subject: sw: DOCX export: put fly before fieldmark start into its own run If a fly starts at the same position as a CH_TXT_ATR_FIELDSTART, it is anchored before the field, and written in OutFlys() before the field is written in EndRun(), but the DOCX export reorders things in confusing ways. StartField_Impl() and CmdField_Impl() will actually end the current run (after putting the field char in it) and start a new one. So do something similar in this situation and create a new run if flys have been processed. Restrict this extra run to when there is actually a fly, because otherwise a dozen tests break; this requires a new FLY_NONE result for OutFlys() because FLY_PROCESSED is returned even if there are no flys. Change-Id: Id469c53d07eacad3992c7c0e451ab3756e02c8fa Reviewed-on: https://gerrit.libreoffice.org/c/core/+/112267 Tested-by: Jenkins Reviewed-by: Michael Stahl --- sw/qa/extras/ooxmlexport/data/fly_fieldmark.fodt | 60 ++++++++++++++++++++++++ sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx | 12 +++++ sw/source/filter/ww8/wrtw8nds.cxx | 23 +++++++-- sw/source/filter/ww8/wrtww8.hxx | 1 + 4 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 sw/qa/extras/ooxmlexport/data/fly_fieldmark.fodt diff --git a/sw/qa/extras/ooxmlexport/data/fly_fieldmark.fodt b/sw/qa/extras/ooxmlexport/data/fly_fieldmark.fodt new file mode 100644 index 000000000000..af1ae9a86243 --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/fly_fieldmark.fodt @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + foobar + + + diff --git a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx index 9c5f05e51534..887ffc7560ad 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx @@ -484,6 +484,18 @@ DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testEditTime, "fdo81341.docx") assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r[5]/w:fldChar", "fldCharType", "end"); } +DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testFlyFieldmark, "fly_fieldmark.fodt") +{ + // the problem was that the flys were written after the field start + xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); + // run 1 contains 2 shapes, one was at-page, one was at-char + assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:r[1]/mc:AlternateContent", 2); + // run 2 contains the field start + assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:r[2]/w:fldChar", "fldCharType", "begin"); + // run 3 contains the field instruction text + assertXPathContent(pXmlDoc, "/w:document/w:body/w:p[1]/w:r[3]/w:instrText", " FORMTEXT "); +} + DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testFdo81945, "fdo81945.docx") { xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx index 9b0853af3b0b..9cfe85c0b1fc 100644 --- a/sw/source/filter/ww8/wrtw8nds.cxx +++ b/sw/source/filter/ww8/wrtw8nds.cxx @@ -710,6 +710,11 @@ FlyProcessingState SwWW8AttrIter::OutFlys(sal_Int32 nSwPos) ++linkedTextboxesIter; } + if (maFlyIter == maFlyFrames.end()) + { + return FLY_NONE; + } + /* #i2916# May have an anchored graphic to be placed, loop through sorted array @@ -2339,7 +2344,6 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) do { const SwRedlineData* pRedlineData = aAttrIter.GetRunLevelRedline( nCurrentPos ); - FlyProcessingState nStateOfFlyFrame = FLY_PROCESSED; bool bPostponeWritingText = false ; OUString aSavedSnippet ; @@ -2385,7 +2389,7 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) bPostponeWritingText = true ; } - nStateOfFlyFrame = aAttrIter.OutFlys( nCurrentPos ); + FlyProcessingState nStateOfFlyFrame = aAttrIter.OutFlys( nCurrentPos ); AttrOutput().SetStateOfFlyFrame( nStateOfFlyFrame ); AttrOutput().SetAnchorIsLinkedToNode( bPostponeWritingText && (FLY_POSTPONED != nStateOfFlyFrame) ); // Append bookmarks in this range after flys, exclusive of final @@ -2413,6 +2417,15 @@ 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, nNextAttr == nEnd); + AttrOutput().StartRun(pRedlineData, nCurrentPos, bSingleEmptyRun); + } IDocumentMarkAccess* const pMarkAccess = m_rDoc.getIDocumentMarkAccess(); if ( ch == CH_TXT_ATR_FIELDSTART ) @@ -2595,7 +2608,8 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) AttrOutput().FormatDrop( rNode, aAttrIter.GetSwFormatDrop(), nStyle, pTextNodeInfo, pTextNodeInfoInner ); // Only output character attributes if this is not a postponed text run. - if (0 != nEnd && !(bPostponeWritingText && FLY_PROCESSED == nStateOfFlyFrame)) + if (0 != nEnd && !(bPostponeWritingText + && (FLY_PROCESSED == nStateOfFlyFrame || FLY_NONE == nStateOfFlyFrame))) { // Output the character attributes // #i51277# do this before writing flys at end of paragraph @@ -2702,7 +2716,8 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) AttrOutput().WritePostitFieldReference(); - if( bPostponeWritingText && FLY_PROCESSED == nStateOfFlyFrame ) + if (bPostponeWritingText + && (FLY_PROCESSED == nStateOfFlyFrame || FLY_NONE == nStateOfFlyFrame)) { AttrOutput().EndRun(&rNode, nCurrentPos, nNextAttr == nEnd); //write the postponed text run diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx index 9778044a8a35..66c4573dc96a 100644 --- a/sw/source/filter/ww8/wrtww8.hxx +++ b/sw/source/filter/ww8/wrtww8.hxx @@ -163,6 +163,7 @@ enum to state the present state of the fly */ enum FlyProcessingState { + FLY_NONE, FLY_PROCESSED, FLY_POSTPONED, FLY_NOT_PROCESSED -- cgit