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