diff --git a/sw/qa/extras/ooxmlimport/data/tdf170236.docx b/sw/qa/extras/ooxmlimport/data/tdf170236.docx new file mode 100644 index 000000000000..1d6fdd1e88d2 Binary files /dev/null and b/sw/qa/extras/ooxmlimport/data/tdf170236.docx differ diff --git a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx index 7442fdb86677..54349c0896a5 100644 --- a/sw/qa/extras/ooxmlimport/ooxmlimport.cxx +++ b/sw/qa/extras/ooxmlimport/ooxmlimport.cxx @@ -1960,6 +1960,31 @@ CPPUNIT_TEST_FIXTURE(Test, testInlineFormulaTextMode) testFitsOnOnePage(); } +CPPUNIT_TEST_FIXTURE(Test, testTdf170236CommentInFormula) +{ + // tdf#170236: a w:commentReference inside an m:oMath formula was dropped on import + createSwDoc("tdf170236.docx"); + uno::Reference xTextFieldsSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xFieldsAccess(xTextFieldsSupplier->getTextFields()); + uno::Reference xFields(xFieldsAccess->createEnumeration()); + + bool bFoundAnnotation = false; + while (xFields->hasMoreElements()) + { + uno::Reference xServiceInfo(xFields->nextElement(), uno::UNO_QUERY); + if (xServiceInfo->supportsService(u"com.sun.star.text.textfield.Annotation"_ustr)) + { + bFoundAnnotation = true; + uno::Reference xPropertySet(xServiceInfo, uno::UNO_QUERY); + OUString aContent; + xPropertySet->getPropertyValue(u"Content"_ustr) >>= aContent; + CPPUNIT_ASSERT_EQUAL(u"Hello World!"_ustr, aContent); + break; + } + } + CPPUNIT_ASSERT_MESSAGE("No annotation found in document", bFoundAnnotation); +} + // tests should only be added to ooxmlIMPORT *if* they fail round-tripping in ooxmlEXPORT } // end of anonymous namespace diff --git a/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.cxx b/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.cxx index a61fcaa2caa5..6c18c4b867e3 100644 --- a/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.cxx +++ b/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.cxx @@ -2492,9 +2492,18 @@ void OOXMLFastContextHandlerLinear::lcl_endFastElement(Token_t Element) } uno::Reference< xml::sax::XFastContextHandler > -OOXMLFastContextHandlerLinear::lcl_createFastChildContext(Token_t, - const uno::Reference< xml::sax::XFastAttributeList >&) +OOXMLFastContextHandlerLinear::lcl_createFastChildContext(Token_t Element, + const uno::Reference< xml::sax::XFastAttributeList >& Attribs) { + // tdf#170236: buffering a w:commentReference would feed it to Starmath, which + // drops it; capture the id instead and resolve it after the formula (process()). + if (Element == W_TOKEN(commentReference)) + { + if (Attribs && Attribs->hasAttribute(W_TOKEN(id))) + m_aCommentIds.push_back(Attribs->getValue(W_TOKEN(id)).toInt32()); + return nullptr; + } + uno::Reference< xml::sax::XFastContextHandler > xContextHandler; xContextHandler.set( this ); return xContextHandler; @@ -2556,6 +2565,10 @@ void OOXMLFastContextHandlerMath::process() else pProps->add(NS_ooxml::LN_starmath, pVal, OOXMLProperty::ATTRIBUTE); mpStream->props( pProps.get() ); + + // tdf#170236: resolve now, so the anchor lands right after the emitted formula + for (sal_Int32 nCommentId : m_aCommentIds) + resolveComment(nCommentId); } OOXMLFastContextHandlerCommentEx::OOXMLFastContextHandlerCommentEx( diff --git a/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.hxx b/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.hxx index 34bd89693c91..7f1976c82ce8 100644 --- a/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.hxx +++ b/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.hxx @@ -20,6 +20,7 @@ #pragma once #include +#include #include #include #include @@ -596,6 +597,9 @@ protected: // should be private, but not much point in making deep copies of it oox::formulaimport::XmlStreamBuilder m_buffer; + // tdf#170236: comment ids referenced inside the formula, resolved in Math::process() + std::vector m_aCommentIds; + private: int m_depthCount; };