sw/qa/extras/htmlexport/data/embedded_formula.fodt |   30 +++
 sw/qa/extras/htmlexport/htmlexport.cxx             |   63 ++++---
 sw/source/filter/html/htmlplug.cxx                 |  184 +++++++++++++--------
 sw/source/filter/html/wrthtml.cxx                  |    6 
 sw/source/filter/html/wrthtml.hxx                  |    3 
 5 files changed, 201 insertions(+), 85 deletions(-)

New commits:
commit 2ecd5da533f8fc4229bb8a38167eb147c1213fa8
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Mon Oct 30 17:14:47 2023 +0300
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Tue Oct 31 05:54:03 2023 +0100

    ReqIF: introduce ExportFormulasAsPDF HTML export filter option
    
    Change-Id: Id400bd5571d0a192d854620abe83d862e0512434
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158663
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/sw/qa/extras/htmlexport/data/embedded_formula.fodt 
b/sw/qa/extras/htmlexport/data/embedded_formula.fodt
new file mode 100644
index 000000000000..46e5391223c0
--- /dev/null
+++ b/sw/qa/extras/htmlexport/data/embedded_formula.fodt
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document 
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" 
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" 
xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" 
office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:body>
+  <office:text>
+   <text:p>Formula:</text:p>
+   <text:p><draw:frame draw:name="Formula1" text:anchor-type="as-char" 
svg:width="1.549cm" svg:height="0.531cm"><draw:object>
+      <math xmlns="http://www.w3.org/1998/Math/MathML"; display="block">
+       <semantics>
+        <mrow>
+         <msup>
+          <mi mathvariant="normal">e</mi>
+          <mrow>
+           <mi>i</mi>
+           <mi>π</mi>
+          </mrow>
+         </msup>
+         <mo stretchy="false">+</mo>
+         <mn>1</mn>
+         <mo stretchy="false">=</mo>
+         <mn>0</mn>
+        </mrow>
+        <annotation encoding="StarMath 5.0">{ func e ^ { i %pi } + 1 } = 
0</annotation>
+       </semantics>
+      </math>
+     </draw:object>
+    </draw:frame></text:p>
+  </office:text>
+ </office:body>
+</office:document>
\ No newline at end of file
diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx 
b/sw/qa/extras/htmlexport/htmlexport.cxx
index a106dd53bf14..b4d3bfaaf10a 100644
--- a/sw/qa/extras/htmlexport/htmlexport.cxx
+++ b/sw/qa/extras/htmlexport/htmlexport.cxx
@@ -13,6 +13,7 @@
 #include <string_view>
 
 #include <com/sun/star/document/XEmbeddedObjectSupplier2.hpp>
+#include <com/sun/star/document/XTypeDetection.hpp>
 #include <com/sun/star/embed/ElementModes.hpp>
 #include <com/sun/star/io/XActiveDataStreamer.hpp>
 #include <com/sun/star/io/XSeekable.hpp>
@@ -215,9 +216,10 @@ public:
     {
     }
 
+    OUString GetObjectPath(const OUString& ext);
     /// Get the .ole path, assuming maTempFile is an XHTML export result.
-    OUString GetOlePath();
-    OUString GetPngPath();
+    OUString GetOlePath() { return GetObjectPath(u".ole"_ustr); }
+    OUString GetPngPath() { return GetObjectPath(u".png"_ustr); }
     /// Parse the ole1 data out of an RTF fragment URL.
     void ParseOle1FromRtfUrl(const OUString& rRtfUrl, SvMemoryStream& rOle1);
     /// Export using the C++ HTML export filter, with xhtmlns=reqif-xhtml.
@@ -228,29 +230,16 @@ public:
     void ExportToHTML();
 };
 
