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