[Libreoffice-commits] core.git: include/xmloff starmath/inc starmath/Library_sm.mk starmath/source xmloff/source

dante (via logerrit) logerrit at kemper.freedesktop.org
Fri Aug 13 08:37:39 UTC 2021


 include/xmloff/xmltoken.hxx       |   12 
 starmath/Library_sm.mk            |    1 
 starmath/inc/mathml/export.hxx    |  241 ++++++++
 starmath/source/mathml/export.cxx | 1113 ++++++++++++++++++++++++++++++++++++++
 xmloff/source/core/xmltoken.cxx   |   12 
 xmloff/source/token/tokens.txt    |   10 
 6 files changed, 1389 insertions(+)

New commits:
commit b8a4eeb24a037d338a61eb4b76acc9fad52fa5c3
Author:     dante <dante19031999 at gmail.com>
AuthorDate: Sun Aug 8 23:56:09 2021 +0200
Commit:     Noel Grandin <noel.grandin at collabora.co.uk>
CommitDate: Fri Aug 13 10:37:03 2021 +0200

    Export Math ML from new mathml nodes
    
    Review tip: thanks for your help
    Code heavily based on: mathmlexport.cxx mathmlexport.hxx
    https://opengrok.libreoffice.org/xref/core/starmath/source/mathml/mathmlexport.cxx?r=e271fce8
    https://opengrok.libreoffice.org/xref/core/starmath/inc/mathml/mathmlexport.hxx?r=10d29c39
    
    Change-Id: I798d0e207b844240f4b25720ee37c394eb4c2e65
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120188
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.grandin at collabora.co.uk>

diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx
index f57403dd0f53..761108d78ad4 100644
--- a/include/xmloff/xmltoken.hxx
+++ b/include/xmloff/xmltoken.hxx
@@ -3421,6 +3421,18 @@ namespace xmloff::token {
 
         XML_LOCAL_URL,
 
+        // Math ml
+        XML_DIR,
+        XML_DISPLAYSTYLE,
+        XML_LSPACE,
+        XML_MATHBACKGROUND,
+        XML_MAXSIZE,
+        XML_MINSIZE,
+        XML_MOVABLELIMITS,
+        XML_RSPACE,
+        XML_RTL,
+        XML_SYMMETRIC,
+
         XML_TOKEN_END
     };
 