-OUString SwHtmlDomExportTest::GetOlePath()
+OUString SwHtmlDomExportTest::GetObjectPath(const OUString& ext)
 {
+    assert(ext.startsWith("."));
     xmlDocUniquePtr pDoc = WrapReqifFromTempFile();
     OUString aOlePath = getXPath(
         pDoc, 
"/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p/reqif-xhtml:object", "data");
-    OUString aOleSuffix(".ole");
-    CPPUNIT_ASSERT(aOlePath.endsWith(aOleSuffix));
+    CPPUNIT_ASSERT(aOlePath.endsWith(ext));
     INetURLObject aUrl(maTempFile.GetURL());
-    aUrl.setBase(aOlePath.subView(0, aOlePath.getLength() - 
aOleSuffix.getLength()));
-    aUrl.setExtension(u"ole");
-    return aUrl.GetMainURL(INetURLObject::DecodeMechanism::NONE);
-}
-
-OUString SwHtmlDomExportTest::GetPngPath()
-{
-    xmlDocUniquePtr pDoc = WrapReqifFromTempFile();
-    OUString aPngPath = getXPath(
-        pDoc, 
"/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p/reqif-xhtml:object", "data");
-    OUString aPngSuffix(".png");
-    CPPUNIT_ASSERT(aPngPath.endsWith(aPngSuffix));
-    INetURLObject aUrl(maTempFile.GetURL());
-    aUrl.setBase(aPngPath.subView(0, aPngPath.getLength() - 
aPngSuffix.getLength()));
-    aUrl.setExtension(u"png");
+    aUrl.setBase(aOlePath.subView(0, aOlePath.getLength() - ext.getLength()));
+    aUrl.setExtension(ext.subView(1));
     return aUrl.GetMainURL(INetURLObject::DecodeMechanism::NONE);
 }
 
