sw/qa/extras/ooxmlexport/data/comment-annotationref.docx |binary sw/qa/extras/ooxmlexport/ooxmlexport22.cxx | 13 +++++++++++++ sw/source/filter/ww8/docxattributeoutput.cxx | 6 +++++- sw/source/filter/ww8/docxexport.cxx | 9 ++++++++- sw/source/filter/ww8/docxexport.hxx | 3 ++- 5 files changed, 28 insertions(+), 3 deletions(-)
New commits: commit 29b79978e280155c26791e520d422cfc75a5cdc7 Author: Jaume Pujantell <jaume.pujant...@collabora.com> AuthorDate: Tue Apr 8 17:56:13 2025 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Wed Apr 9 12:02:15 2025 +0200 sw: docx: add annotationRef on comments Right now we never add <w:annotationRef/> to any comment when saving to docx. According to the standard, not having it is the same as having it in the beginning. But when round-tripping a document with multiple comments without text from MS Word, the comments get mangled if the annotationRef tags aren't kept. So it's better to always write the implicit annotationRef at the beginning of comments. Change-Id: I6c395bbc691a29533e2be9a93663993e083db65b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/183856 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sw/qa/extras/ooxmlexport/data/comment-annotationref.docx b/sw/qa/extras/ooxmlexport/data/comment-annotationref.docx new file mode 100644 index 000000000000..2350a8c6bb1d Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/comment-annotationref.docx differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx index e095ad9760c8..b9ccffd3a37d 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx @@ -134,6 +134,19 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf165047_contextualSpacingTopMargin) CPPUNIT_ASSERT_EQUAL(static_cast<SwTwips>(0), nParaTopMargin); } +CPPUNIT_TEST_FIXTURE(Test, testAnnotationRef) +{ + loadAndSave("comment-annotationref.docx"); + + // Check that the exported comment also has annotationRef + xmlDocUniquePtr pXmlComments = parseExport(u"word/comments.xml"_ustr); + CPPUNIT_ASSERT(pXmlComments); + // Wihtout the fix it fails with + // - Expected: 1 + // - Actual : 0 + assertXPath(pXmlComments, "//w:comments/w:comment[1]/w:p[1]/w:r[1]/w:annotationRef"); +} + } // end of anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index afae3da1fe77..e4ec563e16aa 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -8565,7 +8565,8 @@ DocxAttributeOutput::hasProperties DocxAttributeOutput::WritePostitFields() if (f->GetTextObject() != nullptr) { // richtext - data.lastParaId = GetExport().WriteOutliner(*f->GetTextObject(), TXT_ATN, bNeedParaId); + data.lastParaId + = GetExport().WriteOutliner(*f->GetTextObject(), TXT_ATN, bNeedParaId, true); } else { @@ -8579,6 +8580,9 @@ DocxAttributeOutput::hasProperties DocxAttributeOutput::WritePostitFields() } m_pSerializer->startElementNS(XML_w, XML_p, FSNS(XML_w14, XML_paraId), aParaId); m_pSerializer->startElementNS(XML_w, XML_r); + m_pSerializer->singleElementNS(XML_w, XML_annotationRef); + m_pSerializer->endElementNS(XML_w, XML_r); + m_pSerializer->startElementNS(XML_w, XML_r); RunText(f->GetText()); m_pSerializer->endElementNS(XML_w, XML_r); m_pSerializer->endElementNS(XML_w, XML_p); diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx index 1450bdb63c5d..02ce025e6abe 100644 --- a/sw/source/filter/ww8/docxexport.cxx +++ b/sw/source/filter/ww8/docxexport.cxx @@ -2047,7 +2047,7 @@ bool DocxExport::ignoreAttributeForStyleDefaults( sal_uInt16 nWhich ) const } sal_Int32 DocxExport::WriteOutliner(const OutlinerParaObject& rParaObj, sal_uInt8 nTyp, - bool bNeedsLastParaId) + bool bNeedsLastParaId, bool bWriteAnnotRef) { const EditTextObject& rEditObj = rParaObj.GetTextObject(); MSWord_SdrAttrIter aAttrIter( *this, rEditObj, nTyp ); @@ -2072,6 +2072,13 @@ sal_Int32 DocxExport::WriteOutliner(const OutlinerParaObject& rParaObj, sal_uInt SfxItemSet aParagraphMarkerProperties(m_rDoc.GetAttrPool()); AttrOutput().EndParagraphProperties(aParagraphMarkerProperties, nullptr, nullptr, nullptr); + if (bWriteAnnotRef && n == 0) + { + m_pAttrOutput->GetSerializer()->startElementNS(XML_w, XML_r); + m_pAttrOutput->GetSerializer()->singleElementNS(XML_w, XML_annotationRef); + m_pAttrOutput->GetSerializer()->endElementNS(XML_w, XML_r); + } + do { AttrOutput().StartRun( nullptr, 0 ); const sal_Int32 nNextAttr = std::min(aAttrIter.WhereNext(), nEnd); diff --git a/sw/source/filter/ww8/docxexport.hxx b/sw/source/filter/ww8/docxexport.hxx index 7ed6457d6339..43cdccce8a5c 100644 --- a/sw/source/filter/ww8/docxexport.hxx +++ b/sw/source/filter/ww8/docxexport.hxx @@ -205,7 +205,8 @@ public: /// Writes the shape using drawingML syntax. void OutputDML( css::uno::Reference< css::drawing::XShape > const & xShape ); - sal_Int32 WriteOutliner(const OutlinerParaObject& rOutliner, sal_uInt8 nTyp, bool bNeedsLastParaId); + sal_Int32 WriteOutliner(const OutlinerParaObject& rOutliner, sal_uInt8 nTyp, + bool bNeedsLastParaId, bool bWriteAnnotRef = false); virtual ExportFormat GetExportFormat() const override { return ExportFormat::DOCX; }