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