xref: /trunk/main/starmath/source/mathmlexport.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_starmath.hxx"
30 
31 /*
32  Warning: The SvXMLElementExport helper class creates the beginning and
33  closing tags of xml elements in its constructor and destructor, so theres
34  hidden stuff going on, on occasion the ordering of these classes declarations
35  may be significant
36 */
37 
38 
39 #include <com/sun/star/xml/sax/XErrorHandler.hpp>
40 #include <com/sun/star/xml/sax/XEntityResolver.hpp>
41 #include <com/sun/star/xml/sax/InputSource.hpp>
42 #include <com/sun/star/xml/sax/XDTDHandler.hpp>
43 #include <com/sun/star/xml/sax/XParser.hpp>
44 #include <com/sun/star/io/XActiveDataSource.hpp>
45 #include <com/sun/star/io/XActiveDataControl.hpp>
46 #include <com/sun/star/document/XDocumentProperties.hpp>
47 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
48 #include <com/sun/star/packages/zip/ZipIOException.hpp>
49 #include <com/sun/star/task/XStatusIndicatorFactory.hpp>
50 #include <com/sun/star/beans/PropertyAttribute.hpp>
51 #include <com/sun/star/container/XNameAccess.hpp>
52 #include <com/sun/star/embed/ElementModes.hpp>
53 #include <com/sun/star/uno/Any.h>
54 
55 #include <rtl/math.hxx>
56 #include <sfx2/frame.hxx>
57 #include <sfx2/docfile.hxx>
58 #include <tools/debug.hxx>
59 #include <tools/urlobj.hxx>
60 #include <svtools/sfxecode.hxx>
61 #include <unotools/saveopt.hxx>
62 #include <svl/stritem.hxx>
63 #include <svl/itemprop.hxx>
64 #include <unotools/processfactory.hxx>
65 #include <unotools/streamwrap.hxx>
66 #include <xmloff/xmlnmspe.hxx>
67 #include <xmloff/xmltoken.hxx>
68 #include <xmloff/nmspmap.hxx>
69 #include <xmloff/attrlist.hxx>
70 #include <xmloff/xmluconv.hxx>
71 #include <xmloff/xmlmetai.hxx>
72 #include <osl/mutex.hxx>
73 #include <comphelper/genericpropertyset.hxx>
74 
75 #include <memory>
76 
77 #include "mathmlexport.hxx"
78 #include <starmath.hrc>
79 #include <unomodel.hxx>
80 #include <document.hxx>
81 #include <utility.hxx>
82 #include <config.hxx>
83 
84 using namespace ::com::sun::star::beans;
85 using namespace ::com::sun::star::container;
86 using namespace ::com::sun::star::document;
87 using namespace ::com::sun::star::lang;
88 using namespace ::com::sun::star::uno;
89 using namespace ::com::sun::star;
90 using namespace ::xmloff::token;
91 
92 using ::rtl::OUString;
93 using ::rtl::OUStringBuffer;
94 
95 #define EXPORT_SVC_NAME RTL_CONSTASCII_USTRINGPARAM("com.sun.star.xml.XMLExportFilter")
96 
97 #undef WANTEXCEPT
98 
99 
100 ////////////////////////////////////////////////////////////
101 
102 sal_Bool SmXMLExportWrapper::Export(SfxMedium &rMedium)
103 {
104     sal_Bool bRet=sal_True;
105     uno::Reference<lang::XMultiServiceFactory>
106         xServiceFactory(utl::getProcessServiceFactory());
107     DBG_ASSERT(xServiceFactory.is(),"got no service manager");
108 
109     //Get model
110     uno::Reference< lang::XComponent > xModelComp(xModel, uno::UNO_QUERY );
111 
112     sal_Bool bEmbedded = sal_False;
113     uno::Reference <lang::XUnoTunnel> xTunnel;
114     xTunnel = uno::Reference <lang::XUnoTunnel> (xModel,uno::UNO_QUERY);
115     SmModel *pModel = reinterpret_cast<SmModel *>
116         (xTunnel->getSomething(SmModel::getUnoTunnelId()));
117 
118     SmDocShell *pDocShell = pModel ?
119             static_cast<SmDocShell*>(pModel->GetObjectShell()) : 0;
120     if ( pDocShell &&
121         SFX_CREATE_MODE_EMBEDDED == pDocShell->GetCreateMode() )
122         bEmbedded = sal_True;
123 
124     uno::Reference<task::XStatusIndicator> xStatusIndicator;
125     if (!bEmbedded)
126     {
127         if (pDocShell /*&& pDocShell->GetMedium()*/)
128         {
129             DBG_ASSERT( pDocShell->GetMedium() == &rMedium,
130                     "different SfxMedium found" );
131 
132             SfxItemSet* pSet = rMedium.GetItemSet();
133             if (pSet)
134             {
135                 const SfxUnoAnyItem* pItem = static_cast<const SfxUnoAnyItem*>(
136                     pSet->GetItem(SID_PROGRESS_STATUSBAR_CONTROL) );
137                 if (pItem)
138                     pItem->GetValue() >>= xStatusIndicator;
139             }
140         }
141 
142         // set progress range and start status indicator
143         if (xStatusIndicator.is())
144         {
145             sal_Int32 nProgressRange = bFlat ? 1 : 3;
146             xStatusIndicator->start(String(SmResId(STR_STATSTR_WRITING)),
147                 nProgressRange);
148         }
149     }
150 
151 
152     // create XPropertySet with three properties for status indicator
153     comphelper::PropertyMapEntry aInfoMap[] =
154     {
155         { "UsePrettyPrinting", sizeof("UsePrettyPrinting")-1, 0,
156               &::getBooleanCppuType(),
157               beans::PropertyAttribute::MAYBEVOID, 0},
158         { "BaseURI", sizeof("BaseURI")-1, 0,
159               &::getCppuType( (OUString *)0 ),
160               beans::PropertyAttribute::MAYBEVOID, 0 },
161         { "StreamRelPath", sizeof("StreamRelPath")-1, 0,
162               &::getCppuType( (OUString *)0 ),
163               beans::PropertyAttribute::MAYBEVOID, 0 },
164         { "StreamName", sizeof("StreamName")-1, 0,
165               &::getCppuType( (OUString *)0 ),
166               beans::PropertyAttribute::MAYBEVOID, 0 },
167         { NULL, 0, 0, NULL, 0, 0 }
168     };
169     uno::Reference< beans::XPropertySet > xInfoSet(
170                 comphelper::GenericPropertySet_CreateInstance(
171                             new comphelper::PropertySetInfo( aInfoMap ) ) );
172 
173     SvtSaveOptions aSaveOpt;
174     OUString sUsePrettyPrinting(RTL_CONSTASCII_USTRINGPARAM("UsePrettyPrinting"));
175     sal_Bool bUsePrettyPrinting( bFlat || aSaveOpt.IsPrettyPrinting() );
176     Any aAny;
177     aAny.setValue( &bUsePrettyPrinting, ::getBooleanCppuType() );
178     xInfoSet->setPropertyValue( sUsePrettyPrinting, aAny );
179 
180     // Set base URI
181     OUString sPropName( RTL_CONSTASCII_USTRINGPARAM("BaseURI") );
182     xInfoSet->setPropertyValue( sPropName, makeAny( rMedium.GetBaseURL( true ) ) );
183 
184     sal_Int32 nSteps=0;
185     if (xStatusIndicator.is())
186             xStatusIndicator->setValue(nSteps++);
187     if (!bFlat) //Storage (Package) of Stream
188     {
189         uno::Reference < embed::XStorage > xStg = rMedium.GetOutputStorage();
190         sal_Bool bOASIS = ( SotStorage::GetVersion( xStg ) > SOFFICE_FILEFORMAT_60 );
191 
192         // TODO/LATER: handle the case of embedded links gracefully
193         if ( bEmbedded ) //&& !pStg->IsRoot() )
194         {
195             OUString aName;
196             if ( rMedium.GetItemSet() )
197             {
198                 const SfxStringItem* pDocHierarchItem = static_cast<const SfxStringItem*>(
199                     rMedium.GetItemSet()->GetItem(SID_DOC_HIERARCHICALNAME) );
200                 if ( pDocHierarchItem )
201                     aName = pDocHierarchItem->GetValue();
202             }
203 
204             if ( aName.getLength() )
205             {
206                 sPropName = OUString(RTL_CONSTASCII_USTRINGPARAM("StreamRelPath"));
207                 xInfoSet->setPropertyValue( sPropName, makeAny( aName ) );
208             }
209         }
210 
211         if ( !bEmbedded )
212         {
213             if (xStatusIndicator.is())
214                 xStatusIndicator->setValue(nSteps++);
215 
216             bRet = WriteThroughComponent(
217                     xStg, xModelComp, "meta.xml", xServiceFactory, xInfoSet,
218                     (bOASIS ? "com.sun.star.comp.Math.XMLOasisMetaExporter"
219                             : "com.sun.star.comp.Math.XMLMetaExporter"),
220                     sal_False);
221         }
222         if ( bRet )
223         {
224            if (xStatusIndicator.is())
225                 xStatusIndicator->setValue(nSteps++);
226 
227             bRet = WriteThroughComponent(
228                     xStg, xModelComp, "content.xml", xServiceFactory, xInfoSet,
229                     "com.sun.star.comp.Math.XMLContentExporter");
230         }
231 
232         if ( bRet )
233         {
234             if (xStatusIndicator.is())
235                 xStatusIndicator->setValue(nSteps++);
236 
237             bRet = WriteThroughComponent(
238                     xStg, xModelComp, "settings.xml", xServiceFactory, xInfoSet,
239                     (bOASIS ? "com.sun.star.comp.Math.XMLOasisSettingsExporter"
240                             : "com.sun.star.comp.Math.XMLSettingsExporter") );
241         }
242     }
243     else
244     {
245         SvStream *pStream = rMedium.GetOutStream();
246         uno::Reference<io::XOutputStream> xOut(
247             new utl::OOutputStreamWrapper(*pStream) );
248 
249         if (xStatusIndicator.is())
250             xStatusIndicator->setValue(nSteps++);
251 
252         bRet = WriteThroughComponent(
253             xOut, xModelComp, xServiceFactory, xInfoSet,
254             "com.sun.star.comp.Math.XMLContentExporter");
255     }
256 
257     if (xStatusIndicator.is())
258         xStatusIndicator->end();
259 
260     return bRet;
261 }
262 
263 
264 /// export through an XML exporter component (output stream version)
265 sal_Bool SmXMLExportWrapper::WriteThroughComponent(
266     Reference<io::XOutputStream> xOutputStream,
267     Reference<XComponent> xComponent,
268     Reference<lang::XMultiServiceFactory> & rFactory,
269     Reference<beans::XPropertySet> & rPropSet,
270     const sal_Char* pComponentName )
271 {
272     DBG_ASSERT(xOutputStream.is(), "I really need an output stream!");
273     DBG_ASSERT(xComponent.is(), "Need component!");
274     DBG_ASSERT(NULL != pComponentName, "Need component name!");
275 
276     // get component
277     Reference< io::XActiveDataSource > xSaxWriter(
278         rFactory->createInstance(
279             OUString::createFromAscii("com.sun.star.xml.sax.Writer") ),
280         UNO_QUERY );
281     DBG_ASSERT( xSaxWriter.is(), "can't instantiate XML writer" );
282     if (!xSaxWriter.is())
283         return sal_False;
284 
285     // connect XML writer to output stream
286     xSaxWriter->setOutputStream( xOutputStream );
287 
288     // prepare arguments (prepend doc handler to given arguments)
289     Reference<xml::sax::XDocumentHandler> xDocHandler( xSaxWriter,UNO_QUERY);
290 
291     Sequence<Any> aArgs( 2 );
292     aArgs[0] <<= xDocHandler;
293     aArgs[1] <<= rPropSet;
294 
295     // get filter component
296     Reference< document::XExporter > xExporter(
297         rFactory->createInstanceWithArguments(
298             OUString::createFromAscii(pComponentName), aArgs), UNO_QUERY);
299     DBG_ASSERT( xExporter.is(),
300             "can't instantiate export filter component" );
301     if ( !xExporter.is() )
302         return sal_False;
303 
304 
305     // connect model and filter
306     xExporter->setSourceDocument( xComponent );
307 
308     // filter!
309     Reference < XFilter > xFilter( xExporter, UNO_QUERY );
310     uno::Sequence< PropertyValue > aProps(0);
311     xFilter->filter( aProps );
312 
313     uno::Reference<lang::XUnoTunnel> xFilterTunnel;
314     xFilterTunnel = uno::Reference<lang::XUnoTunnel>
315         ( xFilter, uno::UNO_QUERY );
316     SmXMLExport *pFilter = reinterpret_cast< SmXMLExport * >(
317                 sal::static_int_cast< sal_uIntPtr >(
318                 xFilterTunnel->getSomething( SmXMLExport::getUnoTunnelId() )));
319     return pFilter ? pFilter->GetSuccess() : sal_True;
320 }
321 
322 
323 /// export through an XML exporter component (storage version)
324 sal_Bool SmXMLExportWrapper::WriteThroughComponent(
325     const Reference < embed::XStorage >& xStorage,
326     Reference<XComponent> xComponent,
327     const sal_Char* pStreamName,
328     Reference<lang::XMultiServiceFactory> & rFactory,
329     Reference<beans::XPropertySet> & rPropSet,
330     const sal_Char* pComponentName,
331     sal_Bool bCompress
332     )
333 {
334     DBG_ASSERT(xStorage.is(), "Need storage!");
335     DBG_ASSERT(NULL != pStreamName, "Need stream name!");
336 
337     // open stream
338     Reference < io::XStream > xStream;
339     OUString sStreamName = OUString::createFromAscii(pStreamName);
340     try
341     {
342         xStream = xStorage->openStreamElement( sStreamName,
343             embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
344     }
345     catch ( uno::Exception& )
346     {
347         DBG_ERROR( "Can't create output stream in package!" );
348         return sal_False;
349     }
350 
351     String aPropName( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("MediaType") ) );
352     OUString aMime( RTL_CONSTASCII_USTRINGPARAM("text/xml") );
353     uno::Any aAny;
354     aAny <<= aMime;
355 
356     uno::Reference < beans::XPropertySet > xSet( xStream, uno::UNO_QUERY );
357     xSet->setPropertyValue( aPropName, aAny );
358 
359     if ( !bCompress )
360     {
361         aPropName = String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("Compressed") );
362         sal_Bool bFalse = sal_False;
363         aAny.setValue( &bFalse, ::getBooleanCppuType() );
364         xSet->setPropertyValue( aPropName, aAny );
365     }
366 
367     // even plain stream must be encrypted in encrypted document
368     OUString aTmpPropName( RTL_CONSTASCII_USTRINGPARAM("UseCommonStoragePasswordEncryption") );
369     sal_Bool bTrue = sal_True;
370     aAny.setValue( &bTrue, ::getBooleanCppuType() );
371     xSet->setPropertyValue( aTmpPropName, aAny );
372 
373     // set Base URL
374     if ( rPropSet.is() )
375     {
376         OUString sPropName( RTL_CONSTASCII_USTRINGPARAM("StreamName") );
377         rPropSet->setPropertyValue( sPropName, makeAny( sStreamName ) );
378     }
379 
380     // write the stuff
381     sal_Bool bRet = WriteThroughComponent( xStream->getOutputStream(), xComponent, rFactory,
382         rPropSet, pComponentName );
383 
384     // stream is closed by SAX parser
385     //if ( bRet )
386     //    xStream->getOutputStream()->closeOutput();
387 
388     return bRet;
389 }
390 
391 ////////////////////////////////////////////////////////////
392 
393 // #110680#
394 SmXMLExport::SmXMLExport(
395     const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory,
396     sal_uInt16 nExportFlags)
397 :   SvXMLExport( xServiceFactory, MAP_INCH, XML_MATH, nExportFlags ) ,
398     pTree(0) ,
399     bSuccess(sal_False)
400 {
401 }
402 
403 sal_Int64 SAL_CALL SmXMLExport::getSomething(
404     const uno::Sequence< sal_Int8 >& rId )
405 throw(uno::RuntimeException)
406 {
407     if ( rId.getLength() == 16 &&
408         0 == rtl_compareMemory( getUnoTunnelId().getConstArray(),
409         rId.getConstArray(), 16 ) )
410     return sal::static_int_cast< sal_Int64 >(reinterpret_cast< sal_uIntPtr >(this));
411 
412     return SvXMLExport::getSomething( rId );
413 }
414 
415 const uno::Sequence< sal_Int8 > & SmXMLExport::getUnoTunnelId() throw()
416 {
417     static uno::Sequence< sal_Int8 > * pSeq = 0;
418     if ( !pSeq )
419     {
420         osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() );
421         if ( !pSeq )
422         {
423             static uno::Sequence< sal_Int8 > aSeq( 16 );
424             rtl_createUuid( (sal_uInt8*)aSeq.getArray(), 0, sal_True );
425             pSeq = &aSeq;
426         }
427     }
428     return *pSeq;
429 }
430 
431 OUString SAL_CALL SmXMLExport_getImplementationName() throw()
432 {
433     return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Math.XMLExporter" ) );
434 }
435 
436 uno::Sequence< OUString > SAL_CALL SmXMLExport_getSupportedServiceNames()
437         throw()
438 {
439     const OUString aServiceName( EXPORT_SVC_NAME );
440     const uno::Sequence< OUString > aSeq( &aServiceName, 1 );
441     return aSeq;
442 }
443 
444 uno::Reference< uno::XInterface > SAL_CALL SmXMLExport_createInstance(
445     const uno::Reference< lang::XMultiServiceFactory > & rSMgr)
446     throw( uno::Exception )
447 {
448     // #110680#
449     // return (cppu::OWeakObject*)new SmXMLExport( EXPORT_ALL );
450     // EXPORT_OASIS is required here allthough there is no differrence between
451     // OOo and OASIS, because without the flag, a transformation to OOo would
452     // be chained in.
453     return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_OASIS|EXPORT_ALL );
454 }
455 
456 ////////////////////////////////////////////////////////////
457 
458 OUString SAL_CALL SmXMLExportMetaOOO_getImplementationName() throw()
459 {
460     return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Math.XMLMetaExporter" ) );
461 }
462 
463 uno::Sequence< OUString > SAL_CALL SmXMLExportMetaOOO_getSupportedServiceNames()
464     throw()
465 {
466     const OUString aServiceName( EXPORT_SVC_NAME );
467     const uno::Sequence< OUString > aSeq( &aServiceName, 1 );
468     return aSeq;
469 }
470 
471 uno::Reference< uno::XInterface > SAL_CALL SmXMLExportMetaOOO_createInstance(
472     const uno::Reference< lang::XMultiServiceFactory > & rSMgr)
473 throw( uno::Exception )
474 {
475     // #110680#
476     // return (cppu::OWeakObject*)new SmXMLExport( EXPORT_META );
477     return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_META );
478 }
479 
480 ////////////////////////////////////////////////////////////
481 
482 OUString SAL_CALL SmXMLExportMeta_getImplementationName() throw()
483 {
484     return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Math.XMLOasisMetaExporter" ) );
485 }
486 
487 uno::Sequence< OUString > SAL_CALL SmXMLExportMeta_getSupportedServiceNames()
488 throw()
489 {
490     const OUString aServiceName( EXPORT_SVC_NAME );
491     const uno::Sequence< OUString > aSeq( &aServiceName, 1 );
492     return aSeq;
493 }
494 
495 uno::Reference< uno::XInterface > SAL_CALL SmXMLExportMeta_createInstance(
496     const uno::Reference< lang::XMultiServiceFactory > & rSMgr)
497 throw( uno::Exception )
498 {
499     // #110680#
500     // return (cppu::OWeakObject*)new SmXMLExport( EXPORT_META );
501     return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_OASIS|EXPORT_META );
502 }
503 
504 ////////////////////////////////////////////////////////////
505 
506 OUString SAL_CALL SmXMLExportSettingsOOO_getImplementationName() throw()
507 {
508     return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Math.XMLSettingsExporter" ) );
509 }
510 
511 uno::Sequence< OUString > SAL_CALL SmXMLExportSettingsOOO_getSupportedServiceNames()
512 throw()
513 {
514     const OUString aServiceName( EXPORT_SVC_NAME );
515     const uno::Sequence< OUString > aSeq( &aServiceName, 1 );
516     return aSeq;
517 }
518 
519 uno::Reference< uno::XInterface > SAL_CALL SmXMLExportSettingsOOO_createInstance(
520     const uno::Reference< lang::XMultiServiceFactory > & rSMgr)
521 throw( uno::Exception )
522 {
523     // #110680#
524     // return (cppu::OWeakObject*)new SmXMLExport( EXPORT_SETTINGS );
525     return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_SETTINGS );
526 }
527 
528 ////////////////////////////////////////////////////////////
529 
530 OUString SAL_CALL SmXMLExportSettings_getImplementationName() throw()
531 {
532     return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Math.XMLOasisSettingsExporter" ) );
533 }
534 
535 uno::Sequence< OUString > SAL_CALL SmXMLExportSettings_getSupportedServiceNames()
536 throw()
537 {
538     const OUString aServiceName( EXPORT_SVC_NAME );
539     const uno::Sequence< OUString > aSeq( &aServiceName, 1 );
540     return aSeq;
541 }
542 
543 uno::Reference< uno::XInterface > SAL_CALL SmXMLExportSettings_createInstance(
544     const uno::Reference< lang::XMultiServiceFactory > & rSMgr)
545 throw( uno::Exception )
546 {
547     // #110680#
548     // return (cppu::OWeakObject*)new SmXMLExport( EXPORT_SETTINGS );
549     return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_OASIS|EXPORT_SETTINGS );
550 }
551 
552 ////////////////////////////////////////////////////////////
553 
554 OUString SAL_CALL SmXMLExportContent_getImplementationName() throw()
555 {
556     return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Math.XMLContentExporter" ) );
557 }
558 
559 uno::Sequence< OUString > SAL_CALL SmXMLExportContent_getSupportedServiceNames()
560         throw()
561 {
562     const OUString aServiceName( EXPORT_SVC_NAME );
563     const uno::Sequence< OUString > aSeq( &aServiceName, 1 );
564     return aSeq;
565 }
566 
567 uno::Reference< uno::XInterface > SAL_CALL SmXMLExportContent_createInstance(
568     const uno::Reference< lang::XMultiServiceFactory > & rSMgr)
569 throw( uno::Exception )
570 {
571     // #110680#
572     // return (cppu::OWeakObject*)new SmXMLExport( EXPORT_CONTENT );
573     // The EXPORT_OASIS flag is only required to avoid that a transformer is
574     // chanied in
575     return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_OASIS|EXPORT_CONTENT );
576 }
577 
578 ////////////////////////////////////////////////////////////
579 
580 // XServiceInfo
581 // override empty method from parent class
582 rtl::OUString SAL_CALL SmXMLExport::getImplementationName()
583 throw(uno::RuntimeException)
584 {
585     OUString aTxt;
586     switch( getExportFlags() )
587     {
588         case EXPORT_META:
589             aTxt = SmXMLExportMeta_getImplementationName();
590             break;
591         case EXPORT_SETTINGS:
592             aTxt = SmXMLExportSettings_getImplementationName();
593             break;
594         case EXPORT_CONTENT:
595             aTxt = SmXMLExportContent_getImplementationName();
596             break;
597         case EXPORT_ALL:
598         default:
599             aTxt = SmXMLExport_getImplementationName();
600             break;
601     }
602     return aTxt;
603 }
604 
605 sal_uInt32 SmXMLExport::exportDoc(enum XMLTokenEnum eClass)
606 {
607     if ( (getExportFlags() & EXPORT_CONTENT) == 0 )
608     {
609         SvXMLExport::exportDoc( eClass );
610     }
611     else
612     {
613         uno::Reference <frame::XModel> xModel = GetModel();
614         uno::Reference <lang::XUnoTunnel> xTunnel;
615         xTunnel = uno::Reference <lang::XUnoTunnel> (xModel,uno::UNO_QUERY);
616         SmModel *pModel = reinterpret_cast<SmModel *>
617             (xTunnel->getSomething(SmModel::getUnoTunnelId()));
618 
619         if (pModel)
620         {
621             SmDocShell *pDocShell =
622                 static_cast<SmDocShell*>(pModel->GetObjectShell());
623             pTree = pDocShell->GetFormulaTree();
624             aText = pDocShell->GetText();
625         }
626 
627         GetDocHandler()->startDocument();
628 
629         /*Add xmlns line*/
630         SvXMLAttributeList &rList = GetAttrList();
631 
632         // make use of a default namespace
633         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)
634         _GetNamespaceMap().Add( OUString::createFromAscii(""), GetXMLToken(XML_N_MATH), XML_NAMESPACE_MATH );
635 
636         rList.AddAttribute(GetNamespaceMap().GetAttrNameByKey(XML_NAMESPACE_MATH_IDX),
637                 GetNamespaceMap().GetNameByKey( XML_NAMESPACE_MATH_IDX));
638 
639         //I think we need something like ImplExportEntities();
640         _ExportContent();
641         GetDocHandler()->endDocument();
642     }
643 
644     bSuccess=sal_True;
645     return 0;
646 }
647 
648 void SmXMLExport::_ExportContent()
649 {
650     SvXMLElementExport aEquation(*this, XML_NAMESPACE_MATH, XML_MATH, sal_True, sal_True);
651     SvXMLElementExport *pSemantics=0;
652 
653     if (aText.Len())
654     {
655         pSemantics = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
656             XML_SEMANTICS, sal_True, sal_True);
657     }
658 
659     ExportNodes(pTree, 0);
660 
661     if (aText.Len())
662     {
663         // Convert symbol names
664         uno::Reference <frame::XModel> xModel = GetModel();
665         uno::Reference <lang::XUnoTunnel> xTunnel;
666         xTunnel = uno::Reference <lang::XUnoTunnel> (xModel,uno::UNO_QUERY);
667         SmModel *pModel = reinterpret_cast<SmModel *>
668             (xTunnel->getSomething(SmModel::getUnoTunnelId()));
669         SmDocShell *pDocShell = pModel ?
670             static_cast<SmDocShell*>(pModel->GetObjectShell()) : 0;
671         DBG_ASSERT( pDocShell, "doc shell missing" );
672         if (pDocShell)
673         {
674             SmParser &rParser = pDocShell->GetParser();
675             sal_Bool bVal = rParser.IsExportSymbolNames();
676             rParser.SetExportSymbolNames( sal_True );
677             SmNode *pTmpTree = rParser.Parse( aText );
678             aText = rParser.GetText();
679             delete pTmpTree;
680             rParser.SetExportSymbolNames( bVal );
681         }
682 
683         AddAttribute(XML_NAMESPACE_MATH, XML_ENCODING,
684             OUString(RTL_CONSTASCII_USTRINGPARAM("StarMath 5.0")));
685         SvXMLElementExport aAnnotation(*this, XML_NAMESPACE_MATH,
686             XML_ANNOTATION, sal_True, sal_False);
687         GetDocHandler()->characters(OUString( aText ));
688     }
689     delete pSemantics;
690 }
691 
692 void SmXMLExport::GetViewSettings( Sequence < PropertyValue >& aProps)
693 {
694     uno::Reference <frame::XModel> xModel = GetModel();
695     if ( !xModel.is() )
696         return;
697 
698     uno::Reference <lang::XUnoTunnel> xTunnel;
699     xTunnel = uno::Reference <lang::XUnoTunnel> (xModel,uno::UNO_QUERY);
700     SmModel *pModel = reinterpret_cast<SmModel *>
701         (xTunnel->getSomething(SmModel::getUnoTunnelId()));
702 
703     if ( !pModel )
704         return;
705 
706     SmDocShell *pDocShell =
707         static_cast<SmDocShell*>(pModel->GetObjectShell());
708     if ( !pDocShell )
709         return;
710 
711     aProps.realloc( 4 );
712     PropertyValue *pValue = aProps.getArray();
713     sal_Int32 nIndex = 0;
714 
715     Rectangle aRect( pDocShell->GetVisArea() );
716 
717     pValue[nIndex].Name = OUString( RTL_CONSTASCII_USTRINGPARAM ( "ViewAreaTop") );
718     pValue[nIndex++].Value <<= aRect.Top();
719 
720     pValue[nIndex].Name = OUString( RTL_CONSTASCII_USTRINGPARAM ( "ViewAreaLeft") );
721     pValue[nIndex++].Value <<= aRect.Left();
722 
723     pValue[nIndex].Name = OUString( RTL_CONSTASCII_USTRINGPARAM ( "ViewAreaWidth") );
724     pValue[nIndex++].Value <<= aRect.GetWidth();
725 
726     pValue[nIndex].Name = OUString( RTL_CONSTASCII_USTRINGPARAM ( "ViewAreaHeight") );
727     pValue[nIndex++].Value <<= aRect.GetHeight();
728 }
729 
730 void SmXMLExport::GetConfigurationSettings( Sequence < PropertyValue > & rProps)
731 {
732     Reference < XPropertySet > xProps ( GetModel(), UNO_QUERY );
733     if ( xProps.is() )
734     {
735         Reference< XPropertySetInfo > xPropertySetInfo = xProps->getPropertySetInfo();
736         if (xPropertySetInfo.is())
737         {
738             Sequence< Property > aProps = xPropertySetInfo->getProperties();
739             sal_Int32 nCount(aProps.getLength());
740             if (nCount > 0)
741             {
742                 rProps.realloc(nCount);
743                 PropertyValue* pProps = rProps.getArray();
744                 if (pProps)
745                 {
746                     SmConfig *pConfig = SM_MOD()->GetConfig();
747                     const bool bUsedSymbolsOnly = pConfig ? pConfig->IsSaveOnlyUsedSymbols() : false;
748 
749                     const OUString sFormula ( RTL_CONSTASCII_USTRINGPARAM ( "Formula" ) );
750                     const OUString sBasicLibraries ( RTL_CONSTASCII_USTRINGPARAM ( "BasicLibraries" ) );
751                     const OUString sDialogLibraries ( RTL_CONSTASCII_USTRINGPARAM ( "DialogLibraries" ) );
752                     const OUString sRuntimeUID ( RTL_CONSTASCII_USTRINGPARAM ( "RuntimeUID" ) );
753                     for (sal_Int32 i = 0; i < nCount; i++, pProps++)
754                     {
755                         const OUString &rPropName = aProps[i].Name;
756                         if (rPropName != sFormula &&
757                             rPropName != sBasicLibraries &&
758                             rPropName != sDialogLibraries &&
759                             rPropName != sRuntimeUID)
760                         {
761                             pProps->Name = rPropName;
762 
763                             rtl::OUString aActualName( rPropName );
764 
765                             // handle 'save used symbols only'
766                             if (bUsedSymbolsOnly && rPropName.equalsAscii("Symbols"))
767                                 aActualName = OUString( RTL_CONSTASCII_USTRINGPARAM ( "UserDefinedSymbolsInUse" ) );
768 
769                             pProps->Value = xProps->getPropertyValue( aActualName );
770                         }
771                     }
772                 }
773             }
774         }
775     }
776 }
777 
778 void SmXMLExport::ExportLine(const SmNode *pNode, int nLevel)
779 {
780     ExportExpression(pNode, nLevel);
781 }
782 
783 void SmXMLExport::ExportBinaryHorizontal(const SmNode *pNode, int nLevel)
784 {
785     ExportExpression(pNode, nLevel);
786 }
787 
788 void SmXMLExport::ExportUnaryHorizontal(const SmNode *pNode, int nLevel)
789 {
790     ExportExpression(pNode, nLevel);
791 }
792 
793 void SmXMLExport::ExportExpression(const SmNode *pNode, int nLevel)
794 {
795     SvXMLElementExport *pRow=0;
796     sal_uLong  nSize = pNode->GetNumSubNodes();
797 
798     // #i115443: nodes of type expression always need to be grouped with mrow statement
799     if (nSize > 1 || (pNode && pNode->GetType() == NEXPRESSION))
800         pRow = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MROW, sal_True, sal_True);
801 
802     //if (nSize)
803     //{
804         for (sal_uInt16 i = 0; i < nSize; i++)
805             if (const SmNode *pTemp = pNode->GetSubNode(i))
806                 ExportNodes(pTemp, nLevel+1);
807     //}
808 #if 0
809     else
810     {
811         //This saves us from situations like "a newline" where the
812         //lack of a term following the newline would otherwise create
813         //a incorrect token like <mtr/>
814         SvXMLElementExport aDummy(*this, XML_NAMESPACE_MATH, XML_MI, sal_True, sal_False);
815         sal_Unicode nArse[2] = {'\n','\0'};
816         GetDocHandler()->characters(nArse);
817     }
818 #endif
819 
820     delete pRow;
821 }
822 
823 void SmXMLExport::ExportBinaryVertical(const SmNode *pNode, int nLevel)
824 {
825     DBG_ASSERT(pNode->GetNumSubNodes()==3,"Bad Fraction");
826     SvXMLElementExport aFraction(*this, XML_NAMESPACE_MATH, XML_MFRAC, sal_True, sal_True);
827     ExportNodes(pNode->GetSubNode(0), nLevel);
828     ExportNodes(pNode->GetSubNode(2), nLevel);
829 }
830 
831 void SmXMLExport::ExportTable(const SmNode *pNode, int nLevel)
832 {
833     SvXMLElementExport *pTable=0;
834 
835     sal_uInt16 nSize = pNode->GetNumSubNodes();
836 
837     //If the list ends in newline then the last entry has
838     //no subnodes, the newline is superfulous so we just drop
839     //the last node, inclusion would create a bad MathML
840     //table
841     if (nSize >= 1 && pNode->GetSubNode(nSize-1)->GetNumSubNodes() == 0)
842         --nSize;
843 
844     // try to avoid creating a mtable element when the formula consists only
845     // of a single output line
846     if (nLevel || (nSize >1))
847         pTable = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MTABLE, sal_True, sal_True);
848 
849     for (sal_uInt16 i = 0; i < nSize; i++)
850         if (const SmNode *pTemp = pNode->GetSubNode(i))
851         {
852             SvXMLElementExport *pRow=0;
853             SvXMLElementExport *pCell=0;
854             if (pTable)
855             {
856                 pRow  = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MTR, sal_True, sal_True);
857                 pCell = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MTD, sal_True, sal_True);
858             }
859             ExportNodes(pTemp, nLevel+1);
860             delete pCell;
861             delete pRow;
862         }
863 
864     delete pTable;
865 }
866 
867 void SmXMLExport::ExportMath(const SmNode *pNode, int /*nLevel*/)
868 {
869     const SmMathSymbolNode *pTemp = static_cast<const SmMathSymbolNode *>(pNode);
870     SvXMLElementExport aMath(*this, XML_NAMESPACE_MATH, XML_MO, sal_True, sal_False);
871     sal_Unicode nArse[2];
872     nArse[0] = pTemp->GetText().GetChar(0);
873     sal_Unicode cTmp = ConvertMathToMathML( nArse[0] );
874     if (cTmp != 0)
875         nArse[0] = cTmp;
876     DBG_ASSERT(nArse[0] != 0xffff,"Non existant symbol");
877     nArse[1] = 0;
878     GetDocHandler()->characters(nArse);
879 }
880 
881 void SmXMLExport::ExportText(const SmNode *pNode, int /*nLevel*/)
882 {
883     SvXMLElementExport *pText;
884     const SmTextNode *pTemp = static_cast<const SmTextNode *>(pNode);
885     switch (pNode->GetToken().eType)
886     {
887         default:
888         case TIDENT:
889         {
890             //Note that we change the fontstyle to italic for strings that
891             //are italic and longer than a single character.
892             sal_Bool bIsItalic = IsItalic( pTemp->GetFont() );
893             if ((pTemp->GetText().Len() > 1) && bIsItalic)
894                 AddAttribute(XML_NAMESPACE_MATH, XML_MATHVARIANT, XML_ITALIC);
895             else if ((pTemp->GetText().Len() == 1) && !bIsItalic)
896                 AddAttribute(XML_NAMESPACE_MATH, XML_MATHVARIANT, XML_NORMAL);
897             pText = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MI,sal_True,sal_False);
898             break;
899         }
900         case TNUMBER:
901             pText = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MN,sal_True,sal_False);
902             break;
903         case TTEXT:
904             pText = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MTEXT,sal_True,sal_False);
905             break;
906         }
907     GetDocHandler()->characters(OUString(pTemp->GetText().GetBuffer()));
908     delete pText;
909 }
910 
911 void SmXMLExport::ExportBlank(const SmNode * /*pNode*/, int /*nLevel*/)
912 {
913     //!! exports an empty <mi> tag since for example "~_~" is allowed in
914     //!! Math (so it has no sense at all) but must not result in an empty
915     //!! <msub> tag in MathML !!
916 
917     SvXMLElementExport *pText;
918     //const SmBlankNode *pTemp = static_cast<const SmBlankNode *>(pNode);
919 
920     pText = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MI, sal_True, sal_False);
921 
922     GetDocHandler()->characters( OUString() );
923     delete pText;
924 }
925 
926 void SmXMLExport::ExportSubSupScript(const SmNode *pNode, int nLevel)
927 {
928     const SmNode *pSub  = 0;
929     const SmNode *pSup  = 0;
930     const SmNode *pCSub = 0;
931     const SmNode *pCSup = 0;
932     const SmNode *pLSub = 0;
933     const SmNode *pLSup = 0;
934     SvXMLElementExport *pThing = 0, *pThing2 = 0;
935 
936     //if we have prescripts at all then we must use the tensor notation
937 
938     //This is one of those excellent locations where scope is vital to
939     //arrange the construction and destruction of the element helper
940     //classes correctly
941     pLSub = pNode->GetSubNode(LSUB+1);
942     pLSup = pNode->GetSubNode(LSUP+1);
943     if (pLSub || pLSup)
944     {
945         SvXMLElementExport aMultiScripts(*this, XML_NAMESPACE_MATH,
946             XML_MMULTISCRIPTS, sal_True, sal_True);
947 
948 
949         if (NULL != (pCSub = pNode->GetSubNode(CSUB+1))
950             && NULL != (pCSup = pNode->GetSubNode(CSUP+1)))
951         {
952             pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
953                 XML_MUNDEROVER, sal_True,sal_True);
954         }
955         else if (NULL != (pCSub = pNode->GetSubNode(CSUB+1)))
956         {
957             pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
958                 XML_MUNDER, sal_True,sal_True);
959         }
960         else if (NULL != (pCSup = pNode->GetSubNode(CSUP+1)))
961         {
962             pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
963                 XML_MOVER, sal_True,sal_True);
964         }
965 
966         ExportNodes(pNode->GetSubNode(0), nLevel+1);    //Main Term
967 
968         if (pCSub)
969             ExportNodes(pCSub, nLevel+1);
970         if (pCSup)
971             ExportNodes(pCSup, nLevel+1);
972         delete pThing2;
973 
974         pSub = pNode->GetSubNode(RSUB+1);
975         pSup = pNode->GetSubNode(RSUP+1);
976         if (pSub || pSup)
977         {
978             if (pSub)
979                 ExportNodes(pSub, nLevel+1);
980             else
981             {
982                 SvXMLElementExport aNone(*this, XML_NAMESPACE_MATH, XML_NONE,sal_True,sal_True);
983             }
984             if (pSup)
985                 ExportNodes(pSup, nLevel+1);
986             else
987             {
988                 SvXMLElementExport aNone(*this, XML_NAMESPACE_MATH, XML_NONE,sal_True,sal_True);
989             }
990         }
991 
992         //Seperator element between suffix and prefix sub/sup pairs
993         {
994             SvXMLElementExport aPrescripts(*this, XML_NAMESPACE_MATH,
995                 XML_MPRESCRIPTS, sal_True,sal_True);
996         }
997 
998         if (pLSub)
999             ExportNodes(pLSub, nLevel+1);
1000         else
1001         {
1002             SvXMLElementExport aNone(*this, XML_NAMESPACE_MATH, XML_NONE,
1003                 sal_True,sal_True);
1004 
1005         }
1006         if (pLSup)
1007             ExportNodes(pLSup, nLevel+1);
1008         else
1009         {
1010             SvXMLElementExport aNone(*this, XML_NAMESPACE_MATH, XML_NONE,
1011                 sal_True,sal_True);
1012 
1013         }
1014     }
1015     else
1016     {
1017         if (NULL != (pSub = pNode->GetSubNode(RSUB+1)) &&
1018             NULL != (pSup = pNode->GetSubNode(RSUP+1)))
1019         {
1020             pThing = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
1021                 XML_MSUBSUP, sal_True,sal_True);
1022         }
1023         else if (NULL != (pSub = pNode->GetSubNode(RSUB+1)))
1024         {
1025             pThing = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MSUB,
1026                 sal_True,sal_True);
1027         }
1028         else if (NULL != (pSup = pNode->GetSubNode(RSUP+1)))
1029         {
1030             pThing = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MSUP,
1031                 sal_True,sal_True);
1032         }
1033 
1034         if (NULL != (pCSub = pNode->GetSubNode(CSUB+1))
1035             && NULL != (pCSup=pNode->GetSubNode(CSUP+1)))
1036         {
1037             pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
1038                 XML_MUNDEROVER, sal_True,sal_True);
1039         }
1040         else if (NULL != (pCSub = pNode->GetSubNode(CSUB+1)))
1041         {
1042             pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
1043                 XML_MUNDER, sal_True,sal_True);
1044         }
1045         else if (NULL != (pCSup = pNode->GetSubNode(CSUP+1)))
1046         {
1047             pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
1048                 XML_MOVER, sal_True,sal_True);
1049         }
1050         ExportNodes(pNode->GetSubNode(0), nLevel+1);    //Main Term
1051 
1052         if (pCSub)
1053             ExportNodes(pCSub, nLevel+1);
1054         if (pCSup)
1055             ExportNodes(pCSup, nLevel+1);
1056         delete pThing2;
1057 
1058         if (pSub)
1059             ExportNodes(pSub, nLevel+1);
1060         if (pSup)
1061             ExportNodes(pSup, nLevel+1);
1062         delete pThing;
1063     }
1064 }
1065 
1066 void SmXMLExport::ExportBrace(const SmNode *pNode, int nLevel)
1067 {
1068     const SmNode *pTemp;
1069     const SmNode *pLeft=pNode->GetSubNode(0);
1070     const SmNode *pRight=pNode->GetSubNode(2);
1071     SvXMLElementExport *pFences=0,*pRow=0;
1072     if ( ((pLeft) && (pLeft->GetToken().eType != TNONE)) &&
1073         ((pRight) && (pRight->GetToken().eType != TNONE)) &&
1074         (pNode->GetScaleMode() == SCALE_HEIGHT))
1075     {
1076         sal_Unicode nArse[2];
1077         nArse[1] = 0;
1078         nArse[0] = static_cast<
1079             const SmMathSymbolNode* >(pLeft)->GetText().GetChar(0);
1080         DBG_ASSERT(nArse[0] != 0xffff,"Non existant symbol");
1081         AddAttribute(XML_NAMESPACE_MATH, XML_OPEN,nArse);
1082         nArse[0] = static_cast<
1083             const SmMathSymbolNode* >(pRight)->GetText().GetChar(0);
1084         DBG_ASSERT(nArse[0] != 0xffff,"Non existant symbol");
1085         AddAttribute(XML_NAMESPACE_MATH, XML_CLOSE,nArse);
1086         pFences = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MFENCED,
1087             sal_True,sal_True);
1088     }
1089     else if (pLeft && (pLeft->GetToken().eType != TNONE))
1090     {
1091         pRow = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MROW,
1092             sal_True, sal_True);
1093         if (pNode->GetScaleMode() == SCALE_HEIGHT)
1094             AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_TRUE);
1095         else
1096             AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_FALSE);
1097         ExportNodes(pLeft, nLevel+1);
1098     }
1099     else
1100         pRow = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MROW,
1101             sal_True, sal_True);
1102 
1103     if (NULL != (pTemp = pNode->GetSubNode(1)))
1104         ExportNodes(pTemp, nLevel+1);
1105     if (pFences)
1106         delete pFences;
1107     else if (pRight && (pRight->GetToken().eType != TNONE))
1108     {
1109         if (pNode->GetScaleMode() == SCALE_HEIGHT)
1110             AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_TRUE);
1111         else
1112             AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_FALSE);
1113         ExportNodes(pRight, nLevel+1);
1114     }
1115     delete pRow;
1116 }
1117 
1118 void SmXMLExport::ExportRoot(const SmNode *pNode, int nLevel)
1119 {
1120     if (pNode->GetSubNode(0))
1121     {
1122         SvXMLElementExport aRoot(*this, XML_NAMESPACE_MATH, XML_MROOT,sal_True,
1123             sal_True);
1124         ExportNodes(pNode->GetSubNode(2), nLevel+1);
1125         ExportNodes(pNode->GetSubNode(0), nLevel+1);
1126     }
1127     else
1128     {
1129         SvXMLElementExport aSqrt(*this, XML_NAMESPACE_MATH, XML_MSQRT,sal_True,
1130             sal_True);
1131         ExportNodes(pNode->GetSubNode(2), nLevel+1);
1132     }
1133 }
1134 
1135 void SmXMLExport::ExportOperator(const SmNode *pNode, int nLevel)
1136 {
1137     /*we need to either use content or font and size attributes
1138      *here*/
1139 #if 0
1140     {
1141     SvXMLElementExport aMath(*this, XML_NAMESPACE_MATH, XML_MO,
1142         sal_True,sal_False);
1143     SmTextNode *pTemp = (SmTextNode *)pNode->GetSubNode(0);
1144     GetDocHandler()->characters(pTemp->GetText());
1145     }
1146 #endif
1147     SvXMLElementExport aRow(*this, XML_NAMESPACE_MATH, XML_MROW,
1148         sal_True, sal_True);
1149     ExportNodes(pNode->GetSubNode(0), nLevel+1);
1150     ExportNodes(pNode->GetSubNode(1), nLevel+1);
1151 }
1152 
1153 void SmXMLExport::ExportAttributes(const SmNode *pNode, int nLevel)
1154 {
1155     SvXMLElementExport *pElement=0;
1156 
1157     if (pNode->GetToken().eType == TUNDERLINE)
1158     {
1159         AddAttribute(XML_NAMESPACE_MATH, XML_ACCENTUNDER,
1160             XML_TRUE);
1161         pElement = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MUNDER,
1162             sal_True,sal_True);
1163     }
1164     else if (pNode->GetToken().eType != TOVERSTRIKE)
1165     {
1166         AddAttribute(XML_NAMESPACE_MATH, XML_ACCENT,
1167             XML_TRUE);
1168         pElement = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MOVER,
1169             sal_True,sal_True);
1170     }
1171 
1172     ExportNodes(pNode->GetSubNode(1), nLevel+1);
1173     switch (pNode->GetToken().eType)
1174     {
1175         case TOVERLINE:
1176             {
1177             //proper entity support required
1178             SvXMLElementExport aMath(*this, XML_NAMESPACE_MATH, XML_MO,
1179                 sal_True,sal_True);
1180 #if 0
1181             GetDocHandler()->characters(
1182                 OUString(RTL_CONSTASCII_USTRINGPARAM("&overbar;")));
1183 #else
1184             sal_Unicode nArse[2] = {0xAF,0x00};
1185 #endif
1186             GetDocHandler()->characters(nArse);
1187             }
1188             break;
1189         case TUNDERLINE:
1190             {
1191             //proper entity support required
1192             SvXMLElementExport aMath(*this, XML_NAMESPACE_MATH, XML_MO,
1193                 sal_True,sal_True);
1194 #if 0
1195             GetDocHandler()->characters(
1196                 OUString(RTL_CONSTASCII_USTRINGPARAM("&underbar;")));
1197 #else
1198             sal_Unicode nArse[2] = {0x0332,0x00};
1199 #endif
1200             GetDocHandler()->characters(nArse);
1201             }
1202             break;
1203         case TOVERSTRIKE:
1204             break;
1205         default:
1206             ExportNodes(pNode->GetSubNode(0), nLevel+1);
1207             break;
1208     }
1209     delete pElement;
1210 }
1211 
1212 static bool lcl_HasEffectOnMathvariant( const SmTokenType eType )
1213 {
1214     return  eType == TBOLD || eType == TNBOLD ||
1215             eType == TITALIC || eType == TNBOLD ||
1216             eType == TSANS || eType == TSERIF || eType == TFIXED;
1217 }
1218 
1219 void SmXMLExport::ExportFont(const SmNode *pNode, int nLevel)
1220 {
1221     SvXMLElementExport *pElement = 0;
1222 
1223     //
1224     // gather the mathvariant attribut relevant data from all
1225     // successively following SmFontNodes...
1226     //
1227     int nBold   = -1;   // for the following variables: -1 = yet undefined; 0 = false; 1 = true;
1228     int nItalic = -1;   // for the following variables: -1 = yet undefined; 0 = false; 1 = true;
1229     int nSansSerifFixed   = -1;
1230     SmTokenType eNodeType = TUNKNOWN;
1231     while (lcl_HasEffectOnMathvariant( (eNodeType = pNode->GetToken().eType) ))
1232     {
1233         switch (eNodeType)
1234         {
1235             case TBOLD      : nBold   = 1; break;
1236             case TNBOLD     : nBold   = 0; break;
1237             case TITALIC    : nItalic = 1; break;
1238             case TNITALIC   : nItalic = 0; break;
1239             case TSANS      : nSansSerifFixed  = 0; break;
1240             case TSERIF     : nSansSerifFixed  = 1; break;
1241             case TFIXED     : nSansSerifFixed  = 2; break;
1242             default:
1243                 DBG_ASSERT( 0, "unexpected case" );
1244         }
1245         // According to the parser every node that is to be evaluated heres
1246         // has a single non-zero subnode at index 1!! Thus we only need to check
1247         // that single node for follow-up nodes that have an effect on the attribute.
1248         if (pNode->GetNumSubNodes() > 1 && pNode->GetSubNode(1) &&
1249             lcl_HasEffectOnMathvariant( pNode->GetSubNode(1)->GetToken().eType))
1250         {
1251             pNode = pNode->GetSubNode(1);
1252         }
1253         else
1254             break;
1255     }
1256 
1257     switch (pNode->GetToken().eType)
1258     {
1259         //wrap a phantom element around everything*/
1260         case TPHANTOM:
1261             pElement = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
1262                 XML_MPHANTOM, sal_True,sal_True);
1263             break;
1264         case TBLACK:
1265             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_BLACK);
1266             break;
1267         case TWHITE:
1268             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_WHITE);
1269             break;
1270         case TRED:
1271             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_RED);
1272             break;
1273         case TGREEN:
1274             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_GREEN);
1275             break;
1276         case TBLUE:
1277             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_BLUE);
1278             break;
1279         case TCYAN:
1280             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_AQUA);
1281             break;
1282         case TMAGENTA:
1283             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_FUCHSIA);
1284             break;
1285         case TYELLOW:
1286             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_YELLOW);
1287             break;
1288         case TSIZE:
1289             {
1290                 const SmFontNode *pFontNode = static_cast<const SmFontNode *>(pNode);
1291                 const Fraction &aFrac = pFontNode->GetSizeParameter();
1292 
1293                 OUStringBuffer sStrBuf;
1294                 switch(pFontNode->GetSizeType())
1295                 {
1296                     case FNTSIZ_MULTIPLY:
1297                         SvXMLUnitConverter::convertDouble(sStrBuf,
1298                             static_cast<double>(aFrac*Fraction(100.00)));
1299                         sStrBuf.append(static_cast<sal_Unicode>('%'));
1300                         break;
1301                     case FNTSIZ_DIVIDE:
1302                         SvXMLUnitConverter::convertDouble(sStrBuf,
1303                             static_cast<double>(Fraction(100.00)/aFrac));
1304                         sStrBuf.append(static_cast<sal_Unicode>('%'));
1305                         break;
1306                     case FNTSIZ_ABSOLUT:
1307                         SvXMLUnitConverter::convertDouble(sStrBuf,
1308                             static_cast<double>(aFrac));
1309                         sStrBuf.append(
1310                             GetXMLToken(XML_UNIT_PT));
1311                         break;
1312                     default:
1313                         {
1314                             //The problem here is that the wheels fall off because
1315                             //font size is stored in 100th's of a mm not pts, and
1316                             //rounding errors take their toll on the original
1317                             //value specified in points.
1318 
1319                             //Must fix StarMath to retain the original pt values
1320                             Fraction aTemp = Sm100th_mmToPts(pFontNode->GetFont().
1321                                 GetSize().Height());
1322 
1323                             if (pFontNode->GetSizeType() == FNTSIZ_MINUS)
1324                                 aTemp-=aFrac;
1325                             else
1326                                 aTemp+=aFrac;
1327 
1328                             double mytest = static_cast<double>(aTemp);
1329 
1330                             mytest = ::rtl::math::round(mytest,1);
1331                             SvXMLUnitConverter::convertDouble(sStrBuf,mytest);
1332                             sStrBuf.append(GetXMLToken(XML_UNIT_PT));
1333                         }
1334                         break;
1335                 }
1336 
1337                 OUString sStr(sStrBuf.makeStringAndClear());
1338                 AddAttribute(XML_NAMESPACE_MATH, XML_MATHSIZE, sStr);
1339             }
1340             break;
1341         case TBOLD:
1342         case TITALIC:
1343         case TNBOLD:
1344         case TNITALIC:
1345         case TFIXED:
1346         case TSANS:
1347         case TSERIF:
1348             {
1349                 // nBold:   -1 = yet undefined; 0 = false; 1 = true;
1350                 // nItalic: -1 = yet undefined; 0 = false; 1 = true;
1351                 // nSansSerifFixed: -1 = undefined; 0 = sans; 1 = serif; 2 = fixed;
1352                 const sal_Char *pText = "normal";
1353                 if (nSansSerifFixed == -1 || nSansSerifFixed == 1)
1354                 {
1355                     pText = "normal";
1356                     if (nBold == 1 && nItalic != 1)
1357                         pText = "bold";
1358                     else if (nBold != 1 && nItalic == 1)
1359                         pText = "italic";
1360                     else if (nBold == 1 && nItalic == 1)
1361                         pText = "bold-italic";
1362                 }
1363                 else if (nSansSerifFixed == 0)
1364                 {
1365                     pText = "sans-serif";
1366                     if (nBold == 1 && nItalic != 1)
1367                         pText = "bold-sans-serif";
1368                     else if (nBold != 1 && nItalic == 1)
1369                         pText = "sans-serif-italic";
1370                     else if (nBold == 1 && nItalic == 1)
1371                         pText = "sans-serif-bold-italic";
1372                 }
1373                 else if (nSansSerifFixed == 2)
1374                     pText = "monospace";    // no modifiers allowed for monospace ...
1375                 else
1376                 {
1377                     DBG_ASSERT( 0, "unexpected case" );
1378                 }
1379                 AddAttribute(XML_NAMESPACE_MATH, XML_MATHVARIANT, A2OU(pText));
1380             }
1381             break;
1382         default:
1383             break;
1384 
1385     }
1386 #if 0
1387     if (pNode->GetNumSubNodes() > 1) //or in the future is a node that
1388                                      //cannot take the currently supported
1389                                      //properties
1390 #endif
1391     //for now we will just always export with a style and not worry about
1392     //anyone else for the moment.
1393     {
1394         //wrap a style around it
1395         SvXMLElementExport aStyle(*this, XML_NAMESPACE_MATH, XML_MSTYLE, sal_True,sal_True);
1396         ExportExpression(pNode, nLevel);
1397     }
1398 #if 0
1399     else
1400         ExportNodes(pNode->GetSubNode(0), nLevel+1);
1401 #endif
1402 
1403     delete pElement;
1404 }
1405 
1406 
1407 void SmXMLExport::ExportVerticalBrace(const SmNode *pNode, int nLevel)
1408 {
1409     //Place the overbrace value OVER a vertical brace and then place that
1410     //expression OVER the overbrace value, If someone can find a
1411     //dedicated term in MathML to handle this overbrace/underbrace concept
1412     //let me know. C.
1413     XMLTokenEnum which;
1414 
1415     switch (pNode->GetToken().eType)
1416     {
1417         case TOVERBRACE:
1418         default:
1419             which = XML_MOVER;
1420             break;
1421         case TUNDERBRACE:
1422             which = XML_MUNDER;
1423             break;
1424     }
1425 
1426     DBG_ASSERT(pNode->GetNumSubNodes()==3,"Bad Vertical Brace");
1427     SvXMLElementExport aOver1(*this, XML_NAMESPACE_MATH,which, sal_True, sal_True);
1428     {//Scoping
1429         // using accents will draw the over-/underbraces too close to the base
1430         // see http://www.w3.org/TR/MathML2/chapter3.html#id.3.4.5.2
1431         // also XML_ACCENT is illegal with XML_MUNDER. Thus no XML_ACCENT attribut here!
1432 //        AddAttribute(XML_NAMESPACE_MATH, XML_ACCENT, XML_sal_True);
1433         SvXMLElementExport aOver2(*this, XML_NAMESPACE_MATH,which, sal_True, sal_True);
1434         ExportNodes(pNode->GetSubNode(0), nLevel);
1435         ExportNodes(pNode->GetSubNode(1), nLevel);
1436     }
1437     ExportNodes(pNode->GetSubNode(2), nLevel);
1438 }
1439 
1440 void SmXMLExport::ExportMatrix(const SmNode *pNode, int nLevel)
1441 {
1442     SvXMLElementExport aTable(*this, XML_NAMESPACE_MATH, XML_MTABLE, sal_True, sal_True);
1443     const SmMatrixNode *pMatrix = static_cast<const SmMatrixNode *>(pNode);
1444     sal_uInt16 i=0;
1445     for (sal_uLong y = 0; y < pMatrix->GetNumRows(); y++)
1446     {
1447         SvXMLElementExport aRow(*this, XML_NAMESPACE_MATH, XML_MTR, sal_True, sal_True);
1448         for (sal_uLong x = 0; x < pMatrix->GetNumCols(); x++)
1449             if (const SmNode *pTemp = pNode->GetSubNode(i++))
1450             {
1451                 SvXMLElementExport aCell(*this, XML_NAMESPACE_MATH, XML_MTD, sal_True, sal_True);
1452                 ExportNodes(pTemp, nLevel+1);
1453             }
1454     }
1455 }
1456 
1457 void SmXMLExport::ExportNodes(const SmNode *pNode, int nLevel)
1458 {
1459     if (!pNode)
1460         return;
1461     switch(pNode->GetType())
1462     {
1463         case NTABLE:
1464             ExportTable(pNode, nLevel);
1465             break;
1466         case NALIGN:
1467         case NBRACEBODY:
1468         case NEXPRESSION:
1469             ExportExpression(pNode, nLevel);
1470             break;
1471         case NLINE:
1472             ExportLine(pNode, nLevel);
1473             break;
1474         case NTEXT:
1475             ExportText(pNode, nLevel);
1476             break;
1477         case NSPECIAL: //NSPECIAL requires some sort of Entity preservation in the XML engine.
1478         case NGLYPH_SPECIAL:
1479         case NMATH:
1480             {
1481                 sal_Unicode cTmp = 0;
1482                 const SmTextNode *pTemp = static_cast< const SmTextNode * >(pNode);
1483                 if (pTemp->GetText().Len() > 0)
1484                     cTmp = ConvertMathToMathML( pTemp->GetText().GetChar(0) );
1485                 if (cTmp == 0)
1486                 {
1487                     // no conversion to MathML implemented -> export it as text
1488                     // thus at least it will not vanish into nothing
1489                     ExportText(pNode, nLevel);
1490                 }
1491                 else
1492                 {
1493                     //To fully handle generic MathML we need to implement the full
1494                     //operator dictionary, we will generate MathML with explicit
1495                     //stretchiness for now.
1496                     sal_Int16 nLength = GetAttrList().getLength();
1497                     sal_Bool bAddStretch=sal_True;
1498                     for ( sal_Int16 i = 0; i < nLength; i++ )
1499                     {
1500                         OUString sLocalName;
1501                         sal_uInt16 nPrefix = GetNamespaceMap().GetKeyByAttrName(
1502                             GetAttrList().getNameByIndex(i), &sLocalName );
1503 
1504                         if ( ( XML_NAMESPACE_MATH == nPrefix ) &&
1505                             IsXMLToken(sLocalName, XML_STRETCHY) )
1506                         {
1507                             bAddStretch = sal_False;
1508                             break;
1509                         }
1510                     }
1511                     if (bAddStretch)
1512                     {
1513                         AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_FALSE);
1514                     }
1515                     ExportMath(pNode, nLevel);
1516                 }
1517             }
1518             break;
1519         case NPLACE:
1520             ExportMath(pNode, nLevel);
1521             break;
1522         case NBINHOR:
1523             ExportBinaryHorizontal(pNode, nLevel);
1524             break;
1525         case NUNHOR:
1526             ExportUnaryHorizontal(pNode, nLevel);
1527             break;
1528         case NBRACE:
1529             ExportBrace(pNode, nLevel);
1530             break;
1531         case NBINVER:
1532             ExportBinaryVertical(pNode, nLevel);
1533             break;
1534         case NSUBSUP:
1535             ExportSubSupScript(pNode, nLevel);
1536             break;
1537         case NROOT:
1538             ExportRoot(pNode, nLevel);
1539             break;
1540         case NOPER:
1541             ExportOperator(pNode, nLevel);
1542             break;
1543         case NATTRIBUT:
1544             ExportAttributes(pNode, nLevel);
1545             break;
1546         case NFONT:
1547             ExportFont(pNode, nLevel);
1548             break;
1549         case NVERTICAL_BRACE:
1550             ExportVerticalBrace(pNode, nLevel);
1551             break;
1552         case NMATRIX:
1553             ExportMatrix(pNode, nLevel);
1554             break;
1555         case NBLANK:
1556             ExportBlank(pNode, nLevel);
1557             break;
1558        default:
1559             DBG_ASSERT( 0, "Warning: failed to export a node?" );
1560             break;
1561 
1562 #if 0
1563         default:
1564             {
1565             sal_uLong  nSize = pNode->GetNumSubNodes();
1566             for (sal_uLong i = 0; i < nSize; i++)
1567                 if (SmNode *pTemp = pNode->GetSubNode(i))
1568                     ExportNodes(pTemp, nLevel+1);
1569             }
1570             break;
1571 #endif
1572     }
1573 }
1574 
1575 ////////////////////////////////////////////////////////////
1576 
1577