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