sw/qa/extras/rtfexport/data/tdf167569.rtf | 9 ++++ sw/qa/extras/rtfexport/rtfexport8.cxx | 51 ++++++++++++++++++++++++++++ sw/source/filter/ww8/rtfattributeoutput.cxx | 44 +++++++++++++++++++++++- sw/source/filter/ww8/rtfattributeoutput.hxx | 2 + 4 files changed, 104 insertions(+), 2 deletions(-)
New commits: commit 7f4868348c14b305fcd75744e1e3544d0d3a5d61 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Sat Jul 19 14:26:48 2025 +0500 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Tue Jul 22 22:39:52 2025 +0200 tdf#167569: RTF: Export paragraph mark properties In commits: 5ba30f588d6e41a13d68b1461345fca7a7ca61ac tdf#64222 sw: better DOCX import/export of paragraph marker formatting 2019-09-17 6e1c8bcec511444d2d51c5c5143be56d1900e5e6 tdf#150613 sw: better DOC import of paragraph marker formatting 2022-09-20 6249858a8972aef077e0249bd93cfe8f01bce4d6 sw: ODT import/export of DOCX's paragraph marker formatting 2022-12-19 a25eda715591cfa96136bcfd95360156516239d1 tdf#131386 writerfilter: RTF import paragraph mark formatting 2023-01-13 import and export of paragraph marker (as defined by Word and its file formats) was implemented, except for export to RTF. This change implements the latter. Change-Id: I2208a416377be42d2e6c5d5042cb92bc8109b4c5 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188084 Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> Tested-by: Jenkins diff --git a/sw/qa/extras/rtfexport/data/tdf167569.rtf b/sw/qa/extras/rtfexport/data/tdf167569.rtf new file mode 100644 index 000000000000..b82e4fd2d3d9 --- /dev/null +++ b/sw/qa/extras/rtfexport/data/tdf167569.rtf @@ -0,0 +1,9 @@ +{ tf1 +{onttbl{0romancharset0prq2 Liberation Serif;}} +{\*\defchp s24} +{\*\listtable{\list\listtemplateid1{\listlevel\levelnfc23\leveljc0\levelfollow0{\leveltext \'01\u183 ?;}0}\listid1}} +{\*\listoverridetable{\listoverride\listid1\listoverridecount0\ls1}} +{\*\pnseclvl1\pnucrm\pnqc\pnstart1\pnindent720\pnhang {\pntxta .}} +{\listtext\pard\plain s16 \u183\'b7 ab}\pard i-360\li720 i0\sa60\ls1 in0\lin720 {s12 AAA\par} +{\listtext\pard\plain s16 \u183\'b7 ab}\pard i-360\li720 i0\sa60\ls1 in0\lin720 {s12 BBB\par} +\pard \par} \ No newline at end of file diff --git a/sw/qa/extras/rtfexport/rtfexport8.cxx b/sw/qa/extras/rtfexport/rtfexport8.cxx index b75d44282c17..ff05ce5c4fcd 100644 --- a/sw/qa/extras/rtfexport/rtfexport8.cxx +++ b/sw/qa/extras/rtfexport/rtfexport8.cxx @@ -941,6 +941,57 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf167512) } } +CPPUNIT_TEST_FIXTURE(Test, testTdf167569) +{ + // Given an RTF having default text size of 12 pt, with a list, which elements' markers get + // their size of 6 pt from paragraph marker formatting: + createSwDoc("tdf167569.rtf"); + + { + comphelper::SequenceAsHashMap markerProperties; + markerProperties << getProperty<uno::Sequence<beans::NamedValue>>(getParagraph(1), + u"ListAutoFormat"_ustr); + CPPUNIT_ASSERT_EQUAL(6.0f, markerProperties[u"CharHeight"_ustr].get<float>()); + + markerProperties.clear(); + markerProperties << getProperty<uno::Sequence<beans::NamedValue>>(getParagraph(2), + u"ListAutoFormat"_ustr); + CPPUNIT_ASSERT_EQUAL(6.0f, markerProperties[u"CharHeight"_ustr].get<float>()); + + xmlDocUniquePtr pLayout = parseLayoutDump(); + auto lineHeight = getXPath(pLayout, "//txt[1]['pass 1']/infos/prtBounds", "height"); + CPPUNIT_ASSERT_LESS(sal_Int32(150), lineHeight.toInt32()); // expected value is around 140 + lineHeight = getXPath(pLayout, "//txt[2]['pass 1']/infos/prtBounds", "height"); + CPPUNIT_ASSERT_LESS(sal_Int32(150), lineHeight.toInt32()); + } + + // After round-tripping the RTF, the marker properties must not get lost; previously, the + // bullets became large, which additionally increased overall line height. + saveAndReload(mpFilter); + + { + comphelper::SequenceAsHashMap markerProperties; + // Before the export was implemented, this failed with + // - the property is of unexpected type or void: ListAutoFormat + // meaning that the paragraph marker property was lost + markerProperties << getProperty<uno::Sequence<beans::NamedValue>>(getParagraph(1), + u"ListAutoFormat"_ustr); + CPPUNIT_ASSERT_EQUAL(6.0f, markerProperties[u"CharHeight"_ustr].get<float>()); + + markerProperties.clear(); + markerProperties << getProperty<uno::Sequence<beans::NamedValue>>(getParagraph(2), + u"ListAutoFormat"_ustr); + CPPUNIT_ASSERT_EQUAL(6.0f, markerProperties[u"CharHeight"_ustr].get<float>()); + + xmlDocUniquePtr pLayout = parseLayoutDump(); + auto lineHeight = getXPath(pLayout, "//txt[1]['pass 2']/infos/prtBounds", "height"); + // Before the export was implemented, these were 280 + CPPUNIT_ASSERT_LESS(sal_Int32(150), lineHeight.toInt32()); // expected value is around 140 + lineHeight = getXPath(pLayout, "//txt[2]['pass 2']/infos/prtBounds", "height"); + CPPUNIT_ASSERT_LESS(sal_Int32(150), lineHeight.toInt32()); + } +} + } // end of anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx b/sw/source/filter/ww8/rtfattributeoutput.cxx index 82643081d739..68b758924ab6 100644 --- a/sw/source/filter/ww8/rtfattributeoutput.cxx +++ b/sw/source/filter/ww8/rtfattributeoutput.cxx @@ -91,6 +91,7 @@ #include <oox/mathml/imexport.hxx> #include <com/sun/star/i18n/ScriptType.hpp> #include <svl/grabbagitem.hxx> +#include <svl/itemiter.hxx> #include <frmatr.hxx> #include <swtable.hxx> #include <formatflysplit.hxx> @@ -310,10 +311,13 @@ void RtfAttributeOutput::EndParagraph( // RTF_PAR at the end of the footnote or clipboard, would cause an additional empty paragraph. if (!bLastPara) { + if (!m_aParagraphMarkerProperties.isEmpty()) + aParagraph->append("{" + m_aParagraphMarkerProperties); aParagraph->append(OOO_STRING_SVTOOLS_RTF_PAR); - aParagraph->append(' '); + aParagraph->append(m_aParagraphMarkerProperties.isEmpty() ? ' ' : '}'); } } + m_aParagraphMarkerProperties.clear(); if (m_nColBreakNeeded) { aParagraph->append(OOO_STRING_SVTOOLS_RTF_COLUMN); @@ -392,8 +396,29 @@ void RtfAttributeOutput::StartParagraphProperties() m_aSectionHeaders.append(aPar); } +/// Outputs an item set, that contains the formatting of the paragraph marker. +/// Similar to respective function in sw/source/filter/ww8/docxattributeoutput.cxx. +static void lcl_writeParagraphMarkerProperties(RtfAttributeOutput& rAttributeOutput, + const SfxItemSet& rParagraphMarkerProperties) +{ + for (SfxItemIter it(rParagraphMarkerProperties); !it.IsAtEnd(); it.NextItem()) + { + const auto nWhichId = it.GetCurWhich(); + if (isCHRATR(nWhichId) || nWhichId == RES_TXTATR_CHARFMT) + { + rAttributeOutput.OutputItem(*it.GetCurItem()); + } + else if (nWhichId == RES_TXTATR_AUTOFMT) + { + const SwFormatAutoFormat& rAutoFormat + = it.GetCurItem()->StaticWhichCast(RES_TXTATR_AUTOFMT); + lcl_writeParagraphMarkerProperties(rAttributeOutput, *rAutoFormat.GetStyleHandle()); + } + } +} + void RtfAttributeOutput::EndParagraphProperties( - const SfxItemSet& /*rParagraphMarkerProperties*/, const SwRedlineData* /*pRedlineData*/, + const SfxItemSet& rParagraphMarkerProperties, const SwRedlineData* /*pRedlineData*/, const SwRedlineData* /*pRedlineParagraphMarkerDeleted*/, const SwRedlineData* /*pRedlineParagraphMarkerInserted*/) { @@ -401,6 +426,21 @@ void RtfAttributeOutput::EndParagraphProperties( // Otherwise associate properties in the paragraph style are ruined. const OString aProperties = m_aStyles.makeStringAndClear(); m_rExport.Strm().WriteOString(aProperties); + + // Backup other styles strings, to avoid modification by marker properties + OString aStylesAssocHich(m_aStylesAssocHich.makeStringAndClear()); + OString aStylesAssocDbch(m_aStylesAssocDbch.makeStringAndClear()); + OString aStylesAssocRtlch(m_aStylesAssocRtlch.makeStringAndClear()); + OString aStylesAssocLtrch(m_aStylesAssocLtrch.makeStringAndClear()); + + lcl_writeParagraphMarkerProperties(*this, rParagraphMarkerProperties); + m_aParagraphMarkerProperties = m_aStyles.makeStringAndClear(); + + // Restore these + m_aStylesAssocHich = aStylesAssocHich; + m_aStylesAssocDbch = aStylesAssocDbch; + m_aStylesAssocRtlch = aStylesAssocRtlch; + m_aStylesAssocLtrch = aStylesAssocLtrch; } void RtfAttributeOutput::StartRun(const SwRedlineData* pRedlineData, sal_Int32 /*nPos*/, diff --git a/sw/source/filter/ww8/rtfattributeoutput.hxx b/sw/source/filter/ww8/rtfattributeoutput.hxx index 6f9e2b2d107b..654ee2ab576c 100644 --- a/sw/source/filter/ww8/rtfattributeoutput.hxx +++ b/sw/source/filter/ww8/rtfattributeoutput.hxx @@ -669,6 +669,8 @@ private: editeng::WordPageMargins m_aPageMargins; + OString m_aParagraphMarkerProperties; + public: explicit RtfAttributeOutput(RtfExport& rExport);