| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_starmath.hxx" |
| |
| /* |
| Warning: The SvXMLElementExport helper class creates the beginning and |
| closing tags of xml elements in its constructor and destructor, so theres |
| hidden stuff going on, on occasion the ordering of these classes declarations |
| may be significant |
| */ |
| |
| |
| #include <com/sun/star/xml/sax/XErrorHandler.hpp> |
| #include <com/sun/star/xml/sax/XEntityResolver.hpp> |
| #include <com/sun/star/xml/sax/InputSource.hpp> |
| #include <com/sun/star/xml/sax/XDTDHandler.hpp> |
| #include <com/sun/star/xml/sax/XParser.hpp> |
| #include <com/sun/star/io/XActiveDataSource.hpp> |
| #include <com/sun/star/io/XActiveDataControl.hpp> |
| #include <com/sun/star/document/XDocumentProperties.hpp> |
| #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> |
| #include <com/sun/star/packages/zip/ZipIOException.hpp> |
| #include <com/sun/star/task/XStatusIndicatorFactory.hpp> |
| #include <com/sun/star/beans/PropertyAttribute.hpp> |
| #include <com/sun/star/container/XNameAccess.hpp> |
| #include <com/sun/star/embed/ElementModes.hpp> |
| #include <com/sun/star/uno/Any.h> |
| |
| #include <rtl/math.hxx> |
| #include <sfx2/frame.hxx> |
| #include <sfx2/docfile.hxx> |
| #include <tools/debug.hxx> |
| #include <tools/urlobj.hxx> |
| #include <svtools/sfxecode.hxx> |
| #include <unotools/saveopt.hxx> |
| #include <svl/stritem.hxx> |
| #include <svl/itemprop.hxx> |
| #include <unotools/processfactory.hxx> |
| #include <unotools/streamwrap.hxx> |
| #include <xmloff/xmlnmspe.hxx> |
| #include <xmloff/xmltoken.hxx> |
| #include <xmloff/nmspmap.hxx> |
| #include <xmloff/attrlist.hxx> |
| #include <xmloff/xmluconv.hxx> |
| #include <xmloff/xmlmetai.hxx> |
| #include <osl/mutex.hxx> |
| #include <comphelper/genericpropertyset.hxx> |
| |
| #include <memory> |
| |
| #include "mathmlexport.hxx" |
| #include <starmath.hrc> |
| #include <unomodel.hxx> |
| #include <document.hxx> |
| #include <utility.hxx> |
| #include <config.hxx> |
| |
| using namespace ::com::sun::star::beans; |
| using namespace ::com::sun::star::container; |
| using namespace ::com::sun::star::document; |
| using namespace ::com::sun::star::lang; |
| using namespace ::com::sun::star::uno; |
| using namespace ::com::sun::star; |
| using namespace ::xmloff::token; |
| |
| using ::rtl::OUString; |
| using ::rtl::OUStringBuffer; |
| |
| #define EXPORT_SVC_NAME RTL_CONSTASCII_USTRINGPARAM("com.sun.star.xml.XMLExportFilter") |
| |
| #undef WANTEXCEPT |
| |
| |
| //////////////////////////////////////////////////////////// |
| |
| sal_Bool SmXMLExportWrapper::Export(SfxMedium &rMedium) |
| { |
| sal_Bool bRet=sal_True; |
| uno::Reference<lang::XMultiServiceFactory> |
| xServiceFactory(utl::getProcessServiceFactory()); |
| DBG_ASSERT(xServiceFactory.is(),"got no service manager"); |
| |
| //Get model |
| uno::Reference< lang::XComponent > xModelComp(xModel, uno::UNO_QUERY ); |
| |
| sal_Bool bEmbedded = sal_False; |
| uno::Reference <lang::XUnoTunnel> xTunnel; |
| xTunnel = uno::Reference <lang::XUnoTunnel> (xModel,uno::UNO_QUERY); |
| SmModel *pModel = reinterpret_cast<SmModel *> |
| (xTunnel->getSomething(SmModel::getUnoTunnelId())); |
| |
| SmDocShell *pDocShell = pModel ? |
| static_cast<SmDocShell*>(pModel->GetObjectShell()) : 0; |
| if ( pDocShell && |
| SFX_CREATE_MODE_EMBEDDED == pDocShell->GetCreateMode() ) |
| bEmbedded = sal_True; |
| |
| uno::Reference<task::XStatusIndicator> xStatusIndicator; |
| if (!bEmbedded) |
| { |
| if (pDocShell /*&& pDocShell->GetMedium()*/) |
| { |
| DBG_ASSERT( pDocShell->GetMedium() == &rMedium, |
| "different SfxMedium found" ); |
| |
| SfxItemSet* pSet = rMedium.GetItemSet(); |
| if (pSet) |
| { |
| const SfxUnoAnyItem* pItem = static_cast<const SfxUnoAnyItem*>( |
| pSet->GetItem(SID_PROGRESS_STATUSBAR_CONTROL) ); |
| if (pItem) |
| pItem->GetValue() >>= xStatusIndicator; |
| } |
| } |
| |
| // set progress range and start status indicator |
| if (xStatusIndicator.is()) |
| { |
| sal_Int32 nProgressRange = bFlat ? 1 : 3; |
| xStatusIndicator->start(String(SmResId(STR_STATSTR_WRITING)), |
| nProgressRange); |
| } |
| } |
| |
| |
| // create XPropertySet with three properties for status indicator |
| comphelper::PropertyMapEntry aInfoMap[] = |
| { |
| { "UsePrettyPrinting", sizeof("UsePrettyPrinting")-1, 0, |
| &::getBooleanCppuType(), |
| beans::PropertyAttribute::MAYBEVOID, 0}, |
| { "BaseURI", sizeof("BaseURI")-1, 0, |
| &::getCppuType( (OUString *)0 ), |
| beans::PropertyAttribute::MAYBEVOID, 0 }, |
| { "StreamRelPath", sizeof("StreamRelPath")-1, 0, |
| &::getCppuType( (OUString *)0 ), |
| beans::PropertyAttribute::MAYBEVOID, 0 }, |
| { "StreamName", sizeof("StreamName")-1, 0, |
| &::getCppuType( (OUString *)0 ), |
| beans::PropertyAttribute::MAYBEVOID, 0 }, |
| { NULL, 0, 0, NULL, 0, 0 } |
| }; |
| uno::Reference< beans::XPropertySet > xInfoSet( |
| comphelper::GenericPropertySet_CreateInstance( |
| new comphelper::PropertySetInfo( aInfoMap ) ) ); |
| |
| SvtSaveOptions aSaveOpt; |
| OUString sUsePrettyPrinting(RTL_CONSTASCII_USTRINGPARAM("UsePrettyPrinting")); |
| sal_Bool bUsePrettyPrinting( bFlat || aSaveOpt.IsPrettyPrinting() ); |
| Any aAny; |
| aAny.setValue( &bUsePrettyPrinting, ::getBooleanCppuType() ); |
| xInfoSet->setPropertyValue( sUsePrettyPrinting, aAny ); |
| |
| // Set base URI |
| OUString sPropName( RTL_CONSTASCII_USTRINGPARAM("BaseURI") ); |
| xInfoSet->setPropertyValue( sPropName, makeAny( rMedium.GetBaseURL( true ) ) ); |
| |
| sal_Int32 nSteps=0; |
| if (xStatusIndicator.is()) |
| xStatusIndicator->setValue(nSteps++); |
| if (!bFlat) //Storage (Package) of Stream |
| { |
| uno::Reference < embed::XStorage > xStg = rMedium.GetOutputStorage(); |
| sal_Bool bOASIS = ( SotStorage::GetVersion( xStg ) > SOFFICE_FILEFORMAT_60 ); |
| |
| // TODO/LATER: handle the case of embedded links gracefully |
| if ( bEmbedded ) //&& !pStg->IsRoot() ) |
| { |
| OUString aName; |
| if ( rMedium.GetItemSet() ) |
| { |
| const SfxStringItem* pDocHierarchItem = static_cast<const SfxStringItem*>( |
| rMedium.GetItemSet()->GetItem(SID_DOC_HIERARCHICALNAME) ); |
| if ( pDocHierarchItem ) |
| aName = pDocHierarchItem->GetValue(); |
| } |
| |
| if ( aName.getLength() ) |
| { |
| sPropName = OUString(RTL_CONSTASCII_USTRINGPARAM("StreamRelPath")); |
| xInfoSet->setPropertyValue( sPropName, makeAny( aName ) ); |
| } |
| } |
| |
| if ( !bEmbedded ) |
| { |
| if (xStatusIndicator.is()) |
| xStatusIndicator->setValue(nSteps++); |
| |
| bRet = WriteThroughComponent( |
| xStg, xModelComp, "meta.xml", xServiceFactory, xInfoSet, |
| (bOASIS ? "com.sun.star.comp.Math.XMLOasisMetaExporter" |
| : "com.sun.star.comp.Math.XMLMetaExporter"), |
| sal_False); |
| } |
| if ( bRet ) |
| { |
| if (xStatusIndicator.is()) |
| xStatusIndicator->setValue(nSteps++); |
| |
| bRet = WriteThroughComponent( |
| xStg, xModelComp, "content.xml", xServiceFactory, xInfoSet, |
| "com.sun.star.comp.Math.XMLContentExporter"); |
| } |
| |
| if ( bRet ) |
| { |
| if (xStatusIndicator.is()) |
| xStatusIndicator->setValue(nSteps++); |
| |
| bRet = WriteThroughComponent( |
| xStg, xModelComp, "settings.xml", xServiceFactory, xInfoSet, |
| (bOASIS ? "com.sun.star.comp.Math.XMLOasisSettingsExporter" |
| : "com.sun.star.comp.Math.XMLSettingsExporter") ); |
| } |
| } |
| else |
| { |
| SvStream *pStream = rMedium.GetOutStream(); |
| uno::Reference<io::XOutputStream> xOut( |
| new utl::OOutputStreamWrapper(*pStream) ); |
| |
| if (xStatusIndicator.is()) |
| xStatusIndicator->setValue(nSteps++); |
| |
| bRet = WriteThroughComponent( |
| xOut, xModelComp, xServiceFactory, xInfoSet, |
| "com.sun.star.comp.Math.XMLContentExporter"); |
| } |
| |
| if (xStatusIndicator.is()) |
| xStatusIndicator->end(); |
| |
| return bRet; |
| } |
| |
| |
| /// export through an XML exporter component (output stream version) |
| sal_Bool SmXMLExportWrapper::WriteThroughComponent( |
| Reference<io::XOutputStream> xOutputStream, |
| Reference<XComponent> xComponent, |
| Reference<lang::XMultiServiceFactory> & rFactory, |
| Reference<beans::XPropertySet> & rPropSet, |
| const sal_Char* pComponentName ) |
| { |
| DBG_ASSERT(xOutputStream.is(), "I really need an output stream!"); |
| DBG_ASSERT(xComponent.is(), "Need component!"); |
| DBG_ASSERT(NULL != pComponentName, "Need component name!"); |
| |
| // get component |
| Reference< io::XActiveDataSource > xSaxWriter( |
| rFactory->createInstance( |
| OUString::createFromAscii("com.sun.star.xml.sax.Writer") ), |
| UNO_QUERY ); |
| DBG_ASSERT( xSaxWriter.is(), "can't instantiate XML writer" ); |
| if (!xSaxWriter.is()) |
| return sal_False; |
| |
| // connect XML writer to output stream |
| xSaxWriter->setOutputStream( xOutputStream ); |
| |
| // prepare arguments (prepend doc handler to given arguments) |
| Reference<xml::sax::XDocumentHandler> xDocHandler( xSaxWriter,UNO_QUERY); |
| |
| Sequence<Any> aArgs( 2 ); |
| aArgs[0] <<= xDocHandler; |
| aArgs[1] <<= rPropSet; |
| |
| // get filter component |
| Reference< document::XExporter > xExporter( |
| rFactory->createInstanceWithArguments( |
| OUString::createFromAscii(pComponentName), aArgs), UNO_QUERY); |
| DBG_ASSERT( xExporter.is(), |
| "can't instantiate export filter component" ); |
| if ( !xExporter.is() ) |
| return sal_False; |
| |
| |
| // connect model and filter |
| xExporter->setSourceDocument( xComponent ); |
| |
| // filter! |
| Reference < XFilter > xFilter( xExporter, UNO_QUERY ); |
| uno::Sequence< PropertyValue > aProps(0); |
| xFilter->filter( aProps ); |
| |
| uno::Reference<lang::XUnoTunnel> xFilterTunnel; |
| xFilterTunnel = uno::Reference<lang::XUnoTunnel> |
| ( xFilter, uno::UNO_QUERY ); |
| SmXMLExport *pFilter = reinterpret_cast< SmXMLExport * >( |
| sal::static_int_cast< sal_uIntPtr >( |
| xFilterTunnel->getSomething( SmXMLExport::getUnoTunnelId() ))); |
| return pFilter ? pFilter->GetSuccess() : sal_True; |
| } |
| |
| |
| /// export through an XML exporter component (storage version) |
| sal_Bool SmXMLExportWrapper::WriteThroughComponent( |
| const Reference < embed::XStorage >& xStorage, |
| Reference<XComponent> xComponent, |
| const sal_Char* pStreamName, |
| Reference<lang::XMultiServiceFactory> & rFactory, |
| Reference<beans::XPropertySet> & rPropSet, |
| const sal_Char* pComponentName, |
| sal_Bool bCompress |
| ) |
| { |
| DBG_ASSERT(xStorage.is(), "Need storage!"); |
| DBG_ASSERT(NULL != pStreamName, "Need stream name!"); |
| |
| // open stream |
| Reference < io::XStream > xStream; |
| OUString sStreamName = OUString::createFromAscii(pStreamName); |
| try |
| { |
| xStream = xStorage->openStreamElement( sStreamName, |
| embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE ); |
| } |
| catch ( uno::Exception& ) |
| { |
| DBG_ERROR( "Can't create output stream in package!" ); |
| return sal_False; |
| } |
| |
| String aPropName( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("MediaType") ) ); |
| OUString aMime( RTL_CONSTASCII_USTRINGPARAM("text/xml") ); |
| uno::Any aAny; |
| aAny <<= aMime; |
| |
| uno::Reference < beans::XPropertySet > xSet( xStream, uno::UNO_QUERY ); |
| xSet->setPropertyValue( aPropName, aAny ); |
| |
| if ( !bCompress ) |
| { |
| aPropName = String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("Compressed") ); |
| sal_Bool bFalse = sal_False; |
| aAny.setValue( &bFalse, ::getBooleanCppuType() ); |
| xSet->setPropertyValue( aPropName, aAny ); |
| } |
| |
| // even plain stream must be encrypted in encrypted document |
| OUString aTmpPropName( RTL_CONSTASCII_USTRINGPARAM("UseCommonStoragePasswordEncryption") ); |
| sal_Bool bTrue = sal_True; |
| aAny.setValue( &bTrue, ::getBooleanCppuType() ); |
| xSet->setPropertyValue( aTmpPropName, aAny ); |
| |
| // set Base URL |
| if ( rPropSet.is() ) |
| { |
| OUString sPropName( RTL_CONSTASCII_USTRINGPARAM("StreamName") ); |
| rPropSet->setPropertyValue( sPropName, makeAny( sStreamName ) ); |
| } |
| |
| // write the stuff |
| sal_Bool bRet = WriteThroughComponent( xStream->getOutputStream(), xComponent, rFactory, |
| rPropSet, pComponentName ); |
| |
| // stream is closed by SAX parser |
| //if ( bRet ) |
| // xStream->getOutputStream()->closeOutput(); |
| |
| return bRet; |
| } |
| |
| //////////////////////////////////////////////////////////// |
| |
| // #110680# |
| SmXMLExport::SmXMLExport( |
| const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory, |
| sal_uInt16 nExportFlags) |
| : SvXMLExport( xServiceFactory, MAP_INCH, XML_MATH, nExportFlags ) , |
| pTree(0) , |
| bSuccess(sal_False) |
| { |
| } |
| |
| sal_Int64 SAL_CALL SmXMLExport::getSomething( |
| const uno::Sequence< sal_Int8 >& rId ) |
| throw(uno::RuntimeException) |
| { |
| if ( rId.getLength() == 16 && |
| 0 == rtl_compareMemory( getUnoTunnelId().getConstArray(), |
| rId.getConstArray(), 16 ) ) |
| return sal::static_int_cast< sal_Int64 >(reinterpret_cast< sal_uIntPtr >(this)); |
| |
| return SvXMLExport::getSomething( rId ); |
| } |
| |
| const uno::Sequence< sal_Int8 > & SmXMLExport::getUnoTunnelId() throw() |
| { |
| static uno::Sequence< sal_Int8 > * pSeq = 0; |
| if ( !pSeq ) |
| { |
| osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() ); |
| if ( !pSeq ) |
| { |
| static uno::Sequence< sal_Int8 > aSeq( 16 ); |
| rtl_createUuid( (sal_uInt8*)aSeq.getArray(), 0, sal_True ); |
| pSeq = &aSeq; |
| } |
| } |
| return *pSeq; |
| } |
| |
| OUString SAL_CALL SmXMLExport_getImplementationName() throw() |
| { |
| return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Math.XMLExporter" ) ); |
| } |
| |
| uno::Sequence< OUString > SAL_CALL SmXMLExport_getSupportedServiceNames() |
| throw() |
| { |
| const OUString aServiceName( EXPORT_SVC_NAME ); |
| const uno::Sequence< OUString > aSeq( &aServiceName, 1 ); |
| return aSeq; |
| } |
| |
| uno::Reference< uno::XInterface > SAL_CALL SmXMLExport_createInstance( |
| const uno::Reference< lang::XMultiServiceFactory > & rSMgr) |
| throw( uno::Exception ) |
| { |
| // #110680# |
| // return (cppu::OWeakObject*)new SmXMLExport( EXPORT_ALL ); |
| // EXPORT_OASIS is required here although there is no differrence between |
| // OOo and OASIS, because without the flag, a transformation to OOo would |
| // be chained in. |
| return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_OASIS|EXPORT_ALL ); |
| } |
| |
| //////////////////////////////////////////////////////////// |
| |
| OUString SAL_CALL SmXMLExportMetaOOO_getImplementationName() throw() |
| { |
| return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Math.XMLMetaExporter" ) ); |
| } |
| |
| uno::Sequence< OUString > SAL_CALL SmXMLExportMetaOOO_getSupportedServiceNames() |
| throw() |
| { |
| const OUString aServiceName( EXPORT_SVC_NAME ); |
| const uno::Sequence< OUString > aSeq( &aServiceName, 1 ); |
| return aSeq; |
| } |
| |
| uno::Reference< uno::XInterface > SAL_CALL SmXMLExportMetaOOO_createInstance( |
| const uno::Reference< lang::XMultiServiceFactory > & rSMgr) |
| throw( uno::Exception ) |
| { |
| // #110680# |
| // return (cppu::OWeakObject*)new SmXMLExport( EXPORT_META ); |
| return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_META ); |
| } |
| |
| //////////////////////////////////////////////////////////// |
| |
| OUString SAL_CALL SmXMLExportMeta_getImplementationName() throw() |
| { |
| return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Math.XMLOasisMetaExporter" ) ); |
| } |
| |
| uno::Sequence< OUString > SAL_CALL SmXMLExportMeta_getSupportedServiceNames() |
| throw() |
| { |
| const OUString aServiceName( EXPORT_SVC_NAME ); |
| const uno::Sequence< OUString > aSeq( &aServiceName, 1 ); |
| return aSeq; |
| } |
| |
| uno::Reference< uno::XInterface > SAL_CALL SmXMLExportMeta_createInstance( |
| const uno::Reference< lang::XMultiServiceFactory > & rSMgr) |
| throw( uno::Exception ) |
| { |
| // #110680# |
| // return (cppu::OWeakObject*)new SmXMLExport( EXPORT_META ); |
| return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_OASIS|EXPORT_META ); |
| } |
| |
| //////////////////////////////////////////////////////////// |
| |
| OUString SAL_CALL SmXMLExportSettingsOOO_getImplementationName() throw() |
| { |
| return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Math.XMLSettingsExporter" ) ); |
| } |
| |
| uno::Sequence< OUString > SAL_CALL SmXMLExportSettingsOOO_getSupportedServiceNames() |
| throw() |
| { |
| const OUString aServiceName( EXPORT_SVC_NAME ); |
| const uno::Sequence< OUString > aSeq( &aServiceName, 1 ); |
| return aSeq; |
| } |
| |
| uno::Reference< uno::XInterface > SAL_CALL SmXMLExportSettingsOOO_createInstance( |
| const uno::Reference< lang::XMultiServiceFactory > & rSMgr) |
| throw( uno::Exception ) |
| { |
| // #110680# |
| // return (cppu::OWeakObject*)new SmXMLExport( EXPORT_SETTINGS ); |
| return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_SETTINGS ); |
| } |
| |
| //////////////////////////////////////////////////////////// |
| |
| OUString SAL_CALL SmXMLExportSettings_getImplementationName() throw() |
| { |
| return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Math.XMLOasisSettingsExporter" ) ); |
| } |
| |
| uno::Sequence< OUString > SAL_CALL SmXMLExportSettings_getSupportedServiceNames() |
| throw() |
| { |
| const OUString aServiceName( EXPORT_SVC_NAME ); |
| const uno::Sequence< OUString > aSeq( &aServiceName, 1 ); |
| return aSeq; |
| } |
| |
| uno::Reference< uno::XInterface > SAL_CALL SmXMLExportSettings_createInstance( |
| const uno::Reference< lang::XMultiServiceFactory > & rSMgr) |
| throw( uno::Exception ) |
| { |
| // #110680# |
| // return (cppu::OWeakObject*)new SmXMLExport( EXPORT_SETTINGS ); |
| return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_OASIS|EXPORT_SETTINGS ); |
| } |
| |
| //////////////////////////////////////////////////////////// |
| |
| OUString SAL_CALL SmXMLExportContent_getImplementationName() throw() |
| { |
| return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Math.XMLContentExporter" ) ); |
| } |
| |
| uno::Sequence< OUString > SAL_CALL SmXMLExportContent_getSupportedServiceNames() |
| throw() |
| { |
| const OUString aServiceName( EXPORT_SVC_NAME ); |
| const uno::Sequence< OUString > aSeq( &aServiceName, 1 ); |
| return aSeq; |
| } |
| |
| uno::Reference< uno::XInterface > SAL_CALL SmXMLExportContent_createInstance( |
| const uno::Reference< lang::XMultiServiceFactory > & rSMgr) |
| throw( uno::Exception ) |
| { |
| // #110680# |
| // return (cppu::OWeakObject*)new SmXMLExport( EXPORT_CONTENT ); |
| // The EXPORT_OASIS flag is only required to avoid that a transformer is |
| // chanied in |
| return (cppu::OWeakObject*)new SmXMLExport( rSMgr, EXPORT_OASIS|EXPORT_CONTENT ); |
| } |
| |
| //////////////////////////////////////////////////////////// |
| |
| // XServiceInfo |
| // override empty method from parent class |
| rtl::OUString SAL_CALL SmXMLExport::getImplementationName() |
| throw(uno::RuntimeException) |
| { |
| OUString aTxt; |
| switch( getExportFlags() ) |
| { |
| case EXPORT_META: |
| aTxt = SmXMLExportMeta_getImplementationName(); |
| break; |
| case EXPORT_SETTINGS: |
| aTxt = SmXMLExportSettings_getImplementationName(); |
| break; |
| case EXPORT_CONTENT: |
| aTxt = SmXMLExportContent_getImplementationName(); |
| break; |
| case EXPORT_ALL: |
| default: |
| aTxt = SmXMLExport_getImplementationName(); |
| break; |
| } |
| return aTxt; |
| } |
| |
| sal_uInt32 SmXMLExport::exportDoc(enum XMLTokenEnum eClass) |
| { |
| if ( (getExportFlags() & EXPORT_CONTENT) == 0 ) |
| { |
| SvXMLExport::exportDoc( eClass ); |
| } |
| else |
| { |
| uno::Reference <frame::XModel> xModel = GetModel(); |
| uno::Reference <lang::XUnoTunnel> xTunnel; |
| xTunnel = uno::Reference <lang::XUnoTunnel> (xModel,uno::UNO_QUERY); |
| SmModel *pModel = reinterpret_cast<SmModel *> |
| (xTunnel->getSomething(SmModel::getUnoTunnelId())); |
| |
| if (pModel) |
| { |
| SmDocShell *pDocShell = |
| static_cast<SmDocShell*>(pModel->GetObjectShell()); |
| pTree = pDocShell->GetFormulaTree(); |
| aText = pDocShell->GetText(); |
| } |
| |
| GetDocHandler()->startDocument(); |
| |
| /*Add xmlns line*/ |
| SvXMLAttributeList &rList = GetAttrList(); |
| |
| // make use of a default namespace |
| 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) |
| _GetNamespaceMap().Add( OUString::createFromAscii(""), GetXMLToken(XML_N_MATH), XML_NAMESPACE_MATH ); |
| |
| rList.AddAttribute(GetNamespaceMap().GetAttrNameByKey(XML_NAMESPACE_MATH_IDX), |
| GetNamespaceMap().GetNameByKey( XML_NAMESPACE_MATH_IDX)); |
| |
| //I think we need something like ImplExportEntities(); |
| _ExportContent(); |
| GetDocHandler()->endDocument(); |
| } |
| |
| bSuccess=sal_True; |
| return 0; |
| } |
| |
| void SmXMLExport::_ExportContent() |
| { |
| SvXMLElementExport aEquation(*this, XML_NAMESPACE_MATH, XML_MATH, sal_True, sal_True); |
| SvXMLElementExport *pSemantics=0; |
| |
| if (aText.Len()) |
| { |
| pSemantics = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, |
| XML_SEMANTICS, sal_True, sal_True); |
| } |
| |
| ExportNodes(pTree, 0); |
| |
| if (aText.Len()) |
| { |
| // Convert symbol names |
| uno::Reference <frame::XModel> xModel = GetModel(); |
| uno::Reference <lang::XUnoTunnel> xTunnel; |
| xTunnel = uno::Reference <lang::XUnoTunnel> (xModel,uno::UNO_QUERY); |
| SmModel *pModel = reinterpret_cast<SmModel *> |
| (xTunnel->getSomething(SmModel::getUnoTunnelId())); |
| SmDocShell *pDocShell = pModel ? |
| static_cast<SmDocShell*>(pModel->GetObjectShell()) : 0; |
| DBG_ASSERT( pDocShell, "doc shell missing" ); |
| if (pDocShell) |
| { |
| SmParser &rParser = pDocShell->GetParser(); |
| sal_Bool bVal = rParser.IsExportSymbolNames(); |
| rParser.SetExportSymbolNames( sal_True ); |
| SmNode *pTmpTree = rParser.Parse( aText ); |
| aText = rParser.GetText(); |
| delete pTmpTree; |
| rParser.SetExportSymbolNames( bVal ); |
| } |
| |
| AddAttribute(XML_NAMESPACE_MATH, XML_ENCODING, |
| OUString(RTL_CONSTASCII_USTRINGPARAM("StarMath 5.0"))); |
| SvXMLElementExport aAnnotation(*this, XML_NAMESPACE_MATH, |
| XML_ANNOTATION, sal_True, sal_False); |
| GetDocHandler()->characters(OUString( aText )); |
| } |
| delete pSemantics; |
| } |
| |
| void SmXMLExport::GetViewSettings( Sequence < PropertyValue >& aProps) |
| { |
| uno::Reference <frame::XModel> xModel = GetModel(); |
| if ( !xModel.is() ) |
| return; |
| |
| uno::Reference <lang::XUnoTunnel> xTunnel; |
| xTunnel = uno::Reference <lang::XUnoTunnel> (xModel,uno::UNO_QUERY); |
| SmModel *pModel = reinterpret_cast<SmModel *> |
| (xTunnel->getSomething(SmModel::getUnoTunnelId())); |
| |
| if ( !pModel ) |
| return; |
| |
| SmDocShell *pDocShell = |
| static_cast<SmDocShell*>(pModel->GetObjectShell()); |
| if ( !pDocShell ) |
| return; |
| |
| aProps.realloc( 4 ); |
| PropertyValue *pValue = aProps.getArray(); |
| sal_Int32 nIndex = 0; |
| |
| Rectangle aRect( pDocShell->GetVisArea() ); |
| |
| pValue[nIndex].Name = OUString( RTL_CONSTASCII_USTRINGPARAM ( "ViewAreaTop") ); |
| pValue[nIndex++].Value <<= aRect.Top(); |
| |
| pValue[nIndex].Name = OUString( RTL_CONSTASCII_USTRINGPARAM ( "ViewAreaLeft") ); |
| pValue[nIndex++].Value <<= aRect.Left(); |
| |
| pValue[nIndex].Name = OUString( RTL_CONSTASCII_USTRINGPARAM ( "ViewAreaWidth") ); |
| pValue[nIndex++].Value <<= aRect.GetWidth(); |
| |
| pValue[nIndex].Name = OUString( RTL_CONSTASCII_USTRINGPARAM ( "ViewAreaHeight") ); |
| pValue[nIndex++].Value <<= aRect.GetHeight(); |
| } |
| |
| void SmXMLExport::GetConfigurationSettings( Sequence < PropertyValue > & rProps) |
| { |
| Reference < XPropertySet > xProps ( GetModel(), UNO_QUERY ); |
| if ( xProps.is() ) |
| { |
| Reference< XPropertySetInfo > xPropertySetInfo = xProps->getPropertySetInfo(); |
| if (xPropertySetInfo.is()) |
| { |
| Sequence< Property > aProps = xPropertySetInfo->getProperties(); |
| sal_Int32 nCount(aProps.getLength()); |
| if (nCount > 0) |
| { |
| rProps.realloc(nCount); |
| PropertyValue* pProps = rProps.getArray(); |
| if (pProps) |
| { |
| SmConfig *pConfig = SM_MOD()->GetConfig(); |
| const bool bUsedSymbolsOnly = pConfig ? pConfig->IsSaveOnlyUsedSymbols() : false; |
| |
| const OUString sFormula ( RTL_CONSTASCII_USTRINGPARAM ( "Formula" ) ); |
| const OUString sBasicLibraries ( RTL_CONSTASCII_USTRINGPARAM ( "BasicLibraries" ) ); |
| const OUString sDialogLibraries ( RTL_CONSTASCII_USTRINGPARAM ( "DialogLibraries" ) ); |
| const OUString sRuntimeUID ( RTL_CONSTASCII_USTRINGPARAM ( "RuntimeUID" ) ); |
| for (sal_Int32 i = 0; i < nCount; i++, pProps++) |
| { |
| const OUString &rPropName = aProps[i].Name; |
| if (rPropName != sFormula && |
| rPropName != sBasicLibraries && |
| rPropName != sDialogLibraries && |
| rPropName != sRuntimeUID) |
| { |
| pProps->Name = rPropName; |
| |
| rtl::OUString aActualName( rPropName ); |
| |
| // handle 'save used symbols only' |
| if (bUsedSymbolsOnly && rPropName.equalsAscii("Symbols")) |
| aActualName = OUString( RTL_CONSTASCII_USTRINGPARAM ( "UserDefinedSymbolsInUse" ) ); |
| |
| pProps->Value = xProps->getPropertyValue( aActualName ); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| void SmXMLExport::ExportLine(const SmNode *pNode, int nLevel) |
| { |
| ExportExpression(pNode, nLevel); |
| } |
| |
| void SmXMLExport::ExportBinaryHorizontal(const SmNode *pNode, int nLevel) |
| { |
| ExportExpression(pNode, nLevel); |
| } |
| |
| void SmXMLExport::ExportUnaryHorizontal(const SmNode *pNode, int nLevel) |
| { |
| ExportExpression(pNode, nLevel); |
| } |
| |
| void SmXMLExport::ExportExpression(const SmNode *pNode, int nLevel) |
| { |
| SvXMLElementExport *pRow=0; |
| sal_uLong nSize = pNode->GetNumSubNodes(); |
| |
| // #i115443: nodes of type expression always need to be grouped with mrow statement |
| if (nSize > 1 || (pNode && pNode->GetType() == NEXPRESSION)) |
| pRow = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MROW, sal_True, sal_True); |
| |
| //if (nSize) |
| //{ |
| for (sal_uInt16 i = 0; i < nSize; i++) |
| if (const SmNode *pTemp = pNode->GetSubNode(i)) |
| ExportNodes(pTemp, nLevel+1); |
| //} |
| #if 0 |
| else |
| { |
| //This saves us from situations like "a newline" where the |
| //lack of a term following the newline would otherwise create |
| //a incorrect token like <mtr/> |
| SvXMLElementExport aDummy(*this, XML_NAMESPACE_MATH, XML_MI, sal_True, sal_False); |
| sal_Unicode nArse[2] = {'\n','\0'}; |
| GetDocHandler()->characters(nArse); |
| } |
| #endif |
| |
| delete pRow; |
| } |
| |
| void SmXMLExport::ExportBinaryVertical(const SmNode *pNode, int nLevel) |
| { |
| DBG_ASSERT(pNode->GetNumSubNodes()==3,"Bad Fraction"); |
| SvXMLElementExport aFraction(*this, XML_NAMESPACE_MATH, XML_MFRAC, sal_True, sal_True); |
| ExportNodes(pNode->GetSubNode(0), nLevel); |
| ExportNodes(pNode->GetSubNode(2), nLevel); |
| } |
| |
| void SmXMLExport::ExportTable(const SmNode *pNode, int nLevel) |
| { |
| SvXMLElementExport *pTable=0; |
| |
| sal_uInt16 nSize = pNode->GetNumSubNodes(); |
| |
| //If the list ends in newline then the last entry has |
| //no subnodes, the newline is superfulous so we just drop |
| //the last node, inclusion would create a bad MathML |
| //table |
| if (nSize >= 1 && pNode->GetSubNode(nSize-1)->GetNumSubNodes() == 0) |
| --nSize; |
| |
| // try to avoid creating a mtable element when the formula consists only |
| // of a single output line |
| if (nLevel || (nSize >1)) |
| pTable = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MTABLE, sal_True, sal_True); |
| |
| for (sal_uInt16 i = 0; i < nSize; i++) |
| if (const SmNode *pTemp = pNode->GetSubNode(i)) |
| { |
| SvXMLElementExport *pRow=0; |
| SvXMLElementExport *pCell=0; |
| if (pTable) |
| { |
| pRow = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MTR, sal_True, sal_True); |
| pCell = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MTD, sal_True, sal_True); |
| } |
| ExportNodes(pTemp, nLevel+1); |
| delete pCell; |
| delete pRow; |
| } |
| |
| delete pTable; |
| } |
| |
| void SmXMLExport::ExportMath(const SmNode *pNode, int /*nLevel*/) |
| { |
| const SmMathSymbolNode *pTemp = static_cast<const SmMathSymbolNode *>(pNode); |
| SvXMLElementExport aMath(*this, XML_NAMESPACE_MATH, XML_MO, sal_True, sal_False); |
| sal_Unicode nArse[2]; |
| nArse[0] = pTemp->GetText().GetChar(0); |
| sal_Unicode cTmp = ConvertMathToMathML( nArse[0] ); |
| if (cTmp != 0) |
| nArse[0] = cTmp; |
| DBG_ASSERT(nArse[0] != 0xffff,"Non existent symbol"); |
| nArse[1] = 0; |
| GetDocHandler()->characters(nArse); |
| } |
| |
| void SmXMLExport::ExportText(const SmNode *pNode, int /*nLevel*/) |
| { |
| SvXMLElementExport *pText; |
| const SmTextNode *pTemp = static_cast<const SmTextNode *>(pNode); |
| switch (pNode->GetToken().eType) |
| { |
| default: |
| case TIDENT: |
| { |
| //Note that we change the fontstyle to italic for strings that |
| //are italic and longer than a single character. |
| sal_Bool bIsItalic = IsItalic( pTemp->GetFont() ); |
| if ((pTemp->GetText().Len() > 1) && bIsItalic) |
| AddAttribute(XML_NAMESPACE_MATH, XML_MATHVARIANT, XML_ITALIC); |
| else if ((pTemp->GetText().Len() == 1) && !bIsItalic) |
| AddAttribute(XML_NAMESPACE_MATH, XML_MATHVARIANT, XML_NORMAL); |
| pText = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MI,sal_True,sal_False); |
| break; |
| } |
| case TNUMBER: |
| pText = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MN,sal_True,sal_False); |
| break; |
| case TTEXT: |
| pText = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MTEXT,sal_True,sal_False); |
| break; |
| } |
| GetDocHandler()->characters(OUString(pTemp->GetText().GetBuffer())); |
| delete pText; |
| } |
| |
| void SmXMLExport::ExportBlank(const SmNode * /*pNode*/, int /*nLevel*/) |
| { |
| //!! exports an empty <mi> tag since for example "~_~" is allowed in |
| //!! Math (so it has no sense at all) but must not result in an empty |
| //!! <msub> tag in MathML !! |
| |
| SvXMLElementExport *pText; |
| //const SmBlankNode *pTemp = static_cast<const SmBlankNode *>(pNode); |
| |
| pText = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MI, sal_True, sal_False); |
| |
| GetDocHandler()->characters( OUString() ); |
| delete pText; |
| } |
| |
| void SmXMLExport::ExportSubSupScript(const SmNode *pNode, int nLevel) |
| { |
| const SmNode *pSub = 0; |
| const SmNode *pSup = 0; |
| const SmNode *pCSub = 0; |
| const SmNode *pCSup = 0; |
| const SmNode *pLSub = 0; |
| const SmNode *pLSup = 0; |
| SvXMLElementExport *pThing = 0, *pThing2 = 0; |
| |
| //if we have prescripts at all then we must use the tensor notation |
| |
| //This is one of those excellent locations where scope is vital to |
| //arrange the construction and destruction of the element helper |
| //classes correctly |
| pLSub = pNode->GetSubNode(LSUB+1); |
| pLSup = pNode->GetSubNode(LSUP+1); |
| if (pLSub || pLSup) |
| { |
| SvXMLElementExport aMultiScripts(*this, XML_NAMESPACE_MATH, |
| XML_MMULTISCRIPTS, sal_True, sal_True); |
| |
| |
| if (NULL != (pCSub = pNode->GetSubNode(CSUB+1)) |
| && NULL != (pCSup = pNode->GetSubNode(CSUP+1))) |
| { |
| pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, |
| XML_MUNDEROVER, sal_True,sal_True); |
| } |
| else if (NULL != (pCSub = pNode->GetSubNode(CSUB+1))) |
| { |
| pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, |
| XML_MUNDER, sal_True,sal_True); |
| } |
| else if (NULL != (pCSup = pNode->GetSubNode(CSUP+1))) |
| { |
| pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, |
| XML_MOVER, sal_True,sal_True); |
| } |
| |
| ExportNodes(pNode->GetSubNode(0), nLevel+1); //Main Term |
| |
| if (pCSub) |
| ExportNodes(pCSub, nLevel+1); |
| if (pCSup) |
| ExportNodes(pCSup, nLevel+1); |
| delete pThing2; |
| |
| pSub = pNode->GetSubNode(RSUB+1); |
| pSup = pNode->GetSubNode(RSUP+1); |
| if (pSub || pSup) |
| { |
| if (pSub) |
| ExportNodes(pSub, nLevel+1); |
| else |
| { |
| SvXMLElementExport aNone(*this, XML_NAMESPACE_MATH, XML_NONE,sal_True,sal_True); |
| } |
| if (pSup) |
| ExportNodes(pSup, nLevel+1); |
| else |
| { |
| SvXMLElementExport aNone(*this, XML_NAMESPACE_MATH, XML_NONE,sal_True,sal_True); |
| } |
| } |
| |
| //Seperator element between suffix and prefix sub/sup pairs |
| { |
| SvXMLElementExport aPrescripts(*this, XML_NAMESPACE_MATH, |
| XML_MPRESCRIPTS, sal_True,sal_True); |
| } |
| |
| if (pLSub) |
| ExportNodes(pLSub, nLevel+1); |
| else |
| { |
| SvXMLElementExport aNone(*this, XML_NAMESPACE_MATH, XML_NONE, |
| sal_True,sal_True); |
| |
| } |
| if (pLSup) |
| ExportNodes(pLSup, nLevel+1); |
| else |
| { |
| SvXMLElementExport aNone(*this, XML_NAMESPACE_MATH, XML_NONE, |
| sal_True,sal_True); |
| |
| } |
| } |
| else |
| { |
| if (NULL != (pSub = pNode->GetSubNode(RSUB+1)) && |
| NULL != (pSup = pNode->GetSubNode(RSUP+1))) |
| { |
| pThing = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, |
| XML_MSUBSUP, sal_True,sal_True); |
| } |
| else if (NULL != (pSub = pNode->GetSubNode(RSUB+1))) |
| { |
| pThing = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MSUB, |
| sal_True,sal_True); |
| } |
| else if (NULL != (pSup = pNode->GetSubNode(RSUP+1))) |
| { |
| pThing = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MSUP, |
| sal_True,sal_True); |
| } |
| |
| if (NULL != (pCSub = pNode->GetSubNode(CSUB+1)) |
| && NULL != (pCSup=pNode->GetSubNode(CSUP+1))) |
| { |
| pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, |
| XML_MUNDEROVER, sal_True,sal_True); |
| } |
| else if (NULL != (pCSub = pNode->GetSubNode(CSUB+1))) |
| { |
| pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, |
| XML_MUNDER, sal_True,sal_True); |
| } |
| else if (NULL != (pCSup = pNode->GetSubNode(CSUP+1))) |
| { |
| pThing2 = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, |
| XML_MOVER, sal_True,sal_True); |
| } |
| ExportNodes(pNode->GetSubNode(0), nLevel+1); //Main Term |
| |
| if (pCSub) |
| ExportNodes(pCSub, nLevel+1); |
| if (pCSup) |
| ExportNodes(pCSup, nLevel+1); |
| delete pThing2; |
| |
| if (pSub) |
| ExportNodes(pSub, nLevel+1); |
| if (pSup) |
| ExportNodes(pSup, nLevel+1); |
| delete pThing; |
| } |
| } |
| |
| void SmXMLExport::ExportBrace(const SmNode *pNode, int nLevel) |
| { |
| const SmNode *pTemp; |
| const SmNode *pLeft=pNode->GetSubNode(0); |
| const SmNode *pRight=pNode->GetSubNode(2); |
| SvXMLElementExport *pFences=0,*pRow=0; |
| if ( ((pLeft) && (pLeft->GetToken().eType != TNONE)) && |
| ((pRight) && (pRight->GetToken().eType != TNONE)) && |
| (pNode->GetScaleMode() == SCALE_HEIGHT)) |
| { |
| sal_Unicode nArse[2]; |
| nArse[1] = 0; |
| nArse[0] = static_cast< |
| const SmMathSymbolNode* >(pLeft)->GetText().GetChar(0); |
| DBG_ASSERT(nArse[0] != 0xffff,"Non existent symbol"); |
| AddAttribute(XML_NAMESPACE_MATH, XML_OPEN,nArse); |
| nArse[0] = static_cast< |
| const SmMathSymbolNode* >(pRight)->GetText().GetChar(0); |
| DBG_ASSERT(nArse[0] != 0xffff,"Non existent symbol"); |
| AddAttribute(XML_NAMESPACE_MATH, XML_CLOSE,nArse); |
| pFences = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MFENCED, |
| sal_True,sal_True); |
| } |
| else if (pLeft && (pLeft->GetToken().eType != TNONE)) |
| { |
| pRow = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MROW, |
| sal_True, sal_True); |
| if (pNode->GetScaleMode() == SCALE_HEIGHT) |
| AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_TRUE); |
| else |
| AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_FALSE); |
| ExportNodes(pLeft, nLevel+1); |
| } |
| else |
| pRow = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MROW, |
| sal_True, sal_True); |
| |
| if (NULL != (pTemp = pNode->GetSubNode(1))) |
| ExportNodes(pTemp, nLevel+1); |
| if (pFences) |
| delete pFences; |
| else if (pRight && (pRight->GetToken().eType != TNONE)) |
| { |
| if (pNode->GetScaleMode() == SCALE_HEIGHT) |
| AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_TRUE); |
| else |
| AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_FALSE); |
| ExportNodes(pRight, nLevel+1); |
| } |
| delete pRow; |
| } |
| |
| void SmXMLExport::ExportRoot(const SmNode *pNode, int nLevel) |
| { |
| if (pNode->GetSubNode(0)) |
| { |
| SvXMLElementExport aRoot(*this, XML_NAMESPACE_MATH, XML_MROOT,sal_True, |
| sal_True); |
| ExportNodes(pNode->GetSubNode(2), nLevel+1); |
| ExportNodes(pNode->GetSubNode(0), nLevel+1); |
| } |
| else |
| { |
| SvXMLElementExport aSqrt(*this, XML_NAMESPACE_MATH, XML_MSQRT,sal_True, |
| sal_True); |
| ExportNodes(pNode->GetSubNode(2), nLevel+1); |
| } |
| } |
| |
| void SmXMLExport::ExportOperator(const SmNode *pNode, int nLevel) |
| { |
| /*we need to either use content or font and size attributes |
| *here*/ |
| #if 0 |
| { |
| SvXMLElementExport aMath(*this, XML_NAMESPACE_MATH, XML_MO, |
| sal_True,sal_False); |
| SmTextNode *pTemp = (SmTextNode *)pNode->GetSubNode(0); |
| GetDocHandler()->characters(pTemp->GetText()); |
| } |
| #endif |
| SvXMLElementExport aRow(*this, XML_NAMESPACE_MATH, XML_MROW, |
| sal_True, sal_True); |
| ExportNodes(pNode->GetSubNode(0), nLevel+1); |
| ExportNodes(pNode->GetSubNode(1), nLevel+1); |
| } |
| |
| void SmXMLExport::ExportAttributes(const SmNode *pNode, int nLevel) |
| { |
| SvXMLElementExport *pElement=0; |
| |
| if (pNode->GetToken().eType == TUNDERLINE) |
| { |
| AddAttribute(XML_NAMESPACE_MATH, XML_ACCENTUNDER, |
| XML_TRUE); |
| pElement = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MUNDER, |
| sal_True,sal_True); |
| } |
| else if (pNode->GetToken().eType != TOVERSTRIKE) |
| { |
| AddAttribute(XML_NAMESPACE_MATH, XML_ACCENT, |
| XML_TRUE); |
| pElement = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, XML_MOVER, |
| sal_True,sal_True); |
| } |
| |
| ExportNodes(pNode->GetSubNode(1), nLevel+1); |
| switch (pNode->GetToken().eType) |
| { |
| case TOVERLINE: |
| { |
| //proper entity support required |
| SvXMLElementExport aMath(*this, XML_NAMESPACE_MATH, XML_MO, |
| sal_True,sal_True); |
| #if 0 |
| GetDocHandler()->characters( |
| OUString(RTL_CONSTASCII_USTRINGPARAM("&overbar;"))); |
| #else |
| sal_Unicode nArse[2] = {0xAF,0x00}; |
| #endif |
| GetDocHandler()->characters(nArse); |
| } |
| break; |
| case TUNDERLINE: |
| { |
| //proper entity support required |
| SvXMLElementExport aMath(*this, XML_NAMESPACE_MATH, XML_MO, |
| sal_True,sal_True); |
| #if 0 |
| GetDocHandler()->characters( |
| OUString(RTL_CONSTASCII_USTRINGPARAM("&underbar;"))); |
| #else |
| sal_Unicode nArse[2] = {0x0332,0x00}; |
| #endif |
| GetDocHandler()->characters(nArse); |
| } |
| break; |
| case TOVERSTRIKE: |
| break; |
| default: |
| ExportNodes(pNode->GetSubNode(0), nLevel+1); |
| break; |
| } |
| delete pElement; |
| } |
| |
| static bool lcl_HasEffectOnMathvariant( const SmTokenType eType ) |
| { |
| return eType == TBOLD || eType == TNBOLD || |
| eType == TITALIC || eType == TNBOLD || |
| eType == TSANS || eType == TSERIF || eType == TFIXED; |
| } |
| |
| void SmXMLExport::ExportFont(const SmNode *pNode, int nLevel) |
| { |
| SvXMLElementExport *pElement = 0; |
| |
| // |
| // gather the mathvariant attribut relevant data from all |
| // successively following SmFontNodes... |
| // |
| int nBold = -1; // for the following variables: -1 = yet undefined; 0 = false; 1 = true; |
| int nItalic = -1; // for the following variables: -1 = yet undefined; 0 = false; 1 = true; |
| int nSansSerifFixed = -1; |
| SmTokenType eNodeType = TUNKNOWN; |
| while (lcl_HasEffectOnMathvariant( (eNodeType = pNode->GetToken().eType) )) |
| { |
| switch (eNodeType) |
| { |
| case TBOLD : nBold = 1; break; |
| case TNBOLD : nBold = 0; break; |
| case TITALIC : nItalic = 1; break; |
| case TNITALIC : nItalic = 0; break; |
| case TSANS : nSansSerifFixed = 0; break; |
| case TSERIF : nSansSerifFixed = 1; break; |
| case TFIXED : nSansSerifFixed = 2; break; |
| default: |
| DBG_ASSERT( 0, "unexpected case" ); |
| } |
| // According to the parser every node that is to be evaluated heres |
| // has a single non-zero subnode at index 1!! Thus we only need to check |
| // that single node for follow-up nodes that have an effect on the attribute. |
| if (pNode->GetNumSubNodes() > 1 && pNode->GetSubNode(1) && |
| lcl_HasEffectOnMathvariant( pNode->GetSubNode(1)->GetToken().eType)) |
| { |
| pNode = pNode->GetSubNode(1); |
| } |
| else |
| break; |
| } |
| |
| switch (pNode->GetToken().eType) |
| { |
| //wrap a phantom element around everything*/ |
| case TPHANTOM: |
| pElement = new SvXMLElementExport(*this, XML_NAMESPACE_MATH, |
| XML_MPHANTOM, sal_True,sal_True); |
| break; |
| case TBLACK: |
| AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_BLACK); |
| break; |
| case TWHITE: |
| AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_WHITE); |
| break; |
| case TRED: |
| AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_RED); |
| break; |
| case TGREEN: |
| AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_GREEN); |
| break; |
| case TBLUE: |
| AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_BLUE); |
| break; |
| case TCYAN: |
| AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_AQUA); |
| break; |
| case TMAGENTA: |
| AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_FUCHSIA); |
| break; |
| case TYELLOW: |
| AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_YELLOW); |
| break; |
| case TSILVER: |
| AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_SILVER); |
| break; |
| case TGRAY: |
| AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_GRAY); |
| break; |
| case TMAROON: |
| AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_MAROON); |
| break; |
| case TOLIVE: |
| AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_OLIVE); |
| break; |
| case TLIME: |
| AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_LIME); |
| break; |
| case TAQUA: |
| AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_AQUA); |
| break; |
| case TTEAL: |
| AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_TEAL); |
| break; |
| case TNAVY: |
| AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_NAVY); |
| break; |
| case TFUCHSIA: |
| AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_FUCHSIA); |
| break; |
| case TPURPLE: |
| AddAttribute(XML_NAMESPACE_MATH, XML_COLOR, XML_PURPLE); |
| break; |
| case TSIZE: |
| { |
| const SmFontNode *pFontNode = static_cast<const SmFontNode *>(pNode); |
| const Fraction &aFrac = pFontNode->GetSizeParameter(); |
| |
| OUStringBuffer sStrBuf; |
| switch(pFontNode->GetSizeType()) |
| { |
| case FNTSIZ_MULTIPLY: |
| SvXMLUnitConverter::convertDouble(sStrBuf, |
| static_cast<double>(aFrac*Fraction(100.00))); |
| sStrBuf.append(static_cast<sal_Unicode>('%')); |
| break; |
| case FNTSIZ_DIVIDE: |
| SvXMLUnitConverter::convertDouble(sStrBuf, |
| static_cast<double>(Fraction(100.00)/aFrac)); |
| sStrBuf.append(static_cast<sal_Unicode>('%')); |
| break; |
| case FNTSIZ_ABSOLUT: |
| SvXMLUnitConverter::convertDouble(sStrBuf, |
| static_cast<double>(aFrac)); |
| sStrBuf.append( |
| GetXMLToken(XML_UNIT_PT)); |
| break; |
| default: |
| { |
| //The problem here is that the wheels fall off because |
| //font size is stored in 100th's of a mm not pts, and |
| //rounding errors take their toll on the original |
| //value specified in points. |
| |
| //Must fix StarMath to retain the original pt values |
| Fraction aTemp = Sm100th_mmToPts(pFontNode->GetFont(). |
| GetSize().Height()); |
| |
| if (pFontNode->GetSizeType() == FNTSIZ_MINUS) |
| aTemp-=aFrac; |
| else |
| aTemp+=aFrac; |
| |
| double mytest = static_cast<double>(aTemp); |
| |
| mytest = ::rtl::math::round(mytest,1); |
| SvXMLUnitConverter::convertDouble(sStrBuf,mytest); |
| sStrBuf.append(GetXMLToken(XML_UNIT_PT)); |
| } |
| break; |
| } |
| |
| OUString sStr(sStrBuf.makeStringAndClear()); |
| AddAttribute(XML_NAMESPACE_MATH, XML_MATHSIZE, sStr); |
| } |
| break; |
| case TBOLD: |
| case TITALIC: |
| case TNBOLD: |
| case TNITALIC: |
| case TFIXED: |
| case TSANS: |
| case TSERIF: |
| { |
| // nBold: -1 = yet undefined; 0 = false; 1 = true; |
| // nItalic: -1 = yet undefined; 0 = false; 1 = true; |
| // nSansSerifFixed: -1 = undefined; 0 = sans; 1 = serif; 2 = fixed; |
| const sal_Char *pText = "normal"; |
| if (nSansSerifFixed == -1 || nSansSerifFixed == 1) |
| { |
| pText = "normal"; |
| if (nBold == 1 && nItalic != 1) |
| pText = "bold"; |
| else if (nBold != 1 && nItalic == 1) |
| pText = "italic"; |
| else if (nBold == 1 && nItalic == 1) |
| pText = "bold-italic"; |
| } |
| else if (nSansSerifFixed == 0) |
| { |
| pText = "sans-serif"; |
| if (nBold == 1 && nItalic != 1) |
| pText = "bold-sans-serif"; |
| else if (nBold != 1 && nItalic == 1) |
| pText = "sans-serif-italic"; |
| else if (nBold == 1 && nItalic == 1) |
| pText = "sans-serif-bold-italic"; |
| } |
| else if (nSansSerifFixed == 2) |
| pText = "monospace"; // no modifiers allowed for monospace ... |
| else |
| { |
| DBG_ASSERT( 0, "unexpected case" ); |
| } |
| AddAttribute(XML_NAMESPACE_MATH, XML_MATHVARIANT, A2OU(pText)); |
| } |
| break; |
| default: |
| break; |
| |
| } |
| #if 0 |
| if (pNode->GetNumSubNodes() > 1) //or in the future is a node that |
| //cannot take the currently supported |
| //properties |
| #endif |
| //for now we will just always export with a style and not worry about |
| //anyone else for the moment. |
| { |
| //wrap a style around it |
| SvXMLElementExport aStyle(*this, XML_NAMESPACE_MATH, XML_MSTYLE, sal_True,sal_True); |
| ExportExpression(pNode, nLevel); |
| } |
| #if 0 |
| else |
| ExportNodes(pNode->GetSubNode(0), nLevel+1); |
| #endif |
| |
| delete pElement; |
| } |
| |
| |
| void SmXMLExport::ExportVerticalBrace(const SmNode *pNode, int nLevel) |
| { |
| //Place the overbrace value OVER a vertical brace and then place that |
| //expression OVER the overbrace value, If someone can find a |
| //dedicated term in MathML to handle this overbrace/underbrace concept |
| //let me know. C. |
| XMLTokenEnum which; |
| |
| switch (pNode->GetToken().eType) |
| { |
| case TOVERBRACE: |
| default: |
| which = XML_MOVER; |
| break; |
| case TUNDERBRACE: |
| which = XML_MUNDER; |
| break; |
| } |
| |
| DBG_ASSERT(pNode->GetNumSubNodes()==3,"Bad Vertical Brace"); |
| SvXMLElementExport aOver1(*this, XML_NAMESPACE_MATH,which, sal_True, sal_True); |
| {//Scoping |
| // using accents will draw the over-/underbraces too close to the base |
| // see http://www.w3.org/TR/MathML2/chapter3.html#id.3.4.5.2 |
| // also XML_ACCENT is illegal with XML_MUNDER. Thus no XML_ACCENT attribut here! |
| // AddAttribute(XML_NAMESPACE_MATH, XML_ACCENT, XML_sal_True); |
| SvXMLElementExport aOver2(*this, XML_NAMESPACE_MATH,which, sal_True, sal_True); |
| ExportNodes(pNode->GetSubNode(0), nLevel); |
| ExportNodes(pNode->GetSubNode(1), nLevel); |
| } |
| ExportNodes(pNode->GetSubNode(2), nLevel); |
| } |
| |
| void SmXMLExport::ExportMatrix(const SmNode *pNode, int nLevel) |
| { |
| SvXMLElementExport aTable(*this, XML_NAMESPACE_MATH, XML_MTABLE, sal_True, sal_True); |
| const SmMatrixNode *pMatrix = static_cast<const SmMatrixNode *>(pNode); |
| sal_uInt16 i=0; |
| for (sal_uLong y = 0; y < pMatrix->GetNumRows(); y++) |
| { |
| SvXMLElementExport aRow(*this, XML_NAMESPACE_MATH, XML_MTR, sal_True, sal_True); |
| for (sal_uLong x = 0; x < pMatrix->GetNumCols(); x++) |
| if (const SmNode *pTemp = pNode->GetSubNode(i++)) |
| { |
| SvXMLElementExport aCell(*this, XML_NAMESPACE_MATH, XML_MTD, sal_True, sal_True); |
| ExportNodes(pTemp, nLevel+1); |
| } |
| } |
| } |
| |
| void SmXMLExport::ExportNodes(const SmNode *pNode, int nLevel) |
| { |
| if (!pNode) |
| return; |
| switch(pNode->GetType()) |
| { |
| case NTABLE: |
| ExportTable(pNode, nLevel); |
| break; |
| case NALIGN: |
| case NBRACEBODY: |
| case NEXPRESSION: |
| ExportExpression(pNode, nLevel); |
| break; |
| case NLINE: |
| ExportLine(pNode, nLevel); |
| break; |
| case NTEXT: |
| ExportText(pNode, nLevel); |
| break; |
| case NSPECIAL: //NSPECIAL requires some sort of Entity preservation in the XML engine. |
| case NGLYPH_SPECIAL: |
| case NMATH: |
| { |
| sal_Unicode cTmp = 0; |
| const SmTextNode *pTemp = static_cast< const SmTextNode * >(pNode); |
| if (pTemp->GetText().Len() > 0) |
| cTmp = ConvertMathToMathML( pTemp->GetText().GetChar(0) ); |
| if (cTmp == 0) |
| { |
| // no conversion to MathML implemented -> export it as text |
| // thus at least it will not vanish into nothing |
| ExportText(pNode, nLevel); |
| } |
| else |
| { |
| //To fully handle generic MathML we need to implement the full |
| //operator dictionary, we will generate MathML with explicit |
| //stretchiness for now. |
| sal_Int16 nLength = GetAttrList().getLength(); |
| sal_Bool bAddStretch=sal_True; |
| for ( sal_Int16 i = 0; i < nLength; i++ ) |
| { |
| OUString sLocalName; |
| sal_uInt16 nPrefix = GetNamespaceMap().GetKeyByAttrName( |
| GetAttrList().getNameByIndex(i), &sLocalName ); |
| |
| if ( ( XML_NAMESPACE_MATH == nPrefix ) && |
| IsXMLToken(sLocalName, XML_STRETCHY) ) |
| { |
| bAddStretch = sal_False; |
| break; |
| } |
| } |
| if (bAddStretch) |
| { |
| AddAttribute(XML_NAMESPACE_MATH, XML_STRETCHY, XML_FALSE); |
| } |
| ExportMath(pNode, nLevel); |
| } |
| } |
| break; |
| case NPLACE: |
| ExportMath(pNode, nLevel); |
| break; |
| case NBINHOR: |
| ExportBinaryHorizontal(pNode, nLevel); |
| break; |
| case NUNHOR: |
| ExportUnaryHorizontal(pNode, nLevel); |
| break; |
| case NBRACE: |
| ExportBrace(pNode, nLevel); |
| break; |
| case NBINVER: |
| ExportBinaryVertical(pNode, nLevel); |
| break; |
| case NSUBSUP: |
| ExportSubSupScript(pNode, nLevel); |
| break; |
| case NROOT: |
| ExportRoot(pNode, nLevel); |
| break; |
| case NOPER: |
| ExportOperator(pNode, nLevel); |
| break; |
| case NATTRIBUT: |
| ExportAttributes(pNode, nLevel); |
| break; |
| case NFONT: |
| ExportFont(pNode, nLevel); |
| break; |
| case NVERTICAL_BRACE: |
| ExportVerticalBrace(pNode, nLevel); |
| break; |
| case NMATRIX: |
| ExportMatrix(pNode, nLevel); |
| break; |
| case NBLANK: |
| ExportBlank(pNode, nLevel); |
| break; |
| default: |
| DBG_ASSERT( 0, "Warning: failed to export a node?" ); |
| break; |
| |
| #if 0 |
| default: |
| { |
| sal_uLong nSize = pNode->GetNumSubNodes(); |
| for (sal_uLong i = 0; i < nSize; i++) |
| if (SmNode *pTemp = pNode->GetSubNode(i)) |
| ExportNodes(pTemp, nLevel+1); |
| } |
| break; |
| #endif |
| } |
| } |
| |
| //////////////////////////////////////////////////////////// |
| |