diff --git a/starmath/Library_sm.mk b/starmath/Library_sm.mk
index e9bb53676b91..585834be74aa 100644
--- a/starmath/Library_sm.mk
+++ b/starmath/Library_sm.mk
@@ -104,6 +104,7 @@ $(eval $(call gb_Library_add_exception_objects,sm,\
         starmath/source/mathml/mathmlexport \
         starmath/source/mathml/mathmlimport \
         starmath/source/mathml/mathmlMo \
+        starmath/source/mathml/export \
         starmath/source/mathml/iterator \
         starmath/source/mathml/attribute \
         starmath/source/mathml/element \
diff --git a/starmath/inc/mathml/export.hxx b/starmath/inc/mathml/export.hxx
new file mode 100644
index 000000000000..d5767ef2e6db
--- /dev/null
+++ b/starmath/inc/mathml/export.hxx
@@ -0,0 +1,241 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+// Our mathml
+#include "element.hxx"
+
+// Xml tools
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/xmlexp.hxx>
+#include <xmloff/xmltoken.hxx>
+
+// Extras
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/xml/sax/Writer.hpp>
+
+class SfxMedium;
+class SmDocShell;
+
+class SmMlExportWrapper
+{
+private:
+    // Model
+    css::uno::Reference<css::frame::XModel> m_xModel;
+    // Save as a flat document ( mml, fodf ... )
+    bool m_bFlat;
+    // Use html / mathml entities
+    bool m_bUseHTMLMLEntities;
+    // Mathmml tree to parse
+    SmMlElement* m_pElementTree;
+    // Export xmlns tag
+    bool m_bUseExportTag;
+
+public:
+    /** Set's the writer to export to flat document
+     */
+    void setFlat(bool bFlat) { m_bFlat = bFlat; }
+
+    /** Checks if the writer is set to export to flat document
+     */
+    bool getFlat() const { return m_bFlat; }
+
+    /** Checks the use of HTML / MathML entities such as &infinity;
+     */
+    void setUseHTMLMLEntities(bool bUseHTMLMLEntities)
+    {
+        m_bUseHTMLMLEntities = bUseHTMLMLEntities;
+    }
+
+    /** Activates the use of HTML / MathML entities such as &infinity;
+     */
+    bool getUseHTMLMLEntities() const { return m_bUseHTMLMLEntities; }
+
+    /** Get's if xmlns field is added
+     */
+    bool getUseExportTag() const { return m_bUseExportTag; }
+
+    /** Set's if xmlns field is added
+     */
+    void setUseExportTag(bool bUseExportTag) { m_bUseExportTag = bUseExportTag; }
+
+public:
+    explicit SmMlExportWrapper(css::uno::Reference<css::frame::XModel> const& rRef)
+        : m_xModel(rRef)
+        , m_bFlat(true)
+        , m_bUseHTMLMLEntities(false)
+        , m_pElementTree(nullptr)
+    {
+    }
+
+    /** Export to an archive
+      */
+    bool Export(SfxMedium& rMedium);
+
+    /** Just export a mathml tree
+      */
+    OUString Export(SmMlElement* pElementTree);
+
+    // Making this protected we can keep it from getting trash as input
+protected:
+    /** export through an XML exporter component (output stream version)
+        */
+    bool WriteThroughComponentOS(const css::uno::Reference<css::io::XOutputStream>& xOutputStream,
+                                 const css::uno::Reference<css::lang::XComponent>& xComponent,
+                                 css::uno::Reference<css::uno::XComponentContext> const& rxContext,
+                                 css::uno::Reference<css::beans::XPropertySet> const& rPropSet,
+                                 const char16_t* pComponentName);
+
+    /** export through an XML exporter component (storage version)
+      */
+    bool WriteThroughComponentS(const css::uno::Reference<css::embed::XStorage>& xStor,
+                                const css::uno::Reference<css::lang::XComponent>& xComponent,
+                                const char16_t* pStreamName,
+                                css::uno::Reference<css::uno::XComponentContext> const& rxContext,
+                                css::uno::Reference<css::beans::XPropertySet> const& rPropSet,
+                                const char16_t* pComponentName);
+
+    /** export through an XML exporter component (memory stream version)
+      */
+    OUString
+    WriteThroughComponentMS(const css::uno::Reference<css::lang::XComponent>& xComponent,
+                            css::uno::Reference<css::uno::XComponentContext> const& rxContext,
+                            css::uno::Reference<css::beans::XPropertySet> const& rPropSet);
+};
+
+class SmMlExport final : public SvXMLExport
+{
+private:
+    SmMlElement* m_pElementTree;
+    bool m_bSuccess;
+    bool m_bUseExportTag;
+
+public:
+    /** Everything was allright
+     */
+    bool getSuccess() const { return m_bSuccess; }
+
+    /** Get's if xmlns field is added
+     */
+    bool getUseExportTag() const { return m_bUseExportTag; }
+
+    /** Set's if xmlns field is added
+     */
+    void setUseExportTag(bool bUseExportTag) { m_bUseExportTag = bUseExportTag; }
+
+    /** Set's the element tree to be exported.
+      * If it isn't nullptr the this will be exported instead of the document
+     */
+    void setElementTree(SmMlElement* pElementTree) { m_pElementTree = pElementTree; }
+
+private:
+    /** Adds an element
+      */
+    SvXMLElementExport* createElementExport(xmloff::token::XMLTokenEnum nElement)
+    {
+        // We can't afford to ignore white spaces. They are part of the code.
+        return new SvXMLElementExport(*this, XML_NAMESPACE_MATH, nElement, false, false);
+    }
+
+    /** Adds an attribute
+      */
+    void addAttribute(xmloff::token::XMLTokenEnum pAttribute,
+                      xmloff::token::XMLTokenEnum pAttributeValue)
+    {
+        AddAttribute(XML_NAMESPACE_MATH, pAttribute, pAttributeValue);
+    }
+
+    /** Adds an attribute
+      */
+    void addAttribute(xmloff::token::XMLTokenEnum pAttribute, const OUString& pAttributeValue)
+    {
+        AddAttribute(XML_NAMESPACE_MATH, pAttribute, pAttributeValue);
+    }
+
+public:
+    /** Exports an attribute of type "length"
+     */
+    void exportMlAttributteLength(xmloff::token::XMLTokenEnum pAttribute,
+                                  const SmLengthValue& aLengthValue);
+
+    /** Exports attributes of an element
+      */
+    void exportMlAttributtes(const SmMlElement* pMlElement);
+
+    /** Exports an element and all it's attributes
+      */
+    SvXMLElementExport* exportMlElement(const SmMlElement* pMlElement);
+
+    /** Exports an element tree
+      */
+    void exportMlElementTree();
+
+    /** Handles an error on the mathml structure
+     */
+    void declareMlError();
+
+public:
+    /** Constructor
+     */
+    SmMlExport(const css::uno::Reference<css::uno::XComponentContext>& rContext,
+               OUString const& implementationName, SvXMLExportFlags nExportFlags);
+
+private:
+    /** Get's document shell
+     */
+    SmDocShell* getSmDocShell();
+
+public:
+    // XUnoTunnel
+    sal_Int64 SAL_CALL getSomething(const css::uno::Sequence<sal_Int8>& rId) override;
+    static const css::uno::Sequence<sal_Int8>& getUnoTunnelId() noexcept;
+
+    /** Exports auto styles
+     * However math doesn't have any
+     */
+    void ExportAutoStyles_() override {}
+
+    /** Exports master styles
+     * However math doesn't have any
+     */
+    void ExportMasterStyles_() override {}
+
+    /** Exports formula
+     * Handler used from exportDoc
+     */
+    void ExportContent_() override { exportMlElementTree(); };
+
+    /** Exports the document
+     * If m_pElementTree isn't null then exports m_pElementTree
+    */
+    ErrCode exportDoc(enum ::xmloff::token::XMLTokenEnum eClass
+                      = ::xmloff::token::XML_TOKEN_INVALID) override;
+
+    /** Get's view settings and prepares them to export
+     */
+    virtual void GetViewSettings(css::uno::Sequence<css::beans::PropertyValue>& aProps) override;
+
+    /** Get's configuration settings and prepares them to export
+     */
+    virtual void
+    GetConfigurationSettings(css::uno::Sequence<css::beans::PropertyValue>& aProps) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/starmath/source/mathml/export.cxx b/starmath/source/mathml/export.cxx
new file mode 100644
index 000000000000..9287df360fa6
--- /dev/null
+++ b/starmath/source/mathml/export.cxx
@@ -0,0 +1,1113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+// Our mathml
+#include <mathml/export.hxx>
+#include <mathml/iterator.hxx>
+
+// LO tools to use
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <com/sun/star/uno/Any.h>
+#include <com/sun/star/util/MeasureUnit.hpp>
+#include <com/sun/star/xml/sax/Writer.hpp>
+
+// Extra LO tools
+#include <comphelper/fileformat.h>
+#include <comphelper/genericpropertyset.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertysetinfo.hxx>
+#include <sax/tools/converter.hxx>
+#include <sfx2/frame.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <sot/storage.hxx>
+#include <svl/itemset.hxx>
+#include <svl/stritem.hxx>
+#include <unotools/streamwrap.hxx>
+#include <xmloff/namespacemap.hxx>
+
+// Our starmath tools
+#include <cfgitem.hxx>
+#include <document.hxx>
+#include <smmod.hxx>
+#include <strings.hrc>
+#include <unomodel.hxx>
+#include <utility.hxx>
+#include <xparsmlbase.hxx>
+#include <starmathdatabase.hxx>
+
+using namespace ::com::sun::star;
+using namespace xmloff::token;
+
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star;
+using namespace ::xmloff::token;
+
+// SmMlExportWrapper
+/*************************************************************************************************/
+
+bool SmMlExportWrapper::Export(SfxMedium& rMedium)
+{
+    bool bRet = true;
+    uno::Reference<uno::XComponentContext> xContext(comphelper::getProcessComponentContext());
+
+    // Check all fine
+    SAL_WARN_IF(m_xModel == nullptr, "starmath", "Missing model");
+    SAL_WARN_IF(xContext == nullptr, "starmath", "Missing context");
+    if (m_xModel == nullptr || xContext == nullptr)
+        return false;
+
+    //Get model
+    uno::Reference<lang::XComponent> xModelComp = m_xModel;
+    SAL_WARN_IF(xModelComp == nullptr, "starmath", "Missing model component");
+    SmModel* pModel = comphelper::getUnoTunnelImplementation<SmModel>(m_xModel);
+    SAL_WARN_IF(pModel == nullptr, "starmath", "Failed to get threw uno tunnel");
+    if (xModelComp == nullptr || pModel == nullptr)
+        return false;
+
+    // Get doc shell
+    SmDocShell* pDocShell = static_cast<SmDocShell*>(pModel->GetObjectShell());
+    if (pDocShell == nullptr)
+    {
+        SAL_WARN("starmath", "Failed to fetch sm document");
+        return false;
+    }
+
+    // Check if it is a standalone window or embed object
+    bool bEmbedded = SfxObjectCreateMode::EMBEDDED == pDocShell->GetCreateMode();
+
+    // Medium item set
+    SfxItemSet* pMediumItemSet = rMedium.GetItemSet();
+    if (pDocShell == nullptr)
+    {
+        SAL_WARN("starmath", "Failed to get medium item set");
+        return false;
+    }
+
+    // Progress bar ~
+    uno::Reference<task::XStatusIndicator> xStatusIndicator;
+
+    if (!bEmbedded)
+    {
+        // Extra check to ensure everything is fine
+        if (pDocShell->GetMedium() != &rMedium)
+        {
+            SAL_WARN("starmath", "Input medium and sm document medium do not match");
+            return false;
+        }
+
+        // Fetch progress bar
+        auto pItem = pMediumItemSet->GetItem(SID_PROGRESS_STATUSBAR_CONTROL);
+        if (pItem)
+        {
+            // set progress range and start status indicator
+            static_cast<const SfxUnoAnyItem*>(pItem)->GetValue() >>= xStatusIndicator;
+            xStatusIndicator->start(SmResId(STR_STATSTR_WRITING), 3);
+            xStatusIndicator->setValue(0);
+        }
+    }
+
+    // create XPropertySet with three properties for status indicator
+    comphelper::PropertyMapEntry aInfoMap[]
+        = { { OUString("UsePrettyPrinting"), 0, cppu::UnoType<bool>::get(),
+              beans::PropertyAttribute::MAYBEVOID, 0 },
+            { OUString("BaseURI"), 0, ::cppu::UnoType<OUString>::get(),
+              beans::PropertyAttribute::MAYBEVOID, 0 },
+            { OUString("StreamRelPath"), 0, ::cppu::UnoType<OUString>::get(),
+              beans::PropertyAttribute::MAYBEVOID, 0 },
+            { OUString("StreamName"), 0, ::cppu::UnoType<OUString>::get(),
+              beans::PropertyAttribute::MAYBEVOID, 0 },
+            { OUString(), 0, css::uno::Type(), 0, 0 } };
+    uno::Reference<beans::XPropertySet> xInfoSet(
+        comphelper::GenericPropertySet_CreateInstance(new comphelper::PropertySetInfo(aInfoMap)));
+
+    // Always print pretty
+    xInfoSet->setPropertyValue("UsePrettyPrinting", Any(true));
+
+    // Set base URI
+    xInfoSet->setPropertyValue(u"BaseURI", makeAny(rMedium.GetBaseURL(true)));
+
+    if (!m_bFlat) //Storage (Package) of Stream
+    {
+        // Fetch the output storage
+        uno::Reference<embed::XStorage> xStg = rMedium.GetOutputStorage();
+        if (xStg == nullptr)
+        {
+            SAL_WARN("starmath", "Failed to fetch output storage");
+            return false;
+        }
+        bool bOASIS = SotStorage::GetVersion(xStg) > SOFFICE_FILEFORMAT_60;
+
+        // TODO/LATER: handle the case of embedded links gracefully
+        if (bEmbedded) //&& !pStg->IsRoot() )
+        {
+            auto pDocHierarchItem = pMediumItemSet->GetItem(SID_DOC_HIERARCHICALNAME);
+            if (pDocHierarchItem != nullptr)
+            {
+                OUString aName = static_cast<const SfxStringItem*>(pDocHierarchItem)->GetValue();
+                if (!aName.isEmpty())
+                    xInfoSet->setPropertyValue("StreamRelPath", makeAny(aName));
+            }
+        }
+        else
+        {
+            // Write file metadata ( data, LO version ... )
+            // Note: export through an XML exporter component (storage version)
+            if (xStatusIndicator.is())
+                xStatusIndicator->setValue(1);
+
+            bRet = WriteThroughComponentS(xStg, xModelComp, u"meta.xml", xContext, xInfoSet,
+                                          bOASIS ? u"com.sun.star.comp.Math.XMLOasisMetaExporter"
+                                                 : u"com.sun.star.comp.Math.XMLMetaExporter");
+        }
+
+        // Write starmath formula
+        // Note: export through an XML exporter component (storage version)
+        if (bRet)
+        {
+            if (xStatusIndicator.is())
+                xStatusIndicator->setValue(2);
+
+            bRet = WriteThroughComponentS(xStg, xModelComp, u"content.xml", xContext, xInfoSet,
+                                          u"com.sun.star.comp.Math.XMLContentExporter");
+        }
+
+        // Write starmath settings
+        // Note: export through an XML exporter component (storage version)
+        if (bRet)
+        {
+            if (xStatusIndicator.is())
+                xStatusIndicator->setValue(3);
+
+            bRet
+                = WriteThroughComponentS(xStg, xModelComp, u"settings.xml", xContext, xInfoSet,
+                                         bOASIS ? u"com.sun.star.comp.Math.XMLOasisSettingsExporter"
+                                                : u"com.sun.star.comp.Math.XMLSettingsExporter");
+        }
+    }
+    else
+    {
+        // Fetch the output stream
+        SvStream* pStream = rMedium.GetOutStream();
+        if (pStream == nullptr)
+        {
+            SAL_WARN("starmath", "Missing output stream");
+            return false;
+        }
+        uno::Reference<io::XOutputStream> xOut(new utl::OOutputStreamWrapper(*pStream));
+
+        if (xStatusIndicator.is())
+            xStatusIndicator->setValue(1);
+
+        // Write everything in the same place
+        // Note: export through an XML exporter component (output stream version)
+        bRet = WriteThroughComponentOS(xOut, xModelComp, xContext, xInfoSet,
+                                       u"com.sun.star.comp.Math.XMLContentExporter");
+    }
+
+    if (xStatusIndicator.is())
+        xStatusIndicator->end();
+    return bRet;
+}
+
+OUString SmMlExportWrapper::Export(SmMlElement* pElementTree)
+{
+    uno::Reference<uno::XComponentContext> xContext(comphelper::getProcessComponentContext());
+
+    // Check all fine
+    m_pElementTree = nullptr;
+    SAL_WARN_IF(m_xModel == nullptr, "starmath", "Missing model");
+    SAL_WARN_IF(xContext == nullptr, "starmath", "Missing context");
+    if (m_xModel == nullptr || xContext == nullptr)
+        return u"";
+
+    //Get model
+    uno::Reference<lang::XComponent> xModelComp = m_xModel;
+    SAL_WARN_IF(xModelComp == nullptr, "starmath", "Missing model component");
+    SmModel* pModel = comphelper::getUnoTunnelImplementation<SmModel>(m_xModel);
+    SAL_WARN_IF(pModel == nullptr, "starmath", "Failed to get threw uno tunnel");
+    if (xModelComp == nullptr || pModel == nullptr)
+        return u"";
+
+    // Get doc shell
+    SmDocShell* pDocShell = static_cast<SmDocShell*>(pModel->GetObjectShell());
+    if (pDocShell == nullptr)
+    {
+        SAL_WARN("starmath", "Failed to fetch sm document");
+        return u"";
+    }
+
+    // create XPropertySet with three properties for status indicator
+    comphelper::PropertyMapEntry aInfoMap[]
+        = { { OUString("UsePrettyPrinting"), 0, cppu::UnoType<bool>::get(),
+              beans::PropertyAttribute::MAYBEVOID, 0 },
+            { OUString("BaseURI"), 0, ::cppu::UnoType<OUString>::get(),
+              beans::PropertyAttribute::MAYBEVOID, 0 },
+            { OUString("StreamRelPath"), 0, ::cppu::UnoType<OUString>::get(),
+              beans::PropertyAttribute::MAYBEVOID, 0 },
+            { OUString("StreamName"), 0, ::cppu::UnoType<OUString>::get(),
+              beans::PropertyAttribute::MAYBEVOID, 0 },
+            { OUString(), 0, css::uno::Type(), 0, 0 } };
+    uno::Reference<beans::XPropertySet> xInfoSet(
+        comphelper::GenericPropertySet_CreateInstance(new comphelper::PropertySetInfo(aInfoMap)));
+
+    // Always print pretty
+    xInfoSet->setPropertyValue("UsePrettyPrinting", Any(true));
+
+    // Fetch mathml tree
+    m_pElementTree = pElementTree;
+
+    // Write stuff
+    // Note: export through an XML exporter component (memory stream version)
+    return WriteThroughComponentMS(xModelComp, xContext, xInfoSet);
+}
+
+// export through an XML exporter component (output stream version)
+bool SmMlExportWrapper::WriteThroughComponentOS(const Reference<io::XOutputStream>& xOutputStream,
+                                                const Reference<XComponent>& xComponent,
+                                                Reference<uno::XComponentContext> const& rxContext,
+                                                Reference<beans::XPropertySet> const& rPropSet,
+                                                const char16_t* pComponentName)
+{
+    // We need a output stream but it is already checked by caller
+    // We need a component but it is already checked by caller
+    // We need a context but it is already checked by caller
+    // We need a property set but it is already checked by caller
+    // We need a component name but it is already checked by caller
+
+    // get sax writer
+    Reference<xml::sax::XWriter> xSaxWriter = xml::sax::Writer::create(rxContext);
+
+    // connect XML writer to output stream
+    xSaxWriter->setOutputStream(xOutputStream);
+    if (m_bUseHTMLMLEntities)
+        xSaxWriter->setCustomEntityNames(starmathdatabase::icustomMathmlHtmlEntitiesExport);
+
+    // prepare arguments (prepend doc handler to given arguments)
+    Sequence<Any> aArgs(2);
+    aArgs[0] <<= xSaxWriter;
+    aArgs[1] <<= rPropSet;
+
+    // get filter component
+    auto xExporterData = rxContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+        OUString(pComponentName), aArgs, rxContext);
+    Reference<document::XExporter> xExporter(xExporterData, UNO_QUERY);
+
+    // Check everything is fine
+    if (!xExporter.is())
+    {
+        SAL_WARN("starmath", "can't instantiate export filter component");
+        return false;
+    }
+
+    // connect model and filter
+    xExporter->setSourceDocument(xComponent);
+
+    // filter
+    Reference<XFilter> xFilter(xExporter, UNO_QUERY);
+    SmMlExport* pFilter = comphelper::getUnoTunnelImplementation<SmMlExport>(xFilter);
+
+    // Setup filter
+    if (pFilter == nullptr)
+    {
+        SAL_WARN("starmath", "Failed to fetch SmMlExport");
+        return false;
+    }
+    pFilter->setUseExportTag(m_bUseExportTag);
+    pFilter->setElementTree(m_pElementTree);
+
+    // Execute operation
+    uno::Sequence<PropertyValue> aProps(0);
+    xFilter->filter(aProps);
+    return pFilter->getSuccess();
+}
+
+// export through an XML exporter component (storage version)
+bool SmMlExportWrapper::WriteThroughComponentS(const Reference<embed::XStorage>& xStorage,
+                                               const Reference<XComponent>& xComponent,
+                                               const char16_t* pStreamName,
+                                               Reference<uno::XComponentContext> const& rxContext,
+                                               Reference<beans::XPropertySet> const& rPropSet,
+                                               const char16_t* pComponentName)
+{
+    // We need a storage name but it is already checked by caller
+    // We need a component name but it is already checked by caller
+    // We need a stream name but it is already checked by caller
+    // We need a context but it is already checked by caller
+    // We need a property set but it is already checked by caller
+    // We need a component but it is already checked by caller
+
+    // open stream
+    Reference<io::XStream> xStream;
+    try
+    {
+        xStream = xStorage->openStreamElement(
+            OUString(pStreamName), embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE);
+    }
+    catch (const uno::Exception&)
+    {
+        SAL_WARN("starmath", "Can't create output stream in package");
+        return false;
+    }
+
+    // Set stream as text / xml
+    uno::Reference<beans::XPropertySet> xSet(xStream, uno::UNO_QUERY);
+    xSet->setPropertyValue("MediaType", Any(OUString(u"text/xml")));
+
+    // all streams must be encrypted in encrypted document
+    xSet->setPropertyValue("UseCommonStoragePasswordEncryption", Any(true));
+
+    // set Base URL
+    rPropSet->setPropertyValue("StreamName", makeAny(OUString(pStreamName)));
+
+    // write the stuff
+    // Note: export through an XML exporter component (output stream version)
+    return WriteThroughComponentOS(xStream->getOutputStream(), xComponent, rxContext, rPropSet,
+                                   pComponentName);
+}
+
+// export through an XML exporter component (memory stream version)
+OUString
+SmMlExportWrapper::WriteThroughComponentMS(const Reference<XComponent>& xComponent,
+                                           Reference<uno::XComponentContext> const& rxContext,
+                                           Reference<beans::XPropertySet> const& rPropSet)
+{
+    // We need a component but it is already checked by caller
+    // We need a context but it is already checked by caller
+    // We need a property set it is already checked by caller
+
+    // open stream
+    SvMemoryStream aMemoryStream(8192, 1024);
+    uno::Reference<io::XOutputStream> xStream(new utl::OOutputStreamWrapper(aMemoryStream));
+
+    // Set the stream as text
+    uno::Reference<beans::XPropertySet> xSet(xStream, uno::UNO_QUERY);
+    xSet->setPropertyValue("MediaType", Any(OUString("text/xml")));
+
+    // write the stuff
+    // Note: export through an XML exporter component (output stream version)
+    bool bOk = WriteThroughComponentOS(xStream, xComponent, rxContext, rPropSet,
+                                       u"com.sun.star.comp.Math.XMLContentExporter");
+
+    // We don't want to read unitzialized data
+    if (!bOk)
+        return u"";
+
+    // Recover data and generate string
+    OString aString(static_cast<const char*>(aMemoryStream.GetData()),
+                    aMemoryStream.GetSize() / sizeof(char));
+    return OStringToOUString(aString, RTL_TEXTENCODING_UTF8);
+}
+
+// SmMlExport technical
+/*************************************************************************************************/
+
+sal_Int64 SAL_CALL SmMlExport::getSomething(const uno::Sequence<sal_Int8>& rId)
+{
+    if (isUnoTunnelId<SmMlExport>(rId))
+        return reinterpret_cast<intptr_t>(this);
+    return SvXMLExport::getSomething(rId);
+}
+
+const uno::Sequence<sal_Int8>& SmMlExport::getUnoTunnelId() noexcept
+{
+    static const UnoTunnelIdInit theSmMlExportUnoTunnelId;
+    return theSmMlExportUnoTunnelId.getSeq();
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+Math_MLExporter_get_implementation(css::uno::XComponentContext* context,
+                                   css::uno::Sequence<css::uno::Any> const&)
+{
+    return cppu::acquire(new SmMlExport(context, "com.sun.star.comp.Math.XMLExporter",
+                                        SvXMLExportFlags::OASIS | SvXMLExportFlags::ALL));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+Math_MLMetaExporter_get_implementation(css::uno::XComponentContext* context,
+                                       css::uno::Sequence<css::uno::Any> const&)
+{
+    return cppu::acquire(
+        new SmMlExport(context, "com.sun.star.comp.Math.XMLMetaExporter", SvXMLExportFlags::META));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+Math_MLOasisMetaExporter_get_implementation(css::uno::XComponentContext* context,
+                                            css::uno::Sequence<css::uno::Any> const&)
+{
+    return cppu::acquire(new SmMlExport(context, "com.sun.star.comp.Math.XMLOasisMetaExporter",
+                                        SvXMLExportFlags::OASIS | SvXMLExportFlags::META));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+Math_MLSettingsExporter_get_implementation(css::uno::XComponentContext* context,
+                                           css::uno::Sequence<css::uno::Any> const&)
+{
+    return cppu::acquire(new SmMlExport(context, "com.sun.star.comp.Math.XMLSettingsExporter",
+                                        SvXMLExportFlags::SETTINGS));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+Math_MLOasisSettingsExporter_get_implementation(css::uno::XComponentContext* context,
+                                                css::uno::Sequence<css::uno::Any> const&)
+{
+    return cppu::acquire(new SmMlExport(context, "com.sun.star.comp.Math.XMLOasisSettingsExporter",
+                                        SvXMLExportFlags::OASIS | SvXMLExportFlags::SETTINGS));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+Math_MLContentExporter_get_implementation(css::uno::XComponentContext* context,
+                                          css::uno::Sequence<css::uno::Any> const&)
+{
+    return cppu::acquire(new SmMlExport(context, "com.sun.star.comp.Math.XMLContentExporter",
+                                        SvXMLExportFlags::OASIS | SvXMLExportFlags::CONTENT));
+}
+
+SmDocShell* SmMlExport::getSmDocShell()
+{
+    SmModel* pModel = comphelper::getUnoTunnelImplementation<SmModel>(GetModel());
+    if (pModel != nullptr)
+        return static_cast<SmDocShell*>(pModel->GetObjectShell());
+    return nullptr;
+}
+
+ErrCode SmMlExport::exportDoc(enum XMLTokenEnum eClass)
+{
+    if (!(getExportFlags() & SvXMLExportFlags::CONTENT))
+    {
+        // Everything that isn't the formula itself get's default export
+        SvXMLExport::exportDoc(eClass);
+        return ERRCODE_NONE;
+    }
+
+    /* Needs comented for now or clang complains
+        // Checks if it has to export a particular tree
+        if (m_pElementTree == nullptr)
+        {
+            // Set element tree
+            SmDocShell* pDocShell = getSmDocShell();
+            if (pDocShell != nullptr)
+            {
+                // TODO implement this when available
+                (void)pDocShell;
+            }
+            else
+            {
+                m_bSuccess = false;
+                return SVSTREAM_INVALID_PARAMETER;
+            }
+        }
+        */
+
+    // Start document amd encript if necessary
+    GetDocHandler()->startDocument();
+    addChaffWhenEncryptedStorage();
+
+    // make use of a default namespace
+    // Math doesn't need namespaces from xmloff, since it now uses default namespaces
+    // Because that is common with current MathML usage in the web -> ResetNamespaceMap();
+    GetNamespaceMap_().Add(OUString(u""), GetXMLToken(XML_N_MATH), XML_NAMESPACE_MATH);
+
+    // Add xmlns line
+    if (m_bUseExportTag)
+    {
+        GetAttrList().AddAttribute(GetNamespaceMap().GetAttrNameByKey(XML_NAMESPACE_MATH),
+                                   GetNamespaceMap().GetNameByKey(XML_NAMESPACE_MATH));
+    }
+
+    // Export and close document
+    ExportContent_();
+    GetDocHandler()->endDocument();
+
+    return ERRCODE_NONE;
+}
+
+void SmMlExport::GetViewSettings(Sequence<PropertyValue>& aProps)
+{
+    // Get the document shell
+    SmDocShell* pDocShell = getSmDocShell();
+    if (pDocShell == nullptr)
+    {
+        SAL_WARN("starmath", "Missing document shell so no view settings");
+        return;
+    }
+
+    // Allocate enough memory
+    aProps.realloc(4);
+    PropertyValue* pValue = aProps.getArray();
+
+    // The view settings are the formula display settings
+    tools::Rectangle aRect(pDocShell->GetVisArea());
+
+    pValue[0].Name = "ViewAreaTop";
+    pValue[0].Value <<= aRect.Top();
+
+    pValue[1].Name = "ViewAreaLeft";
+    pValue[1].Value <<= aRect.Left();
+
+    pValue[2].Name = "ViewAreaWidth";
+    pValue[2].Value <<= aRect.GetWidth();
+
+    pValue[3].Name = "ViewAreaHeight";
+    pValue[3].Value <<= aRect.GetHeight();
+}
+
+void SmMlExport::GetConfigurationSettings(Sequence<PropertyValue>& rProps)
+{
+    // Get model property set (settings)
+    Reference<XPropertySet> xProps(GetModel(), UNO_QUERY);
+    if (!xProps.is())
+    {
+        SAL_WARN("starmath", "Missing model properties so no configuration settings");
+        return;
+    }
+
+    // Get model property set info (settings values)
+    Reference<XPropertySetInfo> xPropertySetInfo = xProps->getPropertySetInfo();
+    if (!xPropertySetInfo.is())
+    {
+        SAL_WARN("starmath", "Missing model properties info so no configuration settings");
+        return;
+    }
+
+    // Allocate to store the properties
+    Sequence<Property> aProps = xPropertySetInfo->getProperties();
+    const sal_Int32 nCount = aProps.getLength();
+    rProps.realloc(nCount);
+
+    // Copy properties
+    // This needs further revision
+    // Based in code mathmlexport.cxx::GetConfigurationSettings
+    for (sal_Int32 i = 0; i < nCount; ++i)
+    {
+        if (aProps[i].Name != "Formula" && aProps[i].Name != "BasicLibraries"
+            && aProps[i].Name != "DialogLibraries" && aProps[i].Name != "RuntimeUID")
+        {
+            rProps[i].Name = aProps[i].Name;
+            rProps[i].Value = xProps->getPropertyValue(aProps[i].Name);
+        }
+    }
+}
+
+SmMlExport::SmMlExport(const css::uno::Reference<css::uno::XComponentContext>& rContext,
+                       OUString const& implementationName, SvXMLExportFlags nExportFlags)
+    : SvXMLExport(rContext, implementationName, util::MeasureUnit::INCH, XML_MATH, nExportFlags)
+    , m_pElementTree(nullptr)
+    , m_bSuccess(true)
+    , m_bUseExportTag(false)
+{
+}
+
+// SmMlExport
+/*************************************************************************************************/
+
+void SmMlExport::declareMlError()
+{
+    SAL_WARN("starmath", "Invalid use of mathml.");
+    m_bSuccess = false;
+}
+
+void SmMlExport::exportMlAttributteLength(xmloff::token::XMLTokenEnum pAttribute,
+                                          const SmLengthValue& aLengthValue)
+{
+    if (!aLengthValue.m_aOriginalText->isEmpty())
+    {
+        addAttribute(pAttribute, *aLengthValue.m_aOriginalText);
+    }
+    else
+    {
+        OUStringBuffer aSizeBuffer(64);
+        aSizeBuffer.append(aLengthValue.m_aLengthValue);
+        switch (aLengthValue.m_aLengthUnit)
+        {
+            case SmLengthUnit::MlEm:
+                aSizeBuffer.append(u"em");
+                break;
+            case SmLengthUnit::MlEx:
+                aSizeBuffer.append(u"ex");
+                break;
+            case SmLengthUnit::MlPx:
+                aSizeBuffer.append(u"px");
+                break;
+            case SmLengthUnit::MlIn:
+                aSizeBuffer.append(u"in");
+                break;
+            case SmLengthUnit::MlCm:
+                aSizeBuffer.append(u"cm");
+                break;
+            case SmLengthUnit::MlMm:
+                aSizeBuffer.append(u"mm");
+                break;
+            case SmLengthUnit::MlPt:
+                aSizeBuffer.append(u"pt");
+                break;
+            case SmLengthUnit::MlPc:
+                aSizeBuffer.append(u"pc");
+                break;
+            case SmLengthUnit::MlP:
+                aSizeBuffer.append(u"%");
+                break;
+            case SmLengthUnit::MlM:
+                break;
+            default:
+                declareMlError();
+                break;
+        }
+        addAttribute(pAttribute, aSizeBuffer.makeStringAndClear());
+    }
+}
+
+void SmMlExport::exportMlAttributtes(const SmMlElement* pMlElement)
+{
+    size_t nAttributeCount = pMlElement->getAttributeCount();
+    for (size_t i = 0; i < nAttributeCount; ++i)
+    {
+        SmMlAttribute aAttribute = pMlElement->getAttribute(i);
+        switch (aAttribute.getMlAttributeValueType())
+        {
+            case SmMlAttributeValueType::MlAccent:
+            {
+                auto aAttributeValue = aAttribute.getMlAccent();
+                switch (aAttributeValue->m_aAccent)
+                {
+                    case SmMlAttributeValueAccent::MlFalse:
+                        addAttribute(XML_ACCENT, XML_FALSE);
+                        break;
+                    case SmMlAttributeValueAccent::MlTrue:
+                        addAttribute(XML_ACCENT, XML_TRUE);
+                        break;
+                    default:
+                        declareMlError();
+                        break;
+                }
+                break;
+            }
+            case SmMlAttributeValueType::MlDir:
+            {
+                auto aAttributeValue = aAttribute.getMlDir();
+                switch (aAttributeValue->m_aDir)
+                {
+                    case SmMlAttributeValueDir::MlLtr:
+                        addAttribute(XML_DIR, XML_LTR);
+                        break;
+                    case SmMlAttributeValueDir::MlRtl:
+                        addAttribute(XML_DIR, XML_RTL);
+                        break;
+                    default:
+                        declareMlError();
+                        break;
+                }
+                break;
+            }
+            case SmMlAttributeValueType::MlDisplaystyle:
+            {
+                auto aAttributeValue = aAttribute.getMlDisplaystyle();
+                switch (aAttributeValue->m_aDisplaystyle)
+                {
+                    case SmMlAttributeValueDisplaystyle::MlTrue:
+                        addAttribute(XML_DISPLAYSTYLE, XML_FALSE);
+                        break;
+                    case SmMlAttributeValueDisplaystyle::MlFalse:
+                        addAttribute(XML_DISPLAYSTYLE, XML_TRUE);
+                        break;
+                    default:
+                        declareMlError();
+                        break;
+                }
+                break;
+            }
+            case SmMlAttributeValueType::MlFence:
+            {
+                auto aAttributeValue = aAttribute.getMlFence();
+                switch (aAttributeValue->m_aFence)
+                {
+                    case SmMlAttributeValueFence::MlTrue:
+                        addAttribute(XML_FENCE, XML_FALSE);
+                        break;
+                    case SmMlAttributeValueFence::MlFalse:
+                        addAttribute(XML_FENCE, XML_TRUE);
+                        break;
+                    default:
+                        declareMlError();
+                        break;
+                }
+                break;
+            }
+            case SmMlAttributeValueType::MlHref:
+            {
+                auto aAttributeValue = aAttribute.getMlHref();
+                switch (aAttributeValue->m_aHref)
+                {
+                    case SmMlAttributeValueHref::NMlEmpty:
+                        break;
+                    case SmMlAttributeValueHref::NMlValid:
+                        addAttribute(XML_HREF, *aAttributeValue->m_aLnk);
+                        break;
+                    default:
+                        declareMlError();
+                        break;
+                }
+                break;
+            }
+            case SmMlAttributeValueType::MlLspace:
+            {
+                auto aSizeData = aAttribute.getMlLspace();
+                auto aLengthData = aSizeData->m_aLengthValue;
+                exportMlAttributteLength(XML_LSPACE, aLengthData);
+                break;
+            }
+            case SmMlAttributeValueType::MlMathbackground:
+            {
+                auto aAttributeValue = aAttribute.getMlMathbackground();
+                switch (aAttributeValue->m_aMathbackground)
+                {
+                    case SmMlAttributeValueMathbackground::MlTransparent:
+                        addAttribute(XML_MATHBACKGROUND, "transparent");
+                        break;
+                    case SmMlAttributeValueMathbackground::MlRgb:
+                    {
+                        OUString aTextColor
+                            = OUString::createFromAscii(starmathdatabase::Identify_Color_MATHML(
+                                                            sal_uInt32(aAttributeValue->m_aCol))
+                                                            .pIdent);
+                        addAttribute(XML_MATHBACKGROUND, aTextColor);
+                        break;
+                    }
+                    default:
+                        declareMlError();
+                        break;
+                }
+                break;
+            }
+            case SmMlAttributeValueType::MlMathcolor:
+            {
+                auto aAttributeValue = aAttribute.getMlMathcolor();
+                switch (aAttributeValue->m_aMathcolor)
+                {
+                    case SmMlAttributeValueMathcolor::MlDefault:
+                        break;
+                    case SmMlAttributeValueMathcolor::MlRgb:
+                    {
+                        OUString aTextColor
+                            = OUString::createFromAscii(starmathdatabase::Identify_Color_MATHML(
+                                                            sal_uInt32(aAttributeValue->m_aCol))
+                                                            .pIdent);
+                        addAttribute(XML_MATHCOLOR, aTextColor);
+                        break;
+                    }
+                    default:
+                        declareMlError();
+                        break;
+                }
+                break;
+            }
+            case SmMlAttributeValueType::MlMathsize:
+            {
+                auto aSizeData = aAttribute.getMlMathsize();
+                auto aLengthData = aSizeData->m_aLengthValue;
+                exportMlAttributteLength(XML_MATHSIZE, aLengthData);
+                break;
+            }
+            case SmMlAttributeValueType::MlMathvariant:
+            {
+                auto aAttributeValue = aAttribute.getMlMathvariant();
+                switch (aAttributeValue->m_aMathvariant)
+                {
+                    case SmMlAttributeValueMathvariant::normal:
+                        addAttribute(XML_MATHVARIANT, "normal");
+                        break;
+                    case SmMlAttributeValueMathvariant::bold:
+                        addAttribute(XML_MATHVARIANT, "bold");
+                        break;
+                    case SmMlAttributeValueMathvariant::italic:
+                        addAttribute(XML_MATHVARIANT, "italic");
+                        break;
+                    case SmMlAttributeValueMathvariant::double_struck:
+                        addAttribute(XML_MATHVARIANT, "double-struck");
+                        break;
+                    case SmMlAttributeValueMathvariant::script:
+                        addAttribute(XML_MATHVARIANT, "script");
+                        break;
+                    case SmMlAttributeValueMathvariant::fraktur:
+                        addAttribute(XML_MATHVARIANT, "fraktur");
+                        break;
+                    case SmMlAttributeValueMathvariant::sans_serif:
+                        addAttribute(XML_MATHVARIANT, "sans-serif");
+                        break;
+                    case SmMlAttributeValueMathvariant::monospace:
+                        addAttribute(XML_MATHVARIANT, "monospace");
+                        break;
+                    case SmMlAttributeValueMathvariant::bold_italic:
+                        addAttribute(XML_MATHVARIANT, "bold-italic");
+                        break;
+                    case SmMlAttributeValueMathvariant::bold_fraktur:
+                        addAttribute(XML_MATHVARIANT, "bold-fracktur");
+                        break;
+                    case SmMlAttributeValueMathvariant::bold_script:
+                        addAttribute(XML_MATHVARIANT, "bold-script");
+                        break;
+                    case SmMlAttributeValueMathvariant::bold_sans_serif:
+                        addAttribute(XML_MATHVARIANT, "bold-sans-serif");
+                        break;
+                    case SmMlAttributeValueMathvariant::sans_serif_italic:
+                        addAttribute(XML_MATHVARIANT, "sans-serif-italic");
+                        break;
+                    case SmMlAttributeValueMathvariant::sans_serif_bold_italic:
+                        addAttribute(XML_MATHVARIANT, "sans-serif-bold-italic");
+                        break;
+                    case SmMlAttributeValueMathvariant::initial:
+                        addAttribute(XML_MATHVARIANT, "initial");
+                        break;
+                    case SmMlAttributeValueMathvariant::tailed:
+                        addAttribute(XML_MATHVARIANT, "tailed");
+                        break;
+                    case SmMlAttributeValueMathvariant::looped:
+                        addAttribute(XML_MATHVARIANT, "looped");
+                        break;
+                    case SmMlAttributeValueMathvariant::stretched:
+                        addAttribute(XML_MATHVARIANT, "stretched");
+                        break;
+                    default:
+                        declareMlError();
+                        break;
+                }
+                break;
+            }
+            case SmMlAttributeValueType::MlMaxsize:
+            {
+                auto aSizeData = aAttribute.getMlMaxsize();
+                auto aLengthData = aSizeData->m_aLengthValue;
+                switch (aSizeData->m_aMaxsize)
+                {
+                    case SmMlAttributeValueMaxsize::MlInfinity:
+                    {
+                        addAttribute(XML_MAXSIZE, OUString(u"infinity"));
+                        break;
+                    }
+                    case SmMlAttributeValueMaxsize::MlFinite:
+                    {
+                        exportMlAttributteLength(XML_MAXSIZE, aLengthData);
+                        break;
+                    }
+                }
+                break;
+            }
+            case SmMlAttributeValueType::MlMinsize:
+            {
+                auto aSizeData = aAttribute.getMlMinsize();
+                auto aLengthData = aSizeData->m_aLengthValue;
+                exportMlAttributteLength(XML_MINSIZE, aLengthData);
+                break;
+            }
+            case SmMlAttributeValueType::MlMovablelimits:
+            {
+                auto aAttributeValue = aAttribute.getMlMovablelimits();
+                switch (aAttributeValue->m_aMovablelimits)
+                {
+                    case SmMlAttributeValueMovablelimits::MlFalse:
+                        addAttribute(XML_MOVABLELIMITS, XML_FALSE);
+                        break;
+                    case SmMlAttributeValueMovablelimits::MlTrue:
+                        addAttribute(XML_MOVABLELIMITS, XML_TRUE);
+                        break;
+                    default:
+                        declareMlError();
+                        break;
+                }
+                break;
+            }
+            case SmMlAttributeValueType::MlRspace:
+            {
+                auto aSizeData = aAttribute.getMlRspace();
+                auto aLengthData = aSizeData->m_aLengthValue;
+                exportMlAttributteLength(XML_RSPACE, aLengthData);
+                break;
+            }
+            case SmMlAttributeValueType::MlSeparator:
+            {
+                auto aAttributeValue = aAttribute.getMlSeparator();
+                switch (aAttributeValue->m_aSeparator)
+                {
+                    case SmMlAttributeValueSeparator::MlFalse:
+                        addAttribute(XML_SEPARATOR, XML_FALSE);
+                        break;
+                    case SmMlAttributeValueSeparator::MlTrue:
+                        addAttribute(XML_SEPARATOR, XML_TRUE);
+                        break;
+                    default:
+                        declareMlError();
+                        break;
+                }
+                break;
+            }
+            case SmMlAttributeValueType::MlStretchy:
+            {
+                auto aAttributeValue = aAttribute.getMlStretchy();
+                switch (aAttributeValue->m_aStretchy)
+                {
+                    case SmMlAttributeValueStretchy::MlFalse:
+                        addAttribute(XML_STRETCHY, XML_FALSE);
+                        break;
+                    case SmMlAttributeValueStretchy::MlTrue:
+                        addAttribute(XML_STRETCHY, XML_TRUE);
+                        break;
+                    default:
+                        declareMlError();
+                        break;
+                }
+                break;
+            }
+            case SmMlAttributeValueType::MlSymmetric:
+            {
+                auto aAttributeValue = aAttribute.getMlSymmetric();
+                switch (aAttributeValue->m_aSymmetric)
+                {
+                    case SmMlAttributeValueSymmetric::MlFalse:
+                        addAttribute(XML_SYMMETRIC, XML_FALSE);
+                        break;
+                    case SmMlAttributeValueSymmetric::MlTrue:
+                        addAttribute(XML_SYMMETRIC, XML_TRUE);
+                        break;
+                    default:
+                        declareMlError();
+                        break;
+                }
+                break;
+            }
+            default:
+                declareMlError();
+                break;
+        }
+    }
+}
+
+SvXMLElementExport* SmMlExport::exportMlElement(const SmMlElement* pMlElement)
+{
+    SvXMLElementExport* pElementExport;
+    switch (pMlElement->getMlElementType())
+    {
+        case SmMlElementType::MlMath:
+            pElementExport = createElementExport(XML_MATH);
+            break;
+        case SmMlElementType::MlMi:
+            pElementExport = createElementExport(XML_MI);
+            break;
+        case SmMlElementType::MlMerror:
+            pElementExport = createElementExport(XML_MERROR);
+            break;
+        case SmMlElementType::MlMn:
+            pElementExport = createElementExport(XML_MN);
+            break;
+        case SmMlElementType::MlMo:
+            pElementExport = createElementExport(XML_MO);
+            break;
+        case SmMlElementType::MlMrow:
+            pElementExport = createElementExport(XML_MROW);
+            break;
+        case SmMlElementType::MlMtext:
+            pElementExport = createElementExport(XML_MTEXT);
+            break;
+        case SmMlElementType::MlMstyle:
+            pElementExport = createElementExport(XML_MSTYLE);
+            break;
+        default:
+            pElementExport = nullptr;
+    }
+    const OUString& aElementText = pMlElement->getText();
+    exportMlAttributtes(pMlElement);
+    if (aElementText.isEmpty())
+        GetDocHandler()->characters(aElementText);
+    return pElementExport;
+}
+
+namespace
+{
+struct exportMlElementTreeExecData
+{
+private:
+    SmMlExport* m_pSmMlExport;
+    std::vector<SvXMLElementExport*> m_aSvXMLElementExportList;
+    size_t m_nDepth;
+
+public:
+    inline exportMlElementTreeExecData(SmMlExport* pSmMlExport)
+        : m_pSmMlExport(pSmMlExport)
+        , m_aSvXMLElementExportList(1024)
+        , m_nDepth(0)
+    {
+    }
+
+    inline void deleteDepthData()
+    {
+        delete m_aSvXMLElementExportList[m_nDepth];
+        --m_nDepth;
+    }
+
+    inline void setDepthData(SvXMLElementExport* aSvXMLElementExportList)
+    {
+        if (m_nDepth == m_aSvXMLElementExportList.size())
+            m_aSvXMLElementExportList.reserve(m_aSvXMLElementExportList.size() + 1024);
+        m_aSvXMLElementExportList[m_nDepth] = aSvXMLElementExportList;
+    }
+
+    inline void incrementDepth() { ++m_nDepth; }
+
+    inline SmMlExport* getSmMlExport() { return m_pSmMlExport; };
+};
+
+} // end unnamed namespace
+
+static inline void exportMlElementTreeExec(SmMlElement* aSmMlElement, void* aData)
+{
+    // Prepare data
+    exportMlElementTreeExecData* pData = static_cast<exportMlElementTreeExecData*>(aData);
+    pData->setDepthData(pData->getSmMlExport()->exportMlElement(aSmMlElement));
+
+    // Prepare for following
+    // If it has sub elements, then it will be the next
+    if (aSmMlElement->getSubElementsCount() != 0)
+        pData->incrementDepth();
+    else // Otherwise remounts up to where it should be
+    {
+        while (aSmMlElement->getParentElement() != nullptr)
+        {
+            // get parent
+            SmMlElement* pParent = aSmMlElement->getParentElement();
+            pData->deleteDepthData();
+            // was this the last branch ?
+            if (aSmMlElement->getSubElementId() + 1 != pParent->getSubElementsCount()) // yes -> up
+                break; // no -> stop going up
+            // Prepare for next round
+            aSmMlElement = pParent;
+        }
+    }
+}
+
+void SmMlExport::exportMlElementTree()
+{
+    exportMlElementTreeExecData* aData = new exportMlElementTreeExecData(this);
+    mathml::SmMlIteratorTopToBottom(m_pElementTree, exportMlElementTreeExec, aData);
+    delete aData;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx
index e65de4fc61cb..9bc4fca57a80 100644
--- a/xmloff/source/core/xmltoken.cxx
+++ b/xmloff/source/core/xmltoken.cxx
@@ -3418,6 +3418,18 @@ namespace xmloff::token {
 
         TOKEN("local-url", XML_LOCAL_URL),
 
+        TOKEN("dir",                 XML_DIR ),
+        TOKEN("displaystyle",        XML_DISPLAYSTYLE ),
+        TOKEN("lspace",              XML_LSPACE ),
+        TOKEN("mathbackground",      XML_MATHBACKGROUND ),
+        TOKEN("maxsize",             XML_MAXSIZE ),
+        TOKEN("minsize",             XML_MINSIZE ),
+        TOKEN("movablelimits",       XML_MOVABLELIMITS ),
+        TOKEN("rspace",              XML_RSPACE ),
+        TOKEN("rtl",                 XML_RTL ),
+        TOKEN("symmetric",           XML_SYMMETRIC ),
+
+
 #if OSL_DEBUG_LEVEL > 0
         { 0, nullptr, std::nullopt,               XML_TOKEN_END }
 #else
diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt
index 3524d1ce8686..52b457602c27 100644
--- a/xmloff/source/token/tokens.txt
+++ b/xmloff/source/token/tokens.txt
@@ -3171,4 +3171,14 @@ page-content-top
 page-content-bottom
 margin-gutter
 local-url
+dir
+displaystyle
+lspace
+mathbackground
+maxsize
+minsize
+movablelimits
+rspace
+rtl
+symmetric
 TOKEN_END_DUMMY


More information about the Libreoffice-commits mailing list