@@ -2823,6 +2812,40 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, 
testReqIF_PreserveSpaces)
     CPPUNIT_ASSERT_EQUAL(paraText, getParagraph(1)->getString());
 }
 
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqIF_ExportFormulasAsPDF)
+{
+    // Given a document with a formula:
+    createSwDoc("embedded_formula.fodt");
+
+    // When exporting to reqif with ExportFormulasAsPDF=true:
+    uno::Reference<frame::XStorable> xStorable(mxComponent, 
uno::UNO_QUERY_THROW);
+    uno::Sequence<beans::PropertyValue> aStoreProperties = {
+        comphelper::makePropertyValue(u"FilterName"_ustr, u"HTML 
(StarWriter)"_ustr),
+        comphelper::makePropertyValue(u"FilterOptions"_ustr, 
u"xhtmlns=reqif-xhtml"_ustr),
+        comphelper::makePropertyValue(u"ExportFormulasAsPDF"_ustr, true),
+    };
+    xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
+
+    // Make sure that the formula is exported as PDF:
+    xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+    assertXPath(pXmlDoc,
+                
"/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p[2]/reqif-xhtml:object"_ostr,
+                "type"_ostr, u"application/pdf"_ustr);
+
+    css::uno::Sequence<css::beans::PropertyValue> descr{
+        comphelper::makePropertyValue(u"URL"_ustr, 
GetObjectPath(u".pdf"_ustr)),
+    };
+
+    uno::Reference<lang::XMultiServiceFactory> xFactory(
+        comphelper::getProcessComponentContext()->getServiceManager(), 
uno::UNO_QUERY_THROW);
+    uno::Reference<document::XTypeDetection> xTypeDetection(
+        xFactory->createInstance(u"com.sun.star.document.TypeDetection"_ustr),
+        uno::UNO_QUERY_THROW);
+
+    CPPUNIT_ASSERT_EQUAL(u"pdf_Portable_Document_Format"_ustr,
+                         xTypeDetection->queryTypeByDescriptor(descr, true));
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/html/htmlplug.cxx 
b/sw/source/filter/html/htmlplug.cxx
index 86d5cc0ffe7b..8331751fe431 100644
--- a/sw/source/filter/html/htmlplug.cxx
+++ b/sw/source/filter/html/htmlplug.cxx
@@ -1477,6 +1477,119 @@ SwHTMLWriter& OutHTML_FrameFormatOLENode( SwHTMLWriter& 
rWrt, const SwFrameForma
     return rWrt;
 }
 
+static void OutHTMLGraphic(SwHTMLWriter& rWrt, const SwFrameFormat& 
rFrameFormat, SwOLENode* pOLENd,
+                           const Graphic& rGraphic, bool bObjectOpened, bool 
bInCntnr)
+{
+    OUString aGraphicURL;
+    OUString aMimeType;
+    if (!rWrt.mbEmbedImages)
+    {
+        const OUString* pTempFileName = rWrt.GetOrigFileName();
+        if (pTempFileName)
+            aGraphicURL = *pTempFileName;
+
+        OUString aFilterName(u"JPG"_ustr);
+        XOutFlags nFlags = XOutFlags::UseGifIfPossible | 
XOutFlags::UseNativeIfPossible;
+
+        if (bObjectOpened)
+        {
+            aFilterName = u"PNG"_ustr;
+            nFlags = XOutFlags::NONE;
+            aMimeType = u"image/png"_ustr;
+
+            if (rGraphic.GetType() == GraphicType::NONE)
+            {
+                // The OLE Object has no replacement image, write a stub.
+                aGraphicURL = lcl_CalculateFileName(rWrt.GetOrigFileName(), 
rGraphic, u"png");
+                osl::File aFile(aGraphicURL);
+                aFile.open(osl_File_OpenFlag_Create);
+                aFile.close();
+            }
+        }
+
+        ErrCode nErr = XOutBitmap::WriteGraphic(rGraphic, aGraphicURL, 
aFilterName, nFlags);
+        if (nErr) // error, don't write anything
+        {
+            rWrt.m_nWarn = WARN_SWG_POOR_LOAD;
+            if (bObjectOpened) // Still at least close the tag.
+                rWrt.Strm().WriteOString(
+                    Concat2View("</" + rWrt.GetNamespace() + 
OOO_STRING_SVTOOLS_HTML_object ">"));
+            return;
+        }
+        aGraphicURL = 
URIHelper::SmartRel2Abs(INetURLObject(rWrt.GetBaseURL()), aGraphicURL,
+                                              URIHelper::GetMaybeFileHdl());
+    }
+    HtmlFrmOpts nFlags = bInCntnr ? HtmlFrmOpts::GenImgAllMask : 
HtmlFrmOpts::GenImgMask;
+    if (bObjectOpened)
+        nFlags |= HtmlFrmOpts::Replacement;
+    HtmlWriter aHtml(rWrt.Strm(), rWrt.maNamespace);
+    OutHTML_ImageStart(aHtml, rWrt, rFrameFormat, aGraphicURL, rGraphic, 
pOLENd->GetTitle(),
+                       pOLENd->GetTwipSize(), nFlags, "ole", nullptr, 
aMimeType);
+    OutHTML_ImageEnd(aHtml, rWrt);
+}
+
+static void OutHTMLStartObject(SwHTMLWriter& rWrt, const OUString& rFileName, 
const OUString& rFileType)
+{
+    OUString aFileName = 
URIHelper::simpleNormalizedMakeRelative(rWrt.GetBaseURL(), rFileName);
+
+    if (rWrt.IsLFPossible())
+        rWrt.OutNewLine();
+    rWrt.Strm().WriteOString(
+        Concat2View("<" + rWrt.GetNamespace() + 
OOO_STRING_SVTOOLS_HTML_object));
+    rWrt.Strm().WriteOString(Concat2View(" data=\"" + aFileName.toUtf8() + 
"\""));
+    if (!rFileType.isEmpty())
+        rWrt.Strm().WriteOString(Concat2View(" type=\"" + rFileType.toUtf8() + 
"\""));
+    rWrt.Strm().WriteOString(">");
+    rWrt.SetLFPossible(true);
+}
+
+static void OutHTMLEndObject(SwHTMLWriter& rWrt)
+{
+    rWrt.Strm().WriteOString(
+        Concat2View("</" + rWrt.GetNamespace() + 
OOO_STRING_SVTOOLS_HTML_object ">"));
+}
+
+static bool TrySaveFormulaAsPDF(SwHTMLWriter& rWrt, const SwFrameFormat& 
rFrameFormat,
+                                SwOLENode* pOLENd, bool 
bWriteReplacementGraphic, bool bInCntnr)
+{
+    if (!rWrt.mbReqIF)
+        return false;
+    if (!rWrt.m_bExportFormulasAsPDF)
+        return false;
+
+    auto xTextContent = SwXTextEmbeddedObject::CreateXTextEmbeddedObject(
+        *rWrt.m_pDoc, const_cast<SwFrameFormat*>(&rFrameFormat));
+    uno::Reference<frame::XStorable> 
xStorable(xTextContent->getEmbeddedObject(), uno::UNO_QUERY);
+    uno::Reference<lang::XServiceInfo> xServiceInfo(xStorable, uno::UNO_QUERY);
+    if (!xServiceInfo)
+        return false;
+    if 
(!xServiceInfo->supportsService(u"com.sun.star.formula.FormulaProperties"_ustr))
+        return false;
+
+    Graphic aGraphic(xTextContent->getReplacementGraphic());
+    OUString aFileName = lcl_CalculateFileName(rWrt.GetOrigFileName(), 
aGraphic, u"pdf"_ustr);
+
+    utl::MediaDescriptor aDescr;
+    aDescr[u"FilterName"_ustr] <<= u"math_pdf_Export"_ustr;
+    // Properties from starmath/inc/unomodel.hxx
+    aDescr[u"FilterData"_ustr] <<= comphelper::InitPropertySequence({
+        { u"TitleRow"_ustr, css::uno::Any(false) },
+        { u"FormulaText"_ustr, css::uno::Any(false) },
+        { u"Border"_ustr, css::uno::Any(false) },
+        { u"PrintFormat"_ustr, css::uno::Any(sal_Int32(1)) }, // 
PRINT_SIZE_SCALED
+    });
+    xStorable->storeToURL(aFileName, aDescr.getAsConstPropertyValueList());
+
+    OutHTMLStartObject(rWrt, aFileName, u"application/pdf"_ustr);
+
+    if (bWriteReplacementGraphic)
+        OutHTMLGraphic(rWrt, rFrameFormat, pOLENd, aGraphic, true, bInCntnr);
+
+    OutHTMLEndObject(rWrt);
+
+    return true;
+}
+
 SwHTMLWriter& OutHTML_FrameFormatOLENodeGrf( SwHTMLWriter& rWrt, const 
SwFrameFormat& rFrameFormat,
                                   bool bInCntnr, bool bWriteReplacementGraphic 
)
 {
@@ -1533,6 +1646,9 @@ SwHTMLWriter& OutHTML_FrameFormatOLENodeGrf( 
SwHTMLWriter& rWrt, const SwFrameFo
         return rWrt;
     }
 
+    if (TrySaveFormulaAsPDF(rWrt, rFrameFormat, pOLENd, 
bWriteReplacementGraphic, bInCntnr))
+        return rWrt;
+
     if ( !pOLENd->GetGraphic() )
     {
         SAL_WARN("sw.html", "Unexpected missing OLE fallback graphic");
@@ -1630,80 +1746,18 @@ SwHTMLWriter& OutHTML_FrameFormatOLENodeGrf( 
SwHTMLWriter& rWrt, const SwFrameFo
                 aFileType = aRTFType;
             }
         }
-        aFileName = URIHelper::simpleNormalizedMakeRelative(rWrt.GetBaseURL(), 
aFileName);
 
         // Refer to this data.
-        if (rWrt.IsLFPossible())
-            rWrt.OutNewLine();
-        rWrt.Strm().WriteOString(Concat2View("<" + rWrt.GetNamespace() + 
OOO_STRING_SVTOOLS_HTML_object));
-        rWrt.Strm().WriteOString(Concat2View(" data=\"" + aFileName.toUtf8() + 
"\""));
-        if (!aFileType.isEmpty())
-            rWrt.Strm().WriteOString(Concat2View(" type=\"" + 
aFileType.toUtf8() + "\""));
-        rWrt.Strm().WriteOString(">");
+        OutHTMLStartObject(rWrt, aFileName, aFileType);
         bObjectOpened = true;
-        rWrt.SetLFPossible(true);
     }
 
     if (!bObjectOpened || bWriteReplacementGraphic)
-    {
-        OUString aGraphicURL;
-        OUString aMimeType;
-        if(!rWrt.mbEmbedImages)
-        {
-            const OUString* pTempFileName = rWrt.GetOrigFileName();
-            if(pTempFileName)
-                aGraphicURL = *pTempFileName;
-
-            OUString aFilterName("JPG");
-            XOutFlags nFlags = XOutFlags::UseGifIfPossible | 
XOutFlags::UseNativeIfPossible;
-
-            if (bObjectOpened)
-            {
-                aFilterName = "PNG";
-                nFlags = XOutFlags::NONE;
-                aMimeType = "image/png";
-
-                if (aGraphic.GetType() == GraphicType::NONE)
-                {
-                    // The OLE Object has no replacement image, write a stub.
-                    aGraphicURL = 
lcl_CalculateFileName(rWrt.GetOrigFileName(), aGraphic, u"png");
-                    osl::File aFile(aGraphicURL);
-                    aFile.open(osl_File_OpenFlag_Create);
-                    aFile.close();
-                }
-            }
-
-            ErrCode nErr = XOutBitmap::WriteGraphic( aGraphic, aGraphicURL,
-                                        aFilterName,
-                                        nFlags );
-            if( nErr )              // error, don't write anything
-            {
-                rWrt.m_nWarn = WARN_SWG_POOR_LOAD;
-                if (bObjectOpened) // Still at least close the tag.
-                    rWrt.Strm().WriteOString(Concat2View("</" + 
rWrt.GetNamespace()
-                        + OOO_STRING_SVTOOLS_HTML_object ">"));
-                return rWrt;
-            }
-            aGraphicURL = URIHelper::SmartRel2Abs(
-                INetURLObject(rWrt.GetBaseURL()), aGraphicURL,
-                URIHelper::GetMaybeFileHdl() );
-
-        }
-        HtmlFrmOpts nFlags = bInCntnr ? HtmlFrmOpts::GenImgAllMask
-            : HtmlFrmOpts::GenImgMask;
-        if (bObjectOpened)
-            nFlags |= HtmlFrmOpts::Replacement;
-        HtmlWriter aHtml(rWrt.Strm(), rWrt.maNamespace);
-        OutHTML_ImageStart( aHtml, rWrt, rFrameFormat, aGraphicURL, aGraphic,
-                pOLENd->GetTitle(), pOLENd->GetTwipSize(),
-                nFlags, "ole", nullptr, aMimeType );
-        OutHTML_ImageEnd(aHtml, rWrt);
-    }
+        OutHTMLGraphic(rWrt, rFrameFormat, pOLENd, aGraphic, bObjectOpened, 
bInCntnr);
 
     if (bObjectOpened)
         // Close native data.
-        rWrt.Strm().WriteOString(Concat2View("</" + rWrt.GetNamespace() + 
OOO_STRING_SVTOOLS_HTML_object
-                                 ">"));
+        OutHTMLEndObject(rWrt);
 
     return rWrt;
 }
diff --git a/sw/source/filter/html/wrthtml.cxx 
b/sw/source/filter/html/wrthtml.cxx
index 0578bbbf6682..e4980b311f5e 100644
--- a/sw/source/filter/html/wrthtml.cxx
+++ b/sw/source/filter/html/wrthtml.cxx
@@ -264,6 +264,12 @@ void SwHTMLWriter::SetupFilterFromPropertyValues(
         it->second >>= m_bExportImagesAsOLE;
     }
 
+    it = aStoreMap.find("ExportFormulasAsPDF");
+    if (it != aStoreMap.end())
+    {
+        it->second >>= m_bExportFormulasAsPDF;
+    }
+
     it = aStoreMap.find("ShapeDPI");
     if (it != aStoreMap.end())
     {
diff --git a/sw/source/filter/html/wrthtml.hxx 
b/sw/source/filter/html/wrthtml.hxx
index 6b49fe984119..4f37296cf687 100644
--- a/sw/source/filter/html/wrthtml.hxx
+++ b/sw/source/filter/html/wrthtml.hxx
@@ -430,6 +430,9 @@ public:
     /// ReqIF mode: export images as OLE objects.
     bool m_bExportImagesAsOLE = false;
 
+    /// ReqIF mode: export formulas as PDFs.
+    bool m_bExportFormulasAsPDF = false;
+
     /// DPI used when exporting a vector shape as a bitmap.
     std::optional<sal_Int32> m_nShapeDPI;
 

Reply via email to