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 allthough 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 existant 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 existant 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 existant 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 TSIZE: 1285 { 1286 const SmFontNode *pFontNode = static_cast<const SmFontNode *>(pNode); 1287 const Fraction &aFrac = pFontNode->GetSizeParameter(); 1288 1289 OUStringBuffer sStrBuf; 1290 switch(pFontNode->GetSizeType()) 1291 { 1292 case FNTSIZ_MULTIPLY: 1293 SvXMLUnitConverter::convertDouble(sStrBuf, 1294 static_cast<double>(aFrac*Fraction(100.00))); 1295 sStrBuf.append(static_cast<sal_Unicode>('%')); 1296 break; 1297 case FNTSIZ_DIVIDE: 1298 SvXMLUnitConverter::convertDouble(sStrBuf, 1299 static_cast<double>(Fraction(100.00)/aFrac)); 1300 sStrBuf.append(static_cast<sal_Unicode>('%')); 1301 break; 1302 case FNTSIZ_ABSOLUT: 1303 SvXMLUnitConverter::convertDouble(sStrBuf, 1304 static_cast<double>(aFrac)); 1305 sStrBuf.append( 1306 GetXMLToken(XML_UNIT_PT)); 1307 break; 1308 default: 1309 { 1310 //The problem here is that the wheels fall off because 1311 //font size is stored in 100th's of a mm not pts, and 1312 //rounding errors take their toll on the original 1313 //value specified in points. 1314 1315 //Must fix StarMath to retain the original pt values 1316 Fraction aTemp = Sm100th_mmToPts(pFontNode->GetFont(). 1317 GetSize().Height()); 1318 1319 if (pFontNode->GetSizeType() == FNTSIZ_MINUS) 1320 aTemp-=aFrac; 1321 else 1322 aTemp+=aFrac; 1323 1324 double mytest = static_cast<double>(aTemp); 1325 1326 mytest = ::rtl::math::round(mytest,1); 1327 SvXMLUnitConverter::convertDouble(sStrBuf,mytest); 1328 sStrBuf.append(GetXMLToken(XML_UNIT_PT)); 1329 } 1330 break; 1331 } 1332 1333 OUString sStr(sStrBuf.makeStringAndClear()); 1334 AddAttribute(XML_NAMESPACE_MATH, XML_MATHSIZE, sStr); 1335 } 1336 break; 1337 case TBOLD: 1338 case TITALIC: 1339 case TNBOLD: 1340 case TNITALIC: 1341 case TFIXED: 1342 case TSANS: 1343 case TSERIF: 1344 { 1345 // nBold: -1 = yet undefined; 0 = false; 1 = true; 1346 // nItalic: -1 = yet undefined; 0 = false; 1 = true; 1347 // nSansSerifFixed: -1 = undefined; 0 = sans; 1 = serif; 2 = fixed; 1348 const sal_Char *pText = "normal"; 1349 if (nSansSerifFixed == -1 || nSansSerifFixed == 1) 1350 { 1351 pText = "normal"; 1352 if (nBold == 1 && nItalic != 1) 1353 pText = "bold"; 1354 else if (nBold != 1 && nItalic == 1) 1355 pText = "italic"; 1356 else if (nBold == 1 && nItalic == 1) 1357 pText = "bold-italic"; 1358 } 1359 else if (nSansSerifFixed == 0) 1360 { 1361 pText = "sans-serif"; 1362 if (nBold == 1 && nItalic != 1) 1363 pText = "bold-sans-serif"; 1364 else if (nBold != 1 && nItalic == 1) 1365 pText = "sans-serif-italic"; 1366 else if (nBold == 1 && nItalic == 1) 1367 pText = "sans-serif-bold-italic"; 1368 } 1369 else if (nSansSerifFixed == 2) 1370 pText = "monospace"; // no modifiers allowed for monospace ... 1371 else 1372 { 1373 DBG_ASSERT( 0, "unexpected case" ); 1374 } 1375 AddAttribute(XML_NAMESPACE_MATH, XML_MATHVARIANT, A2OU(pText)); 1376 } 1377 break; 1378 default: 1379 break; 1380 1381 } 1382 #if 0 1383 if (pNode->GetNumSubNodes() > 1) //or in the future is a node that 1384 //cannot take the currently supported 1385 //properties 1386 #endif 1387 //for now we will just always export with a style and not worry about 1388 //anyone else for the moment. 1389 { 1390 //wrap a style around it 1391 SvXMLElementExport aStyle(*this, XML_NAMESPACE_MATH, XML_MSTYLE, sal_True,sal_True); 1392 ExportExpression(pNode, nLevel); 1393 } 1394 #if 0 1395 else 1396 ExportNodes(pNode->GetSubNode(0), nLevel+1); 1397 #endif 1398 1399 delete pElement; 1400 } 1401 1402 1403 void SmXMLExport::ExportVerticalBrace(const SmNode *pNode, int nLevel) 1404 { 1405 //Place the overbrace value OVER a vertical brace and then place that 1406 //expression OVER the overbrace value, If someone can find a 1407 //dedicated term in MathML to handle this overbrace/underbrace concept 1408 //let me know. C. 1409 XMLTokenEnum which; 1410 1411 switch (pNode->GetToken().eType) 1412 { 1413 case TOVERBRACE: 1414 default: 1415 which = XML_MOVER; 1416 break; 1417 case TUNDERBRACE: 1418 which = XML_MUNDER; 1419 break; 1420 } 1421 1422 DBG_ASSERT(pNode->GetNumSubNodes()==3,"Bad Vertical Brace"); 1423 SvXMLElementExport aOver1(*this, XML_NAMESPACE_MATH,which, sal_True, sal_True); 1424 {//Scoping 1425 // using accents will draw the over-/underbraces too close to the base 1426 // see http://www.w3.org/TR/MathML2/chapter3.html#id.3.4.5.2 1427 // also XML_ACCENT is illegal with XML_MUNDER. Thus no XML_ACCENT attribut here! 1428 // AddAttribute(XML_NAMESPACE_MATH, XML_ACCENT, XML_sal_True); 1429 SvXMLElementExport aOver2(*this, XML_NAMESPACE_MATH,which, sal_True, sal_True); 1430 ExportNodes(pNode->GetSubNode(0), nLevel); 1431 ExportNodes(pNode->GetSubNode(1), nLevel); 1432 } 1433 ExportNodes(pNode->GetSubNode(2), nLevel); 1434 } 1435 1436 void SmXMLExport::ExportMatrix(const SmNode *pNode, int nLevel) 1437 { 1438 SvXMLElementExport aTable(*this, XML_NAMESPACE_MATH, XML_MTABLE, sal_True, sal_True); 1439 const SmMatrixNode *pMatrix = static_cast<const SmMatrixNode *>(pNode); 1440 sal_uInt16 i=0; 1441 for (sal_uLong y = 0; y < pMatrix->GetNumRows(); y++) 1442 { 1443 SvXMLElementExport aRow(*this, XML_NAMESPACE_MATH, XML_MTR, sal_True, sal_True); 1444 for (sal_uLong x = 0; x < pMatrix->GetNumCols(); x++) 1445 if (const SmNode *pTemp = pNode->GetSubNode(i++)) 1446 { 1447 SvXMLElementExport aCell(*this, XML_NAMESPACE_MATH, XML_MTD, sal_True, sal_True); 1448 ExportNodes(pTemp, nLevel+1); 1449 } 1450 } 1451 } 1452 1453 void SmXMLExport::ExportNodes(const SmNode *pNode, int nLevel) 1454 { 1455 if (!pNode) 1456 return; 1457 switch(pNode->GetType()) 1458 { 1459 case NTABLE: 1460 ExportTable(pNode, nLevel); 1461 break; 1462 case NALIGN: 1463 case NBRACEBODY: 1464 case NEXPRESSION: 1465 ExportExpression(pNode, nLevel); 1466 break; 1467 case NLINE: 1468 ExportLine(pNode, nLevel); 1469 break; 1470 case NTEXT: 1471 ExportText(pNode, nLevel); 1472 break; 1473 case NSPECIAL: //NSPECIAL requires some sort of Entity preservation in the XML engine. 1474 case NGLYPH_SPECIAL: 1475 case NMATH: 1476 { 1477 sal_Unicode cTmp = 0; 1478 const SmTextNode *pTemp = static_cast< const SmTextNode * >(pNode); 1479 if (pTemp->GetText().Len() > 0) 1480 cTmp = ConvertMathToMathML( pTemp->GetText().GetChar(0) ); 1481 if (cTmp == 0) 1482 { 1483 // no conversion to MathML implemented -> export it as text 1484 // thus at least it will not vanish into nothing 1485 ExportText(pNode, nLevel); 1486 } 1487 else 1488 { 1489 //To fully handle generic MathML we need to implement the full 1490 //operator dictionary, we will generate MathML with explicit 1491 //stretchiness for now. 1492 sal_Int16 nLength = GetAttrList().getLength(); 1493 sal_Bool bAddStretch=sal_True; 1494 for ( sal_Int16 i = 0; i < nLength; i++ ) 1495 { 1496 OUString sLocalName; 1497 sal_uInt16 nPrefix = GetNamespaceMap().GetKeyByAttrName( 1498 GetAttrList().getNameByIndex(i), &sLocalName ); 1499 1500 if ( ( XML_NAMESPACE_MATH == nPrefix ) && 1501 IsXMLToken(sLocalName, XML_STRETCHY) ) 1502 { 1503 bAddStretch = sal_False; 1504 break; 1505 } 1506 } 1507 if (bAddStretch) 1508 { 1509 AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_FALSE); 1510 } 1511 ExportMath(pNode, nLevel); 1512 } 1513 } 1514 break; 1515 case NPLACE: 1516 ExportMath(pNode, nLevel); 1517 break; 1518 case NBINHOR: 1519 ExportBinaryHorizontal(pNode, nLevel); 1520 break; 1521 case NUNHOR: 1522 ExportUnaryHorizontal(pNode, nLevel); 1523 break; 1524 case NBRACE: 1525 ExportBrace(pNode, nLevel); 1526 break; 1527 case NBINVER: 1528 ExportBinaryVertical(pNode, nLevel); 1529 break; 1530 case NSUBSUP: 1531 ExportSubSupScript(pNode, nLevel); 1532 break; 1533 case NROOT: 1534 ExportRoot(pNode, nLevel); 1535 break; 1536 case NOPER: 1537 ExportOperator(pNode, nLevel); 1538 break; 1539 case NATTRIBUT: 1540 ExportAttributes(pNode, nLevel); 1541 break; 1542 case NFONT: 1543 ExportFont(pNode, nLevel); 1544 break; 1545 case NVERTICAL_BRACE: 1546 ExportVerticalBrace(pNode, nLevel); 1547 break; 1548 case NMATRIX: 1549 ExportMatrix(pNode, nLevel); 1550 break; 1551 case NBLANK: 1552 ExportBlank(pNode, nLevel); 1553 break; 1554 default: 1555 DBG_ASSERT( 0, "Warning: failed to export a node?" ); 1556 break; 1557 1558 #if 0 1559 default: 1560 { 1561 sal_uLong nSize = pNode->GetNumSubNodes(); 1562 for (sal_uLong i = 0; i < nSize; i++) 1563 if (SmNode *pTemp = pNode->GetSubNode(i)) 1564 ExportNodes(pTemp, nLevel+1); 1565 } 1566 break; 1567 #endif 1568 } 1569 } 1570 1571 //////////////////////////////////////////////////////////// 1572 1573