2010-10-14 08:30:41 +02:00
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2012-07-04 15:25:45 +01:00
/*
* This file is part of the LibreOffice project .
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2.0 . If a copy of the MPL was not distributed with this
* file , You can obtain one at http : //mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice :
*
* 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 .
*/
2010-02-12 16:56:44 +01:00
/*
Warning : The SvXMLElementExport helper class creates the beginning and
2015-07-02 18:25:02 +02:00
closing tags of xml elements in its constructor and destructor , so there ' s
2010-02-12 16:56:44 +01:00
hidden stuff going on , on occasion the ordering of these classes declarations
may be significant
*/
2012-10-10 10:13:18 +02:00
# include <com/sun/star/xml/sax/Writer.hpp>
2010-02-12 16:56:44 +01:00
# include <com/sun/star/beans/PropertyAttribute.hpp>
# include <com/sun/star/embed/ElementModes.hpp>
2011-10-11 14:19:09 +02:00
# include <com/sun/star/util/MeasureUnit.hpp>
2019-03-17 01:11:29 +01:00
# include <com/sun/star/task/XStatusIndicator.hpp>
2010-02-12 16:56:44 +01:00
# include <com/sun/star/uno/Any.h>
# include <rtl/math.hxx>
# include <sfx2/frame.hxx>
# include <sfx2/docfile.hxx>
2017-10-23 22:31:51 +02:00
# include <sfx2/sfxsids.hrc>
2010-10-07 11:02:05 +01:00
# include <osl/diagnose.h>
2010-02-12 16:56:44 +01:00
# include <unotools/saveopt.hxx>
2018-12-26 18:39:47 +01:00
# include <sot/storage.hxx>
2017-08-02 09:07:31 +02:00
# include <svl/itemset.hxx>
2010-02-12 16:56:44 +01:00
# include <svl/stritem.hxx>
2017-12-13 21:49:20 +01:00
# include <comphelper/fileformat.h>
2011-11-14 11:49:31 +01:00
# include <comphelper/processfactory.hxx>
2010-02-12 16:56:44 +01:00
# include <unotools/streamwrap.hxx>
#i108468#: clean up xmluconv code duplication, part 1:
move convertNumber64 from SvXMLUnitConverter to sax::converter.
remove duplicate methods from SvXMLUnitConverter:
convertBool, convertPercent, convertColor, convertNumber, convertDouble,
indexOfComma, encodeBase64, decodeBase64, decodeBase64SomeChars,
clearUndefinedChars
2011-10-11 14:19:00 +02:00
# include <sax/tools/converter.hxx>
2010-02-12 16:56:44 +01:00
# include <xmloff/xmlnmspe.hxx>
# include <xmloff/xmltoken.hxx>
# include <xmloff/nmspmap.hxx>
# include <xmloff/attrlist.hxx>
# include <comphelper/genericpropertyset.hxx>
2011-04-04 12:23:43 +01:00
# include <comphelper/servicehelper.hxx>
2018-09-20 20:26:40 +02:00
# include <comphelper/propertysetinfo.hxx>
2018-04-05 16:20:13 +02:00
# include <tools/diagnose_ex.h>
2018-07-28 17:23:50 +02:00
# include <sal/log.hxx>
2010-02-12 16:56:44 +01:00
# include <memory>
2014-11-25 19:18:01 -05:00
# include <stack>
2010-02-12 16:56:44 +01:00
# include "mathmlexport.hxx"
2017-06-11 20:56:30 +01:00
# include <strings.hrc>
2018-12-26 18:39:47 +01:00
# include <smmod.hxx>
2010-02-12 16:56:44 +01:00
# include <unomodel.hxx>
# include <document.hxx>
# include <utility.hxx>
2015-05-26 08:38:37 +02:00
# include "cfgitem.hxx"
2010-02-12 16:56:44 +01:00
using namespace : : com : : sun : : star : : beans ;
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 ;
2016-05-20 15:49:04 +09:00
namespace {
2018-10-09 10:28:48 +02:00
bool IsInPrivateUseArea ( sal_Unicode cChar ) { return 0xE000 < = cChar & & cChar < = 0xF8FF ; }
2016-05-20 15:49:04 +09:00
2013-08-14 23:12:27 -03:00
sal_Unicode ConvertMathToMathML ( sal_Unicode cChar )
{
sal_Unicode cRes = cChar ;
if ( IsInPrivateUseArea ( cChar ) )
{
SAL_WARN ( " starmath " , " Error: private use area characters should no longer be in use! " ) ;
2017-04-28 17:55:02 +02:00
cRes = u ' @ ' ; // just some character that should easily be notice as odd in the context
2013-08-14 23:12:27 -03:00
}
return cRes ;
}
2010-02-12 16:56:44 +01:00
2016-05-20 15:49:04 +09:00
}
2014-04-24 12:22:08 +02:00
bool SmXMLExportWrapper : : Export ( SfxMedium & rMedium )
2010-02-12 16:56:44 +01:00
{
2014-04-24 12:22:08 +02:00
bool bRet = true ;
2013-01-03 13:41:37 +02:00
uno : : Reference < uno : : XComponentContext > xContext ( comphelper : : getProcessComponentContext ( ) ) ;
2010-02-12 16:56:44 +01:00
//Get model
2019-07-20 13:29:51 +02:00
uno : : Reference < lang : : XComponent > xModelComp = xModel ;
2010-02-12 16:56:44 +01:00
2014-04-24 12:22:08 +02:00
bool bEmbedded = false ;
2019-09-22 18:20:39 +03:00
SmModel * pModel = comphelper : : getUnoTunnelImplementation < SmModel > ( xModel ) ;
2010-02-12 16:56:44 +01:00
SmDocShell * pDocShell = pModel ?
2015-11-10 10:24:24 +01:00
static_cast < SmDocShell * > ( pModel - > GetObjectShell ( ) ) : nullptr ;
2010-02-12 16:56:44 +01:00
if ( pDocShell & &
2015-04-09 15:24:21 +02:00
SfxObjectCreateMode : : EMBEDDED = = pDocShell - > GetCreateMode ( ) )
2014-04-24 12:22:08 +02:00
bEmbedded = true ;
2010-02-12 16:56:44 +01:00
uno : : Reference < task : : XStatusIndicator > xStatusIndicator ;
if ( ! bEmbedded )
{
if ( pDocShell /*&& pDocShell->GetMedium()*/ )
{
2010-10-07 11:02:05 +01:00
OSL_ENSURE ( pDocShell - > GetMedium ( ) = = & rMedium ,
2010-02-12 16:56:44 +01:00
" 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 ;
2017-05-18 21:14:00 +01:00
xStatusIndicator - > start ( SmResId ( STR_STATSTR_WRITING ) ,
2010-02-12 16:56:44 +01:00
nProgressRange ) ;
}
}
// create XPropertySet with three properties for status indicator
comphelper : : PropertyMapEntry aInfoMap [ ] =
{
2013-12-11 15:16:51 +01:00
{ OUString ( " UsePrettyPrinting " ) , 0 ,
2015-04-01 08:41:06 +02:00
cppu : : UnoType < bool > : : get ( ) ,
2010-02-12 16:56:44 +01:00
beans : : PropertyAttribute : : MAYBEVOID , 0 } ,
2013-12-11 15:16:51 +01:00
{ OUString ( " BaseURI " ) , 0 ,
2014-05-10 00:14:44 +02:00
: : cppu : : UnoType < OUString > : : get ( ) ,
2010-02-12 16:56:44 +01:00
beans : : PropertyAttribute : : MAYBEVOID , 0 } ,
2013-12-11 15:16:51 +01:00
{ OUString ( " StreamRelPath " ) , 0 ,
2014-05-10 00:14:44 +02:00
: : cppu : : UnoType < OUString > : : get ( ) ,
2010-02-12 16:56:44 +01:00
beans : : PropertyAttribute : : MAYBEVOID , 0 } ,
2013-12-11 15:16:51 +01:00
{ OUString ( " StreamName " ) , 0 ,
2014-05-10 00:14:44 +02:00
: : cppu : : UnoType < OUString > : : get ( ) ,
2010-02-12 16:56:44 +01:00
beans : : PropertyAttribute : : MAYBEVOID , 0 } ,
2013-12-11 15:16:51 +01:00
{ OUString ( ) , 0 , css : : uno : : Type ( ) , 0 , 0 }
2010-02-12 16:56:44 +01:00
} ;
uno : : Reference < beans : : XPropertySet > xInfoSet (
comphelper : : GenericPropertySet_CreateInstance (
new comphelper : : PropertySetInfo ( aInfoMap ) ) ) ;
SvtSaveOptions aSaveOpt ;
2016-04-28 14:35:37 +02:00
bool bUsePrettyPrinting ( bFlat | | aSaveOpt . IsPrettyPrinting ( ) ) ;
2017-06-26 14:47:16 +02:00
xInfoSet - > setPropertyValue ( " UsePrettyPrinting " , Any ( bUsePrettyPrinting ) ) ;
2010-02-12 16:56:44 +01:00
// Set base URI
2012-03-08 14:56:00 +01:00
OUString sPropName ( " BaseURI " ) ;
2010-02-12 16:56:44 +01:00
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 ( ) ;
2014-04-24 12:22:08 +02:00
bool bOASIS = ( SotStorage : : GetVersion ( xStg ) > SOFFICE_FILEFORMAT_60 ) ;
2010-02-12 16:56:44 +01:00
// 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 ( ) ;
}
2012-01-11 11:37:33 -02:00
if ( ! aName . isEmpty ( ) )
2010-02-12 16:56:44 +01:00
{
2012-03-08 14:56:00 +01:00
sPropName = " StreamRelPath " ;
2010-02-12 16:56:44 +01:00
xInfoSet - > setPropertyValue ( sPropName , makeAny ( aName ) ) ;
}
}
if ( ! bEmbedded )
{
if ( xStatusIndicator . is ( ) )
xStatusIndicator - > setValue ( nSteps + + ) ;
bRet = WriteThroughComponent (
2013-01-03 13:41:37 +02:00
xStg , xModelComp , " meta.xml " , xContext , xInfoSet ,
2010-02-12 16:56:44 +01:00
( bOASIS ? " com.sun.star.comp.Math.XMLOasisMetaExporter "
2012-11-14 16:42:11 +01:00
: " com.sun.star.comp.Math.XMLMetaExporter " ) ) ;
2010-02-12 16:56:44 +01:00
}
if ( bRet )
{
2019-02-08 13:55:44 +02:00
if ( xStatusIndicator . is ( ) )
2010-02-12 16:56:44 +01:00
xStatusIndicator - > setValue ( nSteps + + ) ;
bRet = WriteThroughComponent (
2013-01-03 13:41:37 +02:00
xStg , xModelComp , " content.xml " , xContext , xInfoSet ,
2010-02-12 16:56:44 +01:00
" com.sun.star.comp.Math.XMLContentExporter " ) ;
}
if ( bRet )
{
if ( xStatusIndicator . is ( ) )
xStatusIndicator - > setValue ( nSteps + + ) ;
bRet = WriteThroughComponent (
2013-01-03 13:41:37 +02:00
xStg , xModelComp , " settings.xml " , xContext , xInfoSet ,
2010-02-12 16:56:44 +01:00
( 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 (
2013-01-03 13:41:37 +02:00
xOut , xModelComp , xContext , xInfoSet ,
2010-02-12 16:56:44 +01:00
" com.sun.star.comp.Math.XMLContentExporter " ) ;
}
if ( xStatusIndicator . is ( ) )
xStatusIndicator - > end ( ) ;
return bRet ;
}
/// export through an XML exporter component (output stream version)
2014-04-24 12:22:08 +02:00
bool SmXMLExportWrapper : : WriteThroughComponent (
2016-04-12 11:55:28 +02:00
const Reference < io : : XOutputStream > & xOutputStream ,
const Reference < XComponent > & xComponent ,
2017-08-03 13:14:02 +02:00
Reference < uno : : XComponentContext > const & rxContext ,
Reference < beans : : XPropertySet > const & rPropSet ,
2010-02-12 16:56:44 +01:00
const sal_Char * pComponentName )
{
2010-10-07 11:02:05 +01:00
OSL_ENSURE ( xOutputStream . is ( ) , " I really need an output stream! " ) ;
OSL_ENSURE ( xComponent . is ( ) , " Need component! " ) ;
2015-11-10 10:24:24 +01:00
OSL_ENSURE ( nullptr ! = pComponentName , " Need component name! " ) ;
2010-02-12 16:56:44 +01:00
// get component
2013-01-03 13:41:37 +02:00
Reference < xml : : sax : : XWriter > xSaxWriter = xml : : sax : : Writer : : create ( rxContext ) ;
2010-02-12 16:56:44 +01:00
// connect XML writer to output stream
xSaxWriter - > setOutputStream ( xOutputStream ) ;
// prepare arguments (prepend doc handler to given arguments)
Sequence < Any > aArgs ( 2 ) ;
2019-07-20 13:29:51 +02:00
aArgs [ 0 ] < < = xSaxWriter ;
2010-02-12 16:56:44 +01:00
aArgs [ 1 ] < < = rPropSet ;
// get filter component
Reference < document : : XExporter > xExporter (
2013-01-03 13:41:37 +02:00
rxContext - > getServiceManager ( ) - > createInstanceWithArgumentsAndContext ( OUString : : createFromAscii ( pComponentName ) , aArgs , rxContext ) ,
UNO_QUERY ) ;
2010-10-07 11:02:05 +01:00
OSL_ENSURE ( xExporter . is ( ) ,
2010-02-12 16:56:44 +01:00
" can't instantiate export filter component " ) ;
if ( ! xExporter . is ( ) )
2014-04-24 12:22:08 +02:00
return false ;
2010-02-12 16:56:44 +01:00
// connect model and filter
xExporter - > setSourceDocument ( xComponent ) ;
// filter!
Reference < XFilter > xFilter ( xExporter , UNO_QUERY ) ;
uno : : Sequence < PropertyValue > aProps ( 0 ) ;
xFilter - > filter ( aProps ) ;
2019-09-22 18:20:39 +03:00
auto pFilter = comphelper : : getUnoTunnelImplementation < SmXMLExport > ( xFilter ) ;
2015-04-24 12:33:33 +02:00
return pFilter = = nullptr | | pFilter - > GetSuccess ( ) ;
2010-02-12 16:56:44 +01:00
}
/// export through an XML exporter component (storage version)
2014-04-24 12:22:08 +02:00
bool SmXMLExportWrapper : : WriteThroughComponent (
2010-02-12 16:56:44 +01:00
const Reference < embed : : XStorage > & xStorage ,
2016-04-12 11:55:28 +02:00
const Reference < XComponent > & xComponent ,
2010-02-12 16:56:44 +01:00
const sal_Char * pStreamName ,
2017-08-03 13:14:02 +02:00
Reference < uno : : XComponentContext > const & rxContext ,
Reference < beans : : XPropertySet > const & rPropSet ,
2012-11-14 16:42:11 +01:00
const sal_Char * pComponentName
2010-02-12 16:56:44 +01:00
)
{
2010-10-07 11:02:05 +01:00
OSL_ENSURE ( xStorage . is ( ) , " Need storage! " ) ;
2015-11-10 10:24:24 +01:00
OSL_ENSURE ( nullptr ! = pStreamName , " Need stream name! " ) ;
2010-02-12 16:56:44 +01:00
// open stream
Reference < io : : XStream > xStream ;
OUString sStreamName = OUString : : createFromAscii ( pStreamName ) ;
try
{
xStream = xStorage - > openStreamElement ( sStreamName ,
embed : : ElementModes : : READWRITE | embed : : ElementModes : : TRUNCATE ) ;
}
2018-04-05 16:20:13 +02:00
catch ( const uno : : Exception & )
2010-02-12 16:56:44 +01:00
{
2018-04-05 16:20:13 +02:00
DBG_UNHANDLED_EXCEPTION ( " starmath " , " Can't create output stream in package " ) ;
2014-04-24 12:22:08 +02:00
return false ;
2010-02-12 16:56:44 +01:00
}
uno : : Reference < beans : : XPropertySet > xSet ( xStream , uno : : UNO_QUERY ) ;
2017-06-26 14:47:16 +02:00
xSet - > setPropertyValue ( " MediaType " , Any ( OUString ( " text/xml " ) ) ) ;
2010-02-12 16:56:44 +01:00
2012-11-14 16:42:11 +01:00
// all streams must be encrypted in encrypted document
2017-06-26 14:47:16 +02:00
xSet - > setPropertyValue ( " UseCommonStoragePasswordEncryption " , Any ( true ) ) ;
2010-02-12 16:56:44 +01:00
// set Base URL
if ( rPropSet . is ( ) )
{
2017-06-26 14:47:16 +02:00
rPropSet - > setPropertyValue ( " StreamName " , makeAny ( sStreamName ) ) ;
2010-02-12 16:56:44 +01:00
}
// write the stuff
2014-04-24 12:22:08 +02:00
bool bRet = WriteThroughComponent ( xStream - > getOutputStream ( ) , xComponent , rxContext ,
2010-02-12 16:56:44 +01:00
rPropSet , pComponentName ) ;
return bRet ;
}
SmXMLExport : : SmXMLExport (
2015-10-29 12:44:31 +02:00
const css : : uno : : Reference < css : : uno : : XComponentContext > & rContext ,
2014-12-28 14:22:51 +02:00
OUString const & implementationName , SvXMLExportFlags nExportFlags )
2015-03-04 16:29:43 +00:00
: SvXMLExport ( util : : MeasureUnit : : INCH , rContext , implementationName , XML_MATH ,
nExportFlags )
2015-11-10 10:24:24 +01:00
, pTree ( nullptr )
2015-03-04 16:29:43 +00:00
, bSuccess ( false )
2010-02-12 16:56:44 +01:00
{
}
sal_Int64 SAL_CALL SmXMLExport : : getSomething (
const uno : : Sequence < sal_Int8 > & rId )
{
2019-06-12 12:18:07 +03:00
if ( isUnoTunnelId < SmXMLExport > ( rId ) )
2012-11-20 16:50:46 +01:00
return sal : : static_int_cast < sal_Int64 > ( reinterpret_cast < sal_uIntPtr > ( this ) ) ;
2010-02-12 16:56:44 +01:00
return SvXMLExport : : getSomething ( rId ) ;
}
2011-04-04 12:23:43 +01:00
namespace
{
class theSmXMLExportUnoTunnelId : public rtl : : Static < UnoTunnelIdInit , theSmXMLExportUnoTunnelId > { } ;
}
2010-02-12 16:56:44 +01:00
const uno : : Sequence < sal_Int8 > & SmXMLExport : : getUnoTunnelId ( ) throw ( )
{
2011-04-04 12:23:43 +01:00
return theSmXMLExportUnoTunnelId : : get ( ) . getSeq ( ) ;
2010-02-12 16:56:44 +01:00
}
2017-12-08 15:58:41 +02:00
extern " C " SAL_DLLPUBLIC_EXPORT css : : uno : : XInterface *
2015-05-03 17:08:28 +02:00
Math_XMLExporter_get_implementation ( css : : uno : : XComponentContext * context , css : : uno : : Sequence < css : : uno : : Any > const & )
2010-02-12 16:56:44 +01:00
{
2015-05-03 17:08:28 +02:00
return cppu : : acquire ( new SmXMLExport ( context , " com.sun.star.comp.Math.XMLExporter " , SvXMLExportFlags : : OASIS | SvXMLExportFlags : : ALL ) ) ;
2010-02-12 16:56:44 +01:00
}
2017-12-08 15:58:41 +02:00
extern " C " SAL_DLLPUBLIC_EXPORT css : : uno : : XInterface *
2015-05-03 17:08:28 +02:00
Math_XMLMetaExporter_get_implementation ( css : : uno : : XComponentContext * context , css : : uno : : Sequence < css : : uno : : Any > const & )
2010-02-12 16:56:44 +01:00
{
2015-05-03 17:08:28 +02:00
return cppu : : acquire ( new SmXMLExport ( context , " com.sun.star.comp.Math.XMLMetaExporter " , SvXMLExportFlags : : META ) ) ;
2010-02-12 16:56:44 +01:00
}
2017-12-08 15:58:41 +02:00
extern " C " SAL_DLLPUBLIC_EXPORT css : : uno : : XInterface *
2015-05-03 17:08:28 +02:00
Math_XMLOasisMetaExporter_get_implementation ( css : : uno : : XComponentContext * context , css : : uno : : Sequence < css : : uno : : Any > const & )
2010-02-12 16:56:44 +01:00
{
2015-05-03 17:08:28 +02:00
return cppu : : acquire ( new SmXMLExport ( context , " com.sun.star.comp.Math.XMLOasisMetaExporter " , SvXMLExportFlags : : OASIS | SvXMLExportFlags : : META ) ) ;
2010-02-12 16:56:44 +01:00
}
2017-12-08 15:58:41 +02:00
extern " C " SAL_DLLPUBLIC_EXPORT css : : uno : : XInterface *
2015-05-03 17:08:28 +02:00
Math_XMLSettingsExporter_get_implementation ( css : : uno : : XComponentContext * context , css : : uno : : Sequence < css : : uno : : Any > const & )
2010-02-12 16:56:44 +01:00
{
2015-05-03 17:08:28 +02:00
return cppu : : acquire ( new SmXMLExport ( context , " com.sun.star.comp.Math.XMLSettingsExporter " , SvXMLExportFlags : : SETTINGS ) ) ;
2010-02-12 16:56:44 +01:00
}
2017-12-08 15:58:41 +02:00
extern " C " SAL_DLLPUBLIC_EXPORT css : : uno : : XInterface *
2015-05-03 17:08:28 +02:00
Math_XMLOasisSettingsExporter_get_implementation ( css : : uno : : XComponentContext * context , css : : uno : : Sequence < css : : uno : : Any > const & )
2010-02-12 16:56:44 +01:00
{
2015-05-03 17:08:28 +02:00
return cppu : : acquire ( new SmXMLExport ( context , " com.sun.star.comp.Math.XMLOasisSettingsExporter " , SvXMLExportFlags : : OASIS | SvXMLExportFlags : : SETTINGS ) ) ;
2010-02-12 16:56:44 +01:00
}
2017-12-08 15:58:41 +02:00
extern " C " SAL_DLLPUBLIC_EXPORT css : : uno : : XInterface *
2015-05-03 17:08:28 +02:00
Math_XMLContentExporter_get_implementation ( css : : uno : : XComponentContext * context , css : : uno : : Sequence < css : : uno : : Any > const & )
2010-02-12 16:56:44 +01:00
{
2015-05-03 17:08:28 +02:00
return cppu : : acquire ( new SmXMLExport ( context , " com.sun.star.comp.Math.XMLContentExporter " , SvXMLExportFlags : : OASIS | SvXMLExportFlags : : CONTENT ) ) ;
2010-02-12 16:56:44 +01:00
}
2017-02-09 08:52:13 +02:00
ErrCode SmXMLExport : : exportDoc ( enum XMLTokenEnum eClass )
2010-02-12 16:56:44 +01:00
{
2014-12-28 14:22:51 +02:00
if ( ! ( getExportFlags ( ) & SvXMLExportFlags : : CONTENT ) )
2010-02-12 16:56:44 +01:00
{
SvXMLExport : : exportDoc ( eClass ) ;
}
else
{
uno : : Reference < frame : : XModel > xModel = GetModel ( ) ;
2019-09-22 18:20:39 +03:00
SmModel * pModel = comphelper : : getUnoTunnelImplementation < SmModel > ( xModel ) ;
2010-02-12 16:56:44 +01:00
if ( pModel )
{
SmDocShell * pDocShell =
static_cast < SmDocShell * > ( pModel - > GetObjectShell ( ) ) ;
pTree = pDocShell - > GetFormulaTree ( ) ;
aText = pDocShell - > GetText ( ) ;
}
GetDocHandler ( ) - > startDocument ( ) ;
2011-09-08 13:50:30 +01:00
addChaffWhenEncryptedStorage ( ) ;
2010-02-12 16:56:44 +01:00
/*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)
2016-03-29 08:07:14 +02:00
GetNamespaceMap_ ( ) . Add ( OUString ( ) , GetXMLToken ( XML_N_MATH ) , XML_NAMESPACE_MATH ) ;
2010-02-12 16:56:44 +01:00
2017-06-27 15:25:53 +02:00
rList . AddAttribute ( GetNamespaceMap ( ) . GetAttrNameByKey ( XML_NAMESPACE_MATH ) ,
GetNamespaceMap ( ) . GetNameByKey ( XML_NAMESPACE_MATH ) ) ;
2010-02-12 16:56:44 +01:00
//I think we need something like ImplExportEntities();
2016-03-29 08:07:14 +02:00
ExportContent_ ( ) ;
2010-02-12 16:56:44 +01:00
GetDocHandler ( ) - > endDocument ( ) ;
}
2014-04-24 12:22:08 +02:00
bSuccess = true ;
2017-06-14 13:34:55 +02:00
return ERRCODE_NONE ;
2010-02-12 16:56:44 +01:00
}
2016-03-29 08:07:14 +02:00
void SmXMLExport : : ExportContent_ ( )
2010-02-12 16:56:44 +01:00
{
2013-06-28 17:07:11 +02:00
uno : : Reference < frame : : XModel > xModel = GetModel ( ) ;
2019-09-22 18:20:39 +03:00
SmModel * pModel = comphelper : : getUnoTunnelImplementation < SmModel > ( xModel ) ;
2013-06-28 17:07:11 +02:00
SmDocShell * pDocShell = pModel ?
2015-11-10 10:24:24 +01:00
static_cast < SmDocShell * > ( pModel - > GetObjectShell ( ) ) : nullptr ;
2013-06-28 17:07:11 +02:00
OSL_ENSURE ( pDocShell , " doc shell missing " ) ;
if ( pDocShell & & ! pDocShell - > GetFormat ( ) . IsTextmode ( ) )
{
// If the Math equation is not in text mode, we attach a display="block"
// attribute on the <math> root. We don't do anything if it is in
// text mode, the default display="inline" value will be used.
AddAttribute ( XML_NAMESPACE_MATH , XML_DISPLAY , XML_BLOCK ) ;
}
2014-03-28 16:28:51 +02:00
SvXMLElementExport aEquation ( * this , XML_NAMESPACE_MATH , XML_MATH , true , true ) ;
2018-09-12 10:25:55 +02:00
std : : unique_ptr < SvXMLElementExport > pSemantics ;
2010-02-12 16:56:44 +01:00
2013-09-03 18:29:30 +02:00
if ( ! aText . isEmpty ( ) )
2010-02-12 16:56:44 +01:00
{
2018-09-12 10:25:55 +02:00
pSemantics . reset ( new SvXMLElementExport ( * this , XML_NAMESPACE_MATH ,
XML_SEMANTICS , true , true ) ) ;
2010-02-12 16:56:44 +01:00
}
ExportNodes ( pTree , 0 ) ;
2019-01-29 11:35:50 +02:00
if ( aText . isEmpty ( ) )
return ;
2010-02-12 16:56:44 +01:00
2019-01-29 11:35:50 +02:00
// Convert symbol names
if ( pDocShell )
{
SmParser & rParser = pDocShell - > GetParser ( ) ;
bool bVal = rParser . IsExportSymbolNames ( ) ;
rParser . SetExportSymbolNames ( true ) ;
auto pTmpTree = rParser . Parse ( aText ) ;
aText = rParser . GetText ( ) ;
pTmpTree . reset ( ) ;
rParser . SetExportSymbolNames ( bVal ) ;
2010-02-12 16:56:44 +01:00
}
2019-01-29 11:35:50 +02:00
AddAttribute ( XML_NAMESPACE_MATH , XML_ENCODING ,
OUString ( " StarMath 5.0 " ) ) ;
SvXMLElementExport aAnnotation ( * this , XML_NAMESPACE_MATH ,
XML_ANNOTATION , true , false ) ;
GetDocHandler ( ) - > characters ( aText ) ;
2010-02-12 16:56:44 +01:00
}
void SmXMLExport : : GetViewSettings ( Sequence < PropertyValue > & aProps )
{
uno : : Reference < frame : : XModel > xModel = GetModel ( ) ;
if ( ! xModel . is ( ) )
return ;
2019-09-22 18:20:39 +03:00
SmModel * pModel = comphelper : : getUnoTunnelImplementation < SmModel > ( xModel ) ;
2010-02-12 16:56:44 +01:00
if ( ! pModel )
return ;
SmDocShell * pDocShell =
static_cast < SmDocShell * > ( pModel - > GetObjectShell ( ) ) ;
if ( ! pDocShell )
return ;
aProps . realloc ( 4 ) ;
PropertyValue * pValue = aProps . getArray ( ) ;
sal_Int32 nIndex = 0 ;
2017-03-30 20:27:55 +02:00
tools : : Rectangle aRect ( pDocShell - > GetVisArea ( ) ) ;
2010-02-12 16:56:44 +01:00
2012-03-08 14:56:00 +01:00
pValue [ nIndex ] . Name = " ViewAreaTop " ;
2010-02-12 16:56:44 +01:00
pValue [ nIndex + + ] . Value < < = aRect . Top ( ) ;
2012-03-08 14:56:00 +01:00
pValue [ nIndex ] . Name = " ViewAreaLeft " ;
2010-02-12 16:56:44 +01:00
pValue [ nIndex + + ] . Value < < = aRect . Left ( ) ;
2013-04-26 09:21:18 +02:00
pValue [ nIndex ] . Name = " ViewAreaWidth " ;
2010-02-12 16:56:44 +01:00
pValue [ nIndex + + ] . Value < < = aRect . GetWidth ( ) ;
2012-03-08 14:56:00 +01:00
pValue [ nIndex ] . Name = " ViewAreaHeight " ;
2010-02-12 16:56:44 +01:00
pValue [ nIndex + + ] . Value < < = aRect . GetHeight ( ) ;
}
void SmXMLExport : : GetConfigurationSettings ( Sequence < PropertyValue > & rProps )
{
Reference < XPropertySet > xProps ( GetModel ( ) , UNO_QUERY ) ;
2019-01-29 11:35:50 +02:00
if ( ! xProps . is ( ) )
return ;
Reference < XPropertySetInfo > xPropertySetInfo = xProps - > getPropertySetInfo ( ) ;
if ( ! xPropertySetInfo . is ( ) )
return ;
Sequence < Property > aProps = xPropertySetInfo - > getProperties ( ) ;
const sal_Int32 nCount = aProps . getLength ( ) ;
if ( ! nCount )
return ;
rProps . realloc ( nCount ) ;
SmMathConfig * pConfig = SM_MOD ( ) - > GetConfig ( ) ;
const bool bUsedSymbolsOnly = pConfig & & pConfig - > IsSaveOnlyUsedSymbols ( ) ;
std : : transform ( aProps . begin ( ) , aProps . end ( ) , rProps . begin ( ) ,
[ bUsedSymbolsOnly , & xProps ] ( Property & prop ) {
PropertyValue aRet ;
if ( prop . Name ! = " Formula " & & prop . Name ! = " BasicLibraries "
& & prop . Name ! = " DialogLibraries "
& & prop . Name ! = " RuntimeUID " )
{
aRet . Name = prop . Name ;
OUString aActualName ( prop . Name ) ;
// handle 'save used symbols only'
if ( bUsedSymbolsOnly & & prop . Name = = " Symbols " )
aActualName = " UserDefinedSymbolsInUse " ;
aRet . Value = xProps - > getPropertyValue ( aActualName ) ;
}
return aRet ;
} ) ;
2010-02-12 16:56:44 +01:00
}
void SmXMLExport : : ExportLine ( const SmNode * pNode , int nLevel )
{
ExportExpression ( pNode , nLevel ) ;
}
void SmXMLExport : : ExportBinaryHorizontal ( const SmNode * pNode , int nLevel )
{
2016-05-13 15:50:42 +02:00
TG nGroup = pNode - > GetToken ( ) . nGroup ;
2013-06-25 22:33:13 +02:00
2017-01-31 14:46:38 +02:00
std : : unique_ptr < SvXMLElementExport > pRow ( new SvXMLElementExport ( * this ,
XML_NAMESPACE_MATH , XML_MROW , true , true ) ) ;
2013-06-25 22:33:13 +02:00
// Unfold the binary tree structure as long as the nodes are SmBinHorNode
// with the same nGroup. This will reduce the number of nested <mrow>
// elements e.g. we only need three <mrow> levels to export
2014-02-25 20:41:20 +01:00
2013-06-25 22:33:13 +02:00
// "a*b*c*d+e*f*g*h+i*j*k*l = a*b*c*d+e*f*g*h+i*j*k*l =
// a*b*c*d+e*f*g*h+i*j*k*l = a*b*c*d+e*f*g*h+i*j*k*l"
2014-02-25 20:41:20 +01:00
2013-06-25 22:33:13 +02:00
// See https://www.libreoffice.org/bugzilla/show_bug.cgi?id=66081
: : std : : stack < const SmNode * > s ;
s . push ( pNode ) ;
while ( ! s . empty ( ) )
{
const SmNode * node = s . top ( ) ;
s . pop ( ) ;
2017-04-17 18:38:38 +09:00
if ( node - > GetType ( ) ! = SmNodeType : : BinHor | | node - > GetToken ( ) . nGroup ! = nGroup )
2013-06-25 22:33:13 +02:00
{
ExportNodes ( node , nLevel + 1 ) ;
continue ;
}
const SmBinHorNode * binNode = static_cast < const SmBinHorNode * > ( node ) ;
s . push ( binNode - > RightOperand ( ) ) ;
s . push ( binNode - > Symbol ( ) ) ;
s . push ( binNode - > LeftOperand ( ) ) ;
}
2010-02-12 16:56:44 +01:00
}
void SmXMLExport : : ExportUnaryHorizontal ( const SmNode * pNode , int nLevel )
{
ExportExpression ( pNode , nLevel ) ;
}
2013-06-30 17:34:40 +02:00
void SmXMLExport : : ExportExpression ( const SmNode * pNode , int nLevel ,
bool bNoMrowContainer /*=false*/ )
2010-02-12 16:56:44 +01:00
{
2018-09-12 10:25:55 +02:00
std : : unique_ptr < SvXMLElementExport > pRow ;
2017-12-21 09:57:46 +00:00
size_t nSize = pNode - > GetNumSubNodes ( ) ;
2010-02-12 16:56:44 +01:00
2010-12-01 14:03:02 +01:00
// #i115443: nodes of type expression always need to be grouped with mrow statement
2013-06-30 17:34:40 +02:00
if ( ! bNoMrowContainer & &
2017-04-17 18:38:38 +09:00
( nSize > 1 | | pNode - > GetType ( ) = = SmNodeType : : Expression ) )
2018-09-12 10:25:55 +02:00
pRow . reset ( new SvXMLElementExport ( * this , XML_NAMESPACE_MATH , XML_MROW , true , true ) ) ;
2010-02-12 16:56:44 +01:00
2017-12-21 09:57:46 +00:00
for ( size_t i = 0 ; i < nSize ; + + i )
{
2010-09-30 22:35:03 +01:00
if ( const SmNode * pTemp = pNode - > GetSubNode ( i ) )
ExportNodes ( pTemp , nLevel + 1 ) ;
2017-12-21 09:57:46 +00:00
}
2010-02-12 16:56:44 +01:00
}
void SmXMLExport : : ExportBinaryVertical ( const SmNode * pNode , int nLevel )
{
2016-08-09 18:25:46 +09:00
assert ( pNode - > GetNumSubNodes ( ) = = 3 ) ;
2013-06-29 22:51:58 +02:00
const SmNode * pNum = pNode - > GetSubNode ( 0 ) ;
const SmNode * pDenom = pNode - > GetSubNode ( 2 ) ;
2017-04-17 18:38:38 +09:00
if ( pNum - > GetType ( ) = = SmNodeType : : Align & & pNum - > GetToken ( ) . eType ! = TALIGNC )
2013-06-29 22:51:58 +02:00
{
// A left or right alignment is specified on the numerator:
// attach the corresponding numalign attribute.
AddAttribute ( XML_NAMESPACE_MATH , XML_NUMALIGN ,
pNum - > GetToken ( ) . eType = = TALIGNL ? XML_LEFT : XML_RIGHT ) ;
}
2017-04-17 18:38:38 +09:00
if ( pDenom - > GetType ( ) = = SmNodeType : : Align & & pDenom - > GetToken ( ) . eType ! = TALIGNC )
2013-06-29 22:51:58 +02:00
{
// A left or right alignment is specified on the denominator:
// attach the corresponding denomalign attribute.
AddAttribute ( XML_NAMESPACE_MATH , XML_DENOMALIGN ,
pDenom - > GetToken ( ) . eType = = TALIGNL ? XML_LEFT : XML_RIGHT ) ;
}
2014-03-28 16:28:51 +02:00
SvXMLElementExport aFraction ( * this , XML_NAMESPACE_MATH , XML_MFRAC , true , true ) ;
2013-06-29 22:51:58 +02:00
ExportNodes ( pNum , nLevel ) ;
ExportNodes ( pDenom , nLevel ) ;
2010-02-12 16:56:44 +01:00
}
2013-06-23 21:32:37 +02:00
void SmXMLExport : : ExportBinaryDiagonal ( const SmNode * pNode , int nLevel )
{
2016-08-09 18:25:46 +09:00
assert ( pNode - > GetNumSubNodes ( ) = = 3 ) ;
2013-06-23 21:32:37 +02:00
if ( pNode - > GetToken ( ) . eType = = TWIDESLASH )
{
// wideslash
// export the node as <mfrac bevelled="true">
AddAttribute ( XML_NAMESPACE_MATH , XML_BEVELLED , XML_TRUE ) ;
SvXMLElementExport aFraction ( * this , XML_NAMESPACE_MATH , XML_MFRAC ,
2014-03-28 16:28:51 +02:00
true , true ) ;
2013-06-23 21:32:37 +02:00
ExportNodes ( pNode - > GetSubNode ( 0 ) , nLevel ) ;
ExportNodes ( pNode - > GetSubNode ( 1 ) , nLevel ) ;
}
else
{
// widebslash
// We can not use <mfrac> to a backslash, so just use <mo>\</mo>
2017-01-31 14:46:38 +02:00
std : : unique_ptr < SvXMLElementExport > pRow ( new SvXMLElementExport ( * this ,
XML_NAMESPACE_MATH , XML_MROW , true , true ) ) ;
2013-06-23 21:32:37 +02:00
ExportNodes ( pNode - > GetSubNode ( 0 ) , nLevel ) ;
{ // Scoping for <mo> creation
SvXMLElementExport aMo ( * this , XML_NAMESPACE_MATH , XML_MO ,
2014-03-28 16:28:51 +02:00
true , true ) ;
2017-07-30 12:16:31 +02:00
sal_Unicode const nArse [ 2 ] = { MS_BACKSLASH , 0x00 } ;
2013-06-23 21:32:37 +02:00
GetDocHandler ( ) - > characters ( nArse ) ;
}
ExportNodes ( pNode - > GetSubNode ( 1 ) , nLevel ) ;
}
}
2010-02-12 16:56:44 +01:00
void SmXMLExport : : ExportTable ( const SmNode * pNode , int nLevel )
{
2018-09-12 10:25:55 +02:00
std : : unique_ptr < SvXMLElementExport > pTable ;
2010-02-12 16:56:44 +01:00
2017-12-21 09:57:46 +00:00
size_t nSize = pNode - > GetNumSubNodes ( ) ;
2010-02-12 16:56:44 +01:00
//If the list ends in newline then the last entry has
2016-01-09 22:55:28 +01:00
//no subnodes, the newline is superfluous so we just drop
2010-02-12 16:56:44 +01:00
//the last node, inclusion would create a bad MathML
//table
2013-07-04 10:57:35 +02:00
if ( nSize > = 1 )
{
const SmNode * pLine = pNode - > GetSubNode ( nSize - 1 ) ;
2017-04-17 18:38:38 +09:00
if ( pLine - > GetType ( ) = = SmNodeType : : Line & & pLine - > GetNumSubNodes ( ) = = 1 & &
2015-11-10 10:24:24 +01:00
pLine - > GetSubNode ( 0 ) ! = nullptr & &
2013-07-04 20:21:06 +01:00
pLine - > GetSubNode ( 0 ) - > GetToken ( ) . eType = = TNEWLINE )
2013-07-04 10:57:35 +02:00
- - nSize ;
}
2010-02-12 16:56:44 +01:00
// try to avoid creating a mtable element when the formula consists only
// of a single output line
if ( nLevel | | ( nSize > 1 ) )
2018-09-12 10:25:55 +02:00
pTable . reset ( new SvXMLElementExport ( * this , XML_NAMESPACE_MATH , XML_MTABLE , true , true ) ) ;
2010-02-12 16:56:44 +01:00
2017-12-21 09:57:46 +00:00
for ( size_t i = 0 ; i < nSize ; + + i )
{
2010-02-12 16:56:44 +01:00
if ( const SmNode * pTemp = pNode - > GetSubNode ( i ) )
{
2019-01-17 16:47:29 +02:00
std : : unique_ptr < SvXMLElementExport > pRow ;
std : : unique_ptr < SvXMLElementExport > pCell ;
2010-02-12 16:56:44 +01:00
if ( pTable )
{
2019-01-17 16:47:29 +02:00
pRow . reset ( new SvXMLElementExport ( * this , XML_NAMESPACE_MATH , XML_MTR , true , true ) ) ;
2013-07-07 08:31:56 +02:00
SmTokenType eAlign = TALIGNC ;
2017-04-17 18:38:38 +09:00
if ( pTemp - > GetType ( ) = = SmNodeType : : Align )
2013-06-29 22:51:58 +02:00
{
2017-04-17 18:38:38 +09:00
// For Binom() and Stack() constructions, the SmNodeType::Align nodes
2013-07-07 08:31:56 +02:00
// are direct children.
// binom{alignl ...}{alignr ...} and
// stack{alignl ... ## alignr ... ## ...}
eAlign = pTemp - > GetToken ( ) . eType ;
}
2017-04-17 18:38:38 +09:00
else if ( pTemp - > GetType ( ) = = SmNodeType : : Line & &
2013-07-07 08:31:56 +02:00
pTemp - > GetNumSubNodes ( ) = = 1 & &
2014-08-20 23:02:56 +02:00
pTemp - > GetSubNode ( 0 ) & &
2017-04-17 18:38:38 +09:00
pTemp - > GetSubNode ( 0 ) - > GetType ( ) = = SmNodeType : : Align )
2013-07-07 08:31:56 +02:00
{
2017-04-17 18:38:38 +09:00
// For the Table() construction, the SmNodeType::Align node is a child
// of an SmNodeType::Line node.
2013-07-07 08:31:56 +02:00
// alignl ... newline alignr ... newline ...
eAlign = pTemp - > GetSubNode ( 0 ) - > GetToken ( ) . eType ;
}
if ( eAlign ! = TALIGNC )
{
// If a left or right alignment is specified on this line,
// attach the corresponding columnalign attribute.
AddAttribute ( XML_NAMESPACE_MATH , XML_COLUMNALIGN ,
eAlign = = TALIGNL ? XML_LEFT : XML_RIGHT ) ;
2013-06-29 22:51:58 +02:00
}
2019-01-17 16:47:29 +02:00
pCell . reset ( new SvXMLElementExport ( * this , XML_NAMESPACE_MATH , XML_MTD , true , true ) ) ;
2010-02-12 16:56:44 +01:00
}
ExportNodes ( pTemp , nLevel + 1 ) ;
}
2017-12-21 09:57:46 +00:00
}
2010-02-12 16:56:44 +01:00
}
2017-05-03 12:02:35 +02:00
void SmXMLExport : : ExportMath ( const SmNode * pNode )
2010-02-12 16:56:44 +01:00
{
2016-07-26 00:30:12 +09:00
const SmTextNode * pTemp = static_cast < const SmTextNode * > ( pNode ) ;
2018-09-12 10:25:55 +02:00
std : : unique_ptr < SvXMLElementExport > pMath ;
2013-06-27 21:35:28 +02:00
2017-04-17 18:38:38 +09:00
if ( pNode - > GetType ( ) = = SmNodeType : : Math | | pNode - > GetType ( ) = = SmNodeType : : GlyphSpecial )
2013-06-27 21:35:28 +02:00
{
2017-04-17 18:38:38 +09:00
// Export SmNodeType::Math and SmNodeType::GlyphSpecial symbols as <mo> elements
2018-09-12 10:25:55 +02:00
pMath . reset ( new SvXMLElementExport ( * this , XML_NAMESPACE_MATH , XML_MO , true , false ) ) ;
2013-06-27 21:35:28 +02:00
}
2017-04-17 18:38:38 +09:00
else if ( pNode - > GetType ( ) = = SmNodeType : : Special )
2016-07-28 09:03:59 +09:00
{
bool bIsItalic = IsItalic ( pNode - > GetFont ( ) ) ;
if ( ! bIsItalic )
AddAttribute ( XML_NAMESPACE_MATH , XML_MATHVARIANT , XML_NORMAL ) ;
2018-09-12 10:25:55 +02:00
pMath . reset ( new SvXMLElementExport ( * this , XML_NAMESPACE_MATH , XML_MI , true , false ) ) ;
2016-07-28 09:03:59 +09:00
}
2013-06-27 21:35:28 +02:00
else
{
2017-04-17 18:38:38 +09:00
// Export SmNodeType::MathIdent and SmNodeType::Place symbols as <mi> elements:
2013-06-27 21:35:28 +02:00
// - These math symbols should not be drawn slanted. Hence we should
// attach a mathvariant="normal" attribute to single-char <mi> elements
// that are not mathematical alphanumeric symbol. For simplicity and to
// work around browser limitations, we always attach such an attribute.
// - The MathML specification suggests to use empty <mi> elements as
// placeholders but they won't be visible in most MathML rendering
2017-04-17 18:38:38 +09:00
// engines so let's use an empty square for SmNodeType::Place instead.
2013-06-27 21:35:28 +02:00
AddAttribute ( XML_NAMESPACE_MATH , XML_MATHVARIANT , XML_NORMAL ) ;
2018-09-12 10:25:55 +02:00
pMath . reset ( new SvXMLElementExport ( * this , XML_NAMESPACE_MATH , XML_MI , true , false ) ) ;
2013-06-27 21:35:28 +02:00
}
2010-02-12 16:56:44 +01:00
sal_Unicode nArse [ 2 ] ;
2012-10-01 20:46:34 +04:00
nArse [ 0 ] = pTemp - > GetText ( ) [ 0 ] ;
2010-02-12 16:56:44 +01:00
sal_Unicode cTmp = ConvertMathToMathML ( nArse [ 0 ] ) ;
if ( cTmp ! = 0 )
nArse [ 0 ] = cTmp ;
2011-04-10 18:30:46 +09:00
OSL_ENSURE ( nArse [ 0 ] ! = 0xffff , " Non existent symbol " ) ;
2010-02-12 16:56:44 +01:00
nArse [ 1 ] = 0 ;
GetDocHandler ( ) - > characters ( nArse ) ;
}
2017-05-03 12:02:35 +02:00
void SmXMLExport : : ExportText ( const SmNode * pNode )
2010-02-12 16:56:44 +01:00
{
2018-09-12 10:25:55 +02:00
std : : unique_ptr < SvXMLElementExport > pText ;
2010-02-12 16:56:44 +01:00
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.
2014-04-24 12:22:08 +02:00
bool bIsItalic = IsItalic ( pTemp - > GetFont ( ) ) ;
2012-10-01 20:46:34 +04:00
if ( ( pTemp - > GetText ( ) . getLength ( ) > 1 ) & & bIsItalic )
2010-02-12 16:56:44 +01:00
AddAttribute ( XML_NAMESPACE_MATH , XML_MATHVARIANT , XML_ITALIC ) ;
2012-10-01 20:46:34 +04:00
else if ( ( pTemp - > GetText ( ) . getLength ( ) = = 1 ) & & ! bIsItalic )
2010-02-12 16:56:44 +01:00
AddAttribute ( XML_NAMESPACE_MATH , XML_MATHVARIANT , XML_NORMAL ) ;
2018-09-12 10:25:55 +02:00
pText . reset ( new SvXMLElementExport ( * this , XML_NAMESPACE_MATH , XML_MI , true , false ) ) ;
2010-02-12 16:56:44 +01:00
break ;
}
case TNUMBER :
2018-09-12 10:25:55 +02:00
pText . reset ( new SvXMLElementExport ( * this , XML_NAMESPACE_MATH , XML_MN , true , false ) ) ;
2010-02-12 16:56:44 +01:00
break ;
case TTEXT :
2018-09-12 10:25:55 +02:00
pText . reset ( new SvXMLElementExport ( * this , XML_NAMESPACE_MATH , XML_MTEXT , true , false ) ) ;
2010-02-12 16:56:44 +01:00
break ;
}
2012-10-01 20:46:34 +04:00
GetDocHandler ( ) - > characters ( pTemp - > GetText ( ) ) ;
2010-02-12 16:56:44 +01:00
}
2017-05-03 12:02:35 +02:00
void SmXMLExport : : ExportBlank ( const SmNode * pNode )
2010-02-12 16:56:44 +01:00
{
2013-06-23 13:28:36 +02:00
const SmBlankNode * pTemp = static_cast < const SmBlankNode * > ( pNode ) ;
//!! exports an <mspace> element. Note that for example "~_~" is allowed in
2010-02-12 16:56:44 +01:00
//!! Math (so it has no sense at all) but must not result in an empty
//!! <msub> tag in MathML !!
2013-06-23 13:28:36 +02:00
if ( pTemp - > GetBlankNum ( ) ! = 0 )
{
// Attach a width attribute. We choose the (somewhat arbitrary) values
// ".5em" for a small gap '`' and "2em" for a large gap '~'.
2016-11-12 11:43:28 +09:00
// (see SmBlankNode::IncreaseBy for how pTemp->mnNum is set).
2013-06-23 13:28:36 +02:00
OUStringBuffer sStrBuf ;
: : sax : : Converter : : convertDouble ( sStrBuf , pTemp - > GetBlankNum ( ) * .5 ) ;
2013-12-13 11:10:10 +02:00
sStrBuf . append ( " em " ) ;
2013-06-23 13:28:36 +02:00
AddAttribute ( XML_NAMESPACE_MATH , XML_WIDTH , sStrBuf . getStr ( ) ) ;
}
2018-09-12 10:25:55 +02:00
std : : unique_ptr < SvXMLElementExport > pText (
new SvXMLElementExport ( * this , XML_NAMESPACE_MATH , XML_MSPACE ,
true , false ) ) ;
2010-02-12 16:56:44 +01:00
GetDocHandler ( ) - > characters ( OUString ( ) ) ;
}
void SmXMLExport : : ExportSubSupScript ( const SmNode * pNode , int nLevel )
{
2015-11-10 10:24:24 +01:00
const SmNode * pSub = nullptr ;
const SmNode * pSup = nullptr ;
const SmNode * pCSub = nullptr ;
const SmNode * pCSup = nullptr ;
const SmNode * pLSub = nullptr ;
const SmNode * pLSup = nullptr ;
2019-01-17 16:48:49 +02:00
std : : unique_ptr < SvXMLElementExport > pThing2 ;
2010-02-12 16:56:44 +01:00
//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 ,
2014-03-28 16:28:51 +02:00
XML_MMULTISCRIPTS , true , true ) ;
2010-02-12 16:56:44 +01:00
2015-11-10 10:24:24 +01:00
if ( nullptr ! = ( pCSub = pNode - > GetSubNode ( CSUB + 1 ) )
& & nullptr ! = ( pCSup = pNode - > GetSubNode ( CSUP + 1 ) ) )
2010-02-12 16:56:44 +01:00
{
2019-01-17 16:48:49 +02:00
pThing2 . reset ( new SvXMLElementExport ( * this , XML_NAMESPACE_MATH ,
XML_MUNDEROVER , true , true ) ) ;
2010-02-12 16:56:44 +01:00
}
2015-11-10 10:24:24 +01:00
else if ( nullptr ! = ( pCSub = pNode - > GetSubNode ( CSUB + 1 ) ) )
2010-02-12 16:56:44 +01:00
{
2019-01-17 16:48:49 +02:00
pThing2 . reset ( new SvXMLElementExport ( * this , XML_NAMESPACE_MATH ,
XML_MUNDER , true , true ) ) ;
2010-02-12 16:56:44 +01:00
}
2015-11-10 10:24:24 +01:00
else if ( nullptr ! = ( pCSup = pNode - > GetSubNode ( CSUP + 1 ) ) )
2010-02-12 16:56:44 +01:00
{
2019-01-17 16:48:49 +02:00
pThing2 . reset ( new SvXMLElementExport ( * this , XML_NAMESPACE_MATH ,
XML_MOVER , true , true ) ) ;
2010-02-12 16:56:44 +01:00
}
ExportNodes ( pNode - > GetSubNode ( 0 ) , nLevel + 1 ) ; //Main Term
if ( pCSub )
ExportNodes ( pCSub , nLevel + 1 ) ;
if ( pCSup )
ExportNodes ( pCSup , nLevel + 1 ) ;
2019-01-17 16:48:49 +02:00
pThing2 . reset ( ) ;
2010-02-12 16:56:44 +01:00
pSub = pNode - > GetSubNode ( RSUB + 1 ) ;
pSup = pNode - > GetSubNode ( RSUP + 1 ) ;
if ( pSub | | pSup )
{
if ( pSub )
ExportNodes ( pSub , nLevel + 1 ) ;
else
{
2014-03-28 16:28:51 +02:00
SvXMLElementExport aNone ( * this , XML_NAMESPACE_MATH , XML_NONE , true , true ) ;
2010-02-12 16:56:44 +01:00
}
if ( pSup )
ExportNodes ( pSup , nLevel + 1 ) ;
else
{
2014-03-28 16:28:51 +02:00
SvXMLElementExport aNone ( * this , XML_NAMESPACE_MATH , XML_NONE , true , true ) ;
2010-02-12 16:56:44 +01:00
}
}
2013-05-15 10:42:04 +03:00
//Separator element between suffix and prefix sub/sup pairs
2010-02-12 16:56:44 +01:00
{
SvXMLElementExport aPrescripts ( * this , XML_NAMESPACE_MATH ,
2014-03-28 16:28:51 +02:00
XML_MPRESCRIPTS , true , true ) ;
2010-02-12 16:56:44 +01:00
}
if ( pLSub )
ExportNodes ( pLSub , nLevel + 1 ) ;
else
{
SvXMLElementExport aNone ( * this , XML_NAMESPACE_MATH , XML_NONE ,
2014-03-28 16:28:51 +02:00
true , true ) ;
2010-02-12 16:56:44 +01:00
}
if ( pLSup )
ExportNodes ( pLSup , nLevel + 1 ) ;
else
{
SvXMLElementExport aNone ( * this , XML_NAMESPACE_MATH , XML_NONE ,
2014-03-28 16:28:51 +02:00
true , true ) ;
2010-02-12 16:56:44 +01:00
}
}
else
{
2019-01-17 16:48:49 +02:00
std : : unique_ptr < SvXMLElementExport > pThing ;
2015-11-10 10:24:24 +01:00
if ( nullptr ! = ( pSub = pNode - > GetSubNode ( RSUB + 1 ) ) & &
nullptr ! = ( pSup = pNode - > GetSubNode ( RSUP + 1 ) ) )
2010-02-12 16:56:44 +01:00
{
2019-01-17 16:48:49 +02:00
pThing . reset ( new SvXMLElementExport ( * this , XML_NAMESPACE_MATH ,
XML_MSUBSUP , true , true ) ) ;
2010-02-12 16:56:44 +01:00
}
2015-11-10 10:24:24 +01:00
else if ( nullptr ! = ( pSub = pNode - > GetSubNode ( RSUB + 1 ) ) )
2010-02-12 16:56:44 +01:00
{
2019-01-17 16:48:49 +02:00
pThing . reset ( new SvXMLElementExport ( * this , XML_NAMESPACE_MATH , XML_MSUB ,
true , true ) ) ;
2010-02-12 16:56:44 +01:00
}
2015-11-10 10:24:24 +01:00
else if ( nullptr ! = ( pSup = pNode - > GetSubNode ( RSUP + 1 ) ) )
2010-02-12 16:56:44 +01:00
{
2019-01-17 16:48:49 +02:00
pThing . reset ( new SvXMLElementExport ( * this , XML_NAMESPACE_MATH , XML_MSUP ,
true , true ) ) ;
2010-02-12 16:56:44 +01:00
}
2015-11-10 10:24:24 +01:00
if ( nullptr ! = ( pCSub = pNode - > GetSubNode ( CSUB + 1 ) )
& & nullptr ! = ( pCSup = pNode - > GetSubNode ( CSUP + 1 ) ) )
2010-02-12 16:56:44 +01:00
{
2019-01-17 16:48:49 +02:00
pThing2 . reset ( new SvXMLElementExport ( * this , XML_NAMESPACE_MATH ,
XML_MUNDEROVER , true , true ) ) ;
2010-02-12 16:56:44 +01:00
}
2015-11-10 10:24:24 +01:00
else if ( nullptr ! = ( pCSub = pNode - > GetSubNode ( CSUB + 1 ) ) )
2010-02-12 16:56:44 +01:00
{
2019-01-17 16:48:49 +02:00
pThing2 . reset ( new SvXMLElementExport ( * this , XML_NAMESPACE_MATH ,
XML_MUNDER , true , true ) ) ;
2010-02-12 16:56:44 +01:00
}
2015-11-10 10:24:24 +01:00
else if ( nullptr ! = ( pCSup = pNode - > GetSubNode ( CSUP + 1 ) ) )
2010-02-12 16:56:44 +01:00
{
2019-01-17 16:48:49 +02:00
pThing2 . reset ( new SvXMLElementExport ( * this , XML_NAMESPACE_MATH ,
XML_MOVER , true , true ) ) ;
2010-02-12 16:56:44 +01:00
}
ExportNodes ( pNode - > GetSubNode ( 0 ) , nLevel + 1 ) ; //Main Term
if ( pCSub )
ExportNodes ( pCSub , nLevel + 1 ) ;
if ( pCSup )
ExportNodes ( pCSup , nLevel + 1 ) ;
2019-01-17 16:48:49 +02:00
pThing2 . reset ( ) ;
2010-02-12 16:56:44 +01:00
if ( pSub )
ExportNodes ( pSub , nLevel + 1 ) ;
if ( pSup )
ExportNodes ( pSup , nLevel + 1 ) ;
2019-01-17 16:48:49 +02:00
pThing . reset ( ) ;
2010-02-12 16:56:44 +01:00
}
}
void SmXMLExport : : ExportBrace ( const SmNode * pNode , int nLevel )
{
const SmNode * pTemp ;
const SmNode * pLeft = pNode - > GetSubNode ( 0 ) ;
const SmNode * pRight = pNode - > GetSubNode ( 2 ) ;
2013-06-30 16:15:14 +02:00
// This used to generate <mfenced> or <mrow>+<mo> elements according to
// the stretchiness of fences. The MathML recommendation defines an
// <mrow>+<mo> construction that is equivalent to the <mfenced> element:
// http://www.w3.org/TR/MathML3/chapter3.html#presm.mfenced
// To simplify our code and avoid issues with mfenced implementations in
// MathML rendering engines, we now always generate <mrow>+<mo> elements.
// See #fdo 66282.
// <mrow>
2018-09-12 10:25:55 +02:00
std : : unique_ptr < SvXMLElementExport > pRow (
new SvXMLElementExport ( * this , XML_NAMESPACE_MATH , XML_MROW ,
true , true ) ) ;
2013-06-30 16:15:14 +02:00
// <mo fence="true"> opening-fence </mo>
if ( pLeft & & ( pLeft - > GetToken ( ) . eType ! = TNONE ) )
2010-02-12 16:56:44 +01:00
{
2013-06-30 16:15:14 +02:00
AddAttribute ( XML_NAMESPACE_MATH , XML_FENCE , XML_TRUE ) ;
2017-04-26 18:27:43 +09:00
if ( pNode - > GetScaleMode ( ) = = SmScaleMode : : Height )
2010-02-12 16:56:44 +01:00
AddAttribute ( XML_NAMESPACE_MATH , XML_STRETCHY , XML_TRUE ) ;
else
AddAttribute ( XML_NAMESPACE_MATH , XML_STRETCHY , XML_FALSE ) ;
ExportNodes ( pLeft , nLevel + 1 ) ;
}
2015-11-10 10:24:24 +01:00
if ( nullptr ! = ( pTemp = pNode - > GetSubNode ( 1 ) ) )
2013-06-30 16:15:14 +02:00
{
// <mrow>
SvXMLElementExport aRow ( * this , XML_NAMESPACE_MATH , XML_MROW ,
2014-03-28 16:28:51 +02:00
true , true ) ;
2010-02-12 16:56:44 +01:00
ExportNodes ( pTemp , nLevel + 1 ) ;
2013-06-30 16:15:14 +02:00
// </mrow>
}
// <mo fence="true"> closing-fence </mo>
if ( pRight & & ( pRight - > GetToken ( ) . eType ! = TNONE ) )
2010-02-12 16:56:44 +01:00
{
2013-06-30 16:15:14 +02:00
AddAttribute ( XML_NAMESPACE_MATH , XML_FENCE , XML_TRUE ) ;
2017-04-26 18:27:43 +09:00
if ( pNode - > GetScaleMode ( ) = = SmScaleMode : : Height )
2010-02-12 16:56:44 +01:00
AddAttribute ( XML_NAMESPACE_MATH , XML_STRETCHY , XML_TRUE ) ;
else
AddAttribute ( XML_NAMESPACE_MATH , XML_STRETCHY , XML_FALSE ) ;
ExportNodes ( pRight , nLevel + 1 ) ;
}
2013-06-30 16:15:14 +02:00
// </mrow>
2010-02-12 16:56:44 +01:00
}
void SmXMLExport : : ExportRoot ( const SmNode * pNode , int nLevel )
{
if ( pNode - > GetSubNode ( 0 ) )
{
2014-03-28 16:28:51 +02:00
SvXMLElementExport aRoot ( * this , XML_NAMESPACE_MATH , XML_MROOT , true ,
true ) ;
2010-02-12 16:56:44 +01:00
ExportNodes ( pNode - > GetSubNode ( 2 ) , nLevel + 1 ) ;
ExportNodes ( pNode - > GetSubNode ( 0 ) , nLevel + 1 ) ;
}
else
{
2014-03-28 16:28:51 +02:00
SvXMLElementExport aSqrt ( * this , XML_NAMESPACE_MATH , XML_MSQRT , true ,
true ) ;
2010-02-12 16:56:44 +01:00
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 */
SvXMLElementExport aRow ( * this , XML_NAMESPACE_MATH , XML_MROW ,
2014-03-28 16:28:51 +02:00
true , true ) ;
2010-02-12 16:56:44 +01:00
ExportNodes ( pNode - > GetSubNode ( 0 ) , nLevel + 1 ) ;
ExportNodes ( pNode - > GetSubNode ( 1 ) , nLevel + 1 ) ;
}
void SmXMLExport : : ExportAttributes ( const SmNode * pNode , int nLevel )
{
2018-09-12 10:25:55 +02:00
std : : unique_ptr < SvXMLElementExport > pElement ;
2010-02-12 16:56:44 +01:00
if ( pNode - > GetToken ( ) . eType = = TUNDERLINE )
{
AddAttribute ( XML_NAMESPACE_MATH , XML_ACCENTUNDER ,
XML_TRUE ) ;
2018-09-12 10:25:55 +02:00
pElement . reset ( new SvXMLElementExport ( * this , XML_NAMESPACE_MATH , XML_MUNDER ,
true , true ) ) ;
2010-02-12 16:56:44 +01:00
}
2013-06-23 21:32:37 +02:00
else if ( pNode - > GetToken ( ) . eType = = TOVERSTRIKE )
{
// export as <menclose notation="horizontalstrike">
AddAttribute ( XML_NAMESPACE_MATH , XML_NOTATION , XML_HORIZONTALSTRIKE ) ;
2018-09-12 10:25:55 +02:00
pElement . reset ( new SvXMLElementExport ( * this , XML_NAMESPACE_MATH ,
XML_MENCLOSE , true , true ) ) ;
2013-06-23 21:32:37 +02:00
}
else
2010-02-12 16:56:44 +01:00
{
AddAttribute ( XML_NAMESPACE_MATH , XML_ACCENT ,
XML_TRUE ) ;
2018-09-12 10:25:55 +02:00
pElement . reset ( new SvXMLElementExport ( * this , XML_NAMESPACE_MATH , XML_MOVER ,
true , true ) ) ;
2010-02-12 16:56:44 +01:00
}
ExportNodes ( pNode - > GetSubNode ( 1 ) , nLevel + 1 ) ;
switch ( pNode - > GetToken ( ) . eType )
{
case TOVERLINE :
{
//proper entity support required
SvXMLElementExport aMath ( * this , XML_NAMESPACE_MATH , XML_MO ,
2014-03-28 16:28:51 +02:00
true , true ) ;
2017-07-30 12:16:31 +02:00
sal_Unicode const nArse [ 2 ] = { 0xAF , 0x00 } ;
2010-02-12 16:56:44 +01:00
GetDocHandler ( ) - > characters ( nArse ) ;
}
break ;
case TUNDERLINE :
{
//proper entity support required
SvXMLElementExport aMath ( * this , XML_NAMESPACE_MATH , XML_MO ,
2014-03-28 16:28:51 +02:00
true , true ) ;
2017-07-30 12:16:31 +02:00
sal_Unicode const nArse [ 2 ] = { 0x0332 , 0x00 } ;
2010-02-12 16:56:44 +01:00
GetDocHandler ( ) - > characters ( nArse ) ;
}
break ;
case TOVERSTRIKE :
break ;
2013-06-22 20:03:59 +02:00
case TWIDETILDE :
case TWIDEHAT :
case TWIDEVEC :
2019-05-27 00:12:28 +09:00
case TWIDEHARPOON :
2013-06-22 20:03:59 +02:00
{
// make these wide accents stretchy
AddAttribute ( XML_NAMESPACE_MATH , XML_STRETCHY , XML_TRUE ) ;
ExportNodes ( pNode - > GetSubNode ( 0 ) , nLevel + 1 ) ;
}
break ;
2010-02-12 16:56:44 +01:00
default :
ExportNodes ( pNode - > GetSubNode ( 0 ) , nLevel + 1 ) ;
break ;
}
}
static bool lcl_HasEffectOnMathvariant ( const SmTokenType eType )
{
return eType = = TBOLD | | eType = = TNBOLD | |
2011-12-29 11:35:59 +01:00
eType = = TITALIC | | eType = = TNITALIC | |
2010-02-12 16:56:44 +01:00
eType = = TSANS | | eType = = TSERIF | | eType = = TFIXED ;
}
void SmXMLExport : : ExportFont ( const SmNode * pNode , int nLevel )
{
2014-02-25 20:41:20 +01:00
2014-04-11 08:52:49 +02:00
// gather the mathvariant attribute relevant data from all
2010-02-12 16:56:44 +01:00
// successively following SmFontNodes...
2014-02-25 20:41:20 +01:00
2010-02-12 16:56:44 +01:00
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 :
2013-09-09 08:52:34 +02:00
SAL_WARN ( " starmath " , " unexpected case " ) ;
2010-02-12 16:56:44 +01:00
}
2015-07-02 18:25:02 +02:00
// According to the parser every node that is to be evaluated here
2010-02-12 16:56:44 +01:00
// 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 )
{
case TPHANTOM :
2013-06-30 17:34:40 +02:00
// No attribute needed. An <mphantom> element will be used below.
2010-02-12 16:56:44 +01:00
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 ;
2014-10-30 18:41:23 +00:00
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 ;
2010-02-12 16:56:44 +01:00
case TSIZE :
{
const SmFontNode * pFontNode = static_cast < const SmFontNode * > ( pNode ) ;
2014-10-23 17:41:47 +02:00
const Fraction & aFrac = pFontNode - > GetSizeParameter ( ) ;
2010-02-12 16:56:44 +01:00
OUStringBuffer sStrBuf ;
switch ( pFontNode - > GetSizeType ( ) )
{
2015-04-01 19:35:19 +09:00
case FontSizeType : : MULTIPLY :
#i108468#: clean up xmluconv code duplication, part 1:
move convertNumber64 from SvXMLUnitConverter to sax::converter.
remove duplicate methods from SvXMLUnitConverter:
convertBool, convertPercent, convertColor, convertNumber, convertDouble,
indexOfComma, encodeBase64, decodeBase64, decodeBase64SomeChars,
clearUndefinedChars
2011-10-11 14:19:00 +02:00
: : sax : : Converter : : convertDouble ( sStrBuf ,
2014-10-23 17:41:47 +02:00
static_cast < double > ( aFrac * Fraction ( 100.00 ) ) ) ;
2013-12-20 14:23:33 +02:00
sStrBuf . append ( ' % ' ) ;
2010-02-12 16:56:44 +01:00
break ;
2015-04-01 19:35:19 +09:00
case FontSizeType : : DIVIDE :
#i108468#: clean up xmluconv code duplication, part 1:
move convertNumber64 from SvXMLUnitConverter to sax::converter.
remove duplicate methods from SvXMLUnitConverter:
convertBool, convertPercent, convertColor, convertNumber, convertDouble,
indexOfComma, encodeBase64, decodeBase64, decodeBase64SomeChars,
clearUndefinedChars
2011-10-11 14:19:00 +02:00
: : sax : : Converter : : convertDouble ( sStrBuf ,
2014-10-23 17:41:47 +02:00
static_cast < double > ( Fraction ( 100.00 ) / aFrac ) ) ;
2013-12-20 14:23:33 +02:00
sStrBuf . append ( ' % ' ) ;
2010-02-12 16:56:44 +01:00
break ;
2015-04-01 19:35:19 +09:00
case FontSizeType : : ABSOLUT :
#i108468#: clean up xmluconv code duplication, part 1:
move convertNumber64 from SvXMLUnitConverter to sax::converter.
remove duplicate methods from SvXMLUnitConverter:
convertBool, convertPercent, convertColor, convertNumber, convertDouble,
indexOfComma, encodeBase64, decodeBase64, decodeBase64SomeChars,
clearUndefinedChars
2011-10-11 14:19:00 +02:00
: : sax : : Converter : : convertDouble ( sStrBuf ,
2014-10-23 17:41:47 +02:00
static_cast < double > ( aFrac ) ) ;
2010-02-12 16:56:44 +01:00
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
2016-02-03 10:13:00 +11:00
Fraction aTemp = Sm100th_mmToPts ( pFontNode - > GetFont ( ) . GetFontSize ( ) . Height ( ) ) ;
2010-02-12 16:56:44 +01:00
2015-04-01 19:35:19 +09:00
if ( pFontNode - > GetSizeType ( ) = = FontSizeType : : MINUS )
2010-02-12 16:56:44 +01:00
aTemp - = aFrac ;
else
aTemp + = aFrac ;
2014-10-23 17:41:47 +02:00
double mytest = static_cast < double > ( aTemp ) ;
2010-02-12 16:56:44 +01:00
mytest = : : rtl : : math : : round ( mytest , 1 ) ;
#i108468#: clean up xmluconv code duplication, part 1:
move convertNumber64 from SvXMLUnitConverter to sax::converter.
remove duplicate methods from SvXMLUnitConverter:
convertBool, convertPercent, convertColor, convertNumber, convertDouble,
indexOfComma, encodeBase64, decodeBase64, decodeBase64SomeChars,
clearUndefinedChars
2011-10-11 14:19:00 +02:00
: : sax : : Converter : : convertDouble ( sStrBuf , mytest ) ;
2010-02-12 16:56:44 +01:00
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
{
2013-09-09 08:52:34 +02:00
SAL_WARN ( " starmath " , " unexpected case " ) ;
2010-02-12 16:56:44 +01:00
}
2012-03-08 14:56:00 +01:00
AddAttribute ( XML_NAMESPACE_MATH , XML_MATHVARIANT , OUString : : createFromAscii ( pText ) ) ;
2010-02-12 16:56:44 +01:00
}
break ;
default :
break ;
}
{
2013-06-30 17:34:40 +02:00
// Wrap everything in an <mphantom> or <mstyle> element. These elements
// are mrow-like, so ExportExpression doesn't need to add an explicit
// <mrow> element. See #fdo 66283.
SvXMLElementExport aElement ( * this , XML_NAMESPACE_MATH ,
pNode - > GetToken ( ) . eType = = TPHANTOM ? XML_MPHANTOM : XML_MSTYLE ,
2014-03-28 16:28:51 +02:00
true , true ) ;
2013-06-30 17:34:40 +02:00
ExportExpression ( pNode , nLevel , true ) ;
2010-02-12 16:56:44 +01:00
}
}
2016-08-01 18:14:21 +09:00
void SmXMLExport : : ExportVerticalBrace ( const SmVerticalBraceNode * pNode , int nLevel )
2010-02-12 16:56:44 +01:00
{
2013-07-03 12:17:53 +02:00
// "[body] overbrace [script]"
2014-02-25 20:41:20 +01:00
2013-07-03 12:17:53 +02:00
// Position body, overbrace and script vertically. First place the overbrace
// OVER the body and then the script OVER this expression.
2014-02-25 20:41:20 +01:00
2013-07-03 12:17:53 +02:00
// [script]
// --[overbrace]--
// XXXXXX[body]XXXXXXX
2014-02-25 20:41:20 +01:00
2013-07-03 12:17:53 +02:00
// Similarly for the underbrace construction.
2010-02-12 16:56:44 +01:00
XMLTokenEnum which ;
switch ( pNode - > GetToken ( ) . eType )
{
case TOVERBRACE :
default :
which = XML_MOVER ;
break ;
case TUNDERBRACE :
which = XML_MUNDER ;
break ;
}
2014-03-28 16:28:51 +02:00
SvXMLElementExport aOver1 ( * this , XML_NAMESPACE_MATH , which , true , true ) ;
2010-02-12 16:56:44 +01:00
{ //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
2014-04-11 08:52:49 +02:00
// also XML_ACCENT is illegal with XML_MUNDER. Thus no XML_ACCENT attribute here!
2014-03-28 16:28:51 +02:00
SvXMLElementExport aOver2 ( * this , XML_NAMESPACE_MATH , which , true , true ) ;
2016-08-01 18:14:21 +09:00
ExportNodes ( pNode - > Body ( ) , nLevel ) ;
2013-06-30 11:08:15 +02:00
AddAttribute ( XML_NAMESPACE_MATH , XML_STRETCHY , XML_TRUE ) ;
2016-08-01 18:14:21 +09:00
ExportNodes ( pNode - > Brace ( ) , nLevel ) ;
2010-02-12 16:56:44 +01:00
}
2016-08-01 18:14:21 +09:00
ExportNodes ( pNode - > Script ( ) , nLevel ) ;
2010-02-12 16:56:44 +01:00
}
void SmXMLExport : : ExportMatrix ( const SmNode * pNode , int nLevel )
{
2014-03-28 16:28:51 +02:00
SvXMLElementExport aTable ( * this , XML_NAMESPACE_MATH , XML_MTABLE , true , true ) ;
2010-02-12 16:56:44 +01:00
const SmMatrixNode * pMatrix = static_cast < const SmMatrixNode * > ( pNode ) ;
2017-12-21 09:57:46 +00:00
size_t i = 0 ;
2015-02-18 17:21:39 +09:00
for ( sal_uInt16 y = 0 ; y < pMatrix - > GetNumRows ( ) ; y + + )
2010-02-12 16:56:44 +01:00
{
2014-03-28 16:28:51 +02:00
SvXMLElementExport aRow ( * this , XML_NAMESPACE_MATH , XML_MTR , true , true ) ;
2015-02-18 17:21:39 +09:00
for ( sal_uInt16 x = 0 ; x < pMatrix - > GetNumCols ( ) ; x + + )
2017-12-21 09:57:46 +00:00
{
2010-02-12 16:56:44 +01:00
if ( const SmNode * pTemp = pNode - > GetSubNode ( i + + ) )
{
2017-04-17 18:38:38 +09:00
if ( pTemp - > GetType ( ) = = SmNodeType : : Align & &
2013-06-29 22:51:58 +02:00
pTemp - > GetToken ( ) . eType ! = TALIGNC )
{
// A left or right alignment is specified on this cell,
// attach the corresponding columnalign attribute.
AddAttribute ( XML_NAMESPACE_MATH , XML_COLUMNALIGN ,
pTemp - > GetToken ( ) . eType = = TALIGNL ?
XML_LEFT : XML_RIGHT ) ;
}
2014-03-28 16:28:51 +02:00
SvXMLElementExport aCell ( * this , XML_NAMESPACE_MATH , XML_MTD , true , true ) ;
2010-02-12 16:56:44 +01:00
ExportNodes ( pTemp , nLevel + 1 ) ;
}
2017-12-21 09:57:46 +00:00
}
2010-02-12 16:56:44 +01:00
}
}
void SmXMLExport : : ExportNodes ( const SmNode * pNode , int nLevel )
{
if ( ! pNode )
return ;
switch ( pNode - > GetType ( ) )
{
2017-04-17 18:38:38 +09:00
case SmNodeType : : Table :
2010-02-12 16:56:44 +01:00
ExportTable ( pNode , nLevel ) ;
break ;
2017-04-17 18:38:38 +09:00
case SmNodeType : : Align :
case SmNodeType : : Bracebody :
case SmNodeType : : Expression :
2010-02-12 16:56:44 +01:00
ExportExpression ( pNode , nLevel ) ;
break ;
2017-04-17 18:38:38 +09:00
case SmNodeType : : Line :
2010-02-12 16:56:44 +01:00
ExportLine ( pNode , nLevel ) ;
break ;
2017-04-17 18:38:38 +09:00
case SmNodeType : : Text :
2017-05-03 12:02:35 +02:00
ExportText ( pNode ) ;
2010-02-12 16:56:44 +01:00
break ;
2017-04-17 18:38:38 +09:00
case SmNodeType : : GlyphSpecial :
case SmNodeType : : Math :
2010-02-12 16:56:44 +01:00
{
sal_Unicode cTmp = 0 ;
const SmTextNode * pTemp = static_cast < const SmTextNode * > ( pNode ) ;
2012-10-01 20:46:34 +04:00
if ( ! pTemp - > GetText ( ) . isEmpty ( ) )
cTmp = ConvertMathToMathML ( pTemp - > GetText ( ) [ 0 ] ) ;
2010-02-12 16:56:44 +01:00
if ( cTmp = = 0 )
{
// no conversion to MathML implemented -> export it as text
// thus at least it will not vanish into nothing
2017-05-03 12:02:35 +02:00
ExportText ( pNode ) ;
2010-02-12 16:56:44 +01:00
}
else
{
2016-09-25 19:56:52 +09:00
switch ( pNode - > GetToken ( ) . eType )
{
case TINTD :
AddAttribute ( XML_NAMESPACE_MATH , XML_STRETCHY , XML_TRUE ) ;
break ;
default :
break ;
}
2010-02-12 16:56:44 +01:00
//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 ( ) ;
2014-04-24 12:22:08 +02:00
bool bAddStretch = true ;
2010-02-12 16:56:44 +01:00
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 ) )
{
2014-04-24 12:22:08 +02:00
bAddStretch = false ;
2010-02-12 16:56:44 +01:00
break ;
}
}
if ( bAddStretch )
{
AddAttribute ( XML_NAMESPACE_MATH , XML_STRETCHY , XML_FALSE ) ;
}
2017-05-03 12:02:35 +02:00
ExportMath ( pNode ) ;
2010-02-12 16:56:44 +01:00
}
}
break ;
2017-04-17 18:38:38 +09:00
case SmNodeType : : Special : //SmNodeType::Special requires some sort of Entity preservation in the XML engine.
case SmNodeType : : MathIdent :
case SmNodeType : : Place :
2017-05-03 12:02:35 +02:00
ExportMath ( pNode ) ;
2010-02-12 16:56:44 +01:00
break ;
2017-04-17 18:38:38 +09:00
case SmNodeType : : BinHor :
2010-02-12 16:56:44 +01:00
ExportBinaryHorizontal ( pNode , nLevel ) ;
break ;
2017-04-17 18:38:38 +09:00
case SmNodeType : : UnHor :
2010-02-12 16:56:44 +01:00
ExportUnaryHorizontal ( pNode , nLevel ) ;
break ;
2017-04-17 18:38:38 +09:00
case SmNodeType : : Brace :
2010-02-12 16:56:44 +01:00
ExportBrace ( pNode , nLevel ) ;
break ;
2017-04-17 18:38:38 +09:00
case SmNodeType : : BinVer :
2010-02-12 16:56:44 +01:00
ExportBinaryVertical ( pNode , nLevel ) ;
break ;
2017-04-17 18:38:38 +09:00
case SmNodeType : : BinDiagonal :
2013-06-23 21:32:37 +02:00
ExportBinaryDiagonal ( pNode , nLevel ) ;
break ;
2017-04-17 18:38:38 +09:00
case SmNodeType : : SubSup :
2010-02-12 16:56:44 +01:00
ExportSubSupScript ( pNode , nLevel ) ;
break ;
2017-04-17 18:38:38 +09:00
case SmNodeType : : Root :
2010-02-12 16:56:44 +01:00
ExportRoot ( pNode , nLevel ) ;
break ;
2017-04-17 18:38:38 +09:00
case SmNodeType : : Oper :
2010-02-12 16:56:44 +01:00
ExportOperator ( pNode , nLevel ) ;
break ;
2017-04-17 18:38:38 +09:00
case SmNodeType : : Attribut :
2010-02-12 16:56:44 +01:00
ExportAttributes ( pNode , nLevel ) ;
break ;
2017-04-17 18:38:38 +09:00
case SmNodeType : : Font :
2010-02-12 16:56:44 +01:00
ExportFont ( pNode , nLevel ) ;
break ;
2017-04-17 18:38:38 +09:00
case SmNodeType : : VerticalBrace :
2016-08-01 18:14:21 +09:00
ExportVerticalBrace ( static_cast < const SmVerticalBraceNode * > ( pNode ) , nLevel ) ;
2010-02-12 16:56:44 +01:00
break ;
2017-04-17 18:38:38 +09:00
case SmNodeType : : Matrix :
2010-02-12 16:56:44 +01:00
ExportMatrix ( pNode , nLevel ) ;
break ;
2017-04-17 18:38:38 +09:00
case SmNodeType : : Blank :
2017-05-03 12:02:35 +02:00
ExportBlank ( pNode ) ;
2010-02-12 16:56:44 +01:00
break ;
default :
2013-09-09 08:52:34 +02:00
SAL_WARN ( " starmath " , " Warning: failed to export a node? " ) ;
2010-02-12 16:56:44 +01:00
break ;
}
}
2010-10-14 08:30:41 +02:00
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */