include/test/xmltesttools.hxx                              |    4 ++
 sw/qa/extras/ooxmlexport/data/tdf152200-field+textbox.docx |binary
 sw/qa/extras/ooxmlexport/ooxmlexport18.cxx                 |   23 +++++++++++++
 sw/source/filter/ww8/wrtw8nds.cxx                          |    8 ++++
 test/source/xmltesttools.cxx                               |   12 +++++-
 5 files changed, 44 insertions(+), 3 deletions(-)

New commits:
commit 4fbdc82cb3afce1f067ae45253b2fe50678cb948
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Fri Nov 25 15:20:48 2022 +0300
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Fri Nov 25 20:56:02 2022 +0100

    tdf#152200: Make sure to not write objects into field character runs
    
    Similar how it's done for preceding objects immediately after calculating
    'ofs', we also need to make sure to create a separate run for the objects
    that may be anchored after the last character; otherwise, the field that
    was just processed (and is waiting in the attributes) would be put out of
    place, inside an inner run (e.g., in a text box inside the object).
    
    Change-Id: I2702693595acf4befdbd25ef07a9f7c444926aab
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143297
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    (cherry picked from commit ec345c02d8fa5a7c7d4ea4ad08ae7be5303d9b20)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143259
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>

diff --git a/include/test/xmltesttools.hxx b/include/test/xmltesttools.hxx
index a4f0ef30d8ba..e37638fa674c 100644
--- a/include/test/xmltesttools.hxx
+++ b/include/test/xmltesttools.hxx
@@ -61,6 +61,10 @@ protected:
      * Useful for checking relative order of elements.
      */
     int           getXPathPosition(const xmlDocUniquePtr& pXmlDoc, const 
OString& rXPath, std::string_view rChildName);
+    /**
+     * Get the number of the nodes returned by the rXPath.
+     */
+    int           countXPathNodes(const xmlDocUniquePtr& pXmlDoc, const 
OString& rXPath);
     /**
      * Assert that rXPath exists, and returns exactly one node.
      */
diff --git a/sw/qa/extras/ooxmlexport/data/tdf152200-field+textbox.docx 
b/sw/qa/extras/ooxmlexport/data/tdf152200-field+textbox.docx
new file mode 100644
index 000000000000..606d1346a27a
Binary files /dev/null and 
b/sw/qa/extras/ooxmlexport/data/tdf152200-field+textbox.docx differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx
index 2d5cca60eb27..c0d3e7c6d161 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx
@@ -92,6 +92,29 @@ CPPUNIT_TEST_FIXTURE(Test, testImageCropping)
     CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aGraphicCropStruct.Bottom);
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testTdf152200)
+{
+    // Given a document with a fly anchored after a FORMTEXT in the end of the 
paragraph:
+    // When exporting that back to DOCX:
+    loadAndSave("tdf152200-field+textbox.docx");
+
+    // Then make sure that fldChar with type 'end' goes prior to the at-char 
anchored fly.
+    xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
+    const int nRunsBeforeFldCharEnd = countXPathNodes(pXmlDoc, 
"//w:fldChar[@w:fldCharType='end']/preceding::w:r");
+    CPPUNIT_ASSERT(nRunsBeforeFldCharEnd);
+    const int nRunsBeforeAlternateContent = countXPathNodes(pXmlDoc, 
"//mc:AlternateContent/preceding::w:r");
+    CPPUNIT_ASSERT(nRunsBeforeAlternateContent);
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected greater than: 6
+    // - Actual  : 5
+    CPPUNIT_ASSERT_GREATER(nRunsBeforeFldCharEnd, nRunsBeforeAlternateContent);
+    // Make sure we only have one paragraph in body, and only three field 
characters overal,
+    // located directly in runs of this paragraph
+    assertXPath(pXmlDoc, "/w:document/w:body/w:p");
+    assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r/w:fldChar", 3);
+    assertXPath(pXmlDoc, "//w:fldChar", 3); // no field characters elsewhere
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/ww8/wrtw8nds.cxx 
b/sw/source/filter/ww8/wrtw8nds.cxx
index 595b700fc663..423b8dc3ee81 100644
--- a/sw/source/filter/ww8/wrtw8nds.cxx
+++ b/sw/source/filter/ww8/wrtw8nds.cxx
@@ -2654,6 +2654,14 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode 
)
                     bPostponeWritingText = false ;
                     AttrOutput().RunText( aSnippet, eChrSet );
                 }
+
+                if (ofs == 1 && nNextAttr == nEnd)
+                {
+                    // tdf#152200: There could be flys anchored after the last 
position; make sure
+                    // to provide a separate run after field character to 
write them
+                    AttrOutput().EndRun(&rNode, nCurrentPos, -1, nNextAttr == 
nEnd);
+                    AttrOutput().StartRun(pRedlineData, nCurrentPos, 
bSingleEmptyRun);
+                }
             }
 
             if ( aAttrIter.IsDropCap( nNextAttr ) )
diff --git a/test/source/xmltesttools.cxx b/test/source/xmltesttools.cxx
index 07dc1f1f59f2..63580366e65e 100644
--- a/test/source/xmltesttools.cxx
+++ b/test/source/xmltesttools.cxx
@@ -183,13 +183,19 @@ void XmlTestTools::assertXPathAttrs(const 
xmlDocUniquePtr& pXmlDoc, const OStrin
     }
 }
 
-void XmlTestTools::assertXPath(const xmlDocUniquePtr& pXmlDoc, const OString& 
rXPath, int nNumberOfNodes)
+int XmlTestTools::countXPathNodes(const xmlDocUniquePtr& pXmlDoc, const 
OString& rXPath)
 {
     xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, rXPath);
     xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
-    CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(OString::Concat("In <") + 
pXmlDoc->name + ">, XPath '" + rXPath + "' number of nodes is 
incorrect").getStr(),
-                                 nNumberOfNodes, 
xmlXPathNodeSetGetLength(pXmlNodes));
+    const int n = xmlXPathNodeSetGetLength(pXmlNodes);
     xmlXPathFreeObject(pXmlObj);
+    return n;
+}
+
+void XmlTestTools::assertXPath(const xmlDocUniquePtr& pXmlDoc, const OString& 
rXPath, int nNumberOfNodes)
+{
+    CPPUNIT_ASSERT_EQUAL_MESSAGE(OString(OString::Concat("In <") + 
pXmlDoc->name + ">, XPath '" + rXPath + "' number of nodes is 
incorrect").getStr(),
+                                 nNumberOfNodes, countXPathNodes(pXmlDoc, 
rXPath));
 }
 
 void XmlTestTools::assertXPathContent(const xmlDocUniquePtr& pXmlDoc, const 
OString& rXPath, const OUString& rContent)

Reply via email to