Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / starmath / source / mathml / export.cxx
blobbafdd7c431a8002c6f6da1afcad3162765f55db6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 // Our mathml
21 #include <mathml/export.hxx>
22 #include <mathml/iterator.hxx>
24 // LO tools to use
25 #include <com/sun/star/beans/PropertyAttribute.hpp>
26 #include <com/sun/star/embed/ElementModes.hpp>
27 #include <com/sun/star/task/XStatusIndicator.hpp>
28 #include <com/sun/star/uno/Any.h>
29 #include <com/sun/star/util/MeasureUnit.hpp>
30 #include <com/sun/star/xml/sax/Writer.hpp>
32 // Extra LO tools
33 #include <comphelper/genericpropertyset.hxx>
34 #include <comphelper/processfactory.hxx>
35 #include <comphelper/propertysetinfo.hxx>
36 #include <sfx2/frame.hxx>
37 #include <sfx2/docfile.hxx>
38 #include <sfx2/sfxsids.hrc>
39 #include <svl/itemset.hxx>
40 #include <svl/stritem.hxx>
41 #include <unotools/streamwrap.hxx>
42 #include <xmloff/namespacemap.hxx>
44 // Our starmath tools
45 #include <document.hxx>
46 #include <smmod.hxx>
47 #include <strings.hrc>
48 #include <unomodel.hxx>
49 #include <xparsmlbase.hxx>
50 #include <starmathdatabase.hxx>
52 // Old parser
53 #include <mathmlexport.hxx>
55 using namespace ::com::sun::star;
56 using namespace xmloff::token;
58 using namespace ::com::sun::star::beans;
59 using namespace ::com::sun::star::document;
60 using namespace ::com::sun::star::lang;
61 using namespace ::com::sun::star::uno;
62 using namespace ::com::sun::star;
63 using namespace ::xmloff::token;
65 // SmMLExportWrapper
66 /*************************************************************************************************/
68 bool SmMLExportWrapper::Export(SfxMedium& rMedium)
70 bool bRet = true;
71 uno::Reference<uno::XComponentContext> xContext(comphelper::getProcessComponentContext());
73 // Check all fine
74 SAL_WARN_IF(m_xModel == nullptr, "starmath", "Missing model");
75 SAL_WARN_IF(xContext == nullptr, "starmath", "Missing context");
76 if (m_xModel == nullptr || xContext == nullptr)
77 return false;
79 // Get doc shell
80 SmDocShell* pDocShell = static_cast<SmDocShell*>(m_xModel->GetObjectShell());
81 if (pDocShell == nullptr)
83 SAL_WARN("starmath", "Failed to fetch sm document");
84 return false;
87 // Check if it is a standalone window or embed object
88 bool bEmbedded = SfxObjectCreateMode::EMBEDDED == pDocShell->GetCreateMode();
90 // Medium item set
91 SfxItemSet* pMediumItemSet = rMedium.GetItemSet();
92 if (pDocShell == nullptr)
94 SAL_WARN("starmath", "Failed to get medium item set");
95 return false;
98 // Progress bar ~
99 uno::Reference<task::XStatusIndicator> xStatusIndicator;
101 if (!bEmbedded)
103 // Extra check to ensure everything is fine
104 if (pDocShell->GetMedium() != &rMedium)
106 SAL_WARN("starmath", "Input medium and sm document medium do not match");
107 //return false;
110 // Fetch progress bar
111 const SfxUnoAnyItem* pItem = pMediumItemSet->GetItem(SID_PROGRESS_STATUSBAR_CONTROL);
112 if (pItem)
114 // set progress range and start status indicator
115 pItem->GetValue() >>= xStatusIndicator;
116 xStatusIndicator->start(SmResId(STR_STATSTR_WRITING), 3);
117 xStatusIndicator->setValue(0);
121 // create XPropertySet with three properties for status indicator
122 static const comphelper::PropertyMapEntry aInfoMap[]{
123 { OUString("UsePrettyPrinting"), 0, cppu::UnoType<bool>::get(),
124 beans::PropertyAttribute::MAYBEVOID, 0 },
125 { OUString("BaseURI"), 0, ::cppu::UnoType<OUString>::get(),
126 beans::PropertyAttribute::MAYBEVOID, 0 },
127 { OUString("StreamRelPath"), 0, ::cppu::UnoType<OUString>::get(),
128 beans::PropertyAttribute::MAYBEVOID, 0 },
129 { OUString("StreamName"), 0, ::cppu::UnoType<OUString>::get(),
130 beans::PropertyAttribute::MAYBEVOID, 0 }
132 uno::Reference<beans::XPropertySet> xInfoSet(
133 comphelper::GenericPropertySet_CreateInstance(new comphelper::PropertySetInfo(aInfoMap)));
135 // Always print pretty
136 xInfoSet->setPropertyValue("UsePrettyPrinting", Any(true));
138 // Set base URI
139 xInfoSet->setPropertyValue(u"BaseURI", Any(rMedium.GetBaseURL(true)));
141 if (!m_bFlat) //Storage (Package) of Stream
143 // Fetch the output storage
144 uno::Reference<embed::XStorage> xStg = rMedium.GetOutputStorage();
145 if (xStg == nullptr)
147 SAL_WARN("starmath", "Failed to fetch output storage");
148 return false;
151 // TODO/LATER: handle the case of embedded links gracefully
152 if (bEmbedded) //&& !pStg->IsRoot() )
154 const SfxStringItem* pDocHierarchItem
155 = pMediumItemSet->GetItem(SID_DOC_HIERARCHICALNAME);
156 if (pDocHierarchItem != nullptr)
158 OUString aName = pDocHierarchItem->GetValue();
159 if (!aName.isEmpty())
160 xInfoSet->setPropertyValue("StreamRelPath", Any(aName));
163 else
165 // Write file metadata ( data, LO version ... )
166 // Note: export through an XML exporter component (storage version)
167 if (xStatusIndicator.is())
168 xStatusIndicator->setValue(1);
170 bRet = WriteThroughComponentS(xStg, m_xModel, u"meta.xml", xContext, xInfoSet,
171 u"com.sun.star.comp.Math.MLOasisMetaExporter", 6);
174 // Write starmath formula
175 // Note: export through an XML exporter component (storage version)
176 if (bRet)
178 if (xStatusIndicator.is())
179 xStatusIndicator->setValue(2);
181 if (pDocShell->GetSmSyntaxVersion() == 5)
182 bRet = WriteThroughComponentS(xStg, m_xModel, u"content.xml", xContext, xInfoSet,
183 u"com.sun.star.comp.Math.XMLContentExporter", 5);
184 else
185 bRet = WriteThroughComponentS(xStg, m_xModel, u"content.xml", xContext, xInfoSet,
186 u"com.sun.star.comp.Math.MLContentExporter", 6);
189 // Write starmath settings
190 // Note: export through an XML exporter component (storage version)
191 if (bRet)
193 if (xStatusIndicator.is())
194 xStatusIndicator->setValue(3);
196 bRet = WriteThroughComponentS(xStg, m_xModel, u"settings.xml", xContext, xInfoSet,
197 u"com.sun.star.comp.Math.MLOasisSettingsExporter", 6);
200 else
202 // Fetch the output stream
203 SvStream* pStream = rMedium.GetOutStream();
204 if (pStream == nullptr)
206 SAL_WARN("starmath", "Missing output stream");
207 return false;
209 uno::Reference<io::XOutputStream> xOut(new utl::OOutputStreamWrapper(*pStream));
211 if (xStatusIndicator.is())
212 xStatusIndicator->setValue(1);
214 // Write everything in the same place
215 // Note: export through an XML exporter component (output stream version)
216 if (pDocShell->GetSmSyntaxVersion() == 5)
217 bRet = WriteThroughComponentOS(xOut, m_xModel, xContext, xInfoSet,
218 u"com.sun.star.comp.Math.XMLContentExporter", 5);
219 else
220 bRet = WriteThroughComponentOS(xOut, m_xModel, xContext, xInfoSet,
221 u"com.sun.star.comp.Math.MLContentExporter", 6);
224 if (xStatusIndicator.is())
225 xStatusIndicator->end();
226 return bRet;
229 OUString SmMLExportWrapper::Export(SmMlElement* pElementTree)
231 uno::Reference<uno::XComponentContext> xContext(comphelper::getProcessComponentContext());
233 // Check all fine
234 m_pElementTree = nullptr;
235 SAL_WARN_IF(m_xModel == nullptr, "starmath", "Missing model");
236 SAL_WARN_IF(xContext == nullptr, "starmath", "Missing context");
237 if (m_xModel == nullptr || xContext == nullptr)
238 return u"";
240 //Get model
241 uno::Reference<lang::XComponent> xModelComp = m_xModel;
242 SAL_WARN_IF(xModelComp == nullptr, "starmath", "Missing model component");
243 SmModel* pModel = m_xModel.get();
244 SAL_WARN_IF(pModel == nullptr, "starmath", "Failed to get threw uno tunnel");
245 if (xModelComp == nullptr || pModel == nullptr)
246 return u"";
248 // Get doc shell
249 SmDocShell* pDocShell = static_cast<SmDocShell*>(pModel->GetObjectShell());
250 if (pDocShell == nullptr)
252 SAL_WARN("starmath", "Failed to fetch sm document");
253 return u"";
256 // create XPropertySet with three properties for status indicator
257 static const comphelper::PropertyMapEntry aInfoMap[]{
258 { OUString("UsePrettyPrinting"), 0, cppu::UnoType<bool>::get(),
259 beans::PropertyAttribute::MAYBEVOID, 0 },
260 { OUString("BaseURI"), 0, ::cppu::UnoType<OUString>::get(),
261 beans::PropertyAttribute::MAYBEVOID, 0 },
262 { OUString("StreamRelPath"), 0, ::cppu::UnoType<OUString>::get(),
263 beans::PropertyAttribute::MAYBEVOID, 0 },
264 { OUString("StreamName"), 0, ::cppu::UnoType<OUString>::get(),
265 beans::PropertyAttribute::MAYBEVOID, 0 }
267 uno::Reference<beans::XPropertySet> xInfoSet(
268 comphelper::GenericPropertySet_CreateInstance(new comphelper::PropertySetInfo(aInfoMap)));
270 // Always print pretty
271 xInfoSet->setPropertyValue("UsePrettyPrinting", Any(true));
273 // Fetch mathml tree
274 m_pElementTree = pElementTree;
276 // Write stuff
277 // Note: export through an XML exporter component (memory stream version)
278 return WriteThroughComponentMS(xModelComp, xContext, xInfoSet);
281 // export through an XML exporter component (output stream version)
282 bool SmMLExportWrapper::WriteThroughComponentOS(const Reference<io::XOutputStream>& xOutputStream,
283 const Reference<XComponent>& xComponent,
284 Reference<uno::XComponentContext> const& rxContext,
285 Reference<beans::XPropertySet> const& rPropSet,
286 const char16_t* pComponentName,
287 int_fast16_t nSyntaxVersion)
289 // We need a output stream but it is already checked by caller
290 // We need a component but it is already checked by caller
291 // We need a context but it is already checked by caller
292 // We need a property set but it is already checked by caller
293 // We need a component name but it is already checked by caller
295 // get sax writer
296 Reference<xml::sax::XWriter> xSaxWriter = xml::sax::Writer::create(rxContext);
298 // connect XML writer to output stream
299 xSaxWriter->setOutputStream(xOutputStream);
300 if (m_bUseHTMLMLEntities)
301 xSaxWriter->setCustomEntityNames(starmathdatabase::icustomMathmlHtmlEntitiesExport);
303 // prepare arguments (prepend doc handler to given arguments)
304 Sequence<Any> aArgs{ Any(xSaxWriter), Any(rPropSet) };
306 // get filter component
307 auto xExporterData = rxContext->getServiceManager()->createInstanceWithArgumentsAndContext(
308 OUString(pComponentName), aArgs, rxContext);
309 Reference<document::XExporter> xExporter(xExporterData, UNO_QUERY);
311 // Check everything is fine
312 if (!xExporter.is())
314 SAL_WARN("starmath", "can't instantiate export filter component");
315 return false;
318 // connect model and filter
319 xExporter->setSourceDocument(xComponent);
320 Reference<XFilter> xFilter(xExporter, UNO_QUERY);
321 uno::Sequence<PropertyValue> aProps(0);
323 // filter
324 if (nSyntaxVersion == 5)
326 SmXMLExport* pFilter = dynamic_cast<SmXMLExport*>(xFilter.get());
327 if (pFilter == nullptr)
329 SAL_WARN("starmath", "Failed to fetch SmMLExport");
330 return false;
332 xFilter->filter(aProps);
333 return pFilter->GetSuccess();
336 // filter
337 SmMLExport* pFilter = dynamic_cast<SmMLExport*>(xFilter.get());
339 // Setup filter
340 if (pFilter == nullptr)
342 SAL_WARN("starmath", "Failed to fetch SmMLExport");
343 return false;
345 pFilter->setUseExportTag(m_bUseExportTag);
346 pFilter->setElementTree(m_pElementTree);
348 // Execute operation
349 xFilter->filter(aProps);
350 return pFilter->getSuccess();
353 // export through an XML exporter component (storage version)
354 bool SmMLExportWrapper::WriteThroughComponentS(const Reference<embed::XStorage>& xStorage,
355 const Reference<XComponent>& xComponent,
356 const char16_t* pStreamName,
357 Reference<uno::XComponentContext> const& rxContext,
358 Reference<beans::XPropertySet> const& rPropSet,
359 const char16_t* pComponentName,
360 int_fast16_t nSyntaxVersion)
362 // We need a storage name but it is already checked by caller
363 // We need a component name but it is already checked by caller
364 // We need a stream name but it is already checked by caller
365 // We need a context but it is already checked by caller
366 // We need a property set but it is already checked by caller
367 // We need a component but it is already checked by caller
369 // open stream
370 Reference<io::XStream> xStream;
373 xStream = xStorage->openStreamElement(
374 OUString(pStreamName), embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE);
376 catch (const uno::Exception&)
378 SAL_WARN("starmath", "Can't create output stream in package");
379 return false;
382 // Set stream as text / xml
383 uno::Reference<beans::XPropertySet> xSet(xStream, uno::UNO_QUERY);
384 xSet->setPropertyValue("MediaType", Any(OUString(u"text/xml")));
386 // all streams must be encrypted in encrypted document
387 xSet->setPropertyValue("UseCommonStoragePasswordEncryption", Any(true));
389 // set Base URL
390 rPropSet->setPropertyValue("StreamName", Any(OUString(pStreamName)));
392 // write the stuff
393 // Note: export through an XML exporter component (output stream version)
394 return WriteThroughComponentOS(xStream->getOutputStream(), xComponent, rxContext, rPropSet,
395 pComponentName, nSyntaxVersion);
398 // export through an XML exporter component (memory stream version)
399 OUString
400 SmMLExportWrapper::WriteThroughComponentMS(const Reference<XComponent>& xComponent,
401 Reference<uno::XComponentContext> const& rxContext,
402 Reference<beans::XPropertySet> const& rPropSet)
404 // We need a component but it is already checked by caller
405 // We need a context but it is already checked by caller
406 // We need a property set it is already checked by caller
408 // open stream
409 SvMemoryStream aMemoryStream(8192, 1024);
410 uno::Reference<io::XOutputStream> xStream(new utl::OOutputStreamWrapper(aMemoryStream));
412 // Set the stream as text
413 uno::Reference<beans::XPropertySet> xSet(xStream, uno::UNO_QUERY);
414 xSet->setPropertyValue("MediaType", Any(OUString("text/xml")));
416 // write the stuff
417 // Note: export through an XML exporter component (output stream version)
418 bool bOk = WriteThroughComponentOS(xStream, xComponent, rxContext, rPropSet,
419 u"com.sun.star.comp.Mathml.MLContentExporter", 6);
421 // We don't want to read uninitialized data
422 if (!bOk)
423 return u"";
425 // Recover data and generate string
426 OString aString(static_cast<const char*>(aMemoryStream.GetData()),
427 aMemoryStream.GetSize() / sizeof(char));
428 return OStringToOUString(aString, RTL_TEXTENCODING_UTF8);
431 // SmMLExport technical
432 /*************************************************************************************************/
434 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
435 Math_MLExporter_get_implementation(css::uno::XComponentContext* context,
436 css::uno::Sequence<css::uno::Any> const&)
438 return cppu::acquire(new SmMLExport(context, "com.sun.star.comp.Math.XMLExporter",
439 SvXMLExportFlags::OASIS | SvXMLExportFlags::ALL));
442 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
443 Math_MLOasisMetaExporter_get_implementation(css::uno::XComponentContext* context,
444 css::uno::Sequence<css::uno::Any> const&)
446 return cppu::acquire(new SmMLExport(context, "com.sun.star.comp.Math.XMLOasisMetaExporter",
447 SvXMLExportFlags::OASIS | SvXMLExportFlags::META));
450 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
451 Math_MLOasisSettingsExporter_get_implementation(css::uno::XComponentContext* context,
452 css::uno::Sequence<css::uno::Any> const&)
454 return cppu::acquire(new SmMLExport(context, "com.sun.star.comp.Math.XMLOasisSettingsExporter",
455 SvXMLExportFlags::OASIS | SvXMLExportFlags::SETTINGS));
458 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
459 Math_MLContentExporter_get_implementation(css::uno::XComponentContext* context,
460 css::uno::Sequence<css::uno::Any> const&)
462 return cppu::acquire(new SmMLExport(context, "com.sun.star.comp.Math.XMLContentExporter",
463 SvXMLExportFlags::OASIS | SvXMLExportFlags::CONTENT));
466 SmDocShell* SmMLExport::getSmDocShell()
468 SmModel* pModel = comphelper::getFromUnoTunnel<SmModel>(GetModel());
469 if (pModel != nullptr)
470 return static_cast<SmDocShell*>(pModel->GetObjectShell());
471 return nullptr;
474 ErrCode SmMLExport::exportDoc(enum XMLTokenEnum eClass)
476 if (!(getExportFlags() & SvXMLExportFlags::CONTENT))
478 // Everything that isn't the formula itself get's default export
479 SvXMLExport::exportDoc(eClass);
480 return ERRCODE_NONE;
483 // Checks if it has to export a particular tree
484 if (m_pElementTree == nullptr)
486 // Set element tree
487 SmDocShell* pDocShell = getSmDocShell();
488 if (pDocShell != nullptr)
489 m_pElementTree = pDocShell->GetMlElementTree();
490 else
492 m_bSuccess = false;
493 return SVSTREAM_INVALID_PARAMETER;
497 // Start document and encrypt if necessary
498 GetDocHandler()->startDocument();
499 addChaffWhenEncryptedStorage();
501 // make use of a default namespace
502 // Math doesn't need namespaces from xmloff, since it now uses default namespaces
503 // Because that is common with current MathML usage in the web -> ResetNamespaceMap();
504 GetNamespaceMap_().Add(OUString(u""), GetXMLToken(XML_N_MATH), XML_NAMESPACE_MATH);
506 // Add xmlns line
507 if (m_bUseExportTag)
509 GetAttrList().AddAttribute(GetNamespaceMap().GetAttrNameByKey(XML_NAMESPACE_MATH),
510 GetNamespaceMap().GetNameByKey(XML_NAMESPACE_MATH));
513 // Export and close document
514 ExportContent_();
515 GetDocHandler()->endDocument();
517 return ERRCODE_NONE;
520 void SmMLExport::GetViewSettings(Sequence<PropertyValue>& aProps)
522 // Get the document shell
523 SmDocShell* pDocShell = getSmDocShell();
524 if (pDocShell == nullptr)
526 SAL_WARN("starmath", "Missing document shell so no view settings");
527 return;
530 // Allocate enough memory
531 aProps.realloc(4);
532 PropertyValue* pValue = aProps.getArray();
534 // The view settings are the formula display settings
535 tools::Rectangle aRect(pDocShell->GetVisArea());
537 pValue[0].Name = "ViewAreaTop";
538 pValue[0].Value <<= aRect.Top();
540 pValue[1].Name = "ViewAreaLeft";
541 pValue[1].Value <<= aRect.Left();
543 pValue[2].Name = "ViewAreaWidth";
544 pValue[2].Value <<= aRect.GetWidth();
546 pValue[3].Name = "ViewAreaHeight";
547 pValue[3].Value <<= aRect.GetHeight();
550 void SmMLExport::GetConfigurationSettings(Sequence<PropertyValue>& rProps)
552 // Get model property set (settings)
553 Reference<XPropertySet> xProps(GetModel(), UNO_QUERY);
554 if (!xProps.is())
556 SAL_WARN("starmath", "Missing model properties so no configuration settings");
557 return;
560 // Get model property set info (settings values)
561 Reference<XPropertySetInfo> xPropertySetInfo = xProps->getPropertySetInfo();
562 if (!xPropertySetInfo.is())
564 SAL_WARN("starmath", "Missing model properties info so no configuration settings");
565 return;
568 // Allocate to store the properties
569 Sequence<Property> aProps = xPropertySetInfo->getProperties();
570 const sal_Int32 nCount = aProps.getLength();
571 rProps.realloc(nCount);
572 auto pProps = rProps.getArray();
574 // Copy properties
575 // This needs further revision
576 // Based in code mathmlexport.cxx::GetConfigurationSettings
577 for (sal_Int32 i = 0; i < nCount; ++i)
579 if (aProps[i].Name != "Formula" && aProps[i].Name != "BasicLibraries"
580 && aProps[i].Name != "DialogLibraries" && aProps[i].Name != "RuntimeUID")
582 pProps[i].Name = aProps[i].Name;
583 pProps[i].Value = xProps->getPropertyValue(aProps[i].Name);
588 SmMLExport::SmMLExport(const css::uno::Reference<css::uno::XComponentContext>& rContext,
589 OUString const& implementationName, SvXMLExportFlags nExportFlags)
590 : SvXMLExport(rContext, implementationName, util::MeasureUnit::INCH, XML_MATH, nExportFlags)
591 , m_pElementTree(nullptr)
592 , m_bSuccess(true)
593 , m_bUseExportTag(true)
597 // SmMLExport
598 /*************************************************************************************************/
600 void SmMLExport::declareMlError()
602 SAL_WARN("starmath", "Invalid use of mathml.");
603 m_bSuccess = false;
606 void SmMLExport::exportMlAttributeLength(xmloff::token::XMLTokenEnum pAttribute,
607 const SmLengthValue& aLengthValue)
609 if (!aLengthValue.m_aOriginalText->isEmpty())
611 addAttribute(pAttribute, *aLengthValue.m_aOriginalText);
613 else
615 OUStringBuffer aSizeBuffer(64);
616 aSizeBuffer.append(aLengthValue.m_aLengthValue);
617 switch (aLengthValue.m_aLengthUnit)
619 case SmLengthUnit::MlEm:
620 aSizeBuffer.append(u"em");
621 break;
622 case SmLengthUnit::MlEx:
623 aSizeBuffer.append(u"ex");
624 break;
625 case SmLengthUnit::MlPx:
626 aSizeBuffer.append(u"px");
627 break;
628 case SmLengthUnit::MlIn:
629 aSizeBuffer.append(u"in");
630 break;
631 case SmLengthUnit::MlCm:
632 aSizeBuffer.append(u"cm");
633 break;
634 case SmLengthUnit::MlMm:
635 aSizeBuffer.append(u"mm");
636 break;
637 case SmLengthUnit::MlPt:
638 aSizeBuffer.append(u"pt");
639 break;
640 case SmLengthUnit::MlPc:
641 aSizeBuffer.append(u"pc");
642 break;
643 case SmLengthUnit::MlP:
644 aSizeBuffer.append(u"%");
645 break;
646 case SmLengthUnit::MlM:
647 break;
648 default:
649 declareMlError();
650 break;
652 addAttribute(pAttribute, aSizeBuffer.makeStringAndClear());
656 void SmMLExport::exportMlAttributes(const SmMlElement* pMlElement)
658 size_t nAttributeCount = pMlElement->getAttributeCount();
659 for (size_t i = 0; i < nAttributeCount; ++i)
661 SmMlAttribute aAttribute = pMlElement->getAttribute(i);
662 if (!aAttribute.isSet())
663 continue;
665 switch (aAttribute.getMlAttributeValueType())
667 case SmMlAttributeValueType::MlAccent:
669 auto aAttributeValue = aAttribute.getMlAccent();
670 switch (aAttributeValue->m_aAccent)
672 case SmMlAttributeValueAccent::MlFalse:
673 addAttribute(XML_ACCENT, XML_FALSE);
674 break;
675 case SmMlAttributeValueAccent::MlTrue:
676 addAttribute(XML_ACCENT, XML_TRUE);
677 break;
678 default:
679 declareMlError();
680 break;
682 break;
684 case SmMlAttributeValueType::MlDir:
686 auto aAttributeValue = aAttribute.getMlDir();
687 switch (aAttributeValue->m_aDir)
689 case SmMlAttributeValueDir::MlLtr:
690 addAttribute(XML_DIR, XML_LTR);
691 break;
692 case SmMlAttributeValueDir::MlRtl:
693 addAttribute(XML_DIR, XML_RTL);
694 break;
695 default:
696 declareMlError();
697 break;
699 break;
701 case SmMlAttributeValueType::MlDisplaystyle:
703 auto aAttributeValue = aAttribute.getMlDisplaystyle();
704 switch (aAttributeValue->m_aDisplaystyle)
706 case SmMlAttributeValueDisplaystyle::MlTrue:
707 addAttribute(XML_DISPLAYSTYLE, XML_FALSE);
708 break;
709 case SmMlAttributeValueDisplaystyle::MlFalse:
710 addAttribute(XML_DISPLAYSTYLE, XML_TRUE);
711 break;
712 default:
713 declareMlError();
714 break;
716 break;
718 case SmMlAttributeValueType::MlFence:
720 auto aAttributeValue = aAttribute.getMlFence();
721 switch (aAttributeValue->m_aFence)
723 case SmMlAttributeValueFence::MlTrue:
724 addAttribute(XML_FENCE, XML_FALSE);
725 break;
726 case SmMlAttributeValueFence::MlFalse:
727 addAttribute(XML_FENCE, XML_TRUE);
728 break;
729 default:
730 declareMlError();
731 break;
733 break;
735 case SmMlAttributeValueType::MlHref:
737 auto aAttributeValue = aAttribute.getMlHref();
738 switch (aAttributeValue->m_aHref)
740 case SmMlAttributeValueHref::NMlEmpty:
741 break;
742 case SmMlAttributeValueHref::NMlValid:
743 addAttribute(XML_HREF, *aAttributeValue->m_aLnk);
744 break;
745 default:
746 declareMlError();
747 break;
749 break;
751 case SmMlAttributeValueType::MlLspace:
753 auto aSizeData = aAttribute.getMlLspace();
754 auto aLengthData = aSizeData->m_aLengthValue;
755 exportMlAttributeLength(XML_LSPACE, aLengthData);
756 break;
758 case SmMlAttributeValueType::MlMathbackground:
760 auto aAttributeValue = aAttribute.getMlMathbackground();
761 switch (aAttributeValue->m_aMathbackground)
763 case SmMlAttributeValueMathbackground::MlTransparent:
764 addAttribute(XML_MATHBACKGROUND, "transparent");
765 break;
766 case SmMlAttributeValueMathbackground::MlRgb:
768 const OUString& rTextColor = starmathdatabase::Identify_Color_MATHML(
769 sal_uInt32(aAttributeValue->m_aCol))
770 .aIdent;
771 addAttribute(XML_MATHBACKGROUND, rTextColor);
772 break;
774 default:
775 declareMlError();
776 break;
778 break;
780 case SmMlAttributeValueType::MlMathcolor:
782 auto aAttributeValue = aAttribute.getMlMathcolor();
783 switch (aAttributeValue->m_aMathcolor)
785 case SmMlAttributeValueMathcolor::MlDefault:
786 break;
787 case SmMlAttributeValueMathcolor::MlRgb:
789 const OUString& rTextColor = starmathdatabase::Identify_Color_MATHML(
790 sal_uInt32(aAttributeValue->m_aCol))
791 .aIdent;
792 addAttribute(XML_MATHCOLOR, rTextColor);
793 break;
795 default:
796 declareMlError();
797 break;
799 break;
801 case SmMlAttributeValueType::MlMathsize:
803 auto aSizeData = aAttribute.getMlMathsize();
804 auto aLengthData = aSizeData->m_aLengthValue;
805 exportMlAttributeLength(XML_MATHSIZE, aLengthData);
806 break;
808 case SmMlAttributeValueType::MlMathvariant:
810 auto aAttributeValue = aAttribute.getMlMathvariant();
811 switch (aAttributeValue->m_aMathvariant)
813 case SmMlAttributeValueMathvariant::normal:
814 addAttribute(XML_MATHVARIANT, "normal");
815 break;
816 case SmMlAttributeValueMathvariant::bold:
817 addAttribute(XML_MATHVARIANT, "bold");
818 break;
819 case SmMlAttributeValueMathvariant::italic:
820 addAttribute(XML_MATHVARIANT, "italic");
821 break;
822 case SmMlAttributeValueMathvariant::double_struck:
823 addAttribute(XML_MATHVARIANT, "double-struck");
824 break;
825 case SmMlAttributeValueMathvariant::script:
826 addAttribute(XML_MATHVARIANT, "script");
827 break;
828 case SmMlAttributeValueMathvariant::fraktur:
829 addAttribute(XML_MATHVARIANT, "fraktur");
830 break;
831 case SmMlAttributeValueMathvariant::sans_serif:
832 addAttribute(XML_MATHVARIANT, "sans-serif");
833 break;
834 case SmMlAttributeValueMathvariant::monospace:
835 addAttribute(XML_MATHVARIANT, "monospace");
836 break;
837 case SmMlAttributeValueMathvariant::bold_italic:
838 addAttribute(XML_MATHVARIANT, "bold-italic");
839 break;
840 case SmMlAttributeValueMathvariant::bold_fraktur:
841 addAttribute(XML_MATHVARIANT, "bold-fracktur");
842 break;
843 case SmMlAttributeValueMathvariant::bold_script:
844 addAttribute(XML_MATHVARIANT, "bold-script");
845 break;
846 case SmMlAttributeValueMathvariant::bold_sans_serif:
847 addAttribute(XML_MATHVARIANT, "bold-sans-serif");
848 break;
849 case SmMlAttributeValueMathvariant::sans_serif_italic:
850 addAttribute(XML_MATHVARIANT, "sans-serif-italic");
851 break;
852 case SmMlAttributeValueMathvariant::sans_serif_bold_italic:
853 addAttribute(XML_MATHVARIANT, "sans-serif-bold-italic");
854 break;
855 case SmMlAttributeValueMathvariant::initial:
856 addAttribute(XML_MATHVARIANT, "initial");
857 break;
858 case SmMlAttributeValueMathvariant::tailed:
859 addAttribute(XML_MATHVARIANT, "tailed");
860 break;
861 case SmMlAttributeValueMathvariant::looped:
862 addAttribute(XML_MATHVARIANT, "looped");
863 break;
864 case SmMlAttributeValueMathvariant::stretched:
865 addAttribute(XML_MATHVARIANT, "stretched");
866 break;
867 default:
868 declareMlError();
869 break;
871 break;
873 case SmMlAttributeValueType::MlMaxsize:
875 auto aSizeData = aAttribute.getMlMaxsize();
876 auto aLengthData = aSizeData->m_aLengthValue;
877 switch (aSizeData->m_aMaxsize)
879 case SmMlAttributeValueMaxsize::MlInfinity:
881 addAttribute(XML_MAXSIZE, XML_INFINITY);
882 break;
884 case SmMlAttributeValueMaxsize::MlFinite:
886 exportMlAttributeLength(XML_MAXSIZE, aLengthData);
887 break;
890 break;
892 case SmMlAttributeValueType::MlMinsize:
894 auto aSizeData = aAttribute.getMlMinsize();
895 auto aLengthData = aSizeData->m_aLengthValue;
896 exportMlAttributeLength(XML_MINSIZE, aLengthData);
897 break;
899 case SmMlAttributeValueType::MlMovablelimits:
901 auto aAttributeValue = aAttribute.getMlMovablelimits();
902 switch (aAttributeValue->m_aMovablelimits)
904 case SmMlAttributeValueMovablelimits::MlFalse:
905 addAttribute(XML_MOVABLELIMITS, XML_FALSE);
906 break;
907 case SmMlAttributeValueMovablelimits::MlTrue:
908 addAttribute(XML_MOVABLELIMITS, XML_TRUE);
909 break;
910 default:
911 declareMlError();
912 break;
914 break;
916 case SmMlAttributeValueType::MlRspace:
918 auto aSizeData = aAttribute.getMlRspace();
919 auto aLengthData = aSizeData->m_aLengthValue;
920 exportMlAttributeLength(XML_RSPACE, aLengthData);
921 break;
923 case SmMlAttributeValueType::MlSeparator:
925 auto aAttributeValue = aAttribute.getMlSeparator();
926 switch (aAttributeValue->m_aSeparator)
928 case SmMlAttributeValueSeparator::MlFalse:
929 addAttribute(XML_SEPARATOR, XML_FALSE);
930 break;
931 case SmMlAttributeValueSeparator::MlTrue:
932 addAttribute(XML_SEPARATOR, XML_TRUE);
933 break;
934 default:
935 declareMlError();
936 break;
938 break;
940 case SmMlAttributeValueType::MlStretchy:
942 auto aAttributeValue = aAttribute.getMlStretchy();
943 switch (aAttributeValue->m_aStretchy)
945 case SmMlAttributeValueStretchy::MlFalse:
946 addAttribute(XML_STRETCHY, XML_FALSE);
947 break;
948 case SmMlAttributeValueStretchy::MlTrue:
949 addAttribute(XML_STRETCHY, XML_TRUE);
950 break;
951 default:
952 declareMlError();
953 break;
955 break;
957 case SmMlAttributeValueType::MlSymmetric:
959 auto aAttributeValue = aAttribute.getMlSymmetric();
960 switch (aAttributeValue->m_aSymmetric)
962 case SmMlAttributeValueSymmetric::MlFalse:
963 addAttribute(XML_SYMMETRIC, XML_FALSE);
964 break;
965 case SmMlAttributeValueSymmetric::MlTrue:
966 addAttribute(XML_SYMMETRIC, XML_TRUE);
967 break;
968 default:
969 declareMlError();
970 break;
972 break;
974 default:
975 declareMlError();
976 break;
981 SvXMLElementExport* SmMLExport::exportMlElement(const SmMlElement* pMlElement)
983 SvXMLElementExport* pElementExport;
984 switch (pMlElement->getMlElementType())
986 case SmMlElementType::MlMath:
987 pElementExport = createElementExport(XML_MATH);
988 break;
989 case SmMlElementType::MlMi:
990 pElementExport = createElementExport(XML_MI);
991 break;
992 case SmMlElementType::MlMerror:
993 pElementExport = createElementExport(XML_MERROR);
994 break;
995 case SmMlElementType::MlMn:
996 pElementExport = createElementExport(XML_MN);
997 break;
998 case SmMlElementType::MlMo:
999 pElementExport = createElementExport(XML_MO);
1000 break;
1001 case SmMlElementType::MlMrow:
1002 pElementExport = createElementExport(XML_MROW);
1003 break;
1004 case SmMlElementType::MlMtext:
1005 pElementExport = createElementExport(XML_MTEXT);
1006 break;
1007 case SmMlElementType::MlMstyle:
1008 pElementExport = createElementExport(XML_MSTYLE);
1009 break;
1010 default:
1011 pElementExport = nullptr;
1013 const OUString& aElementText = pMlElement->getText();
1014 exportMlAttributes(pMlElement);
1015 if (aElementText.isEmpty())
1016 GetDocHandler()->characters(aElementText);
1017 return pElementExport;
1020 namespace
1022 struct exportMlElementTreeExecData
1024 private:
1025 SmMLExport* m_pSmMLExport;
1026 std::vector<SvXMLElementExport*> m_aSvXMLElementExportList;
1027 size_t m_nDepth;
1029 public:
1030 inline exportMlElementTreeExecData(SmMLExport* pSmMLExport)
1031 : m_pSmMLExport(pSmMLExport)
1032 , m_aSvXMLElementExportList(1024)
1033 , m_nDepth(0)
1037 inline void deleteDepthData()
1039 delete m_aSvXMLElementExportList[m_nDepth];
1040 --m_nDepth;
1043 inline void setDepthData(SvXMLElementExport* aSvXMLElementExportList)
1045 if (m_nDepth == m_aSvXMLElementExportList.size())
1046 m_aSvXMLElementExportList.resize(m_aSvXMLElementExportList.size() + 1024);
1047 m_aSvXMLElementExportList[m_nDepth] = aSvXMLElementExportList;
1050 inline void incrementDepth() { ++m_nDepth; }
1052 inline SmMLExport* getSmMLExport() { return m_pSmMLExport; };
1055 } // end unnamed namespace
1057 static inline void exportMlElementTreeExec(SmMlElement* aSmMlElement, void* aData)
1059 // Prepare data
1060 exportMlElementTreeExecData* pData = static_cast<exportMlElementTreeExecData*>(aData);
1061 pData->setDepthData(pData->getSmMLExport()->exportMlElement(aSmMlElement));
1063 // Prepare for following
1064 // If it has sub elements, then it will be the next
1065 if (aSmMlElement->getSubElementsCount() != 0)
1066 pData->incrementDepth();
1067 else // Otherwise remounts up to where it should be
1069 while (aSmMlElement->getParentElement() != nullptr)
1071 // get parent
1072 SmMlElement* pParent = aSmMlElement->getParentElement();
1073 pData->deleteDepthData();
1074 // was this the last branch ?
1075 if (aSmMlElement->getSubElementId() + 1 != pParent->getSubElementsCount()) // yes -> up
1076 break; // no -> stop going up
1077 // Prepare for next round
1078 aSmMlElement = pParent;
1083 void SmMLExport::exportMlElementTree()
1085 exportMlElementTreeExecData* aData = new exportMlElementTreeExecData(this);
1086 mathml::SmMlIteratorTopToBottom(m_pElementTree, exportMlElementTreeExec, aData);
1087 delete aData;
1090 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */