Coverage Report

Created: 2026-06-30 11:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/starmath/source/ooxmlexport.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 */
9
10
#include "ooxmlexport.hxx"
11
12
#include <oox/token/tokens.hxx>
13
#include <rtl/ustring.hxx>
14
#include <sal/log.hxx>
15
#include <oox/mathml/imexport.hxx>
16
17
using namespace oox;
18
using namespace oox::core;
19
20
SmOoxmlExport::SmOoxmlExport(const SmNode *const pIn, OoxmlVersion const v,
21
        drawingml::DocumentType const documentType)
22
0
: SmWordExportBase( pIn )
23
0
, version( v )
24
0
, m_DocumentType(documentType)
25
0
{
26
0
}
27
28
void SmOoxmlExport::ConvertFromStarMath( const ::sax_fastparser::FSHelperPtr& serializer, const sal_Int8 nAlign )
29
0
{
30
0
    if( GetTree() == nullptr )
31
0
        return;
32
0
    m_pSerializer = serializer;
33
34
    //Formula alignment situations:
35
    //
36
    //  1)Inline(as before):
37
    //
38
    //      <m:oMath>
39
    //          <m:r>  ... </m:r>
40
    //      </m:oMath>
41
    //
42
    //  2)Aligned:
43
    //
44
    //      <m:oMathPara>
45
    //          <m:oMathParaPr>
46
    //              <m:jc m:val="left|right|center">
47
    //          </m:oMathParaPr>
48
    //          <m:oMath>
49
    //              <m:r>  ... </m:r>
50
    //          </m:oMath>
51
    //      </m:oMathPara>
52
53
0
    if (nAlign != FormulaImExportBase::eFormulaAlign::INLINE)
54
0
    {
55
0
        m_pSerializer->startElementNS(XML_m, XML_oMathPara,
56
0
            FSNS(XML_xmlns, XML_m), "http://schemas.openxmlformats.org/officeDocument/2006/math");
57
0
        m_pSerializer->startElementNS(XML_m, XML_oMathParaPr);
58
0
        if (nAlign == FormulaImExportBase::eFormulaAlign::CENTER)
59
0
            m_pSerializer->singleElementNS(XML_m, XML_jc, FSNS(XML_m, XML_val), "center");
60
0
        if (nAlign == FormulaImExportBase::eFormulaAlign::LEFT)
61
0
            m_pSerializer->singleElementNS(XML_m, XML_jc, FSNS(XML_m, XML_val), "left");
62
0
        if (nAlign == FormulaImExportBase::eFormulaAlign::RIGHT)
63
0
            m_pSerializer->singleElementNS(XML_m, XML_jc, FSNS(XML_m, XML_val), "right");
64
0
        m_pSerializer->endElementNS(XML_m, XML_oMathParaPr);
65
0
        m_pSerializer->startElementNS(XML_m, XML_oMath);
66
0
        HandleNode(GetTree(), 0);
67
0
        m_pSerializer->endElementNS(XML_m, XML_oMath);
68
0
        m_pSerializer->endElementNS(XML_m, XML_oMathPara);
69
0
    }
70
0
    else //else, inline as was before
71
0
    {
72
0
        m_pSerializer->startElementNS(XML_m, XML_oMath,
73
0
            FSNS(XML_xmlns, XML_m), "http://schemas.openxmlformats.org/officeDocument/2006/math");
74
0
        HandleNode( GetTree(), 0 );
75
0
        m_pSerializer->endElementNS( XML_m, XML_oMath );
76
0
    }
77
0
}
78
79
// NOTE: This is still work in progress and unfinished, but it already covers a good
80
// part of the ooxml math stuff.
81
82
void SmOoxmlExport::HandleVerticalStack( const SmNode* pNode, int nLevel )
83
0
{
84
0
    m_pSerializer->startElementNS(XML_m, XML_eqArr);
85
0
    int size = pNode->GetNumSubNodes();
86
0
    for( int i = 0;
87
0
         i < size;
88
0
         ++i )
89
0
    {
90
0
        m_pSerializer->startElementNS(XML_m, XML_e);
91
0
        HandleNode( pNode->GetSubNode( i ), nLevel + 1 );
92
0
        m_pSerializer->endElementNS( XML_m, XML_e );
93
0
    }
94
0
    m_pSerializer->endElementNS( XML_m, XML_eqArr );
95
0
}
96
97
void SmOoxmlExport::HandleText( const SmNode* pNode, int /*nLevel*/)
98
0
{
99
0
    m_pSerializer->startElementNS(XML_m, XML_r);
100
101
0
    if( pNode->GetToken().eType == TTEXT ) // literal text (in quotes)
102
0
    {
103
0
        m_pSerializer->startElementNS(XML_m, XML_rPr);
104
0
        m_pSerializer->singleElementNS(XML_m, XML_lit);
105
0
        m_pSerializer->singleElementNS(XML_m, XML_nor);
106
0
        m_pSerializer->endElementNS( XML_m, XML_rPr );
107
0
    }
108
0
    if (drawingml::DOCUMENT_DOCX == m_DocumentType && ECMA_376_1ST_EDITION == version)
109
0
    { // HACK: MSOffice2007 does not import characters properly unless this font is explicitly given
110
0
        m_pSerializer->startElementNS(XML_w, XML_rPr);
111
0
        m_pSerializer->singleElementNS( XML_w, XML_rFonts, FSNS( XML_w, XML_ascii ), "Cambria Math",
112
0
            FSNS( XML_w, XML_hAnsi ), "Cambria Math" );
113
0
        m_pSerializer->endElementNS( XML_w, XML_rPr );
114
0
    }
115
0
    m_pSerializer->startElementNS(XML_m, XML_t, FSNS(XML_xml, XML_space), "preserve");
116
0
    const SmTextNode* pTemp = static_cast<const SmTextNode* >(pNode);
117
0
    SAL_INFO( "starmath.ooxml", "Text:" << pTemp->GetText());
118
0
    OUStringBuffer buf(pTemp->GetText());
119
0
    for(sal_Int32 i=0;i<pTemp->GetText().getLength();i++)
120
0
    {
121
#if 0
122
        if ((nPendingAttributes) &&
123
            (i == ((pTemp->GetText().getLength()+1)/2)-1))
124
        {
125
            *pS << sal_uInt8(0x22);     //char, with attributes right
126
                                //after the character
127
        }
128
        else
129
            *pS << sal_uInt8(CHAR);
130
131
        sal_uInt8 nFace = 0x1;
132
        if (pNode->GetFont().GetItalic() == ITALIC_NORMAL)
133
            nFace = 0x3;
134
        else if (pNode->GetFont().GetWeight() == WEIGHT_BOLD)
135
            nFace = 0x7;
136
        *pS << sal_uInt8(nFace+128); //typeface
137
#endif
138
0
        buf[i] = SmTextNode::ConvertSymbolToUnicode(buf[i]);
139
#if 0
140
        //Mathtype can only have these sort of character
141
        //attributes on a single character, starmath can put them
142
        //anywhere, when the entity involved is a text run this is
143
        //a large effort to place the character attribute on the
144
        //central mathtype character so that it does pretty much
145
        //what the user probably has in mind. The attributes
146
        //filled in here are dummy ones which are replaced in the
147
        //ATTRIBUTE handler if a suitable location for the
148
        //attributes was found here. Unfortunately it is
149
        //possible for starmath to place character attributes on
150
        //entities which cannot occur in mathtype e.g. a Summation
151
        //symbol so these attributes may be lost
152
        if ((nPendingAttributes) &&
153
            (i == ((pTemp->GetText().getLength()+1)/2)-1))
154
        {
155
            *pS << sal_uInt8(EMBEL);
156
            while (nPendingAttributes)
157
            {
158
                *pS << sal_uInt8(2);
159
                //wedge the attributes in here and clear
160
                //the pending stack
161
                nPendingAttributes--;
162
            }
163
            nInsertion=pS->Tell();
164
            *pS << sal_uInt8(END); //end embel
165
            *pS << sal_uInt8(END); //end embel
166
        }
167
#endif
168
0
    }
169
0
    m_pSerializer->writeEscaped(buf);
170
0
    m_pSerializer->endElementNS( XML_m, XML_t );
171
0
    m_pSerializer->endElementNS( XML_m, XML_r );
172
0
}
173
174
void SmOoxmlExport::HandleFractions( const SmNode* pNode, int nLevel, const char* type )
175
0
{
176
0
    m_pSerializer->startElementNS(XML_m, XML_f);
177
0
    if( type != nullptr )
178
0
    {
179
0
        m_pSerializer->startElementNS(XML_m, XML_fPr);
180
0
        m_pSerializer->singleElementNS(XML_m, XML_type, FSNS(XML_m, XML_val), type);
181
0
        m_pSerializer->endElementNS( XML_m, XML_fPr );
182
0
    }
183
0
    assert( pNode->GetNumSubNodes() == 3 );
184
0
    m_pSerializer->startElementNS(XML_m, XML_num);
185
0
    HandleNode( pNode->GetSubNode( 0 ), nLevel + 1 );
186
0
    m_pSerializer->endElementNS( XML_m, XML_num );
187
0
    m_pSerializer->startElementNS(XML_m, XML_den);
188
0
    HandleNode( pNode->GetSubNode( 2 ), nLevel + 1 );
189
0
    m_pSerializer->endElementNS( XML_m, XML_den );
190
0
    m_pSerializer->endElementNS( XML_m, XML_f );
191
0
}
192
193
void SmOoxmlExport::HandleAttribute( const SmAttributeNode* pNode, int nLevel )
194
0
{
195
0
    switch( pNode->Attribute()->GetToken().eType )
196
0
    {
197
0
        case TCHECK:
198
0
        case TACUTE:
199
0
        case TGRAVE:
200
0
        case TBREVE:
201
0
        case TCIRCLE:
202
0
        case TVEC:
203
0
        case TTILDE:
204
0
        case THAT:
205
0
        case TDOT:
206
0
        case TDDOT:
207
0
        case TDDDOT:
208
0
        case TWIDETILDE:
209
0
        case TWIDEHAT:
210
0
        case TWIDEHARPOON:
211
0
        case TWIDELHARPOON:
212
0
        case TWIDEVEC:
213
0
        case TWIDELVEC:
214
0
        case TBAR:
215
0
        {
216
0
            m_pSerializer->startElementNS(XML_m, XML_acc);
217
0
            m_pSerializer->startElementNS(XML_m, XML_accPr);
218
0
            OString value = OUStringToOString(pNode->Attribute()->GetToken().cMathChar, RTL_TEXTENCODING_UTF8 );
219
0
            m_pSerializer->singleElementNS(XML_m, XML_chr, FSNS(XML_m, XML_val), value);
220
0
            m_pSerializer->endElementNS( XML_m, XML_accPr );
221
0
            m_pSerializer->startElementNS(XML_m, XML_e);
222
0
            HandleNode( pNode->Body(), nLevel + 1 );
223
0
            m_pSerializer->endElementNS( XML_m, XML_e );
224
0
            m_pSerializer->endElementNS( XML_m, XML_acc );
225
0
            break;
226
0
        }
227
0
        case TOVERLINE:
228
0
        case TUNDERLINE:
229
0
            m_pSerializer->startElementNS(XML_m, XML_bar);
230
0
            m_pSerializer->startElementNS(XML_m, XML_barPr);
231
0
            m_pSerializer->singleElementNS( XML_m, XML_pos, FSNS( XML_m, XML_val ),
232
0
                ( pNode->Attribute()->GetToken().eType == TUNDERLINE ) ? "bot" : "top" );
233
0
            m_pSerializer->endElementNS( XML_m, XML_barPr );
234
0
            m_pSerializer->startElementNS(XML_m, XML_e);
235
0
            HandleNode( pNode->Body(), nLevel + 1 );
236
0
            m_pSerializer->endElementNS( XML_m, XML_e );
237
0
            m_pSerializer->endElementNS( XML_m, XML_bar );
238
0
            break;
239
0
        case TOVERSTRIKE:
240
0
            m_pSerializer->startElementNS(XML_m, XML_borderBox);
241
0
            m_pSerializer->startElementNS(XML_m, XML_borderBoxPr);
242
0
            m_pSerializer->singleElementNS(XML_m, XML_hideTop, FSNS(XML_m, XML_val), "1");
243
0
            m_pSerializer->singleElementNS(XML_m, XML_hideBot, FSNS(XML_m, XML_val), "1");
244
0
            m_pSerializer->singleElementNS(XML_m, XML_hideLeft, FSNS(XML_m, XML_val), "1");
245
0
            m_pSerializer->singleElementNS(XML_m, XML_hideRight, FSNS(XML_m, XML_val), "1");
246
0
            m_pSerializer->singleElementNS(XML_m, XML_strikeH, FSNS(XML_m, XML_val), "1");
247
0
            m_pSerializer->endElementNS( XML_m, XML_borderBoxPr );
248
0
            m_pSerializer->startElementNS(XML_m, XML_e);
249
0
            HandleNode( pNode->Body(), nLevel + 1 );
250
0
            m_pSerializer->endElementNS( XML_m, XML_e );
251
0
            m_pSerializer->endElementNS( XML_m, XML_borderBox );
252
0
            break;
253
0
        default:
254
0
            HandleAllSubNodes( pNode, nLevel );
255
0
            break;
256
0
    }
257
0
}
258
259
void SmOoxmlExport::HandleRoot( const SmRootNode* pNode, int nLevel )
260
0
{
261
0
    m_pSerializer->startElementNS(XML_m, XML_rad);
262
0
    if( const SmNode* argument = pNode->Argument())
263
0
    {
264
0
        m_pSerializer->startElementNS(XML_m, XML_deg);
265
0
        HandleNode( argument, nLevel + 1 );
266
0
        m_pSerializer->endElementNS( XML_m, XML_deg );
267
0
    }
268
0
    else
269
0
    {
270
0
        m_pSerializer->startElementNS(XML_m, XML_radPr);
271
0
        m_pSerializer->singleElementNS(XML_m, XML_degHide, FSNS(XML_m, XML_val), "1");
272
0
        m_pSerializer->endElementNS( XML_m, XML_radPr );
273
0
        m_pSerializer->singleElementNS(XML_m, XML_deg); // empty but present
274
0
    }
275
0
    m_pSerializer->startElementNS(XML_m, XML_e);
276
0
    HandleNode( pNode->Body(), nLevel + 1 );
277
0
    m_pSerializer->endElementNS( XML_m, XML_e );
278
0
    m_pSerializer->endElementNS( XML_m, XML_rad );
279
0
}
280
281
static OString mathSymbolToString( const SmNode* node )
282
0
{
283
0
    assert( node->GetType() == SmNodeType::Math || node->GetType() == SmNodeType::MathIdent );
284
0
    const SmTextNode* txtnode = static_cast< const SmTextNode* >( node );
285
0
    assert( txtnode->GetText().getLength() == 1 );
286
0
    sal_Unicode chr = SmTextNode::ConvertSymbolToUnicode( txtnode->GetText()[0] );
287
0
    return OUStringToOString( OUStringChar( chr ), RTL_TEXTENCODING_UTF8 );
288
0
}
289
290
void SmOoxmlExport::HandleOperator( const SmOperNode* pNode, int nLevel )
291
0
{
292
0
    SAL_INFO( "starmath.ooxml", "Operator: " << int( pNode->GetToken().eType ));
293
0
    switch( pNode->GetToken().eType )
294
0
    {
295
0
        case TINT:
296
0
        case TINTD:
297
0
        case TIINT:
298
0
        case TIIINT:
299
0
        case TLINT:
300
0
        case TLLINT:
301
0
        case TLLLINT:
302
0
        case TPROD:
303
0
        case TCOPROD:
304
0
        case TSUM:
305
0
        {
306
0
            const SmSubSupNode* subsup = pNode->GetSubNode( 0 )->GetType() == SmNodeType::SubSup
307
0
                ? static_cast< const SmSubSupNode* >( pNode->GetSubNode( 0 )) : nullptr;
308
0
            const SmNode* operation = subsup != nullptr ? subsup->GetBody() : pNode->GetSubNode( 0 );
309
0
            m_pSerializer->startElementNS(XML_m, XML_nary);
310
0
            m_pSerializer->startElementNS(XML_m, XML_naryPr);
311
0
            m_pSerializer->singleElementNS( XML_m, XML_chr,
312
0
                FSNS( XML_m, XML_val ), mathSymbolToString(operation) );
313
0
            if( subsup == nullptr || subsup->GetSubSup( CSUB ) == nullptr )
314
0
                m_pSerializer->singleElementNS(XML_m, XML_subHide, FSNS(XML_m, XML_val), "1");
315
0
            if( subsup == nullptr || subsup->GetSubSup( CSUP ) == nullptr )
316
0
                m_pSerializer->singleElementNS(XML_m, XML_supHide, FSNS(XML_m, XML_val), "1");
317
0
            m_pSerializer->endElementNS( XML_m, XML_naryPr );
318
0
            if( subsup == nullptr || subsup->GetSubSup( CSUB ) == nullptr )
319
0
                m_pSerializer->singleElementNS(XML_m, XML_sub);
320
0
            else
321
0
            {
322
0
                m_pSerializer->startElementNS(XML_m, XML_sub);
323
0
                HandleNode( subsup->GetSubSup( CSUB ), nLevel + 1 );
324
0
                m_pSerializer->endElementNS( XML_m, XML_sub );
325
0
            }
326
0
            if( subsup == nullptr || subsup->GetSubSup( CSUP ) == nullptr )
327
0
                m_pSerializer->singleElementNS(XML_m, XML_sup);
328
0
            else
329
0
            {
330
0
                m_pSerializer->startElementNS(XML_m, XML_sup);
331
0
                HandleNode( subsup->GetSubSup( CSUP ), nLevel + 1 );
332
0
                m_pSerializer->endElementNS( XML_m, XML_sup );
333
0
            }
334
0
            m_pSerializer->startElementNS(XML_m, XML_e);
335
0
            HandleNode( pNode->GetSubNode( 1 ), nLevel + 1 ); // body
336
0
            m_pSerializer->endElementNS( XML_m, XML_e );
337
0
            m_pSerializer->endElementNS( XML_m, XML_nary );
338
0
            break;
339
0
        }
340
0
        case TLIM:
341
0
            m_pSerializer->startElementNS(XML_m, XML_func);
342
0
            m_pSerializer->startElementNS(XML_m, XML_fName);
343
0
            m_pSerializer->startElementNS(XML_m, XML_limLow);
344
0
            m_pSerializer->startElementNS(XML_m, XML_e);
345
0
            HandleNode( pNode->GetSymbol(), nLevel + 1 );
346
0
            m_pSerializer->endElementNS( XML_m, XML_e );
347
0
            m_pSerializer->startElementNS(XML_m, XML_lim);
348
0
            if( const SmSubSupNode* subsup = pNode->GetSubNode( 0 )->GetType() == SmNodeType::SubSup
349
0
                ? static_cast< const SmSubSupNode* >( pNode->GetSubNode( 0 )) : nullptr )
350
0
            {
351
0
                if( subsup->GetSubSup( CSUB ) != nullptr )
352
0
                    HandleNode( subsup->GetSubSup( CSUB ), nLevel + 1 );
353
0
            }
354
0
            m_pSerializer->endElementNS( XML_m, XML_lim );
355
0
            m_pSerializer->endElementNS( XML_m, XML_limLow );
356
0
            m_pSerializer->endElementNS( XML_m, XML_fName );
357
0
            m_pSerializer->startElementNS(XML_m, XML_e);
358
0
            HandleNode( pNode->GetSubNode( 1 ), nLevel + 1 ); // body
359
0
            m_pSerializer->endElementNS( XML_m, XML_e );
360
0
            m_pSerializer->endElementNS( XML_m, XML_func );
361
0
            break;
362
0
        default:
363
0
            SAL_WARN("starmath.ooxml", "Unhandled operation");
364
0
            HandleAllSubNodes( pNode, nLevel );
365
0
            break;
366
0
    }
367
0
}
368
369
void SmOoxmlExport::HandleSubSupScriptInternal( const SmSubSupNode* pNode, int nLevel, int flags )
370
0
{
371
// docx supports only a certain combination of sub/super scripts, but LO can have any,
372
// so try to merge it using several tags if necessary
373
0
    if( flags == 0 ) // none
374
0
        return;
375
0
    if(( flags & ( 1 << RSUP | 1 << RSUB )) == ( 1 << RSUP | 1 << RSUB ))
376
0
    { // m:sSubSup
377
0
        m_pSerializer->startElementNS(XML_m, XML_sSubSup);
378
0
        m_pSerializer->startElementNS(XML_m, XML_e);
379
0
        flags &= ~( 1 << RSUP | 1 << RSUB );
380
0
        if( flags == 0 )
381
0
            HandleNode( pNode->GetBody(), nLevel + 1 );
382
0
        else
383
0
            HandleSubSupScriptInternal( pNode, nLevel, flags );
384
0
        m_pSerializer->endElementNS( XML_m, XML_e );
385
0
        m_pSerializer->startElementNS(XML_m, XML_sub);
386
0
        HandleNode( pNode->GetSubSup( RSUB ), nLevel + 1 );
387
0
        m_pSerializer->endElementNS( XML_m, XML_sub );
388
0
        m_pSerializer->startElementNS(XML_m, XML_sup);
389
0
        HandleNode( pNode->GetSubSup( RSUP ), nLevel + 1 );
390
0
        m_pSerializer->endElementNS( XML_m, XML_sup );
391
0
        m_pSerializer->endElementNS( XML_m, XML_sSubSup );
392
0
    }
393
0
    else if(( flags & ( 1 << RSUB )) == 1 << RSUB )
394
0
    { // m:sSub
395
0
        m_pSerializer->startElementNS(XML_m, XML_sSub);
396
0
        m_pSerializer->startElementNS(XML_m, XML_e);
397
0
        flags &= ~( 1 << RSUB );
398
0
        if( flags == 0 )
399
0
            HandleNode( pNode->GetBody(), nLevel + 1 );
400
0
        else
401
0
            HandleSubSupScriptInternal( pNode, nLevel, flags );
402
0
        m_pSerializer->endElementNS( XML_m, XML_e );
403
0
        m_pSerializer->startElementNS(XML_m, XML_sub);
404
0
        HandleNode( pNode->GetSubSup( RSUB ), nLevel + 1 );
405
0
        m_pSerializer->endElementNS( XML_m, XML_sub );
406
0
        m_pSerializer->endElementNS( XML_m, XML_sSub );
407
0
    }
408
0
    else if(( flags & ( 1 << RSUP )) == 1 << RSUP )
409
0
    { // m:sSup
410
0
        m_pSerializer->startElementNS(XML_m, XML_sSup);
411
0
        m_pSerializer->startElementNS(XML_m, XML_e);
412
0
        flags &= ~( 1 << RSUP );
413
0
        if( flags == 0 )
414
0
            HandleNode( pNode->GetBody(), nLevel + 1 );
415
0
        else
416
0
            HandleSubSupScriptInternal( pNode, nLevel, flags );
417
0
        m_pSerializer->endElementNS( XML_m, XML_e );
418
0
        m_pSerializer->startElementNS(XML_m, XML_sup);
419
0
        HandleNode( pNode->GetSubSup( RSUP ), nLevel + 1 );
420
0
        m_pSerializer->endElementNS( XML_m, XML_sup );
421
0
        m_pSerializer->endElementNS( XML_m, XML_sSup );
422
0
    }
423
0
    else if(( flags & ( 1 << LSUP | 1 << LSUB )) == ( 1 << LSUP | 1 << LSUB ))
424
0
    { // m:sPre
425
0
        m_pSerializer->startElementNS(XML_m, XML_sPre);
426
0
        m_pSerializer->startElementNS(XML_m, XML_sub);
427
0
        HandleNode( pNode->GetSubSup( LSUB ), nLevel + 1 );
428
0
        m_pSerializer->endElementNS( XML_m, XML_sub );
429
0
        m_pSerializer->startElementNS(XML_m, XML_sup);
430
0
        HandleNode( pNode->GetSubSup( LSUP ), nLevel + 1 );
431
0
        m_pSerializer->endElementNS( XML_m, XML_sup );
432
0
        m_pSerializer->startElementNS(XML_m, XML_e);
433
0
        flags &= ~( 1 << LSUP | 1 << LSUB );
434
0
        if( flags == 0 )
435
0
            HandleNode( pNode->GetBody(), nLevel + 1 );
436
0
        else
437
0
            HandleSubSupScriptInternal( pNode, nLevel, flags );
438
0
        m_pSerializer->endElementNS( XML_m, XML_e );
439
0
        m_pSerializer->endElementNS( XML_m, XML_sPre );
440
0
    }
441
0
    else if(( flags & ( 1 << CSUB )) == ( 1 << CSUB ))
442
0
    { // m:limLow looks like a good element for central superscript
443
0
        m_pSerializer->startElementNS(XML_m, XML_limLow);
444
0
        m_pSerializer->startElementNS(XML_m, XML_e);
445
0
        flags &= ~( 1 << CSUB );
446
0
        if( flags == 0 )
447
0
            HandleNode( pNode->GetBody(), nLevel + 1 );
448
0
        else
449
0
            HandleSubSupScriptInternal( pNode, nLevel, flags );
450
0
        m_pSerializer->endElementNS( XML_m, XML_e );
451
0
        m_pSerializer->startElementNS(XML_m, XML_lim);
452
0
        HandleNode( pNode->GetSubSup( CSUB ), nLevel + 1 );
453
0
        m_pSerializer->endElementNS( XML_m, XML_lim );
454
0
        m_pSerializer->endElementNS( XML_m, XML_limLow );
455
0
    }
456
0
    else if(( flags & ( 1 << CSUP )) == ( 1 << CSUP ))
457
0
    { // m:limUpp looks like a good element for central superscript
458
0
        m_pSerializer->startElementNS(XML_m, XML_limUpp);
459
0
        m_pSerializer->startElementNS(XML_m, XML_e);
460
0
        flags &= ~( 1 << CSUP );
461
0
        if( flags == 0 )
462
0
            HandleNode( pNode->GetBody(), nLevel + 1 );
463
0
        else
464
0
            HandleSubSupScriptInternal( pNode, nLevel, flags );
465
0
        m_pSerializer->endElementNS( XML_m, XML_e );
466
0
        m_pSerializer->startElementNS(XML_m, XML_lim);
467
0
        HandleNode( pNode->GetSubSup( CSUP ), nLevel + 1 );
468
0
        m_pSerializer->endElementNS( XML_m, XML_lim );
469
0
        m_pSerializer->endElementNS( XML_m, XML_limUpp );
470
0
    }
471
0
    else
472
0
    {
473
0
        SAL_WARN("starmath.ooxml", "Unhandled sub/sup combination");
474
        // TODO do not do anything, this should be probably an assert()
475
        // HandleAllSubNodes( pNode, nLevel );
476
0
    }
477
0
}
478
479
void SmOoxmlExport::HandleMatrix( const SmMatrixNode* pNode, int nLevel )
480
0
{
481
0
    m_pSerializer->startElementNS(XML_m, XML_m);
482
0
    for (size_t row = 0; row < pNode->GetNumRows(); ++row)
483
0
    {
484
0
        m_pSerializer->startElementNS(XML_m, XML_mr);
485
0
        for (size_t col = 0; col < pNode->GetNumCols(); ++col)
486
0
        {
487
0
            m_pSerializer->startElementNS(XML_m, XML_e);
488
0
            if( const SmNode* node = pNode->GetSubNode( row * pNode->GetNumCols() + col ))
489
0
                HandleNode( node, nLevel + 1 );
490
0
            m_pSerializer->endElementNS( XML_m, XML_e );
491
0
        }
492
0
        m_pSerializer->endElementNS( XML_m, XML_mr );
493
0
    }
494
0
    m_pSerializer->endElementNS( XML_m, XML_m );
495
0
}
496
497
void SmOoxmlExport::HandleBrace( const SmBraceNode* pNode, int nLevel )
498
0
{
499
0
    m_pSerializer->startElementNS(XML_m, XML_d);
500
0
    m_pSerializer->startElementNS(XML_m, XML_dPr);
501
502
    //check if the node has an opening brace
503
0
    if( TNONE == pNode->OpeningBrace()->GetToken().eType )
504
0
        m_pSerializer->singleElementNS(XML_m, XML_begChr, FSNS(XML_m, XML_val), "");
505
0
    else
506
0
        m_pSerializer->singleElementNS( XML_m, XML_begChr,
507
0
            FSNS( XML_m, XML_val ), mathSymbolToString( pNode->OpeningBrace()) );
508
509
0
    std::vector< const SmNode* > subnodes;
510
0
    if( pNode->Body()->GetType() == SmNodeType::Bracebody )
511
0
    {
512
0
        const SmBracebodyNode* body = static_cast< const SmBracebodyNode* >( pNode->Body());
513
0
        bool separatorWritten = false; // assume all separators are the same
514
0
        for (size_t i = 0; i < body->GetNumSubNodes(); ++i)
515
0
        {
516
0
            const SmNode* subnode = body->GetSubNode( i );
517
0
            if (subnode->GetType() == SmNodeType::Math || subnode->GetType() == SmNodeType::MathIdent)
518
0
            { // do not write, but write what separator it is
519
0
                const SmMathSymbolNode* math = static_cast< const SmMathSymbolNode* >( subnode );
520
0
                if( !separatorWritten )
521
0
                {
522
0
                    m_pSerializer->singleElementNS( XML_m, XML_sepChr,
523
0
                        FSNS( XML_m, XML_val ), mathSymbolToString(math) );
524
0
                    separatorWritten = true;
525
0
                }
526
0
            }
527
0
            else
528
0
                subnodes.push_back( subnode );
529
0
        }
530
0
    }
531
0
    else
532
0
        subnodes.push_back( pNode->Body());
533
534
0
    if( TNONE == pNode->ClosingBrace()->GetToken().eType )
535
0
        m_pSerializer->singleElementNS(XML_m, XML_endChr, FSNS(XML_m, XML_val), "");
536
0
    else
537
0
        m_pSerializer->singleElementNS( XML_m, XML_endChr,
538
0
            FSNS( XML_m, XML_val ), mathSymbolToString(pNode->ClosingBrace()) );
539
540
0
    m_pSerializer->endElementNS( XML_m, XML_dPr );
541
0
    if (subnodes.empty())
542
0
    {
543
        // e element is required
544
0
        m_pSerializer->singleElementNS(XML_m, XML_e);
545
0
    }
546
0
    else
547
0
    {
548
0
        for(const SmNode* subnode : subnodes)
549
0
        {
550
0
            m_pSerializer->startElementNS(XML_m, XML_e);
551
0
            HandleNode( subnode, nLevel + 1 );
552
0
            m_pSerializer->endElementNS( XML_m, XML_e );
553
0
        }
554
0
    }
555
0
    m_pSerializer->endElementNS( XML_m, XML_d );
556
0
}
557
558
void SmOoxmlExport::HandleVerticalBrace( const SmVerticalBraceNode* pNode, int nLevel )
559
0
{
560
0
    SAL_INFO( "starmath.ooxml", "Vertical: " << int( pNode->GetToken().eType ));
561
0
    switch( pNode->GetToken().eType )
562
0
    {
563
0
        case TOVERBRACE:
564
0
        case TUNDERBRACE:
565
0
        {
566
0
            bool top = ( pNode->GetToken().eType == TOVERBRACE );
567
0
            m_pSerializer->startElementNS(XML_m, top ? XML_limUpp : XML_limLow);
568
0
            m_pSerializer->startElementNS(XML_m, XML_e);
569
0
            m_pSerializer->startElementNS(XML_m, XML_groupChr);
570
0
            m_pSerializer->startElementNS(XML_m, XML_groupChrPr);
571
0
            m_pSerializer->singleElementNS( XML_m, XML_chr,
572
0
                FSNS( XML_m, XML_val ), mathSymbolToString(pNode->Brace()) );
573
            // TODO not sure if pos and vertJc are correct
574
0
            m_pSerializer->singleElementNS( XML_m, XML_pos,
575
0
                FSNS( XML_m, XML_val ), top ? "top" : "bot" );
576
0
            m_pSerializer->singleElementNS(XML_m, XML_vertJc, FSNS(XML_m, XML_val),
577
0
                                           top ? "bot" : "top");
578
0
            m_pSerializer->endElementNS( XML_m, XML_groupChrPr );
579
0
            m_pSerializer->startElementNS(XML_m, XML_e);
580
0
            HandleNode( pNode->Body(), nLevel + 1 );
581
0
            m_pSerializer->endElementNS( XML_m, XML_e );
582
0
            m_pSerializer->endElementNS( XML_m, XML_groupChr );
583
0
            m_pSerializer->endElementNS( XML_m, XML_e );
584
0
            m_pSerializer->startElementNS(XML_m, XML_lim);
585
0
            HandleNode( pNode->Script(), nLevel + 1 );
586
0
            m_pSerializer->endElementNS( XML_m, XML_lim );
587
0
            m_pSerializer->endElementNS( XML_m, top ? XML_limUpp : XML_limLow );
588
0
            break;
589
0
        }
590
0
        default:
591
0
            SAL_WARN("starmath.ooxml", "Unhandled vertical brace");
592
0
            HandleAllSubNodes( pNode, nLevel );
593
0
            break;
594
0
    }
595
0
}
596
597
void SmOoxmlExport::HandleBlank()
598
0
{
599
0
    m_pSerializer->startElementNS(XML_m, XML_r);
600
0
    m_pSerializer->startElementNS(XML_m, XML_t, FSNS(XML_xml, XML_space), "preserve");
601
0
    m_pSerializer->write( " " );
602
0
    m_pSerializer->endElementNS( XML_m, XML_t );
603
0
    m_pSerializer->endElementNS( XML_m, XML_r );
604
0
}
605
606
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */