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