1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
21 Warning: The SvXMLElementExport helper class creates the beginning and
22 closing tags of xml elements in its constructor and destructor, so theres
23 hidden stuff going on, on occasion the ordering of these classes declarations
27 #include <com/sun/star/xml/sax/XErrorHandler.hpp>
28 #include <com/sun/star/xml/sax/XEntityResolver.hpp>
29 #include <com/sun/star/xml/sax/InputSource.hpp>
30 #include <com/sun/star/xml/sax/XDTDHandler.hpp>
31 #include <com/sun/star/xml/sax/XParser.hpp>
32 #include <com/sun/star/xml/sax/Writer.hpp>
33 #include <com/sun/star/io/XActiveDataSource.hpp>
34 #include <com/sun/star/io/XActiveDataControl.hpp>
35 #include <com/sun/star/document/XDocumentProperties.hpp>
36 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
37 #include <com/sun/star/packages/zip/ZipIOException.hpp>
38 #include <com/sun/star/task/XStatusIndicatorFactory.hpp>
39 #include <com/sun/star/beans/PropertyAttribute.hpp>
40 #include <com/sun/star/container/XNameAccess.hpp>
41 #include <com/sun/star/embed/ElementModes.hpp>
42 #include <com/sun/star/util/MeasureUnit.hpp>
43 #include <com/sun/star/uno/Any.h>
45 #include <rtl/math.hxx>
46 #include <sfx2/frame.hxx>
47 #include <sfx2/docfile.hxx>
48 #include <osl/diagnose.h>
49 #include <svtools/sfxecode.hxx>
50 #include <unotools/saveopt.hxx>
51 #include <svl/stritem.hxx>
52 #include <svl/itemprop.hxx>
53 #include <comphelper/processfactory.hxx>
54 #include <unotools/streamwrap.hxx>
55 #include <sax/tools/converter.hxx>
56 #include <xmloff/xmlnmspe.hxx>
57 #include <xmloff/xmltoken.hxx>
58 #include <xmloff/nmspmap.hxx>
59 #include <xmloff/attrlist.hxx>
60 #include <xmloff/xmlmetai.hxx>
61 #include <osl/mutex.hxx>
62 #include <comphelper/genericpropertyset.hxx>
63 #include <comphelper/servicehelper.hxx>
68 #include "mathmlexport.hxx"
69 #include "register.hxx"
70 #include <starmath.hrc>
71 #include <unomodel.hxx>
72 #include <document.hxx>
73 #include <utility.hxx>
76 using namespace ::com::sun::star::beans
;
77 using namespace ::com::sun::star::container
;
78 using namespace ::com::sun::star::document
;
79 using namespace ::com::sun::star::lang
;
80 using namespace ::com::sun::star::uno
;
81 using namespace ::com::sun::star
;
82 using namespace ::xmloff::token
;
84 sal_Unicode
ConvertMathToMathML( sal_Unicode cChar
)
86 sal_Unicode cRes
= cChar
;
87 if (IsInPrivateUseArea( cChar
))
89 SAL_WARN("starmath", "Error: private use area characters should no longer be in use!" );
90 cRes
= (sal_Unicode
) '@'; // just some character that should easily be notice as odd in the context
95 bool SmXMLExportWrapper::Export(SfxMedium
&rMedium
)
98 uno::Reference
<uno::XComponentContext
> xContext(comphelper::getProcessComponentContext());
101 uno::Reference
< lang::XComponent
> xModelComp(xModel
, uno::UNO_QUERY
);
103 bool bEmbedded
= false;
104 uno::Reference
<lang::XUnoTunnel
> xTunnel
;
105 xTunnel
= uno::Reference
<lang::XUnoTunnel
> (xModel
,uno::UNO_QUERY
);
106 SmModel
*pModel
= reinterpret_cast<SmModel
*>
107 (xTunnel
->getSomething(SmModel::getUnoTunnelId()));
109 SmDocShell
*pDocShell
= pModel
?
110 static_cast<SmDocShell
*>(pModel
->GetObjectShell()) : 0;
112 SfxObjectCreateMode::EMBEDDED
== pDocShell
->GetCreateMode() )
115 uno::Reference
<task::XStatusIndicator
> xStatusIndicator
;
118 if (pDocShell
/*&& pDocShell->GetMedium()*/)
120 OSL_ENSURE( pDocShell
->GetMedium() == &rMedium
,
121 "different SfxMedium found" );
123 SfxItemSet
* pSet
= rMedium
.GetItemSet();
126 const SfxUnoAnyItem
* pItem
= static_cast<const SfxUnoAnyItem
*>(
127 pSet
->GetItem(SID_PROGRESS_STATUSBAR_CONTROL
) );
129 pItem
->GetValue() >>= xStatusIndicator
;
133 // set progress range and start status indicator
134 if (xStatusIndicator
.is())
136 sal_Int32 nProgressRange
= bFlat
? 1 : 3;
137 xStatusIndicator
->start(SM_RESSTR(STR_STATSTR_WRITING
),
143 // create XPropertySet with three properties for status indicator
144 comphelper::PropertyMapEntry aInfoMap
[] =
146 { OUString("UsePrettyPrinting"), 0,
147 cppu::UnoType
<bool>::get(),
148 beans::PropertyAttribute::MAYBEVOID
, 0},
149 { OUString("BaseURI"), 0,
150 ::cppu::UnoType
<OUString
>::get(),
151 beans::PropertyAttribute::MAYBEVOID
, 0 },
152 { OUString("StreamRelPath"), 0,
153 ::cppu::UnoType
<OUString
>::get(),
154 beans::PropertyAttribute::MAYBEVOID
, 0 },
155 { OUString("StreamName"), 0,
156 ::cppu::UnoType
<OUString
>::get(),
157 beans::PropertyAttribute::MAYBEVOID
, 0 },
158 { OUString(), 0, css::uno::Type(), 0, 0 }
160 uno::Reference
< beans::XPropertySet
> xInfoSet(
161 comphelper::GenericPropertySet_CreateInstance(
162 new comphelper::PropertySetInfo( aInfoMap
) ) );
164 SvtSaveOptions aSaveOpt
;
165 OUString
sUsePrettyPrinting("UsePrettyPrinting");
166 sal_Bool
bUsePrettyPrinting( bFlat
|| aSaveOpt
.IsPrettyPrinting() );
168 aAny
.setValue( &bUsePrettyPrinting
, cppu::UnoType
<bool>::get() );
169 xInfoSet
->setPropertyValue( sUsePrettyPrinting
, aAny
);
172 OUString
sPropName( "BaseURI" );
173 xInfoSet
->setPropertyValue( sPropName
, makeAny( rMedium
.GetBaseURL( true ) ) );
176 if (xStatusIndicator
.is())
177 xStatusIndicator
->setValue(nSteps
++);
178 if (!bFlat
) //Storage (Package) of Stream
180 uno::Reference
< embed::XStorage
> xStg
= rMedium
.GetOutputStorage();
181 bool bOASIS
= ( SotStorage::GetVersion( xStg
) > SOFFICE_FILEFORMAT_60
);
183 // TODO/LATER: handle the case of embedded links gracefully
184 if ( bEmbedded
) //&& !pStg->IsRoot() )
187 if ( rMedium
.GetItemSet() )
189 const SfxStringItem
* pDocHierarchItem
= static_cast<const SfxStringItem
*>(
190 rMedium
.GetItemSet()->GetItem(SID_DOC_HIERARCHICALNAME
) );
191 if ( pDocHierarchItem
)
192 aName
= pDocHierarchItem
->GetValue();
195 if ( !aName
.isEmpty() )
197 sPropName
= "StreamRelPath";
198 xInfoSet
->setPropertyValue( sPropName
, makeAny( aName
) );
204 if (xStatusIndicator
.is())
205 xStatusIndicator
->setValue(nSteps
++);
207 bRet
= WriteThroughComponent(
208 xStg
, xModelComp
, "meta.xml", xContext
, xInfoSet
,
209 (bOASIS
? "com.sun.star.comp.Math.XMLOasisMetaExporter"
210 : "com.sun.star.comp.Math.XMLMetaExporter"));
214 if (xStatusIndicator
.is())
215 xStatusIndicator
->setValue(nSteps
++);
217 bRet
= WriteThroughComponent(
218 xStg
, xModelComp
, "content.xml", xContext
, xInfoSet
,
219 "com.sun.star.comp.Math.XMLContentExporter");
224 if (xStatusIndicator
.is())
225 xStatusIndicator
->setValue(nSteps
++);
227 bRet
= WriteThroughComponent(
228 xStg
, xModelComp
, "settings.xml", xContext
, xInfoSet
,
229 (bOASIS
? "com.sun.star.comp.Math.XMLOasisSettingsExporter"
230 : "com.sun.star.comp.Math.XMLSettingsExporter") );
235 SvStream
*pStream
= rMedium
.GetOutStream();
236 uno::Reference
<io::XOutputStream
> xOut(
237 new utl::OOutputStreamWrapper(*pStream
) );
239 if (xStatusIndicator
.is())
240 xStatusIndicator
->setValue(nSteps
++);
242 bRet
= WriteThroughComponent(
243 xOut
, xModelComp
, xContext
, xInfoSet
,
244 "com.sun.star.comp.Math.XMLContentExporter");
247 if (xStatusIndicator
.is())
248 xStatusIndicator
->end();
254 /// export through an XML exporter component (output stream version)
255 bool SmXMLExportWrapper::WriteThroughComponent(
256 Reference
<io::XOutputStream
> xOutputStream
,
257 Reference
<XComponent
> xComponent
,
258 Reference
<uno::XComponentContext
> & rxContext
,
259 Reference
<beans::XPropertySet
> & rPropSet
,
260 const sal_Char
* pComponentName
)
262 OSL_ENSURE(xOutputStream
.is(), "I really need an output stream!");
263 OSL_ENSURE(xComponent
.is(), "Need component!");
264 OSL_ENSURE(NULL
!= pComponentName
, "Need component name!");
267 Reference
< xml::sax::XWriter
> xSaxWriter
= xml::sax::Writer::create(rxContext
);
269 // connect XML writer to output stream
270 xSaxWriter
->setOutputStream( xOutputStream
);
272 // prepare arguments (prepend doc handler to given arguments)
273 Reference
<xml::sax::XDocumentHandler
> xDocHandler( xSaxWriter
,UNO_QUERY
);
275 Sequence
<Any
> aArgs( 2 );
276 aArgs
[0] <<= xDocHandler
;
277 aArgs
[1] <<= rPropSet
;
279 // get filter component
280 Reference
< document::XExporter
> xExporter(
281 rxContext
->getServiceManager()->createInstanceWithArgumentsAndContext(OUString::createFromAscii(pComponentName
), aArgs
, rxContext
),
283 OSL_ENSURE( xExporter
.is(),
284 "can't instantiate export filter component" );
285 if ( !xExporter
.is() )
289 // connect model and filter
290 xExporter
->setSourceDocument( xComponent
);
293 Reference
< XFilter
> xFilter( xExporter
, UNO_QUERY
);
294 uno::Sequence
< PropertyValue
> aProps(0);
295 xFilter
->filter( aProps
);
297 uno::Reference
<lang::XUnoTunnel
> xFilterTunnel
;
298 xFilterTunnel
= uno::Reference
<lang::XUnoTunnel
>
299 ( xFilter
, uno::UNO_QUERY
);
300 SmXMLExport
*pFilter
= reinterpret_cast< SmXMLExport
* >(
301 sal::static_int_cast
< sal_uIntPtr
>(
302 xFilterTunnel
->getSomething( SmXMLExport::getUnoTunnelId() )));
303 return pFilter
== nullptr || pFilter
->GetSuccess();
307 /// export through an XML exporter component (storage version)
308 bool SmXMLExportWrapper::WriteThroughComponent(
309 const Reference
< embed::XStorage
>& xStorage
,
310 Reference
<XComponent
> xComponent
,
311 const sal_Char
* pStreamName
,
312 Reference
<uno::XComponentContext
> & rxContext
,
313 Reference
<beans::XPropertySet
> & rPropSet
,
314 const sal_Char
* pComponentName
317 OSL_ENSURE(xStorage
.is(), "Need storage!");
318 OSL_ENSURE(NULL
!= pStreamName
, "Need stream name!");
321 Reference
< io::XStream
> xStream
;
322 OUString sStreamName
= OUString::createFromAscii(pStreamName
);
325 xStream
= xStorage
->openStreamElement( sStreamName
,
326 embed::ElementModes::READWRITE
| embed::ElementModes::TRUNCATE
);
328 catch ( uno::Exception
& rEx
)
330 SAL_WARN("starmath", "Can't create output stream in package: " << rEx
.Message
);
334 OUString
aPropName( "MediaType" );
335 OUString
aMime( "text/xml" );
339 uno::Reference
< beans::XPropertySet
> xSet( xStream
, uno::UNO_QUERY
);
340 xSet
->setPropertyValue( aPropName
, aAny
);
342 // all streams must be encrypted in encrypted document
343 OUString
aTmpPropName( "UseCommonStoragePasswordEncryption" );
344 sal_Bool bTrue
= sal_True
;
345 aAny
.setValue( &bTrue
, cppu::UnoType
<bool>::get() );
346 xSet
->setPropertyValue( aTmpPropName
, aAny
);
351 OUString
sPropName( "StreamName" );
352 rPropSet
->setPropertyValue( sPropName
, makeAny( sStreamName
) );
356 bool bRet
= WriteThroughComponent( xStream
->getOutputStream(), xComponent
, rxContext
,
357 rPropSet
, pComponentName
);
362 SmXMLExport::SmXMLExport(
363 const ::com::sun::star::uno::Reference
< ::com::sun::star::uno::XComponentContext
>& rContext
,
364 OUString
const & implementationName
, SvXMLExportFlags nExportFlags
)
365 : SvXMLExport(util::MeasureUnit::INCH
, rContext
, implementationName
, XML_MATH
,
372 sal_Int64 SAL_CALL
SmXMLExport::getSomething(
373 const uno::Sequence
< sal_Int8
>& rId
)
374 throw(uno::RuntimeException
, std::exception
)
376 if ( rId
.getLength() == 16 &&
377 0 == memcmp( getUnoTunnelId().getConstArray(),
378 rId
.getConstArray(), 16 ) )
379 return sal::static_int_cast
< sal_Int64
>(reinterpret_cast< sal_uIntPtr
>(this));
381 return SvXMLExport::getSomething( rId
);
386 class theSmXMLExportUnoTunnelId
: public rtl::Static
< UnoTunnelIdInit
, theSmXMLExportUnoTunnelId
> {};
389 const uno::Sequence
< sal_Int8
> & SmXMLExport::getUnoTunnelId() throw()
391 return theSmXMLExportUnoTunnelId::get().getSeq();
394 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
* SAL_CALL
395 Math_XMLExporter_get_implementation(css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const &)
397 return cppu::acquire(new SmXMLExport(context
, "com.sun.star.comp.Math.XMLExporter", SvXMLExportFlags::OASIS
|SvXMLExportFlags::ALL
));
400 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
* SAL_CALL
401 Math_XMLMetaExporter_get_implementation(css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const &)
403 return cppu::acquire(new SmXMLExport(context
, "com.sun.star.comp.Math.XMLMetaExporter", SvXMLExportFlags::META
));
406 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
* SAL_CALL
407 Math_XMLOasisMetaExporter_get_implementation(css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const &)
409 return cppu::acquire(new SmXMLExport(context
, "com.sun.star.comp.Math.XMLOasisMetaExporter", SvXMLExportFlags::OASIS
|SvXMLExportFlags::META
));
412 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
* SAL_CALL
413 Math_XMLSettingsExporter_get_implementation(css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const &)
415 return cppu::acquire(new SmXMLExport(context
, "com.sun.star.comp.Math.XMLSettingsExporter", SvXMLExportFlags::SETTINGS
));
418 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
* SAL_CALL
419 Math_XMLOasisSettingsExporter_get_implementation(css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const &)
421 return cppu::acquire(new SmXMLExport(context
, "com.sun.star.comp.Math.XMLOasisSettingsExporter", SvXMLExportFlags::OASIS
|SvXMLExportFlags::SETTINGS
));
424 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
* SAL_CALL
425 Math_XMLContentExporter_get_implementation(css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const &)
427 return cppu::acquire(new SmXMLExport(context
, "com.sun.star.comp.Math.XMLContentExporter", SvXMLExportFlags::OASIS
|SvXMLExportFlags::CONTENT
));
430 sal_uInt32
SmXMLExport::exportDoc(enum XMLTokenEnum eClass
)
432 if ( !(getExportFlags() & SvXMLExportFlags::CONTENT
) )
434 SvXMLExport::exportDoc( eClass
);
438 uno::Reference
<frame::XModel
> xModel
= GetModel();
439 uno::Reference
<lang::XUnoTunnel
> xTunnel
;
440 xTunnel
= uno::Reference
<lang::XUnoTunnel
> (xModel
,uno::UNO_QUERY
);
441 SmModel
*pModel
= reinterpret_cast<SmModel
*>
442 (xTunnel
->getSomething(SmModel::getUnoTunnelId()));
446 SmDocShell
*pDocShell
=
447 static_cast<SmDocShell
*>(pModel
->GetObjectShell());
448 pTree
= pDocShell
->GetFormulaTree();
449 aText
= pDocShell
->GetText();
452 GetDocHandler()->startDocument();
454 addChaffWhenEncryptedStorage();
457 SvXMLAttributeList
&rList
= GetAttrList();
459 // make use of a default namespace
460 ResetNamespaceMap(); // Math doesn't need namespaces from xmloff, since it now uses default namespaces (because that is common with current MathML usage in the web)
461 _GetNamespaceMap().Add( OUString(), GetXMLToken(XML_N_MATH
), XML_NAMESPACE_MATH
);
463 rList
.AddAttribute(GetNamespaceMap().GetAttrNameByKey(XML_NAMESPACE_MATH_IDX
),
464 GetNamespaceMap().GetNameByKey( XML_NAMESPACE_MATH_IDX
));
466 //I think we need something like ImplExportEntities();
468 GetDocHandler()->endDocument();
475 void SmXMLExport::_ExportContent()
477 uno::Reference
<frame::XModel
> xModel
= GetModel();
478 uno::Reference
<lang::XUnoTunnel
> xTunnel
;
479 xTunnel
= uno::Reference
<lang::XUnoTunnel
> (xModel
,uno::UNO_QUERY
);
480 SmModel
*pModel
= reinterpret_cast<SmModel
*>
481 (xTunnel
->getSomething(SmModel::getUnoTunnelId()));
482 SmDocShell
*pDocShell
= pModel
?
483 static_cast<SmDocShell
*>(pModel
->GetObjectShell()) : 0;
484 OSL_ENSURE( pDocShell
, "doc shell missing" );
486 if (pDocShell
&& !pDocShell
->GetFormat().IsTextmode())
488 // If the Math equation is not in text mode, we attach a display="block"
489 // attribute on the <math> root. We don't do anything if it is in
490 // text mode, the default display="inline" value will be used.
491 AddAttribute(XML_NAMESPACE_MATH
, XML_DISPLAY
, XML_BLOCK
);
493 SvXMLElementExport
aEquation(*this, XML_NAMESPACE_MATH
, XML_MATH
, true, true);
494 SvXMLElementExport
*pSemantics
=0;
496 if (!aText
.isEmpty())
498 pSemantics
= new SvXMLElementExport(*this, XML_NAMESPACE_MATH
,
499 XML_SEMANTICS
, true, true);
502 ExportNodes(pTree
, 0);
504 if (!aText
.isEmpty())
506 // Convert symbol names
509 SmParser
&rParser
= pDocShell
->GetParser();
510 bool bVal
= rParser
.IsExportSymbolNames();
511 rParser
.SetExportSymbolNames( true );
512 SmNode
*pTmpTree
= rParser
.Parse( aText
);
513 aText
= rParser
.GetText();
515 rParser
.SetExportSymbolNames( bVal
);
518 AddAttribute(XML_NAMESPACE_MATH
, XML_ENCODING
,
519 OUString("StarMath 5.0"));
520 SvXMLElementExport
aAnnotation(*this, XML_NAMESPACE_MATH
,
521 XML_ANNOTATION
, true, false);
522 GetDocHandler()->characters( aText
);
527 void SmXMLExport::GetViewSettings( Sequence
< PropertyValue
>& aProps
)
529 uno::Reference
<frame::XModel
> xModel
= GetModel();
533 uno::Reference
<lang::XUnoTunnel
> xTunnel
;
534 xTunnel
= uno::Reference
<lang::XUnoTunnel
> (xModel
,uno::UNO_QUERY
);
535 SmModel
*pModel
= reinterpret_cast<SmModel
*>
536 (xTunnel
->getSomething(SmModel::getUnoTunnelId()));
541 SmDocShell
*pDocShell
=
542 static_cast<SmDocShell
*>(pModel
->GetObjectShell());
547 PropertyValue
*pValue
= aProps
.getArray();
548 sal_Int32 nIndex
= 0;
550 Rectangle
aRect( pDocShell
->GetVisArea() );
552 pValue
[nIndex
].Name
= "ViewAreaTop";
553 pValue
[nIndex
++].Value
<<= aRect
.Top();
555 pValue
[nIndex
].Name
= "ViewAreaLeft";
556 pValue
[nIndex
++].Value
<<= aRect
.Left();
558 pValue
[nIndex
].Name
= "ViewAreaWidth";
559 pValue
[nIndex
++].Value
<<= aRect
.GetWidth();
561 pValue
[nIndex
].Name
= "ViewAreaHeight";
562 pValue
[nIndex
++].Value
<<= aRect
.GetHeight();
565 void SmXMLExport::GetConfigurationSettings( Sequence
< PropertyValue
> & rProps
)
567 Reference
< XPropertySet
> xProps ( GetModel(), UNO_QUERY
);
570 Reference
< XPropertySetInfo
> xPropertySetInfo
= xProps
->getPropertySetInfo();
571 if (xPropertySetInfo
.is())
573 Sequence
< Property
> aProps
= xPropertySetInfo
->getProperties();
574 sal_Int32
nCount(aProps
.getLength());
577 rProps
.realloc(nCount
);
578 PropertyValue
* pProps
= rProps
.getArray();
581 SmConfig
*pConfig
= SM_MOD()->GetConfig();
582 const bool bUsedSymbolsOnly
= pConfig
&& pConfig
->IsSaveOnlyUsedSymbols();
584 const OUString
sFormula ( "Formula" );
585 const OUString
sBasicLibraries ( "BasicLibraries" );
586 const OUString
sDialogLibraries ( "DialogLibraries" );
587 const OUString
sRuntimeUID ( "RuntimeUID" );
588 for (sal_Int32 i
= 0; i
< nCount
; i
++, pProps
++)
590 const OUString
&rPropName
= aProps
[i
].Name
;
591 if (rPropName
!= sFormula
&&
592 rPropName
!= sBasicLibraries
&&
593 rPropName
!= sDialogLibraries
&&
594 rPropName
!= sRuntimeUID
)
596 pProps
->Name
= rPropName
;
598 OUString
aActualName( rPropName
);
600 // handle 'save used symbols only'
601 if (bUsedSymbolsOnly
&& rPropName
== "Symbols" )
602 aActualName
= "UserDefinedSymbolsInUse";
604 pProps
->Value
= xProps
->getPropertyValue( aActualName
);
613 void SmXMLExport::ExportLine(const SmNode
*pNode
, int nLevel
)
615 ExportExpression(pNode
, nLevel
);
618 void SmXMLExport::ExportBinaryHorizontal(const SmNode
*pNode
, int nLevel
)
620 sal_uLong nGroup
= pNode
->GetToken().nGroup
;
622 SvXMLElementExport
* pRow
= new SvXMLElementExport(*this,
623 XML_NAMESPACE_MATH
, XML_MROW
, true, true);
625 // Unfold the binary tree structure as long as the nodes are SmBinHorNode
626 // with the same nGroup. This will reduce the number of nested <mrow>
627 // elements e.g. we only need three <mrow> levels to export
629 // "a*b*c*d+e*f*g*h+i*j*k*l = a*b*c*d+e*f*g*h+i*j*k*l =
630 // a*b*c*d+e*f*g*h+i*j*k*l = a*b*c*d+e*f*g*h+i*j*k*l"
632 // See https://www.libreoffice.org/bugzilla/show_bug.cgi?id=66081
633 ::std::stack
< const SmNode
* > s
;
637 const SmNode
*node
= s
.top();
639 if (node
->GetType() != NBINHOR
|| node
->GetToken().nGroup
!= nGroup
)
641 ExportNodes(node
, nLevel
+1);
644 const SmBinHorNode
* binNode
= static_cast<const SmBinHorNode
*>(node
);
645 s
.push(binNode
->RightOperand());
646 s
.push(binNode
->Symbol());
647 s
.push(binNode
->LeftOperand());
653 void SmXMLExport::ExportUnaryHorizontal(const SmNode
*pNode
, int nLevel
)
655 ExportExpression(pNode
, nLevel
);
658 void SmXMLExport::ExportExpression(const SmNode
*pNode
, int nLevel
,
659 bool bNoMrowContainer
/*=false*/)
661 SvXMLElementExport
*pRow
=0;
662 auto nSize
= pNode
->GetNumSubNodes();
664 // #i115443: nodes of type expression always need to be grouped with mrow statement
665 if (!bNoMrowContainer
&&
666 (nSize
> 1 || pNode
->GetType() == NEXPRESSION
))
667 pRow
= new SvXMLElementExport(*this, XML_NAMESPACE_MATH
, XML_MROW
, true, true);
669 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
670 if (const SmNode
*pTemp
= pNode
->GetSubNode(i
))
671 ExportNodes(pTemp
, nLevel
+1);
676 void SmXMLExport::ExportBinaryVertical(const SmNode
*pNode
, int nLevel
)
678 OSL_ENSURE(pNode
->GetNumSubNodes()==3,"Bad Fraction");
679 const SmNode
*pNum
= pNode
->GetSubNode(0);
680 const SmNode
*pDenom
= pNode
->GetSubNode(2);
681 if (pNum
->GetType() == NALIGN
&& pNum
->GetToken().eType
!= TALIGNC
)
683 // A left or right alignment is specified on the numerator:
684 // attach the corresponding numalign attribute.
685 AddAttribute(XML_NAMESPACE_MATH
, XML_NUMALIGN
,
686 pNum
->GetToken().eType
== TALIGNL
? XML_LEFT
: XML_RIGHT
);
688 if (pDenom
->GetType() == NALIGN
&& pDenom
->GetToken().eType
!= TALIGNC
)
690 // A left or right alignment is specified on the denominator:
691 // attach the corresponding denomalign attribute.
692 AddAttribute(XML_NAMESPACE_MATH
, XML_DENOMALIGN
,
693 pDenom
->GetToken().eType
== TALIGNL
? XML_LEFT
: XML_RIGHT
);
695 SvXMLElementExport
aFraction(*this, XML_NAMESPACE_MATH
, XML_MFRAC
, true, true);
696 ExportNodes(pNum
, nLevel
);
697 ExportNodes(pDenom
, nLevel
);
700 void SmXMLExport::ExportBinaryDiagonal(const SmNode
*pNode
, int nLevel
)
702 OSL_ENSURE(pNode
->GetNumSubNodes()==3, "Bad Slash");
704 if (pNode
->GetToken().eType
== TWIDESLASH
)
707 // export the node as <mfrac bevelled="true">
708 AddAttribute(XML_NAMESPACE_MATH
, XML_BEVELLED
, XML_TRUE
);
709 SvXMLElementExport
aFraction(*this, XML_NAMESPACE_MATH
, XML_MFRAC
,
711 ExportNodes(pNode
->GetSubNode(0), nLevel
);
712 ExportNodes(pNode
->GetSubNode(1), nLevel
);
717 // We can not use <mfrac> to a backslash, so just use <mo>\</mo>
718 SvXMLElementExport
*pRow
= new SvXMLElementExport(*this,
719 XML_NAMESPACE_MATH
, XML_MROW
, true, true);
721 ExportNodes(pNode
->GetSubNode(0), nLevel
);
723 { // Scoping for <mo> creation
724 SvXMLElementExport
aMo(*this, XML_NAMESPACE_MATH
, XML_MO
,
726 sal_Unicode nArse
[2] = {MS_BACKSLASH
,0x00};
727 GetDocHandler()->characters(nArse
);
730 ExportNodes(pNode
->GetSubNode(1), nLevel
);
736 void SmXMLExport::ExportTable(const SmNode
*pNode
, int nLevel
)
738 SvXMLElementExport
*pTable
=0;
740 sal_uInt16 nSize
= pNode
->GetNumSubNodes();
742 //If the list ends in newline then the last entry has
743 //no subnodes, the newline is superfulous so we just drop
744 //the last node, inclusion would create a bad MathML
748 const SmNode
*pLine
= pNode
->GetSubNode(nSize
-1);
749 if (pLine
->GetType() == NLINE
&& pLine
->GetNumSubNodes() == 1 &&
750 pLine
->GetSubNode(0) != NULL
&&
751 pLine
->GetSubNode(0)->GetToken().eType
== TNEWLINE
)
755 // try to avoid creating a mtable element when the formula consists only
756 // of a single output line
757 if (nLevel
|| (nSize
>1))
758 pTable
= new SvXMLElementExport(*this, XML_NAMESPACE_MATH
, XML_MTABLE
, true, true);
760 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
761 if (const SmNode
*pTemp
= pNode
->GetSubNode(i
))
763 SvXMLElementExport
*pRow
=0;
764 SvXMLElementExport
*pCell
=0;
767 pRow
= new SvXMLElementExport(*this, XML_NAMESPACE_MATH
, XML_MTR
, true, true);
768 SmTokenType eAlign
= TALIGNC
;
769 if (pTemp
->GetType() == NALIGN
)
771 // For Binom() and Stack() constructions, the NALIGN nodes
772 // are direct children.
773 // binom{alignl ...}{alignr ...} and
774 // stack{alignl ... ## alignr ... ## ...}
775 eAlign
= pTemp
->GetToken().eType
;
777 else if (pTemp
->GetType() == NLINE
&&
778 pTemp
->GetNumSubNodes() == 1 &&
779 pTemp
->GetSubNode(0) &&
780 pTemp
->GetSubNode(0)->GetType() == NALIGN
)
782 // For the Table() construction, the NALIGN node is a child
784 // alignl ... newline alignr ... newline ...
785 eAlign
= pTemp
->GetSubNode(0)->GetToken().eType
;
787 if (eAlign
!= TALIGNC
)
789 // If a left or right alignment is specified on this line,
790 // attach the corresponding columnalign attribute.
791 AddAttribute(XML_NAMESPACE_MATH
, XML_COLUMNALIGN
,
792 eAlign
== TALIGNL
? XML_LEFT
: XML_RIGHT
);
794 pCell
= new SvXMLElementExport(*this, XML_NAMESPACE_MATH
, XML_MTD
, true, true);
796 ExportNodes(pTemp
, nLevel
+1);
804 void SmXMLExport::ExportMath(const SmNode
*pNode
, int /*nLevel*/)
806 const SmMathSymbolNode
*pTemp
= static_cast<const SmMathSymbolNode
*>(pNode
);
807 SvXMLElementExport
*pMath
= 0;
809 if (pNode
->GetType() == NMATH
|| pNode
->GetType() == NGLYPH_SPECIAL
)
811 // Export NMATH and NGLYPH_SPECIAL symbols as <mo> elements
812 pMath
= new SvXMLElementExport(*this, XML_NAMESPACE_MATH
, XML_MO
, true, false);
816 // Export NMATHIDENT and NPLACE symbols as <mi> elements:
817 // - These math symbols should not be drawn slanted. Hence we should
818 // attach a mathvariant="normal" attribute to single-char <mi> elements
819 // that are not mathematical alphanumeric symbol. For simplicity and to
820 // work around browser limitations, we always attach such an attribute.
821 // - The MathML specification suggests to use empty <mi> elements as
822 // placeholders but they won't be visible in most MathML rendering
823 // engines so let's use an empty square for NPLACE instead.
824 AddAttribute(XML_NAMESPACE_MATH
, XML_MATHVARIANT
, XML_NORMAL
);
825 pMath
= new SvXMLElementExport(*this, XML_NAMESPACE_MATH
, XML_MI
, true, false);
827 sal_Unicode nArse
[2];
828 nArse
[0] = pTemp
->GetText()[0];
829 sal_Unicode cTmp
= ConvertMathToMathML( nArse
[0] );
832 OSL_ENSURE(nArse
[0] != 0xffff,"Non existent symbol");
834 GetDocHandler()->characters(nArse
);
839 void SmXMLExport::ExportText(const SmNode
*pNode
, int /*nLevel*/)
841 SvXMLElementExport
*pText
;
842 const SmTextNode
*pTemp
= static_cast<const SmTextNode
*>(pNode
);
843 switch (pNode
->GetToken().eType
)
848 //Note that we change the fontstyle to italic for strings that
849 //are italic and longer than a single character.
850 bool bIsItalic
= IsItalic( pTemp
->GetFont() );
851 if ((pTemp
->GetText().getLength() > 1) && bIsItalic
)
852 AddAttribute(XML_NAMESPACE_MATH
, XML_MATHVARIANT
, XML_ITALIC
);
853 else if ((pTemp
->GetText().getLength() == 1) && !bIsItalic
)
854 AddAttribute(XML_NAMESPACE_MATH
, XML_MATHVARIANT
, XML_NORMAL
);
855 pText
= new SvXMLElementExport(*this, XML_NAMESPACE_MATH
, XML_MI
, true, false);
859 pText
= new SvXMLElementExport(*this, XML_NAMESPACE_MATH
, XML_MN
, true, false);
862 pText
= new SvXMLElementExport(*this, XML_NAMESPACE_MATH
, XML_MTEXT
, true, false);
865 GetDocHandler()->characters(pTemp
->GetText());
869 void SmXMLExport::ExportBlank(const SmNode
*pNode
, int /*nLevel*/)
871 const SmBlankNode
*pTemp
= static_cast<const SmBlankNode
*>(pNode
);
872 //!! exports an <mspace> element. Note that for example "~_~" is allowed in
873 //!! Math (so it has no sense at all) but must not result in an empty
874 //!! <msub> tag in MathML !!
876 if (pTemp
->GetBlankNum() != 0)
878 // Attach a width attribute. We choose the (somewhat arbitrary) values
879 // ".5em" for a small gap '`' and "2em" for a large gap '~'.
880 // (see SmBlankNode::IncreaseBy for how pTemp->nNum is set).
881 OUStringBuffer sStrBuf
;
882 ::sax::Converter::convertDouble(sStrBuf
, pTemp
->GetBlankNum() * .5);
883 sStrBuf
.append("em");
884 AddAttribute(XML_NAMESPACE_MATH
, XML_WIDTH
, sStrBuf
.getStr());
887 SvXMLElementExport
*pText
;
889 pText
= new SvXMLElementExport(*this, XML_NAMESPACE_MATH
, XML_MSPACE
,
892 GetDocHandler()->characters( OUString() );
896 void SmXMLExport::ExportSubSupScript(const SmNode
*pNode
, int nLevel
)
898 const SmNode
*pSub
= 0;
899 const SmNode
*pSup
= 0;
900 const SmNode
*pCSub
= 0;
901 const SmNode
*pCSup
= 0;
902 const SmNode
*pLSub
= 0;
903 const SmNode
*pLSup
= 0;
904 SvXMLElementExport
*pThing
= 0, *pThing2
= 0;
906 //if we have prescripts at all then we must use the tensor notation
908 //This is one of those excellent locations where scope is vital to
909 //arrange the construction and destruction of the element helper
911 pLSub
= pNode
->GetSubNode(LSUB
+1);
912 pLSup
= pNode
->GetSubNode(LSUP
+1);
915 SvXMLElementExport
aMultiScripts(*this, XML_NAMESPACE_MATH
,
916 XML_MMULTISCRIPTS
, true, true);
919 if (NULL
!= (pCSub
= pNode
->GetSubNode(CSUB
+1))
920 && NULL
!= (pCSup
= pNode
->GetSubNode(CSUP
+1)))
922 pThing2
= new SvXMLElementExport(*this, XML_NAMESPACE_MATH
,
923 XML_MUNDEROVER
, true, true);
925 else if (NULL
!= (pCSub
= pNode
->GetSubNode(CSUB
+1)))
927 pThing2
= new SvXMLElementExport(*this, XML_NAMESPACE_MATH
,
928 XML_MUNDER
, true, true);
930 else if (NULL
!= (pCSup
= pNode
->GetSubNode(CSUP
+1)))
932 pThing2
= new SvXMLElementExport(*this, XML_NAMESPACE_MATH
,
933 XML_MOVER
, true, true);
936 ExportNodes(pNode
->GetSubNode(0), nLevel
+1); //Main Term
939 ExportNodes(pCSub
, nLevel
+1);
941 ExportNodes(pCSup
, nLevel
+1);
944 pSub
= pNode
->GetSubNode(RSUB
+1);
945 pSup
= pNode
->GetSubNode(RSUP
+1);
949 ExportNodes(pSub
, nLevel
+1);
952 SvXMLElementExport
aNone(*this, XML_NAMESPACE_MATH
, XML_NONE
, true, true);
955 ExportNodes(pSup
, nLevel
+1);
958 SvXMLElementExport
aNone(*this, XML_NAMESPACE_MATH
, XML_NONE
, true, true);
962 //Separator element between suffix and prefix sub/sup pairs
964 SvXMLElementExport
aPrescripts(*this, XML_NAMESPACE_MATH
,
965 XML_MPRESCRIPTS
, true, true);
969 ExportNodes(pLSub
, nLevel
+1);
972 SvXMLElementExport
aNone(*this, XML_NAMESPACE_MATH
, XML_NONE
,
977 ExportNodes(pLSup
, nLevel
+1);
980 SvXMLElementExport
aNone(*this, XML_NAMESPACE_MATH
, XML_NONE
,
987 if (NULL
!= (pSub
= pNode
->GetSubNode(RSUB
+1)) &&
988 NULL
!= (pSup
= pNode
->GetSubNode(RSUP
+1)))
990 pThing
= new SvXMLElementExport(*this, XML_NAMESPACE_MATH
,
991 XML_MSUBSUP
, true, true);
993 else if (NULL
!= (pSub
= pNode
->GetSubNode(RSUB
+1)))
995 pThing
= new SvXMLElementExport(*this, XML_NAMESPACE_MATH
, XML_MSUB
,
998 else if (NULL
!= (pSup
= pNode
->GetSubNode(RSUP
+1)))
1000 pThing
= new SvXMLElementExport(*this, XML_NAMESPACE_MATH
, XML_MSUP
,
1004 if (NULL
!= (pCSub
= pNode
->GetSubNode(CSUB
+1))
1005 && NULL
!= (pCSup
=pNode
->GetSubNode(CSUP
+1)))
1007 pThing2
= new SvXMLElementExport(*this, XML_NAMESPACE_MATH
,
1008 XML_MUNDEROVER
, true, true);
1010 else if (NULL
!= (pCSub
= pNode
->GetSubNode(CSUB
+1)))
1012 pThing2
= new SvXMLElementExport(*this, XML_NAMESPACE_MATH
,
1013 XML_MUNDER
, true, true);
1015 else if (NULL
!= (pCSup
= pNode
->GetSubNode(CSUP
+1)))
1017 pThing2
= new SvXMLElementExport(*this, XML_NAMESPACE_MATH
,
1018 XML_MOVER
, true, true);
1020 ExportNodes(pNode
->GetSubNode(0), nLevel
+1); //Main Term
1023 ExportNodes(pCSub
, nLevel
+1);
1025 ExportNodes(pCSup
, nLevel
+1);
1029 ExportNodes(pSub
, nLevel
+1);
1031 ExportNodes(pSup
, nLevel
+1);
1036 void SmXMLExport::ExportBrace(const SmNode
*pNode
, int nLevel
)
1038 const SmNode
*pTemp
;
1039 const SmNode
*pLeft
=pNode
->GetSubNode(0);
1040 const SmNode
*pRight
=pNode
->GetSubNode(2);
1041 SvXMLElementExport
*pRow
=0;
1043 // This used to generate <mfenced> or <mrow>+<mo> elements according to
1044 // the stretchiness of fences. The MathML recommendation defines an
1045 // <mrow>+<mo> construction that is equivalent to the <mfenced> element:
1046 // http://www.w3.org/TR/MathML3/chapter3.html#presm.mfenced
1047 // To simplify our code and avoid issues with mfenced implementations in
1048 // MathML rendering engines, we now always generate <mrow>+<mo> elements.
1052 pRow
= new SvXMLElementExport(*this, XML_NAMESPACE_MATH
, XML_MROW
,
1055 // <mo fence="true"> opening-fence </mo>
1056 if (pLeft
&& (pLeft
->GetToken().eType
!= TNONE
))
1058 AddAttribute(XML_NAMESPACE_MATH
, XML_FENCE
, XML_TRUE
);
1059 if (pNode
->GetScaleMode() == SCALE_HEIGHT
)
1060 AddAttribute(XML_NAMESPACE_MATH
, XML_STRETCHY
, XML_TRUE
);
1062 AddAttribute(XML_NAMESPACE_MATH
, XML_STRETCHY
, XML_FALSE
);
1063 ExportNodes(pLeft
, nLevel
+1);
1066 if (NULL
!= (pTemp
= pNode
->GetSubNode(1)))
1069 SvXMLElementExport
aRow(*this, XML_NAMESPACE_MATH
, XML_MROW
,
1071 ExportNodes(pTemp
, nLevel
+1);
1075 // <mo fence="true"> closing-fence </mo>
1076 if (pRight
&& (pRight
->GetToken().eType
!= TNONE
))
1078 AddAttribute(XML_NAMESPACE_MATH
, XML_FENCE
, XML_TRUE
);
1079 if (pNode
->GetScaleMode() == SCALE_HEIGHT
)
1080 AddAttribute(XML_NAMESPACE_MATH
, XML_STRETCHY
, XML_TRUE
);
1082 AddAttribute(XML_NAMESPACE_MATH
, XML_STRETCHY
, XML_FALSE
);
1083 ExportNodes(pRight
, nLevel
+1);
1090 void SmXMLExport::ExportRoot(const SmNode
*pNode
, int nLevel
)
1092 if (pNode
->GetSubNode(0))
1094 SvXMLElementExport
aRoot(*this, XML_NAMESPACE_MATH
, XML_MROOT
, true,
1096 ExportNodes(pNode
->GetSubNode(2), nLevel
+1);
1097 ExportNodes(pNode
->GetSubNode(0), nLevel
+1);
1101 SvXMLElementExport
aSqrt(*this, XML_NAMESPACE_MATH
, XML_MSQRT
, true,
1103 ExportNodes(pNode
->GetSubNode(2), nLevel
+1);
1107 void SmXMLExport::ExportOperator(const SmNode
*pNode
, int nLevel
)
1109 /*we need to either use content or font and size attributes
1111 SvXMLElementExport
aRow(*this, XML_NAMESPACE_MATH
, XML_MROW
,
1113 ExportNodes(pNode
->GetSubNode(0), nLevel
+1);
1114 ExportNodes(pNode
->GetSubNode(1), nLevel
+1);
1117 void SmXMLExport::ExportAttributes(const SmNode
*pNode
, int nLevel
)
1119 SvXMLElementExport
*pElement
=0;
1121 if (pNode
->GetToken().eType
== TUNDERLINE
)
1123 AddAttribute(XML_NAMESPACE_MATH
, XML_ACCENTUNDER
,
1125 pElement
= new SvXMLElementExport(*this, XML_NAMESPACE_MATH
, XML_MUNDER
,
1128 else if (pNode
->GetToken().eType
== TOVERSTRIKE
)
1130 // export as <menclose notation="horizontalstrike">
1131 AddAttribute(XML_NAMESPACE_MATH
, XML_NOTATION
, XML_HORIZONTALSTRIKE
);
1132 pElement
= new SvXMLElementExport(*this, XML_NAMESPACE_MATH
,
1133 XML_MENCLOSE
, true, true);
1137 AddAttribute(XML_NAMESPACE_MATH
, XML_ACCENT
,
1139 pElement
= new SvXMLElementExport(*this, XML_NAMESPACE_MATH
, XML_MOVER
,
1143 ExportNodes(pNode
->GetSubNode(1), nLevel
+1);
1144 switch (pNode
->GetToken().eType
)
1148 //proper entity support required
1149 SvXMLElementExport
aMath(*this, XML_NAMESPACE_MATH
, XML_MO
,
1151 sal_Unicode nArse
[2] = {0xAF,0x00};
1152 GetDocHandler()->characters(nArse
);
1157 //proper entity support required
1158 SvXMLElementExport
aMath(*this, XML_NAMESPACE_MATH
, XML_MO
,
1160 sal_Unicode nArse
[2] = {0x0332,0x00};
1161 GetDocHandler()->characters(nArse
);
1170 // make these wide accents stretchy
1171 AddAttribute(XML_NAMESPACE_MATH
, XML_STRETCHY
, XML_TRUE
);
1172 ExportNodes(pNode
->GetSubNode(0), nLevel
+1);
1176 ExportNodes(pNode
->GetSubNode(0), nLevel
+1);
1182 static bool lcl_HasEffectOnMathvariant( const SmTokenType eType
)
1184 return eType
== TBOLD
|| eType
== TNBOLD
||
1185 eType
== TITALIC
|| eType
== TNITALIC
||
1186 eType
== TSANS
|| eType
== TSERIF
|| eType
== TFIXED
;
1189 void SmXMLExport::ExportFont(const SmNode
*pNode
, int nLevel
)
1192 // gather the mathvariant attribute relevant data from all
1193 // successively following SmFontNodes...
1195 int nBold
= -1; // for the following variables: -1 = yet undefined; 0 = false; 1 = true;
1196 int nItalic
= -1; // for the following variables: -1 = yet undefined; 0 = false; 1 = true;
1197 int nSansSerifFixed
= -1;
1198 SmTokenType eNodeType
= TUNKNOWN
;
1199 while (lcl_HasEffectOnMathvariant( (eNodeType
= pNode
->GetToken().eType
) ))
1203 case TBOLD
: nBold
= 1; break;
1204 case TNBOLD
: nBold
= 0; break;
1205 case TITALIC
: nItalic
= 1; break;
1206 case TNITALIC
: nItalic
= 0; break;
1207 case TSANS
: nSansSerifFixed
= 0; break;
1208 case TSERIF
: nSansSerifFixed
= 1; break;
1209 case TFIXED
: nSansSerifFixed
= 2; break;
1211 SAL_WARN("starmath", "unexpected case");
1213 // According to the parser every node that is to be evaluated heres
1214 // has a single non-zero subnode at index 1!! Thus we only need to check
1215 // that single node for follow-up nodes that have an effect on the attribute.
1216 if (pNode
->GetNumSubNodes() > 1 && pNode
->GetSubNode(1) &&
1217 lcl_HasEffectOnMathvariant( pNode
->GetSubNode(1)->GetToken().eType
))
1219 pNode
= pNode
->GetSubNode(1);
1225 switch (pNode
->GetToken().eType
)
1228 // No attribute needed. An <mphantom> element will be used below.
1231 AddAttribute(XML_NAMESPACE_MATH
, XML_COLOR
, XML_BLACK
);
1234 AddAttribute(XML_NAMESPACE_MATH
, XML_COLOR
, XML_WHITE
);
1237 AddAttribute(XML_NAMESPACE_MATH
, XML_COLOR
, XML_RED
);
1240 AddAttribute(XML_NAMESPACE_MATH
, XML_COLOR
, XML_GREEN
);
1243 AddAttribute(XML_NAMESPACE_MATH
, XML_COLOR
, XML_BLUE
);
1246 AddAttribute(XML_NAMESPACE_MATH
, XML_COLOR
, XML_AQUA
);
1249 AddAttribute(XML_NAMESPACE_MATH
, XML_COLOR
, XML_FUCHSIA
);
1252 AddAttribute(XML_NAMESPACE_MATH
, XML_COLOR
, XML_YELLOW
);
1255 AddAttribute(XML_NAMESPACE_MATH
, XML_COLOR
, XML_SILVER
);
1258 AddAttribute(XML_NAMESPACE_MATH
, XML_COLOR
, XML_GRAY
);
1261 AddAttribute(XML_NAMESPACE_MATH
, XML_COLOR
, XML_MAROON
);
1264 AddAttribute(XML_NAMESPACE_MATH
, XML_COLOR
, XML_OLIVE
);
1267 AddAttribute(XML_NAMESPACE_MATH
, XML_COLOR
, XML_LIME
);
1270 AddAttribute(XML_NAMESPACE_MATH
, XML_COLOR
, XML_AQUA
);
1273 AddAttribute(XML_NAMESPACE_MATH
, XML_COLOR
, XML_TEAL
);
1276 AddAttribute(XML_NAMESPACE_MATH
, XML_COLOR
, XML_NAVY
);
1279 AddAttribute(XML_NAMESPACE_MATH
, XML_COLOR
, XML_FUCHSIA
);
1282 AddAttribute(XML_NAMESPACE_MATH
, XML_COLOR
, XML_PURPLE
);
1286 const SmFontNode
*pFontNode
= static_cast<const SmFontNode
*>(pNode
);
1287 const Fraction
&aFrac
= pFontNode
->GetSizeParameter();
1289 OUStringBuffer sStrBuf
;
1290 switch(pFontNode
->GetSizeType())
1292 case FontSizeType::MULTIPLY
:
1293 ::sax::Converter::convertDouble(sStrBuf
,
1294 static_cast<double>(aFrac
*Fraction(100.00)));
1295 sStrBuf
.append('%');
1297 case FontSizeType::DIVIDE
:
1298 ::sax::Converter::convertDouble(sStrBuf
,
1299 static_cast<double>(Fraction(100.00)/aFrac
));
1300 sStrBuf
.append('%');
1302 case FontSizeType::ABSOLUT
:
1303 ::sax::Converter::convertDouble(sStrBuf
,
1304 static_cast<double>(aFrac
));
1306 GetXMLToken(XML_UNIT_PT
));
1310 //The problem here is that the wheels fall off because
1311 //font size is stored in 100th's of a mm not pts, and
1312 //rounding errors take their toll on the original
1313 //value specified in points.
1315 //Must fix StarMath to retain the original pt values
1316 Fraction aTemp
= Sm100th_mmToPts(pFontNode
->GetFont().
1317 GetSize().Height());
1319 if (pFontNode
->GetSizeType() == FontSizeType::MINUS
)
1324 double mytest
= static_cast<double>(aTemp
);
1326 mytest
= ::rtl::math::round(mytest
,1);
1327 ::sax::Converter::convertDouble(sStrBuf
,mytest
);
1328 sStrBuf
.append(GetXMLToken(XML_UNIT_PT
));
1333 OUString
sStr(sStrBuf
.makeStringAndClear());
1334 AddAttribute(XML_NAMESPACE_MATH
, XML_MATHSIZE
, sStr
);
1345 // nBold: -1 = yet undefined; 0 = false; 1 = true;
1346 // nItalic: -1 = yet undefined; 0 = false; 1 = true;
1347 // nSansSerifFixed: -1 = undefined; 0 = sans; 1 = serif; 2 = fixed;
1348 const sal_Char
*pText
= "normal";
1349 if (nSansSerifFixed
== -1 || nSansSerifFixed
== 1)
1352 if (nBold
== 1 && nItalic
!= 1)
1354 else if (nBold
!= 1 && nItalic
== 1)
1356 else if (nBold
== 1 && nItalic
== 1)
1357 pText
= "bold-italic";
1359 else if (nSansSerifFixed
== 0)
1361 pText
= "sans-serif";
1362 if (nBold
== 1 && nItalic
!= 1)
1363 pText
= "bold-sans-serif";
1364 else if (nBold
!= 1 && nItalic
== 1)
1365 pText
= "sans-serif-italic";
1366 else if (nBold
== 1 && nItalic
== 1)
1367 pText
= "sans-serif-bold-italic";
1369 else if (nSansSerifFixed
== 2)
1370 pText
= "monospace"; // no modifiers allowed for monospace ...
1373 SAL_WARN("starmath", "unexpected case");
1375 AddAttribute(XML_NAMESPACE_MATH
, XML_MATHVARIANT
, OUString::createFromAscii( pText
));
1383 // Wrap everything in an <mphantom> or <mstyle> element. These elements
1384 // are mrow-like, so ExportExpression doesn't need to add an explicit
1385 // <mrow> element. See #fdo 66283.
1386 SvXMLElementExport
aElement(*this, XML_NAMESPACE_MATH
,
1387 pNode
->GetToken().eType
== TPHANTOM
? XML_MPHANTOM
: XML_MSTYLE
,
1389 ExportExpression(pNode
, nLevel
, true);
1394 void SmXMLExport::ExportVerticalBrace(const SmNode
*pNode
, int nLevel
)
1396 // "[body] overbrace [script]"
1398 // Position body, overbrace and script vertically. First place the overbrace
1399 // OVER the body and then the script OVER this expression.
1403 // XXXXXX[body]XXXXXXX
1405 // Similarly for the underbrace construction.
1409 switch (pNode
->GetToken().eType
)
1420 OSL_ENSURE(pNode
->GetNumSubNodes()==3,"Bad Vertical Brace");
1421 SvXMLElementExport
aOver1(*this, XML_NAMESPACE_MATH
,which
, true, true);
1423 // using accents will draw the over-/underbraces too close to the base
1424 // see http://www.w3.org/TR/MathML2/chapter3.html#id.3.4.5.2
1425 // also XML_ACCENT is illegal with XML_MUNDER. Thus no XML_ACCENT attribute here!
1426 SvXMLElementExport
aOver2(*this, XML_NAMESPACE_MATH
,which
, true, true);
1427 ExportNodes(pNode
->GetSubNode(0), nLevel
);
1428 AddAttribute(XML_NAMESPACE_MATH
, XML_STRETCHY
, XML_TRUE
);
1429 ExportNodes(pNode
->GetSubNode(1), nLevel
);
1431 ExportNodes(pNode
->GetSubNode(2), nLevel
);
1434 void SmXMLExport::ExportMatrix(const SmNode
*pNode
, int nLevel
)
1436 SvXMLElementExport
aTable(*this, XML_NAMESPACE_MATH
, XML_MTABLE
, true, true);
1437 const SmMatrixNode
*pMatrix
= static_cast<const SmMatrixNode
*>(pNode
);
1439 for (sal_uInt16 y
= 0; y
< pMatrix
->GetNumRows(); y
++)
1441 SvXMLElementExport
aRow(*this, XML_NAMESPACE_MATH
, XML_MTR
, true, true);
1442 for (sal_uInt16 x
= 0; x
< pMatrix
->GetNumCols(); x
++)
1443 if (const SmNode
*pTemp
= pNode
->GetSubNode(i
++))
1445 if (pTemp
->GetType() == NALIGN
&&
1446 pTemp
->GetToken().eType
!= TALIGNC
)
1448 // A left or right alignment is specified on this cell,
1449 // attach the corresponding columnalign attribute.
1450 AddAttribute(XML_NAMESPACE_MATH
, XML_COLUMNALIGN
,
1451 pTemp
->GetToken().eType
== TALIGNL
?
1452 XML_LEFT
: XML_RIGHT
);
1454 SvXMLElementExport
aCell(*this, XML_NAMESPACE_MATH
, XML_MTD
, true, true);
1455 ExportNodes(pTemp
, nLevel
+1);
1460 void SmXMLExport::ExportNodes(const SmNode
*pNode
, int nLevel
)
1464 switch(pNode
->GetType())
1467 ExportTable(pNode
, nLevel
);
1472 ExportExpression(pNode
, nLevel
);
1475 ExportLine(pNode
, nLevel
);
1478 ExportText(pNode
, nLevel
);
1480 case NGLYPH_SPECIAL
:
1483 sal_Unicode cTmp
= 0;
1484 const SmTextNode
*pTemp
= static_cast< const SmTextNode
* >(pNode
);
1485 if (!pTemp
->GetText().isEmpty())
1486 cTmp
= ConvertMathToMathML( pTemp
->GetText()[0] );
1489 // no conversion to MathML implemented -> export it as text
1490 // thus at least it will not vanish into nothing
1491 ExportText(pNode
, nLevel
);
1495 //To fully handle generic MathML we need to implement the full
1496 //operator dictionary, we will generate MathML with explicit
1497 //stretchiness for now.
1498 sal_Int16 nLength
= GetAttrList().getLength();
1499 bool bAddStretch
=true;
1500 for ( sal_Int16 i
= 0; i
< nLength
; i
++ )
1502 OUString sLocalName
;
1503 sal_uInt16 nPrefix
= GetNamespaceMap().GetKeyByAttrName(
1504 GetAttrList().getNameByIndex(i
), &sLocalName
);
1506 if ( ( XML_NAMESPACE_MATH
== nPrefix
) &&
1507 IsXMLToken(sLocalName
, XML_STRETCHY
) )
1509 bAddStretch
= false;
1515 AddAttribute(XML_NAMESPACE_MATH
, XML_STRETCHY
, XML_FALSE
);
1517 ExportMath(pNode
, nLevel
);
1521 case NSPECIAL
: //NSPECIAL requires some sort of Entity preservation in the XML engine.
1524 ExportMath(pNode
, nLevel
);
1527 ExportBinaryHorizontal(pNode
, nLevel
);
1530 ExportUnaryHorizontal(pNode
, nLevel
);
1533 ExportBrace(pNode
, nLevel
);
1536 ExportBinaryVertical(pNode
, nLevel
);
1539 ExportBinaryDiagonal(pNode
, nLevel
);
1542 ExportSubSupScript(pNode
, nLevel
);
1545 ExportRoot(pNode
, nLevel
);
1548 ExportOperator(pNode
, nLevel
);
1551 ExportAttributes(pNode
, nLevel
);
1554 ExportFont(pNode
, nLevel
);
1556 case NVERTICAL_BRACE
:
1557 ExportVerticalBrace(pNode
, nLevel
);
1560 ExportMatrix(pNode
, nLevel
);
1563 ExportBlank(pNode
, nLevel
);
1566 SAL_WARN("starmath", "Warning: failed to export a node?");
1572 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */