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