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