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