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)