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