/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * Version: MPL 1.1 / GPLv3+ / LGPLv3+ * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License or as specified alternatively below. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * Major Contributor(s): * Copyright (C) 2011 Lubos Lunak (initial developer) * * All Rights Reserved. * * For minor contributions see the git repository. * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 3 or later (the "GPLv3+"), or * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"), * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable * instead of those above. */ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_starmath.hxx" #include "ooxml.hxx" #include using namespace oox; using namespace oox::core; // TODO duped from MathType static sal_Unicode Convert(sal_Unicode nIn) { //Find the best match in accepted unicode for our private area symbols static sal_Unicode aStarMathPrivateToUnicode[] = { 0x2030, 0xF613, 0xF612, 0x002B, 0x003C, 0x003E, 0xE425, 0xE421, 0xE088, 0x2208, 0x0192, 0x2026, 0x2192, 0x221A, 0x221A, 0x221A, 0xE090, 0x005E, 0x02C7, 0x02D8, 0x00B4, 0x0060, 0x02DC, 0x00AF, 0x0362, 0xE099, 0xE09A, 0x20DB, 0xE09C, 0xE09D, 0x0028, 0x0029, 0x2220, 0x22AF, 0xE0A2, 0xE0A3, 0xE0A4, 0xE0A5, 0xE0A6, 0xE0A7, 0x002F, 0x005C, 0x274F, 0xE0AB, 0x0393, 0x0394, 0x0398, 0x039b, 0x039e, 0x03A0, 0x03a3, 0x03a5, 0x03a6, 0x03a8, 0x03A9, 0x03B1, 0x03B2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, 0x03c0, 0x03c1, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, 0x03c9, 0x03b5, 0x03d1, 0x03d6, 0xE0D2, 0x03db, 0x2118, 0x2202, 0x2129, 0xE0D7, 0xE0D8, 0x22A4, 0xE0DA, 0x2190, 0x2191, 0x2193 }; if ((nIn >= 0xE080) && (nIn <= 0xE0DD)) nIn = aStarMathPrivateToUnicode[nIn-0xE080]; //For whatever unicode glyph that equation editor doesn't ship with that //we have a possible match we can munge it to. switch (nIn) { case 0x2223: nIn = '|'; break; default: break; } return nIn; } SmOoxml::SmOoxml( const String &rIn, const SmNode* pIn, OoxmlVersion v ) : str( rIn ) , pTree( pIn ) , version( v ) { } bool SmOoxml::ConvertFromStarMath( ::sax_fastparser::FSHelperPtr serializer ) { if( pTree == NULL ) return false; m_pSerializer = serializer; m_pSerializer->startElementNS( XML_m, XML_oMath, FSNS( XML_xmlns, XML_m ), "http://schemas.openxmlformats.org/officeDocument/2006/math", FSEND ); HandleNode( pTree, 0 ); m_pSerializer->endElementNS( XML_m, XML_oMath ); return true; } // NOTE: This is still work in progress and unfinished, but it already covers a good // part of the ooxml math stuff. void SmOoxml::HandleNode( const SmNode* pNode, int nLevel ) { // fprintf(stderr,"XX %d %d %d\n", nLevel, pNode->GetType(), pNode->GetNumSubNodes()); switch(pNode->GetType()) { case NATTRIBUT: HandleAttribute( static_cast< const SmAttributNode* >( pNode ), nLevel ); break; case NTEXT: HandleText(pNode,nLevel); break; case NVERTICAL_BRACE: HandleVerticalBrace( static_cast< const SmVerticalBraceNode* >( pNode ), nLevel ); break; case NBRACE: HandleBrace( static_cast< const SmBraceNode* >( pNode ), nLevel ); break; case NOPER: HandleOperator( static_cast< const SmOperNode* >( pNode ), nLevel ); break; case NUNHOR: HandleUnaryOperation( static_cast< const SmUnHorNode* >( pNode ), nLevel ); break; case NBINHOR: HandleBinaryOperation( static_cast< const SmBinHorNode* >( pNode ), nLevel ); break; case NBINVER: HandleFractions(pNode,nLevel); break; case NROOT: HandleRoot( static_cast< const SmRootNode* >( pNode ), nLevel ); break; case NSPECIAL: { const SmTextNode* pText= static_cast< const SmTextNode* >( pNode ); //if the token str and the result text are the same then this //is to be seen as text, else assume its a mathchar if (pText->GetText() == pText->GetToken().aText) HandleText(pText,nLevel); else HandleMath(pText,nLevel); break; } case NMATH: HandleMath(pNode,nLevel); break; case NSUBSUP: HandleSubSupScript( static_cast< const SmSubSupNode* >( pNode ), nLevel ); break; case NEXPRESSION: HandleAllSubNodes( pNode, nLevel ); break; case NTABLE: //Root Node, PILE equivalent, i.e. vertical stack HandleTable(pNode,nLevel); break; case NMATRIX: HandleMatrix( static_cast< const SmMatrixNode* >( pNode ), nLevel ); break; case NLINE: { // TODO HandleAllSubNodes( pNode, nLevel ); } break; #if 0 case NALIGN: HandleMAlign(pNode,nLevel); break; #endif case NPLACE: // explicitly do nothing, MSOffice treats that as a placeholder if item is missing break; case NBLANK: m_pSerializer->startElementNS( XML_m, XML_r, FSEND ); m_pSerializer->startElementNS( XML_m, XML_t, FSNS( XML_xml, XML_space ), "preserve", FSEND ); m_pSerializer->write( " " ); m_pSerializer->endElementNS( XML_m, XML_t ); m_pSerializer->endElementNS( XML_m, XML_r ); break; default: HandleAllSubNodes( pNode, nLevel ); break; } } //Root Node, PILE equivalent, i.e. vertical stack void SmOoxml::HandleTable( const SmNode* pNode, int nLevel ) { //The root of the starmath is a table, if //we convert this them each iteration of //conversion from starmath to OOXML will //add an extra unnecessary level to the //OOXML output stack which would grow //without bound in a multi step conversion if( nLevel || pNode->GetNumSubNodes() > 1 ) HandleVerticalStack( pNode, nLevel, 0 ); else HandleAllSubNodes( pNode, nLevel ); } void SmOoxml::HandleAllSubNodes( const SmNode* pNode, int nLevel ) { int size = pNode->GetNumSubNodes(); for( int i = 0; i < size; ++i ) { // TODO remove when all types of nodes are handled properly if( pNode->GetSubNode( i ) == NULL ) { OSL_FAIL( "Subnode is NULL, parent node not handled properly" ); continue; } HandleNode( pNode->GetSubNode( i ), nLevel + 1 ); } } // output vertical stack, firstItem says which child to use as first (if there // are more than two children, OOXML can have only a vertical stack of two items, // so create a bigger vertical stack recursively) void SmOoxml::HandleVerticalStack( const SmNode* pNode, int nLevel, int firstItem ) { if( firstItem == pNode->GetNumSubNodes() - 1 ) // only one item, just output the item { HandleNode( pNode->GetSubNode( firstItem ), nLevel + 1 ); return; } m_pSerializer->startElementNS( XML_m, XML_f, FSEND ); m_pSerializer->startElementNS( XML_m, XML_fPr, FSEND ); m_pSerializer->singleElementNS( XML_m, XML_type, FSNS( XML_m, XML_val ), "noBar", FSEND ); m_pSerializer->endElementNS( XML_m, XML_fPr ); m_pSerializer->startElementNS( XML_m, XML_num, FSEND ); HandleNode( pNode->GetSubNode( firstItem ), nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_num ); // TODO this nesting means MSOffice will use smaller fonts for nested items, // not sure if there's another way to represent a bigger stack than 2 items m_pSerializer->startElementNS( XML_m, XML_den, FSEND ); HandleVerticalStack( pNode, nLevel, firstItem + 1 ); m_pSerializer->endElementNS( XML_m, XML_den ); m_pSerializer->endElementNS( XML_m, XML_f ); } void SmOoxml::HandleText( const SmNode* pNode, int /*nLevel*/) { m_pSerializer->startElementNS( XML_m, XML_r, FSEND ); if( version == ECMA_DIALECT ) { // HACK: MSOffice2007 does not import characters properly unless this font is explicitly given m_pSerializer->startElementNS( XML_w, XML_rPr, FSEND ); m_pSerializer->singleElementNS( XML_w, XML_rFonts, FSNS( XML_w, XML_ascii ), "Cambria Math", FSNS( XML_w, XML_hAnsi ), "Cambria Math", FSEND ); m_pSerializer->endElementNS( XML_w, XML_rPr ); } m_pSerializer->startElementNS( XML_m, XML_t, FSNS( XML_xml, XML_space ), "preserve", FSEND ); SmTextNode* pTemp=(SmTextNode* )pNode; // fprintf(stderr, "T %s\n", rtl::OUStringToOString( pTemp->GetText(), RTL_TEXTENCODING_UTF8 ).getStr()); for(xub_StrLen i=0;iGetText().Len();i++) { #if 0 if ((nPendingAttributes) && (i == ((pTemp->GetText().Len()+1)/2)-1)) { *pS << sal_uInt8(0x22); //char, with attributes right //after the character } else *pS << sal_uInt8(CHAR); sal_uInt8 nFace = 0x1; if (pNode->GetFont().GetItalic() == ITALIC_NORMAL) nFace = 0x3; else if (pNode->GetFont().GetWeight() == WEIGHT_BOLD) nFace = 0x7; *pS << sal_uInt8(nFace+128); //typeface #endif sal_uInt16 nChar = pTemp->GetText().GetChar(i); m_pSerializer->write( rtl::OUString( Convert(nChar))); #if 0 //Mathtype can only have these sort of character //attributes on a single character, starmath can put them //anywhere, when the entity involved is a text run this is //a large effort to place the character attribute on the //central mathtype character so that it does pretty much //what the user probably has in mind. The attributes //filled in here are dummy ones which are replaced in the //ATTRIBUT handler if a suitable location for the //attributes was found here. Unfortunately it is //possible for starmath to place character attributes on //entities which cannot occur in mathtype e.g. a Summation //symbol so these attributes may be lost if ((nPendingAttributes) && (i == ((pTemp->GetText().Len()+1)/2)-1)) { *pS << sal_uInt8(EMBEL); while (nPendingAttributes) { *pS << sal_uInt8(2); //wedge the attributes in here and clear //the pending stack nPendingAttributes--; } nInsertion=pS->Tell(); *pS << sal_uInt8(END); //end embel *pS << sal_uInt8(END); //end embel } #endif } m_pSerializer->endElementNS( XML_m, XML_t ); m_pSerializer->endElementNS( XML_m, XML_r ); } void SmOoxml::HandleFractions( const SmNode* pNode, int nLevel, const char* type ) { m_pSerializer->startElementNS( XML_m, XML_f, FSEND ); if( type != NULL ) { m_pSerializer->startElementNS( XML_m, XML_fPr, FSEND ); m_pSerializer->singleElementNS( XML_m, XML_type, FSNS( XML_m, XML_val ), type, FSEND ); m_pSerializer->endElementNS( XML_m, XML_fPr ); } OSL_ASSERT( pNode->GetNumSubNodes() == 3 ); m_pSerializer->startElementNS( XML_m, XML_num, FSEND ); HandleNode( pNode->GetSubNode( 0 ), nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_num ); m_pSerializer->startElementNS( XML_m, XML_den, FSEND ); HandleNode( pNode->GetSubNode( 2 ), nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_den ); m_pSerializer->endElementNS( XML_m, XML_f ); } void SmOoxml::HandleUnaryOperation( const SmUnHorNode* pNode, int nLevel ) { // update HandleMath() when adding new items // fprintf(stderr,"UNARY %d\n", pNode->GetToken().eType ); switch( pNode->GetToken().eType ) { default: HandleAllSubNodes( pNode, nLevel ); break; } } void SmOoxml::HandleBinaryOperation( const SmBinHorNode* pNode, int nLevel ) { // fprintf(stderr,"BINARY %d\n", pNode->Symbol()->GetToken().eType ); // update HandleMath() when adding new items switch( pNode->Symbol()->GetToken().eType ) { case TDIVIDEBY: return HandleFractions( pNode, nLevel, "lin" ); default: HandleAllSubNodes( pNode, nLevel ); break; } } void SmOoxml::HandleAttribute( const SmAttributNode* pNode, int nLevel ) { switch( pNode->Attribute()->GetToken().eType ) { case TCHECK: case TACUTE: case TGRAVE: case TBREVE: case TCIRCLE: case TVEC: case TTILDE: case THAT: case TDOT: case TDDOT: case TDDDOT: case TWIDETILDE: case TWIDEHAT: case TWIDEVEC: { m_pSerializer->startElementNS( XML_m, XML_acc, FSEND ); m_pSerializer->startElementNS( XML_m, XML_accPr, FSEND ); rtl::OString value = rtl::OUStringToOString( rtl::OUString( pNode->Attribute()->GetToken().cMathChar ), RTL_TEXTENCODING_UTF8 ); m_pSerializer->singleElementNS( XML_m, XML_chr, FSNS( XML_m, XML_val ), value.getStr(), FSEND ); m_pSerializer->endElementNS( XML_m, XML_accPr ); m_pSerializer->startElementNS( XML_m, XML_e, FSEND ); HandleNode( pNode->Body(), nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_e ); m_pSerializer->endElementNS( XML_m, XML_acc ); break; } case TBAR: case TOVERLINE: case TUNDERLINE: m_pSerializer->startElementNS( XML_m, XML_bar, FSEND ); m_pSerializer->startElementNS( XML_m, XML_barPr, FSEND ); m_pSerializer->singleElementNS( XML_m, XML_pos, FSNS( XML_m, XML_val ), ( pNode->Attribute()->GetToken().eType == TUNDERLINE ) ? "bot" : "top", FSEND ); m_pSerializer->endElementNS( XML_m, XML_barPr ); m_pSerializer->startElementNS( XML_m, XML_e, FSEND ); HandleNode( pNode->Body(), nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_e ); m_pSerializer->endElementNS( XML_m, XML_bar ); break; case TOVERSTRIKE: m_pSerializer->startElementNS( XML_m, XML_borderBox, FSEND ); m_pSerializer->startElementNS( XML_m, XML_borderBoxPr, FSEND ); m_pSerializer->singleElementNS( XML_m, XML_hideTop, FSNS( XML_m, XML_val ), "1", FSEND ); m_pSerializer->singleElementNS( XML_m, XML_hideBot, FSNS( XML_m, XML_val ), "1", FSEND ); m_pSerializer->singleElementNS( XML_m, XML_hideLeft, FSNS( XML_m, XML_val ), "1", FSEND ); m_pSerializer->singleElementNS( XML_m, XML_hideRight, FSNS( XML_m, XML_val ), "1", FSEND ); m_pSerializer->singleElementNS( XML_m, XML_strikeH, FSNS( XML_m, XML_val ), "1", FSEND ); m_pSerializer->endElementNS( XML_m, XML_borderBoxPr ); m_pSerializer->startElementNS( XML_m, XML_e, FSEND ); HandleNode( pNode->Body(), nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_e ); m_pSerializer->endElementNS( XML_m, XML_borderBox ); break; default: HandleAllSubNodes( pNode, nLevel ); break; } } void SmOoxml::HandleMath( const SmNode* pNode, int nLevel ) { // fprintf(stderr,"MATH %d\n", pNode->GetToken().eType); switch( pNode->GetToken().eType ) { case TDIVIDEBY: case TACUTE: // these are handled elsewhere, e.g. when handling BINHOR OSL_ASSERT( false ); default: HandleText( pNode, nLevel ); break; } } void SmOoxml::HandleRoot( const SmRootNode* pNode, int nLevel ) { m_pSerializer->startElementNS( XML_m, XML_rad, FSEND ); if( const SmNode* argument = pNode->Argument()) { m_pSerializer->startElementNS( XML_m, XML_deg, FSEND ); HandleNode( argument, nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_deg ); } else { m_pSerializer->startElementNS( XML_m, XML_radPr, FSEND ); m_pSerializer->singleElementNS( XML_m, XML_degHide, FSNS( XML_m, XML_val ), "1", FSEND ); m_pSerializer->endElementNS( XML_m, XML_radPr ); m_pSerializer->singleElementNS( XML_m, XML_deg, FSEND ); // empty but present } m_pSerializer->startElementNS( XML_m, XML_e, FSEND ); HandleNode( pNode->Body(), nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_e ); m_pSerializer->endElementNS( XML_m, XML_rad ); } static rtl::OString mathSymbolToString( const SmNode* node ) { OSL_ASSERT( node->GetType() == NMATH && static_cast< const SmTextNode* >( node )->GetText().Len() == 1 ); sal_Unicode chr = Convert( static_cast< const SmTextNode* >( node )->GetText().GetChar( 0 )); return rtl::OUStringToOString( rtl::OUString( chr ), RTL_TEXTENCODING_UTF8 ); } void SmOoxml::HandleOperator( const SmOperNode* pNode, int nLevel ) { // fprintf( stderr, "OPER %d\n", pNode->GetToken().eType ); switch( pNode->GetToken().eType ) { case TINT: case TIINT: case TIIINT: case TLINT: case TLLINT: case TLLLINT: case TPROD: case TCOPROD: { const SmSubSupNode* subsup = pNode->GetSubNode( 0 )->GetType() == NSUBSUP ? static_cast< const SmSubSupNode* >( pNode->GetSubNode( 0 )) : NULL; const SmNode* operation = subsup != NULL ? subsup->GetBody() : pNode->GetSubNode( 0 ); m_pSerializer->startElementNS( XML_m, XML_nary, FSEND ); m_pSerializer->startElementNS( XML_m, XML_naryPr, FSEND ); m_pSerializer->singleElementNS( XML_m, XML_chr, FSNS( XML_m, XML_val ), mathSymbolToString( operation ).getStr(), FSEND ); if( subsup == NULL || subsup->GetSubSup( CSUB ) == NULL ) m_pSerializer->singleElementNS( XML_m, XML_subHide, FSNS( XML_m, XML_val ), "1", FSEND ); if( subsup == NULL || subsup->GetSubSup( CSUP ) == NULL ) m_pSerializer->singleElementNS( XML_m, XML_supHide, FSNS( XML_m, XML_val ), "1", FSEND ); m_pSerializer->endElementNS( XML_m, XML_naryPr ); if( subsup == NULL || subsup->GetSubSup( CSUB ) == NULL ) m_pSerializer->singleElementNS( XML_m, XML_sub, FSEND ); else { m_pSerializer->startElementNS( XML_m, XML_sub, FSEND ); HandleNode( subsup->GetSubSup( CSUB ), nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_sub ); } if( subsup == NULL || subsup->GetSubSup( CSUP ) == NULL ) m_pSerializer->singleElementNS( XML_m, XML_sup, FSEND ); else { m_pSerializer->startElementNS( XML_m, XML_sup, FSEND ); HandleNode( subsup->GetSubSup( CSUP ), nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_sup ); } m_pSerializer->startElementNS( XML_m, XML_e, FSEND ); HandleNode( pNode->GetSubNode( 1 ), nLevel + 1 ); // body m_pSerializer->endElementNS( XML_m, XML_e ); m_pSerializer->endElementNS( XML_m, XML_nary ); break; } case TLIM: m_pSerializer->startElementNS( XML_m, XML_func, FSEND ); m_pSerializer->startElementNS( XML_m, XML_fName, FSEND ); m_pSerializer->startElementNS( XML_m, XML_limLow, FSEND ); m_pSerializer->startElementNS( XML_m, XML_e, FSEND ); HandleNode( pNode->GetSymbol(), nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_e ); m_pSerializer->startElementNS( XML_m, XML_lim, FSEND ); if( const SmSubSupNode* subsup = pNode->GetSubNode( 0 )->GetType() == NSUBSUP ? static_cast< const SmSubSupNode* >( pNode->GetSubNode( 0 )) : NULL ) { if( subsup->GetSubSup( CSUB ) != NULL ) HandleNode( subsup->GetSubSup( CSUB ), nLevel + 1 ); } m_pSerializer->endElementNS( XML_m, XML_lim ); m_pSerializer->endElementNS( XML_m, XML_limLow ); m_pSerializer->endElementNS( XML_m, XML_fName ); m_pSerializer->startElementNS( XML_m, XML_e, FSEND ); HandleNode( pNode->GetSubNode( 1 ), nLevel + 1 ); // body m_pSerializer->endElementNS( XML_m, XML_e ); m_pSerializer->endElementNS( XML_m, XML_func ); break; default: OSL_FAIL( "Unhandled operation" ); HandleAllSubNodes( pNode, nLevel ); break; } } void SmOoxml::HandleSubSupScript( const SmSubSupNode* pNode, int nLevel ) { // set flags to a bitfield of which sub/sup items exists int flags = ( pNode->GetSubSup( CSUB ) != NULL ? ( 1 << CSUB ) : 0 ) | ( pNode->GetSubSup( CSUP ) != NULL ? ( 1 << CSUP ) : 0 ) | ( pNode->GetSubSup( RSUB ) != NULL ? ( 1 << RSUB ) : 0 ) | ( pNode->GetSubSup( RSUP ) != NULL ? ( 1 << RSUP ) : 0 ) | ( pNode->GetSubSup( LSUB ) != NULL ? ( 1 << RSUB ) : 0 ) | ( pNode->GetSubSup( LSUP ) != NULL ? ( 1 << LSUP ) : 0 ); if( flags == 0 ) // none return; HandleSubSupScriptInternal( pNode, nLevel, flags ); } void SmOoxml::HandleSubSupScriptInternal( const SmSubSupNode* pNode, int nLevel, int flags ) { if( flags == ( 1 << RSUP | 1 << RSUB )) { // m:sSubSup m_pSerializer->startElementNS( XML_m, XML_sSubSup, FSEND ); m_pSerializer->startElementNS( XML_m, XML_e, FSEND ); HandleNode( pNode->GetBody(), nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_e ); m_pSerializer->startElementNS( XML_m, XML_sub, FSEND ); HandleNode( pNode->GetSubSup( RSUB ), nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_sub ); m_pSerializer->startElementNS( XML_m, XML_sup, FSEND ); HandleNode( pNode->GetSubSup( RSUP ), nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_sup ); m_pSerializer->endElementNS( XML_m, XML_sSubSup ); } else if( flags == 1 << RSUB ) { // m:sSub m_pSerializer->startElementNS( XML_m, XML_sSub, FSEND ); m_pSerializer->startElementNS( XML_m, XML_e, FSEND ); HandleNode( pNode->GetBody(), nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_e ); m_pSerializer->startElementNS( XML_m, XML_sub, FSEND ); HandleNode( pNode->GetSubSup( RSUB ), nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_sub ); m_pSerializer->endElementNS( XML_m, XML_sSub ); } else if( flags == 1 << RSUP ) { // m:sSup m_pSerializer->startElementNS( XML_m, XML_sSup, FSEND ); m_pSerializer->startElementNS( XML_m, XML_e, FSEND ); HandleNode( pNode->GetBody(), nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_e ); m_pSerializer->startElementNS( XML_m, XML_sup, FSEND ); HandleNode( pNode->GetSubSup( RSUP ), nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_sup ); m_pSerializer->endElementNS( XML_m, XML_sSup ); } else if( flags == ( 1 << LSUP | 1 << LSUB )) { // m:sPre m_pSerializer->startElementNS( XML_m, XML_sPre, FSEND ); m_pSerializer->startElementNS( XML_m, XML_sub, FSEND ); HandleNode( pNode->GetSubSup( LSUB ), nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_sub ); m_pSerializer->startElementNS( XML_m, XML_sup, FSEND ); HandleNode( pNode->GetSubSup( LSUP ), nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_sup ); m_pSerializer->startElementNS( XML_m, XML_e, FSEND ); HandleNode( pNode->GetBody(), nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_e ); m_pSerializer->endElementNS( XML_m, XML_sSubSup ); } else { OSL_FAIL( "Unhandled sub/sup combination" ); HandleAllSubNodes( pNode, nLevel ); } } void SmOoxml::HandleMatrix( const SmMatrixNode* pNode, int nLevel ) { m_pSerializer->startElementNS( XML_m, XML_m, FSEND ); for( int row = 0; row < pNode->GetNumRows(); ++row ) { m_pSerializer->startElementNS( XML_m, XML_mr, FSEND ); for( int col = 0; col < pNode->GetNumCols(); ++col ) { m_pSerializer->startElementNS( XML_m, XML_e, FSEND ); if( const SmNode* node = pNode->GetSubNode( row * pNode->GetNumCols() + col )) HandleNode( node, nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_e ); } m_pSerializer->endElementNS( XML_m, XML_mr ); } m_pSerializer->endElementNS( XML_m, XML_m ); } void SmOoxml::HandleBrace( const SmBraceNode* pNode, int nLevel ) { m_pSerializer->startElementNS( XML_m, XML_d, FSEND ); m_pSerializer->startElementNS( XML_m, XML_dPr, FSEND ); m_pSerializer->singleElementNS( XML_m, XML_begChr, FSNS( XML_m, XML_val ), mathSymbolToString( pNode->OpeningBrace()).getStr(), FSEND ); std::vector< const SmNode* > subnodes; if( pNode->Body()->GetType() == NBRACEBODY ) { const SmBracebodyNode* body = static_cast< const SmBracebodyNode* >( pNode->Body()); bool separatorWritten = false; // assume all separators are the same for( int i = 0; i < body->GetNumSubNodes(); ++i ) { const SmNode* subnode = body->GetSubNode( i ); if( subnode->GetType() == NMATH ) { // do not write, but write what separator it is const SmMathSymbolNode* math = static_cast< const SmMathSymbolNode* >( subnode ); if( !separatorWritten ) { m_pSerializer->singleElementNS( XML_m, XML_sepChr, FSNS( XML_m, XML_val ), mathSymbolToString( math ).getStr(), FSEND ); separatorWritten = true; } } else subnodes.push_back( subnode ); } } else subnodes.push_back( pNode->Body()); m_pSerializer->singleElementNS( XML_m, XML_endChr, FSNS( XML_m, XML_val ), mathSymbolToString( pNode->ClosingBrace()).getStr(), FSEND ); m_pSerializer->endElementNS( XML_m, XML_dPr ); for( unsigned int i = 0; i < subnodes.size(); ++i ) { m_pSerializer->startElementNS( XML_m, XML_e, FSEND ); HandleNode( subnodes[ i ], nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_e ); } m_pSerializer->endElementNS( XML_m, XML_d ); } void SmOoxml::HandleVerticalBrace( const SmVerticalBraceNode* pNode, int nLevel ) { // fprintf( stderr, "VERT %d\n", pNode->GetToken().eType ); switch( pNode->GetToken().eType ) { case TOVERBRACE: case TUNDERBRACE: { bool top = ( pNode->GetToken().eType == TOVERBRACE ); m_pSerializer->startElementNS( XML_m, top ? XML_limUpp : XML_limLow, FSEND ); m_pSerializer->startElementNS( XML_m, XML_e, FSEND ); m_pSerializer->startElementNS( XML_m, XML_groupChr, FSEND ); m_pSerializer->startElementNS( XML_m, XML_groupChrPr, FSEND ); m_pSerializer->singleElementNS( XML_m, XML_chr, FSNS( XML_m, XML_val ), mathSymbolToString( pNode->Brace()).getStr(), FSEND ); // TODO not sure if pos and vertJc are correct m_pSerializer->singleElementNS( XML_m, XML_pos, FSNS( XML_m, XML_val ), top ? "top" : "bot", FSEND ); m_pSerializer->singleElementNS( XML_m, XML_vertJc, FSNS( XML_m, XML_val ), top ? "bot" : "top", FSEND ); m_pSerializer->endElementNS( XML_m, XML_groupChrPr ); m_pSerializer->startElementNS( XML_m, XML_e, FSEND ); HandleNode( pNode->Body(), nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_e ); m_pSerializer->endElementNS( XML_m, XML_groupChr ); m_pSerializer->endElementNS( XML_m, XML_e ); m_pSerializer->startElementNS( XML_m, XML_lim, FSEND ); HandleNode( pNode->Script(), nLevel + 1 ); m_pSerializer->endElementNS( XML_m, XML_lim ); m_pSerializer->endElementNS( XML_m, top ? XML_limUpp : XML_limLow ); break; } default: OSL_FAIL( "Unhandled vertical brace" ); HandleAllSubNodes( pNode, nLevel ); break; } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */