xref: /trunk/main/starmath/source/mathmlexport.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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 {
400     if ( rId.getLength() == 16 &&
401         0 == rtl_compareMemory( getUnoTunnelId().getConstArray(),
402         rId.getConstArray(), 16 ) )
403     return sal::static_int_cast< sal_Int64 >(reinterpret_cast< sal_uIntPtr >(this));
404 
405     return SvXMLExport::getSomething( rId );
406 }
407 
getUnoTunnelId()408 const uno::Sequence< sal_Int8 > & SmXMLExport::getUnoTunnelId() throw()
409 {
410     static uno::Sequence< sal_Int8 > * pSeq = 0;
411     if ( !pSeq )
412     {
413         osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() );
414         if ( !pSeq )
415         {
416             static uno::Sequence< sal_Int8 > aSeq( 16 );
417             rtl_createUuid( (sal_uInt8*)aSeq.getArray(), 0, sal_True );
418             pSeq = &aSeq;
419         }
420     }
421     return *pSeq;
422 }
423 
SmXMLExport_getImplementationName()424 OUString SAL_CALL SmXMLExport_getImplementationName() throw()
425 {
426     return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Math.XMLExporter" ) );
427 }
428 
SmXMLExport_getSupportedServiceNames()429 uno::Sequence< OUString > SAL_CALL SmXMLExport_getSupportedServiceNames()
430         throw()
431 {
432     const OUString aServiceName( EXPORT_SVC_NAME );
433     const uno::Sequence< OUString > aSeq( &aServiceName, 1 );
434     return aSeq;
435 }
436 
SmXMLExport_createInstance(const uno::Reference<lang::XMultiServiceFactory> & rSMgr)437 uno::Reference< uno::XInterface > SAL_CALL SmXMLExport_createInstance(
438     const uno::Reference< lang::XMultiServiceFactory > & rSMgr)
439 {
440     // #110680#
441     // return (cppu::OWeakObject*)new SmXMLExport( EXPORT_ALL );
442     // EXPORT_OASIS is required here although there is no difference between
443     // OOo and OASIS, because without the flag, a transformation to OOo would
444     // be chained in.
445     return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_OASIS|EXPORT_ALL );
446 }
447 
448 ////////////////////////////////////////////////////////////
449 
SmXMLExportMetaOOO_getImplementationName()450 OUString SAL_CALL SmXMLExportMetaOOO_getImplementationName() throw()
451 {
452     return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Math.XMLMetaExporter" ) );
453 }
454 
SmXMLExportMetaOOO_getSupportedServiceNames()455 uno::Sequence< OUString > SAL_CALL SmXMLExportMetaOOO_getSupportedServiceNames()
456     throw()
457 {
458     const OUString aServiceName( EXPORT_SVC_NAME );
459     const uno::Sequence< OUString > aSeq( &aServiceName, 1 );
460     return aSeq;
461 }
462 
SmXMLExportMetaOOO_createInstance(const uno::Reference<lang::XMultiServiceFactory> & rSMgr)463 uno::Reference< uno::XInterface > SAL_CALL SmXMLExportMetaOOO_createInstance(
464     const uno::Reference< lang::XMultiServiceFactory > & rSMgr)
465 {
466     // #110680#
467     // return (cppu::OWeakObject*)new SmXMLExport( EXPORT_META );
468     return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_META );
469 }
470 
471 ////////////////////////////////////////////////////////////
472 
SmXMLExportMeta_getImplementationName()473 OUString SAL_CALL SmXMLExportMeta_getImplementationName() throw()
474 {
475     return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Math.XMLOasisMetaExporter" ) );
476 }
477 
SmXMLExportMeta_getSupportedServiceNames()478 uno::Sequence< OUString > SAL_CALL SmXMLExportMeta_getSupportedServiceNames()
479 throw()
480 {
481     const OUString aServiceName( EXPORT_SVC_NAME );
482     const uno::Sequence< OUString > aSeq( &aServiceName, 1 );
483     return aSeq;
484 }
485 
SmXMLExportMeta_createInstance(const uno::Reference<lang::XMultiServiceFactory> & rSMgr)486 uno::Reference< uno::XInterface > SAL_CALL SmXMLExportMeta_createInstance(
487     const uno::Reference< lang::XMultiServiceFactory > & rSMgr)
488 {
489     // #110680#
490     // return (cppu::OWeakObject*)new SmXMLExport( EXPORT_META );
491     return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_OASIS|EXPORT_META );
492 }
493 
494 ////////////////////////////////////////////////////////////
495 
SmXMLExportSettingsOOO_getImplementationName()496 OUString SAL_CALL SmXMLExportSettingsOOO_getImplementationName() throw()
497 {
498     return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Math.XMLSettingsExporter" ) );
499 }
500 
SmXMLExportSettingsOOO_getSupportedServiceNames()501 uno::Sequence< OUString > SAL_CALL SmXMLExportSettingsOOO_getSupportedServiceNames()
502 throw()
503 {
504     const OUString aServiceName( EXPORT_SVC_NAME );
505     const uno::Sequence< OUString > aSeq( &aServiceName, 1 );
506     return aSeq;
507 }
508 
SmXMLExportSettingsOOO_createInstance(const uno::Reference<lang::XMultiServiceFactory> & rSMgr)509 uno::Reference< uno::XInterface > SAL_CALL SmXMLExportSettingsOOO_createInstance(
510     const uno::Reference< lang::XMultiServiceFactory > & rSMgr)
511 {
512     // #110680#
513     // return (cppu::OWeakObject*)new SmXMLExport( EXPORT_SETTINGS );
514     return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_SETTINGS );
515 }
516 
517 ////////////////////////////////////////////////////////////
518 
SmXMLExportSettings_getImplementationName()519 OUString SAL_CALL SmXMLExportSettings_getImplementationName() throw()
520 {
521     return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Math.XMLOasisSettingsExporter" ) );
522 }
523 
SmXMLExportSettings_getSupportedServiceNames()524 uno::Sequence< OUString > SAL_CALL SmXMLExportSettings_getSupportedServiceNames()
525 throw()
526 {
527     const OUString aServiceName( EXPORT_SVC_NAME );
528     const uno::Sequence< OUString > aSeq( &aServiceName, 1 );
529     return aSeq;
530 }
531 
SmXMLExportSettings_createInstance(const uno::Reference<lang::XMultiServiceFactory> & rSMgr)532 uno::Reference< uno::XInterface > SAL_CALL SmXMLExportSettings_createInstance(
533     const uno::Reference< lang::XMultiServiceFactory > & rSMgr)
534 {
535     // #110680#
536     // return (cppu::OWeakObject*)new SmXMLExport( EXPORT_SETTINGS );
537     return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_OASIS|EXPORT_SETTINGS );
538 }
539 
540 ////////////////////////////////////////////////////////////
541 
SmXMLExportContent_getImplementationName()542 OUString SAL_CALL SmXMLExportContent_getImplementationName() throw()
543 {
544     return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Math.XMLContentExporter" ) );
545 }
546 
SmXMLExportContent_getSupportedServiceNames()547 uno::Sequence< OUString > SAL_CALL SmXMLExportContent_getSupportedServiceNames()
548         throw()
549 {
550     const OUString aServiceName( EXPORT_SVC_NAME );
551     const uno::Sequence< OUString > aSeq( &aServiceName, 1 );
552     return aSeq;
553 }
554 
SmXMLExportContent_createInstance(const uno::Reference<lang::XMultiServiceFactory> & rSMgr)555 uno::Reference< uno::XInterface > SAL_CALL SmXMLExportContent_createInstance(
556     const uno::Reference< lang::XMultiServiceFactory > & rSMgr)
557 {
558     // #110680#
559     // return (cppu::OWeakObject*)new SmXMLExport( EXPORT_CONTENT );
560     // The EXPORT_OASIS flag is only required to avoid that a transformer is
561     // chanied in
562     return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_OASIS|EXPORT_CONTENT );
563 }
564 
565 ////////////////////////////////////////////////////////////
566 
567 // XServiceInfo
568 // override empty method from parent class
getImplementationName()569 rtl::OUString SAL_CALL SmXMLExport::getImplementationName()
570 {
571     OUString aTxt;
572     switch( getExportFlags() )
573     {
574         case EXPORT_META:
575             aTxt = SmXMLExportMeta_getImplementationName();
576             break;
577         case EXPORT_SETTINGS:
578             aTxt = SmXMLExportSettings_getImplementationName();
579             break;
580         case EXPORT_CONTENT:
581             aTxt = SmXMLExportContent_getImplementationName();
582             break;
583         case EXPORT_ALL:
584         default:
585             aTxt = SmXMLExport_getImplementationName();
586             break;
587     }
588     return aTxt;
589 }
590 
exportDoc(enum XMLTokenEnum eClass)591 sal_uInt32 SmXMLExport::exportDoc(enum XMLTokenEnum eClass)
592 {
593     if ( (getExportFlags() & EXPORT_CONTENT) == 0 )
594     {
595         SvXMLExport::exportDoc( eClass );
596     }
597     else
598     {
599         uno::Reference <frame::XModel> xModel = GetModel();
600         uno::Reference <lang::XUnoTunnel> xTunnel;
601         xTunnel = uno::Reference <lang::XUnoTunnel> (xModel,uno::UNO_QUERY);
602         SmModel *pModel = reinterpret_cast<SmModel *>
603             (xTunnel->getSomething(SmModel::getUnoTunnelId()));
604 
605         if (pModel)
606         {
607             SmDocShell *pDocShell =
608                 static_cast<SmDocShell*>(pModel->GetObjectShell());
609             pTree = pDocShell->GetFormulaTree();
610             aText = pDocShell->GetText();
611         }
612 
613         GetDocHandler()->startDocument();
614 
615         /*Add xmlns line*/
616         SvXMLAttributeList &rList = GetAttrList();
617 
618         // make use of a default namespace
619         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)
620         _GetNamespaceMap().Add( OUString::createFromAscii(""), GetXMLToken(XML_N_MATH), XML_NAMESPACE_MATH );
621 
622         rList.AddAttribute(GetNamespaceMap().GetAttrNameByKey(XML_NAMESPACE_MATH_IDX),
623                 GetNamespaceMap().GetNameByKey( XML_NAMESPACE_MATH_IDX));
624 
625         //I think we need something like ImplExportEntities();
626         _ExportContent();
627         GetDocHandler()->endDocument();
628     }
629 
630     bSuccess=sal_True;
631     return 0;
632 }
633 
_ExportContent()634 void SmXMLExport::_ExportContent()
635 {
636     SvXMLElementExport aEquation(*this, XML_NAMESPACE_MATH, XML_MATH, sal_True, sal_True);
637     SvXMLElementExport *pSemantics=0;
638 
639     if (aText.Len())
640     {
641         pSemantics = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
642             XML_SEMANTICS, sal_True, sal_True);
643     }
644 
645     ExportNodes(pTree, 0);
646 
647     if (aText.Len())
648     {
649         // Convert symbol names
650         uno::Reference <frame::XModel> xModel = GetModel();
651         uno::Reference <lang::XUnoTunnel> xTunnel;
652         xTunnel = uno::Reference <lang::XUnoTunnel> (xModel,uno::UNO_QUERY);
653         SmModel *pModel = reinterpret_cast<SmModel *>
654             (xTunnel->getSomething(SmModel::getUnoTunnelId()));
655         SmDocShell *pDocShell = pModel ?
656             static_cast<SmDocShell*>(pModel->GetObjectShell()) : 0;
657         DBG_ASSERT( pDocShell, "doc shell missing" );
658         if (pDocShell)
659         {
660             SmParser &rParser = pDocShell->GetParser();
661             sal_Bool bVal = rParser.IsExportSymbolNames();
662             rParser.SetExportSymbolNames( sal_True );
663             SmNode *pTmpTree = rParser.Parse( aText );
664             aText = rParser.GetText();
665             delete pTmpTree;
666             rParser.SetExportSymbolNames( bVal );
667         }
668 
669         AddAttribute(XML_NAMESPACE_MATH, XML_ENCODING,
670             OUString(RTL_CONSTASCII_USTRINGPARAM("StarMath 5.0")));
671         SvXMLElementExport aAnnotation(*this, XML_NAMESPACE_MATH,
672             XML_ANNOTATION, sal_True, sal_False);
673         GetDocHandler()->characters(OUString( aText ));
674     }
675     delete pSemantics;
676 }
677 
GetViewSettings(Sequence<PropertyValue> & aProps)678 void SmXMLExport::GetViewSettings( Sequence < PropertyValue >& aProps)
679 {
680     uno::Reference <frame::XModel> xModel = GetModel();
681     if ( !xModel.is() )
682         return;
683 
684     uno::Reference <lang::XUnoTunnel> xTunnel;
685     xTunnel = uno::Reference <lang::XUnoTunnel> (xModel,uno::UNO_QUERY);
686     SmModel *pModel = reinterpret_cast<SmModel *>
687         (xTunnel->getSomething(SmModel::getUnoTunnelId()));
688 
689     if ( !pModel )
690         return;
691 
692     SmDocShell *pDocShell =
693         static_cast<SmDocShell*>(pModel->GetObjectShell());
694     if ( !pDocShell )
695         return;
696 
697     aProps.realloc( 4 );
698     PropertyValue *pValue = aProps.getArray();
699     sal_Int32 nIndex = 0;
700 
701     Rectangle aRect( pDocShell->GetVisArea() );
702 
703     pValue[nIndex].Name = OUString( RTL_CONSTASCII_USTRINGPARAM ( "ViewAreaTop") );
704     pValue[nIndex++].Value <<= aRect.Top();
705 
706     pValue[nIndex].Name = OUString( RTL_CONSTASCII_USTRINGPARAM ( "ViewAreaLeft") );
707     pValue[nIndex++].Value <<= aRect.Left();
708 
709     pValue[nIndex].Name = OUString( RTL_CONSTASCII_USTRINGPARAM ( "ViewAreaWidth") );
710     pValue[nIndex++].Value <<= aRect.GetWidth();
711 
712     pValue[nIndex].Name = OUString( RTL_CONSTASCII_USTRINGPARAM ( "ViewAreaHeight") );
713     pValue[nIndex++].Value <<= aRect.GetHeight();
714 }
715 
GetConfigurationSettings(Sequence<PropertyValue> & rProps)716 void SmXMLExport::GetConfigurationSettings( Sequence < PropertyValue > & rProps)
717 {
718     Reference < XPropertySet > xProps ( GetModel(), UNO_QUERY );
719     if ( xProps.is() )
720     {
721         Reference< XPropertySetInfo > xPropertySetInfo = xProps->getPropertySetInfo();
722         if (xPropertySetInfo.is())
723         {
724             Sequence< Property > aProps = xPropertySetInfo->getProperties();
725             sal_Int32 nCount(aProps.getLength());
726             if (nCount > 0)
727             {
728                 rProps.realloc(nCount);
729                 PropertyValue* pProps = rProps.getArray();
730                 if (pProps)
731                 {
732                     SmConfig *pConfig = SM_MOD()->GetConfig();
733                     const bool bUsedSymbolsOnly = pConfig ? pConfig->IsSaveOnlyUsedSymbols() : false;
734 
735                     const OUString sFormula ( RTL_CONSTASCII_USTRINGPARAM ( "Formula" ) );
736                     const OUString sBasicLibraries ( RTL_CONSTASCII_USTRINGPARAM ( "BasicLibraries" ) );
737                     const OUString sDialogLibraries ( RTL_CONSTASCII_USTRINGPARAM ( "DialogLibraries" ) );
738                     const OUString sRuntimeUID ( RTL_CONSTASCII_USTRINGPARAM ( "RuntimeUID" ) );
739                     for (sal_Int32 i = 0; i < nCount; i++, pProps++)
740                     {
741                         const OUString &rPropName = aProps[i].Name;
742                         if (rPropName != sFormula &&
743                             rPropName != sBasicLibraries &&
744                             rPropName != sDialogLibraries &&
745                             rPropName != sRuntimeUID)
746                         {
747                             pProps->Name = rPropName;
748 
749                             rtl::OUString aActualName( rPropName );
750 
751                             // handle 'save used symbols only'
752                             if (bUsedSymbolsOnly && rPropName.equalsAscii("Symbols"))
753                                 aActualName = OUString( RTL_CONSTASCII_USTRINGPARAM ( "UserDefinedSymbolsInUse" ) );
754 
755                             pProps->Value = xProps->getPropertyValue( aActualName );
756                         }
757                     }
758                 }
759             }
760         }
761     }
762 }
763 
ExportLine(const SmNode * pNode,int nLevel)764 void SmXMLExport::ExportLine(const SmNode *pNode, int nLevel)
765 {
766     ExportExpression(pNode, nLevel);
767 }
768 
ExportBinaryHorizontal(const SmNode * pNode,int nLevel)769 void SmXMLExport::ExportBinaryHorizontal(const SmNode *pNode, int nLevel)
770 {
771     ExportExpression(pNode, nLevel);
772 }
773 
ExportUnaryHorizontal(const SmNode * pNode,int nLevel)774 void SmXMLExport::ExportUnaryHorizontal(const SmNode *pNode, int nLevel)
775 {
776     ExportExpression(pNode, nLevel);
777 }
778 
ExportExpression(const SmNode * pNode,int nLevel)779 void SmXMLExport::ExportExpression(const SmNode *pNode, int nLevel)
780 {
781     SvXMLElementExport *pRow=0;
782     sal_uLong  nSize = pNode->GetNumSubNodes();
783 
784     // #i115443: nodes of type expression always need to be grouped with mrow statement
785     if (nSize > 1 || (pNode && pNode->GetType() == NEXPRESSION))
786         pRow = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MROW, sal_True, sal_True);
787 
788     //if (nSize)
789     //{
790         for (sal_uInt16 i = 0; i < nSize; i++)
791             if (const SmNode *pTemp = pNode->GetSubNode(i))
792                 ExportNodes(pTemp, nLevel+1);
793     //}
794 #if 0
795     else
796     {
797         //This saves us from situations like "a newline" where the
798         //lack of a term following the newline would otherwise create
799         //a incorrect token like <mtr/>
800         SvXMLElementExport aDummy(*this, XML_NAMESPACE_MATH, XML_MI, sal_True, sal_False);
801         sal_Unicode nArse[2] = {'\n','\0'};
802         GetDocHandler()->characters(nArse);
803     }
804 #endif
805 
806     delete pRow;
807 }
808 
ExportBinaryVertical(const SmNode * pNode,int nLevel)809 void SmXMLExport::ExportBinaryVertical(const SmNode *pNode, int nLevel)
810 {
811     DBG_ASSERT(pNode->GetNumSubNodes()==3,"Bad Fraction");
812     SvXMLElementExport aFraction(*this, XML_NAMESPACE_MATH, XML_MFRAC, sal_True, sal_True);
813     ExportNodes(pNode->GetSubNode(0), nLevel);
814     ExportNodes(pNode->GetSubNode(2), nLevel);
815 }
816 
ExportTable(const SmNode * pNode,int nLevel)817 void SmXMLExport::ExportTable(const SmNode *pNode, int nLevel)
818 {
819     SvXMLElementExport *pTable=0;
820 
821     sal_uInt16 nSize = pNode->GetNumSubNodes();
822 
823     //If the list ends in newline then the last entry has
824     //no subnodes, the newline is superfulous so we just drop
825     //the last node, inclusion would create a bad MathML
826     //table
827     if (nSize >= 1 && pNode->GetSubNode(nSize-1)->GetNumSubNodes() == 0)
828         --nSize;
829 
830     // try to avoid creating a mtable element when the formula consists only
831     // of a single output line
832     if (nLevel || (nSize >1))
833         pTable = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MTABLE, sal_True, sal_True);
834 
835     for (sal_uInt16 i = 0; i < nSize; i++)
836         if (const SmNode *pTemp = pNode->GetSubNode(i))
837         {
838             SvXMLElementExport *pRow=0;
839             SvXMLElementExport *pCell=0;
840             if (pTable)
841             {
842                 pRow  = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MTR, sal_True, sal_True);
843                 pCell = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MTD, sal_True, sal_True);
844             }
845             ExportNodes(pTemp, nLevel+1);
846             delete pCell;
847             delete pRow;
848         }
849 
850     delete pTable;
851 }
852 
ExportMath(const SmNode * pNode,int)853 void SmXMLExport::ExportMath(const SmNode *pNode, int /*nLevel*/)
854 {
855     const SmMathSymbolNode *pTemp = static_cast<const SmMathSymbolNode *>(pNode);
856     SvXMLElementExport aMath(*this, XML_NAMESPACE_MATH, XML_MO, sal_True, sal_False);
857     sal_Unicode nArse[2];
858     nArse[0] = pTemp->GetText().GetChar(0);
859     sal_Unicode cTmp = ConvertMathToMathML( nArse[0] );
860     if (cTmp != 0)
861         nArse[0] = cTmp;
862     DBG_ASSERT(nArse[0] != 0xffff,"Non existent symbol");
863     nArse[1] = 0;
864     GetDocHandler()->characters(nArse);
865 }
866 
ExportText(const SmNode * pNode,int)867 void SmXMLExport::ExportText(const SmNode *pNode, int /*nLevel*/)
868 {
869     SvXMLElementExport *pText;
870     const SmTextNode *pTemp = static_cast<const SmTextNode *>(pNode);
871     switch (pNode->GetToken().eType)
872     {
873         default:
874         case TIDENT:
875         {
876             //Note that we change the fontstyle to italic for strings that
877             //are italic and longer than a single character.
878             sal_Bool bIsItalic = IsItalic( pTemp->GetFont() );
879             if ((pTemp->GetText().Len() > 1) && bIsItalic)
880                 AddAttribute(XML_NAMESPACE_MATH, XML_MATHVARIANT, XML_ITALIC);
881             else if ((pTemp->GetText().Len() == 1) && !bIsItalic)
882                 AddAttribute(XML_NAMESPACE_MATH, XML_MATHVARIANT, XML_NORMAL);
883             pText = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MI,sal_True,sal_False);
884             break;
885         }
886         case TNUMBER:
887             pText = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MN,sal_True,sal_False);
888             break;
889         case TTEXT:
890             pText = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MTEXT,sal_True,sal_False);
891             break;
892         }
893     GetDocHandler()->characters(OUString(pTemp->GetText().GetBuffer()));
894     delete pText;
895 }
896 
ExportBlank(const SmNode *,int)897 void SmXMLExport::ExportBlank(const SmNode * /*pNode*/, int /*nLevel*/)
898 {
899     //!! exports an empty <mi> tag since for example "~_~" is allowed in
900     //!! Math (so it has no sense at all) but must not result in an empty
901     //!! <msub> tag in MathML !!
902 
903     SvXMLElementExport *pText;
904     //const SmBlankNode *pTemp = static_cast<const SmBlankNode *>(pNode);
905 
906     pText = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MI, sal_True, sal_False);
907 
908     GetDocHandler()->characters( OUString() );
909     delete pText;
910 }
911 
ExportSubSupScript(const SmNode * pNode,int nLevel)912 void SmXMLExport::ExportSubSupScript(const SmNode *pNode, int nLevel)
913 {
914     const SmNode *pSub  = 0;
915     const SmNode *pSup  = 0;
916     const SmNode *pCSub = 0;
917     const SmNode *pCSup = 0;
918     const SmNode *pLSub = 0;
919     const SmNode *pLSup = 0;
920     SvXMLElementExport *pThing = 0, *pThing2 = 0;
921 
922     //if we have prescripts at all then we must use the tensor notation
923 
924     //This is one of those excellent locations where scope is vital to
925     //arrange the construction and destruction of the element helper
926     //classes correctly
927     pLSub = pNode->GetSubNode(LSUB+1);
928     pLSup = pNode->GetSubNode(LSUP+1);
929     if (pLSub || pLSup)
930     {
931         SvXMLElementExport aMultiScripts(*this, XML_NAMESPACE_MATH,
932             XML_MMULTISCRIPTS, sal_True, sal_True);
933 
934 
935         if (NULL != (pCSub = pNode->GetSubNode(CSUB+1))
936             && NULL != (pCSup = pNode->GetSubNode(CSUP+1)))
937         {
938             pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
939                 XML_MUNDEROVER, sal_True,sal_True);
940         }
941         else if (NULL != (pCSub = pNode->GetSubNode(CSUB+1)))
942         {
943             pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
944                 XML_MUNDER, sal_True,sal_True);
945         }
946         else if (NULL != (pCSup = pNode->GetSubNode(CSUP+1)))
947         {
948             pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
949                 XML_MOVER, sal_True,sal_True);
950         }
951 
952         ExportNodes(pNode->GetSubNode(0), nLevel+1);    //Main Term
953 
954         if (pCSub)
955             ExportNodes(pCSub, nLevel+1);
956         if (pCSup)
957             ExportNodes(pCSup, nLevel+1);
958         delete pThing2;
959 
960         pSub = pNode->GetSubNode(RSUB+1);
961         pSup = pNode->GetSubNode(RSUP+1);
962         if (pSub || pSup)
963         {
964             if (pSub)
965                 ExportNodes(pSub, nLevel+1);
966             else
967             {
968                 SvXMLElementExport aNone(*this, XML_NAMESPACE_MATH, XML_NONE,sal_True,sal_True);
969             }
970             if (pSup)
971                 ExportNodes(pSup, nLevel+1);
972             else
973             {
974                 SvXMLElementExport aNone(*this, XML_NAMESPACE_MATH, XML_NONE,sal_True,sal_True);
975             }
976         }
977 
978         //Seperator element between suffix and prefix sub/sup pairs
979         {
980             SvXMLElementExport aPrescripts(*this, XML_NAMESPACE_MATH,
981                 XML_MPRESCRIPTS, sal_True,sal_True);
982         }
983 
984         if (pLSub)
985             ExportNodes(pLSub, nLevel+1);
986         else
987         {
988             SvXMLElementExport aNone(*this, XML_NAMESPACE_MATH, XML_NONE,
989                 sal_True,sal_True);
990 
991         }
992         if (pLSup)
993             ExportNodes(pLSup, nLevel+1);
994         else
995         {
996             SvXMLElementExport aNone(*this, XML_NAMESPACE_MATH, XML_NONE,
997                 sal_True,sal_True);
998 
999         }
1000     }
1001     else
1002     {
1003         if (NULL != (pSub = pNode->GetSubNode(RSUB+1)) &&
1004             NULL != (pSup = pNode->GetSubNode(RSUP+1)))
1005         {
1006             pThing = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
1007                 XML_MSUBSUP, sal_True,sal_True);
1008         }
1009         else if (NULL != (pSub = pNode->GetSubNode(RSUB+1)))
1010         {
1011             pThing = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MSUB,
1012                 sal_True,sal_True);
1013         }
1014         else if (NULL != (pSup = pNode->GetSubNode(RSUP+1)))
1015         {
1016             pThing = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MSUP,
1017                 sal_True,sal_True);
1018         }
1019 
1020         if (NULL != (pCSub = pNode->GetSubNode(CSUB+1))
1021             && NULL != (pCSup=pNode->GetSubNode(CSUP+1)))
1022         {
1023             pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
1024                 XML_MUNDEROVER, sal_True,sal_True);
1025         }
1026         else if (NULL != (pCSub = pNode->GetSubNode(CSUB+1)))
1027         {
1028             pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
1029                 XML_MUNDER, sal_True,sal_True);
1030         }
1031         else if (NULL != (pCSup = pNode->GetSubNode(CSUP+1)))
1032         {
1033             pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
1034                 XML_MOVER, sal_True,sal_True);
1035         }
1036         ExportNodes(pNode->GetSubNode(0), nLevel+1);    //Main Term
1037 
1038         if (pCSub)
1039             ExportNodes(pCSub, nLevel+1);
1040         if (pCSup)
1041             ExportNodes(pCSup, nLevel+1);
1042         delete pThing2;
1043 
1044         if (pSub)
1045             ExportNodes(pSub, nLevel+1);
1046         if (pSup)
1047             ExportNodes(pSup, nLevel+1);
1048         delete pThing;
1049     }
1050 }
1051 
ExportBrace(const SmNode * pNode,int nLevel)1052 void SmXMLExport::ExportBrace(const SmNode *pNode, int nLevel)
1053 {
1054     const SmNode *pTemp;
1055     const SmNode *pLeft=pNode->GetSubNode(0);
1056     const SmNode *pRight=pNode->GetSubNode(2);
1057     SvXMLElementExport *pFences=0,*pRow=0;
1058     if ( ((pLeft) && (pLeft->GetToken().eType != TNONE)) &&
1059         ((pRight) && (pRight->GetToken().eType != TNONE)) &&
1060         (pNode->GetScaleMode() == SCALE_HEIGHT))
1061     {
1062         sal_Unicode nArse[2];
1063         nArse[1] = 0;
1064         nArse[0] = static_cast<
1065             const SmMathSymbolNode* >(pLeft)->GetText().GetChar(0);
1066         DBG_ASSERT(nArse[0] != 0xffff,"Non existent symbol");
1067         AddAttribute(XML_NAMESPACE_MATH, XML_OPEN,nArse);
1068         nArse[0] = static_cast<
1069             const SmMathSymbolNode* >(pRight)->GetText().GetChar(0);
1070         DBG_ASSERT(nArse[0] != 0xffff,"Non existent symbol");
1071         AddAttribute(XML_NAMESPACE_MATH, XML_CLOSE,nArse);
1072         pFences = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MFENCED,
1073             sal_True,sal_True);
1074     }
1075     else if (pLeft && (pLeft->GetToken().eType != TNONE))
1076     {
1077         pRow = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MROW,
1078             sal_True, sal_True);
1079         if (pNode->GetScaleMode() == SCALE_HEIGHT)
1080             AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_TRUE);
1081         else
1082             AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_FALSE);
1083         ExportNodes(pLeft, nLevel+1);
1084     }
1085     else
1086         pRow = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MROW,
1087             sal_True, sal_True);
1088 
1089     if (NULL != (pTemp = pNode->GetSubNode(1)))
1090         ExportNodes(pTemp, nLevel+1);
1091     if (pFences)
1092         delete pFences;
1093     else if (pRight && (pRight->GetToken().eType != TNONE))
1094     {
1095         if (pNode->GetScaleMode() == SCALE_HEIGHT)
1096             AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_TRUE);
1097         else
1098             AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_FALSE);
1099         ExportNodes(pRight, nLevel+1);
1100     }
1101     delete pRow;
1102 }
1103 
ExportRoot(const SmNode * pNode,int nLevel)1104 void SmXMLExport::ExportRoot(const SmNode *pNode, int nLevel)
1105 {
1106     if (pNode->GetSubNode(0))
1107     {
1108         SvXMLElementExport aRoot(*this, XML_NAMESPACE_MATH, XML_MROOT,sal_True,
1109             sal_True);
1110         ExportNodes(pNode->GetSubNode(2), nLevel+1);
1111         ExportNodes(pNode->GetSubNode(0), nLevel+1);
1112     }
1113     else
1114     {
1115         SvXMLElementExport aSqrt(*this, XML_NAMESPACE_MATH, XML_MSQRT,sal_True,
1116             sal_True);
1117         ExportNodes(pNode->GetSubNode(2), nLevel+1);
1118     }
1119 }
1120 
ExportOperator(const SmNode * pNode,int nLevel)1121 void SmXMLExport::ExportOperator(const SmNode *pNode, int nLevel)
1122 {
1123     /*we need to either use content or font and size attributes
1124      *here*/
1125 #if 0
1126     {
1127     SvXMLElementExport aMath(*this, XML_NAMESPACE_MATH, XML_MO,
1128         sal_True,sal_False);
1129     SmTextNode *pTemp = (SmTextNode *)pNode->GetSubNode(0);
1130     GetDocHandler()->characters(pTemp->GetText());
1131     }
1132 #endif
1133     SvXMLElementExport aRow(*this, XML_NAMESPACE_MATH, XML_MROW,
1134         sal_True, sal_True);
1135     ExportNodes(pNode->GetSubNode(0), nLevel+1);
1136     ExportNodes(pNode->GetSubNode(1), nLevel+1);
1137 }
1138 
ExportAttributes(const SmNode * pNode,int nLevel)1139 void SmXMLExport::ExportAttributes(const SmNode *pNode, int nLevel)
1140 {
1141     SvXMLElementExport *pElement=0;
1142 
1143     if (pNode->GetToken().eType == TUNDERLINE)
1144     {
1145         AddAttribute(XML_NAMESPACE_MATH, XML_ACCENTUNDER,
1146             XML_TRUE);
1147         pElement = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MUNDER,
1148             sal_True,sal_True);
1149     }
1150     else if (pNode->GetToken().eType != TOVERSTRIKE)
1151     {
1152         AddAttribute(XML_NAMESPACE_MATH, XML_ACCENT,
1153             XML_TRUE);
1154         pElement = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MOVER,
1155             sal_True,sal_True);
1156     }
1157 
1158     ExportNodes(pNode->GetSubNode(1), nLevel+1);
1159     switch (pNode->GetToken().eType)
1160     {
1161         case TOVERLINE:
1162             {
1163             //proper entity support required
1164             SvXMLElementExport aMath(*this, XML_NAMESPACE_MATH, XML_MO,
1165                 sal_True,sal_True);
1166 #if 0
1167             GetDocHandler()->characters(
1168                 OUString(RTL_CONSTASCII_USTRINGPARAM("&overbar;")));
1169 #else
1170             sal_Unicode nArse[2] = {0xAF,0x00};
1171 #endif
1172             GetDocHandler()->characters(nArse);
1173             }
1174             break;
1175         case TUNDERLINE:
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("&underbar;")));
1183 #else
1184             sal_Unicode nArse[2] = {0x0332,0x00};
1185 #endif
1186             GetDocHandler()->characters(nArse);
1187             }
1188             break;
1189         case TOVERSTRIKE:
1190             break;
1191         default:
1192             ExportNodes(pNode->GetSubNode(0), nLevel+1);
1193             break;
1194     }
1195     delete pElement;
1196 }
1197 
lcl_HasEffectOnMathvariant(const SmTokenType eType)1198 static bool lcl_HasEffectOnMathvariant( const SmTokenType eType )
1199 {
1200     return  eType == TBOLD || eType == TNBOLD ||
1201             eType == TITALIC || eType == TNBOLD ||
1202             eType == TSANS || eType == TSERIF || eType == TFIXED;
1203 }
1204 
ExportFont(const SmNode * pNode,int nLevel)1205 void SmXMLExport::ExportFont(const SmNode *pNode, int nLevel)
1206 {
1207     SvXMLElementExport *pElement = 0;
1208 
1209     //
1210     // gather the mathvariant attribut relevant data from all
1211     // successively following SmFontNodes...
1212     //
1213     int nBold   = -1;   // for the following variables: -1 = yet undefined; 0 = false; 1 = true;
1214     int nItalic = -1;   // for the following variables: -1 = yet undefined; 0 = false; 1 = true;
1215     int nSansSerifFixed   = -1;
1216     SmTokenType eNodeType = TUNKNOWN;
1217     while (lcl_HasEffectOnMathvariant( (eNodeType = pNode->GetToken().eType) ))
1218     {
1219         switch (eNodeType)
1220         {
1221             case TBOLD      : nBold   = 1; break;
1222             case TNBOLD     : nBold   = 0; break;
1223             case TITALIC    : nItalic = 1; break;
1224             case TNITALIC   : nItalic = 0; break;
1225             case TSANS      : nSansSerifFixed  = 0; break;
1226             case TSERIF     : nSansSerifFixed  = 1; break;
1227             case TFIXED     : nSansSerifFixed  = 2; break;
1228             default:
1229                 DBG_ASSERT( 0, "unexpected case" );
1230         }
1231         // According to the parser every node that is to be evaluated heres
1232         // has a single non-zero subnode at index 1!! Thus we only need to check
1233         // that single node for follow-up nodes that have an effect on the attribute.
1234         if (pNode->GetNumSubNodes() > 1 && pNode->GetSubNode(1) &&
1235             lcl_HasEffectOnMathvariant( pNode->GetSubNode(1)->GetToken().eType))
1236         {
1237             pNode = pNode->GetSubNode(1);
1238         }
1239         else
1240             break;
1241     }
1242 
1243     switch (pNode->GetToken().eType)
1244     {
1245         //wrap a phantom element around everything*/
1246         case TPHANTOM:
1247             pElement = new SvXMLElementExport(*this, XML_NAMESPACE_MATH,
1248                 XML_MPHANTOM, sal_True,sal_True);
1249             break;
1250         case TBLACK:
1251             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_BLACK);
1252             break;
1253         case TWHITE:
1254             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_WHITE);
1255             break;
1256         case TRED:
1257             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_RED);
1258             break;
1259         case TGREEN:
1260             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_GREEN);
1261             break;
1262         case TBLUE:
1263             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_BLUE);
1264             break;
1265         case TCYAN:
1266             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_AQUA);
1267             break;
1268         case TMAGENTA:
1269             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_FUCHSIA);
1270             break;
1271         case TYELLOW:
1272             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_YELLOW);
1273             break;
1274         case TSILVER:
1275             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_SILVER);
1276             break;
1277         case TGRAY:
1278             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_GRAY);
1279             break;
1280         case TMAROON:
1281             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_MAROON);
1282             break;
1283         case TOLIVE:
1284             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_OLIVE);
1285             break;
1286         case TLIME:
1287             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_LIME);
1288             break;
1289         case TAQUA:
1290             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_AQUA);
1291             break;
1292         case TTEAL:
1293             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_TEAL);
1294             break;
1295         case TNAVY:
1296             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_NAVY);
1297             break;
1298         case TFUCHSIA:
1299             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_FUCHSIA);
1300             break;
1301         case TPURPLE:
1302             AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_PURPLE);
1303             break;
1304         case TSIZE:
1305             {
1306                 const SmFontNode *pFontNode = static_cast<const SmFontNode *>(pNode);
1307                 const Fraction &aFrac = pFontNode->GetSizeParameter();
1308 
1309                 OUStringBuffer sStrBuf;
1310                 switch(pFontNode->GetSizeType())
1311                 {
1312                     case FNTSIZ_MULTIPLY:
1313                         SvXMLUnitConverter::convertDouble(sStrBuf,
1314                             static_cast<double>(aFrac*Fraction(100.00)));
1315                         sStrBuf.append(static_cast<sal_Unicode>('%'));
1316                         break;
1317                     case FNTSIZ_DIVIDE:
1318                         SvXMLUnitConverter::convertDouble(sStrBuf,
1319                             static_cast<double>(Fraction(100.00)/aFrac));
1320                         sStrBuf.append(static_cast<sal_Unicode>('%'));
1321                         break;
1322                     case FNTSIZ_ABSOLUT:
1323                         SvXMLUnitConverter::convertDouble(sStrBuf,
1324                             static_cast<double>(aFrac));
1325                         sStrBuf.append(
1326                             GetXMLToken(XML_UNIT_PT));
1327                         break;
1328                     default:
1329                         {
1330                             //The problem here is that the wheels fall off because
1331                             //font size is stored in 100th's of a mm not pts, and
1332                             //rounding errors take their toll on the original
1333                             //value specified in points.
1334 
1335                             //Must fix StarMath to retain the original pt values
1336                             Fraction aTemp = Sm100th_mmToPts(pFontNode->GetFont().
1337                                 GetSize().Height());
1338 
1339                             if (pFontNode->GetSizeType() == FNTSIZ_MINUS)
1340                                 aTemp-=aFrac;
1341                             else
1342                                 aTemp+=aFrac;
1343 
1344                             double mytest = static_cast<double>(aTemp);
1345 
1346                             mytest = ::rtl::math::round(mytest,1);
1347                             SvXMLUnitConverter::convertDouble(sStrBuf,mytest);
1348                             sStrBuf.append(GetXMLToken(XML_UNIT_PT));
1349                         }
1350                         break;
1351                 }
1352 
1353                 OUString sStr(sStrBuf.makeStringAndClear());
1354                 AddAttribute(XML_NAMESPACE_MATH, XML_MATHSIZE, sStr);
1355             }
1356             break;
1357         case TBOLD:
1358         case TITALIC:
1359         case TNBOLD:
1360         case TNITALIC:
1361         case TFIXED:
1362         case TSANS:
1363         case TSERIF:
1364             {
1365                 // nBold:   -1 = yet undefined; 0 = false; 1 = true;
1366                 // nItalic: -1 = yet undefined; 0 = false; 1 = true;
1367                 // nSansSerifFixed: -1 = undefined; 0 = sans; 1 = serif; 2 = fixed;
1368                 const sal_Char *pText = "normal";
1369                 if (nSansSerifFixed == -1 || nSansSerifFixed == 1)
1370                 {
1371                     pText = "normal";
1372                     if (nBold == 1 && nItalic != 1)
1373                         pText = "bold";
1374                     else if (nBold != 1 && nItalic == 1)
1375                         pText = "italic";
1376                     else if (nBold == 1 && nItalic == 1)
1377                         pText = "bold-italic";
1378                 }
1379                 else if (nSansSerifFixed == 0)
1380                 {
1381                     pText = "sans-serif";
1382                     if (nBold == 1 && nItalic != 1)
1383                         pText = "bold-sans-serif";
1384                     else if (nBold != 1 && nItalic == 1)
1385                         pText = "sans-serif-italic";
1386                     else if (nBold == 1 && nItalic == 1)
1387                         pText = "sans-serif-bold-italic";
1388                 }
1389                 else if (nSansSerifFixed == 2)
1390                     pText = "monospace";    // no modifiers allowed for monospace ...
1391                 else
1392                 {
1393                     DBG_ASSERT( 0, "unexpected case" );
1394                 }
1395                 AddAttribute(XML_NAMESPACE_MATH, XML_MATHVARIANT, A2OU(pText));
1396             }
1397             break;
1398         default:
1399             break;
1400 
1401     }
1402 #if 0
1403     if (pNode->GetNumSubNodes() > 1) //or in the future is a node that
1404                                      //cannot take the currently supported
1405                                      //properties
1406 #endif
1407     //for now we will just always export with a style and not worry about
1408     //anyone else for the moment.
1409     {
1410         //wrap a style around it
1411         SvXMLElementExport aStyle(*this, XML_NAMESPACE_MATH, XML_MSTYLE, sal_True,sal_True);
1412         ExportExpression(pNode, nLevel);
1413     }
1414 #if 0
1415     else
1416         ExportNodes(pNode->GetSubNode(0), nLevel+1);
1417 #endif
1418 
1419     delete pElement;
1420 }
1421 
1422 
ExportVerticalBrace(const SmNode * pNode,int nLevel)1423 void SmXMLExport::ExportVerticalBrace(const SmNode *pNode, int nLevel)
1424 {
1425     //Place the overbrace value OVER a vertical brace and then place that
1426     //expression OVER the overbrace value, If someone can find a
1427     //dedicated term in MathML to handle this overbrace/underbrace concept
1428     //let me know. C.
1429     XMLTokenEnum which;
1430 
1431     switch (pNode->GetToken().eType)
1432     {
1433         case TOVERBRACE:
1434         default:
1435             which = XML_MOVER;
1436             break;
1437         case TUNDERBRACE:
1438             which = XML_MUNDER;
1439             break;
1440     }
1441 
1442     DBG_ASSERT(pNode->GetNumSubNodes()==3,"Bad Vertical Brace");
1443     SvXMLElementExport aOver1(*this, XML_NAMESPACE_MATH,which, sal_True, sal_True);
1444     {//Scoping
1445         // using accents will draw the over-/underbraces too close to the base
1446         // see http://www.w3.org/TR/MathML2/chapter3.html#id.3.4.5.2
1447         // also XML_ACCENT is illegal with XML_MUNDER. Thus no XML_ACCENT attribut here!
1448 //        AddAttribute(XML_NAMESPACE_MATH, XML_ACCENT, XML_sal_True);
1449         SvXMLElementExport aOver2(*this, XML_NAMESPACE_MATH,which, sal_True, sal_True);
1450         ExportNodes(pNode->GetSubNode(0), nLevel);
1451         ExportNodes(pNode->GetSubNode(1), nLevel);
1452     }
1453     ExportNodes(pNode->GetSubNode(2), nLevel);
1454 }
1455 
ExportMatrix(const SmNode * pNode,int nLevel)1456 void SmXMLExport::ExportMatrix(const SmNode *pNode, int nLevel)
1457 {
1458     SvXMLElementExport aTable(*this, XML_NAMESPACE_MATH, XML_MTABLE, sal_True, sal_True);
1459     const SmMatrixNode *pMatrix = static_cast<const SmMatrixNode *>(pNode);
1460     sal_uInt16 i=0;
1461     for (sal_uLong y = 0; y < pMatrix->GetNumRows(); y++)
1462     {
1463         SvXMLElementExport aRow(*this, XML_NAMESPACE_MATH, XML_MTR, sal_True, sal_True);
1464         for (sal_uLong x = 0; x < pMatrix->GetNumCols(); x++)
1465             if (const SmNode *pTemp = pNode->GetSubNode(i++))
1466             {
1467                 SvXMLElementExport aCell(*this, XML_NAMESPACE_MATH, XML_MTD, sal_True, sal_True);
1468                 ExportNodes(pTemp, nLevel+1);
1469             }
1470     }
1471 }
1472 
ExportNodes(const SmNode * pNode,int nLevel)1473 void SmXMLExport::ExportNodes(const SmNode *pNode, int nLevel)
1474 {
1475     if (!pNode)
1476         return;
1477     switch(pNode->GetType())
1478     {
1479         case NTABLE:
1480             ExportTable(pNode, nLevel);
1481             break;
1482         case NALIGN:
1483         case NBRACEBODY:
1484         case NEXPRESSION:
1485             ExportExpression(pNode, nLevel);
1486             break;
1487         case NLINE:
1488             ExportLine(pNode, nLevel);
1489             break;
1490         case NTEXT:
1491             ExportText(pNode, nLevel);
1492             break;
1493         case NSPECIAL: //NSPECIAL requires some sort of Entity preservation in the XML engine.
1494         case NGLYPH_SPECIAL:
1495         case NMATH:
1496             {
1497                 sal_Unicode cTmp = 0;
1498                 const SmTextNode *pTemp = static_cast< const SmTextNode * >(pNode);
1499                 if (pTemp->GetText().Len() > 0)
1500                     cTmp = ConvertMathToMathML( pTemp->GetText().GetChar(0) );
1501                 if (cTmp == 0)
1502                 {
1503                     // no conversion to MathML implemented -> export it as text
1504                     // thus at least it will not vanish into nothing
1505                     ExportText(pNode, nLevel);
1506                 }
1507                 else
1508                 {
1509                     //To fully handle generic MathML we need to implement the full
1510                     //operator dictionary, we will generate MathML with explicit
1511                     //stretchiness for now.
1512                     sal_Int16 nLength = GetAttrList().getLength();
1513                     sal_Bool bAddStretch=sal_True;
1514                     for ( sal_Int16 i = 0; i < nLength; i++ )
1515                     {
1516                         OUString sLocalName;
1517                         sal_uInt16 nPrefix = GetNamespaceMap().GetKeyByAttrName(
1518                             GetAttrList().getNameByIndex(i), &sLocalName );
1519 
1520                         if ( ( XML_NAMESPACE_MATH == nPrefix ) &&
1521                             IsXMLToken(sLocalName, XML_STRETCHY) )
1522                         {
1523                             bAddStretch = sal_False;
1524                             break;
1525                         }
1526                     }
1527                     if (bAddStretch)
1528                     {
1529                         AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_FALSE);
1530                     }
1531                     ExportMath(pNode, nLevel);
1532                 }
1533             }
1534             break;
1535         case NPLACE:
1536             ExportMath(pNode, nLevel);
1537             break;
1538         case NBINHOR:
1539             ExportBinaryHorizontal(pNode, nLevel);
1540             break;
1541         case NUNHOR:
1542             ExportUnaryHorizontal(pNode, nLevel);
1543             break;
1544         case NBRACE:
1545             ExportBrace(pNode, nLevel);
1546             break;
1547         case NBINVER:
1548             ExportBinaryVertical(pNode, nLevel);
1549             break;
1550         case NSUBSUP:
1551             ExportSubSupScript(pNode, nLevel);
1552             break;
1553         case NROOT:
1554             ExportRoot(pNode, nLevel);
1555             break;
1556         case NOPER:
1557             ExportOperator(pNode, nLevel);
1558             break;
1559         case NATTRIBUT:
1560             ExportAttributes(pNode, nLevel);
1561             break;
1562         case NFONT:
1563             ExportFont(pNode, nLevel);
1564             break;
1565         case NVERTICAL_BRACE:
1566             ExportVerticalBrace(pNode, nLevel);
1567             break;
1568         case NMATRIX:
1569             ExportMatrix(pNode, nLevel);
1570             break;
1571         case NBLANK:
1572             ExportBlank(pNode, nLevel);
1573             break;
1574        default:
1575             DBG_ASSERT( 0, "Warning: failed to export a node?" );
1576             break;
1577 
1578 #if 0
1579         default:
1580             {
1581             sal_uLong  nSize = pNode->GetNumSubNodes();
1582             for (sal_uLong i = 0; i < nSize; i++)
1583                 if (SmNode *pTemp = pNode->GetSubNode(i))
1584                     ExportNodes(pTemp, nLevel+1);
1585             }
1586             break;
1587 #endif
1588     }
1589 }
1590 
1591 ////////////////////////////////////////////////////////////
1592