Bump version to 21.06.18.1
[LibreOffice.git] / starmath / source / ooxmlimport.cxx
blob5290ad12606c8318234375c5f6423c9f1b32f082
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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 */
11 #include "ooxmlimport.hxx"
12 #include <types.hxx>
14 #include <oox/mathml/importutils.hxx>
15 #include <oox/token/namespaces.hxx>
16 #include <rtl/ustring.hxx>
17 #include <rtl/ustrbuf.hxx>
18 #include <sal/log.hxx>
20 using namespace oox::formulaimport;
23 The primary internal data structure for the formula is the text representation
24 (the SmNode tree is built from it), so read data must be converted into this format.
27 #define OPENING( token ) XML_STREAM_OPENING( token )
28 #define CLOSING( token ) XML_STREAM_CLOSING( token )
30 // TODO create IS_OPENING(), IS_CLOSING() instead of doing 'next == OPENING( next )' ?
32 SmOoxmlImport::SmOoxmlImport( oox::formulaimport::XmlStream& s )
33 : m_rStream( s )
37 OUString SmOoxmlImport::ConvertToStarMath()
39 return handleStream();
42 // "toplevel" of reading, there will be oMath (if there was oMathPara, that was
43 // up to the parent component to handle)
45 // NOT complete
46 OUString SmOoxmlImport::handleStream()
48 m_rStream.ensureOpeningTag( M_TOKEN( oMath ));
49 OUStringBuffer ret;
50 while( !m_rStream.atEnd() && m_rStream.currentToken() != CLOSING( M_TOKEN( oMath )))
52 // strictly speaking, it is not OMathArg here, but currently supported
53 // functionality is the same like OMathArg, in the future this may need improving
54 OUString item = readOMathArg( M_TOKEN( oMath ));
55 if( item.isEmpty())
56 continue;
57 if( !ret.isEmpty())
58 ret.append(" ");
59 ret.append(item);
61 m_rStream.ensureClosingTag( M_TOKEN( oMath ));
62 // Placeholders are written out as nothing (i.e. nothing inside e.g. the <e> element),
63 // which will result in "{}" in the formula text. Fix this up.
64 OUString ret2 = ret.makeStringAndClear().replaceAll( "{}", "<?>" );
65 // And as a result, empty parts of the formula that are not placeholders are written out
66 // as a single space, so fix that up too.
67 ret2 = ret2.replaceAll( "{ }", "{}" );
68 SAL_INFO( "starmath.ooxml", "Formula: " << ret2 );
69 return ret2;
72 OUString SmOoxmlImport::readOMathArg( int stoptoken )
74 OUStringBuffer ret;
75 while( !m_rStream.atEnd() && m_rStream.currentToken() != CLOSING( stoptoken ))
77 if( !ret.isEmpty())
78 ret.append(" ");
79 switch( m_rStream.currentToken())
81 case OPENING( M_TOKEN( acc )):
82 ret.append(handleAcc());
83 break;
84 case OPENING( M_TOKEN( bar )):
85 ret.append(handleBar());
86 break;
87 case OPENING( M_TOKEN( box )):
88 ret.append(handleBox());
89 break;
90 case OPENING( M_TOKEN( borderBox )):
91 ret.append(handleBorderBox());
92 break;
93 case OPENING( M_TOKEN( d )):
94 ret.append(handleD());
95 break;
96 case OPENING( M_TOKEN( eqArr )):
97 ret.append(handleEqArr());
98 break;
99 case OPENING( M_TOKEN( f )):
100 ret.append(handleF());
101 break;
102 case OPENING( M_TOKEN( func )):
103 ret.append(handleFunc());
104 break;
105 case OPENING( M_TOKEN( limLow )):
106 ret.append(handleLimLowUpp( LimLow ));
107 break;
108 case OPENING( M_TOKEN( limUpp )):
109 ret.append(handleLimLowUpp( LimUpp ));
110 break;
111 case OPENING( M_TOKEN( groupChr )):
112 ret.append(handleGroupChr());
113 break;
114 case OPENING( M_TOKEN( m )):
115 ret.append(handleM());
116 break;
117 case OPENING( M_TOKEN( nary )):
118 ret.append(handleNary());
119 break;
120 case OPENING( M_TOKEN( r )):
121 ret.append(handleR());
122 break;
123 case OPENING( M_TOKEN( rad )):
124 ret.append(handleRad());
125 break;
126 case OPENING( M_TOKEN( sPre )):
127 ret.append(handleSpre());
128 break;
129 case OPENING( M_TOKEN( sSub )):
130 ret.append(handleSsub());
131 break;
132 case OPENING( M_TOKEN( sSubSup )):
133 ret.append(handleSsubsup());
134 break;
135 case OPENING( M_TOKEN( sSup )):
136 ret.append(handleSsup());
137 break;
138 default:
139 m_rStream.handleUnexpectedTag();
140 break;
143 return ret.makeStringAndClear();
146 OUString SmOoxmlImport::readOMathArgInElement( int token )
148 m_rStream.ensureOpeningTag( token );
149 OUString ret = readOMathArg( token );
150 m_rStream.ensureClosingTag( token );
151 return ret;
154 OUString SmOoxmlImport::handleAcc()
156 m_rStream.ensureOpeningTag( M_TOKEN( acc ));
157 sal_Unicode accChr = 0x302;
158 if( XmlStream::Tag accPr = m_rStream.checkOpeningTag( M_TOKEN( accPr )))
160 if( XmlStream::Tag chr = m_rStream.checkOpeningTag( M_TOKEN( chr )))
162 accChr = chr.attribute( M_TOKEN( val ), accChr );
163 m_rStream.ensureClosingTag( M_TOKEN( chr ));
165 m_rStream.ensureClosingTag( M_TOKEN( accPr ));
167 // see aTokenTable in parse.cxx
168 OUString acc;
169 switch( accChr )
171 case MS_BAR:
172 case MS_COMBBAR:
173 acc = "bar";
174 break;
175 case MS_CHECK:
176 case MS_COMBCHECK:
177 acc = "check";
178 break;
179 case MS_ACUTE:
180 case MS_COMBACUTE:
181 acc = "acute";
182 break;
183 case MS_COMBOVERLINE:
184 acc = "overline";
185 break;
186 case MS_GRAVE:
187 case MS_COMBGRAVE:
188 acc = "grave";
189 break;
190 case MS_BREVE:
191 case MS_COMBBREVE:
192 acc = "breve";
193 break;
194 case MS_CIRCLE:
195 case MS_COMBCIRCLE:
196 acc = "circle";
197 break;
198 case MS_RIGHTARROW:
199 case MS_VEC:
200 // prefer wide variants for these 3, .docx can't seem to differentiate
201 // between e.g. 'vec' and 'widevec', if whatever the accent is above is short, this
202 // shouldn't matter, but short above a longer expression doesn't look right
203 acc = "widevec";
204 break;
205 case MS_HARPOON:
206 acc = "wideharpoon";
207 break;
208 case MS_TILDE:
209 case MS_COMBTILDE:
210 acc = "widetilde";
211 break;
212 case MS_HAT:
213 case MS_COMBHAT:
214 acc = "widehat";
215 break;
216 case MS_DOT:
217 case MS_COMBDOT:
218 acc = "dot";
219 break;
220 case MS_DDOT:
221 case MS_COMBDDOT:
222 acc = "ddot";
223 break;
224 case MS_DDDOT:
225 acc = "dddot";
226 break;
227 default:
228 acc = "acute";
229 SAL_WARN( "starmath.ooxml", "Unknown m:chr in m:acc \'" << OUString(accChr) << "\'" );
230 break;
232 OUString e = readOMathArgInElement( M_TOKEN( e ));
233 m_rStream.ensureClosingTag( M_TOKEN( acc ));
234 return acc + " {" + e + "}";
237 OUString SmOoxmlImport::handleBar()
239 m_rStream.ensureOpeningTag( M_TOKEN( bar ));
240 enum pos_t { top, bot } topbot = bot;
241 if( m_rStream.checkOpeningTag( M_TOKEN( barPr )))
243 if( XmlStream::Tag pos = m_rStream.checkOpeningTag( M_TOKEN( pos )))
245 if( pos.attribute( M_TOKEN( val )) == "top" )
246 topbot = top;
247 else if( pos.attribute( M_TOKEN( val )) == "bot" )
248 topbot = bot;
249 m_rStream.ensureClosingTag( M_TOKEN( pos ));
251 m_rStream.ensureClosingTag( M_TOKEN( barPr ));
253 OUString e = readOMathArgInElement( M_TOKEN( e ));
254 m_rStream.ensureClosingTag( M_TOKEN( bar ));
255 if( topbot == top )
256 return "overline {" + e + "}";
257 else
258 return "underline {" + e + "}";
261 OUString SmOoxmlImport::handleBox()
263 // there does not seem to be functionality in LO to actually implement this
264 // (or is there), but at least read in the contents instead of ignoring them
265 m_rStream.ensureOpeningTag( M_TOKEN( box ));
266 OUString e = readOMathArgInElement( M_TOKEN( e ));
267 m_rStream.ensureClosingTag( M_TOKEN( box ));
268 return e;
272 OUString SmOoxmlImport::handleBorderBox()
274 m_rStream.ensureOpeningTag( M_TOKEN( borderBox ));
275 bool isStrikeH = false;
276 if( m_rStream.checkOpeningTag( M_TOKEN( borderBoxPr )))
278 if( XmlStream::Tag strikeH = m_rStream.checkOpeningTag( M_TOKEN( strikeH )))
280 if( strikeH.attribute( M_TOKEN( val ), false ))
281 isStrikeH = true;
282 m_rStream.ensureClosingTag( M_TOKEN( strikeH ));
284 m_rStream.ensureClosingTag( M_TOKEN( borderBoxPr ));
286 OUString e = readOMathArgInElement( M_TOKEN( e ));
287 m_rStream.ensureClosingTag( M_TOKEN( borderBox ));
288 if( isStrikeH )
289 return "overstrike {" + e + "}";
290 // LO does not seem to implement anything for handling the other cases
291 return e;
294 OUString SmOoxmlImport::handleD()
296 m_rStream.ensureOpeningTag( M_TOKEN( d ));
297 OUString opening = "(";
298 OUString closing = ")";
299 OUString separator = "|";
300 if( XmlStream::Tag dPr = m_rStream.checkOpeningTag( M_TOKEN( dPr )))
302 if( XmlStream::Tag begChr = m_rStream.checkOpeningTag( M_TOKEN( begChr )))
304 opening = begChr.attribute( M_TOKEN( val ), opening );
305 m_rStream.ensureClosingTag( M_TOKEN( begChr ));
307 if( XmlStream::Tag sepChr = m_rStream.checkOpeningTag( M_TOKEN( sepChr )))
309 separator = sepChr.attribute( M_TOKEN( val ), separator );
310 m_rStream.ensureClosingTag( M_TOKEN( sepChr ));
312 if( XmlStream::Tag endChr = m_rStream.checkOpeningTag( M_TOKEN( endChr )))
314 closing = endChr.attribute( M_TOKEN( val ), closing );
315 m_rStream.ensureClosingTag( M_TOKEN( endChr ));
317 m_rStream.ensureClosingTag( M_TOKEN( dPr ));
319 if( opening == "{" )
320 opening = "left lbrace ";
321 if( closing == "}" )
322 closing = " right rbrace";
323 if( opening == u"\u27e6" )
324 opening = "left ldbracket ";
325 if( closing == u"\u27e7" )
326 closing = " right rdbracket";
327 if( opening == "|" )
328 opening = "left lline ";
329 if( closing == "|" )
330 closing = " right rline";
331 if (opening == OUStringChar(MS_DLINE)
332 || opening == OUStringChar(MS_DVERTLINE))
333 opening = "left ldline ";
334 if (closing == OUStringChar(MS_DLINE)
335 || closing == OUStringChar(MS_DVERTLINE))
336 closing = " right rdline";
337 if (opening == OUStringChar(MS_LANGLE)
338 || opening == OUStringChar(MS_LMATHANGLE))
339 opening = "left langle ";
340 if (closing == OUStringChar(MS_RANGLE)
341 || closing == OUStringChar(MS_RMATHANGLE))
342 closing = " right rangle";
343 // use scalable brackets (the explicit "left" or "right")
344 if( opening == "(" || opening == "[" )
345 opening = "left " + opening;
346 if( closing == ")" || closing == "]" )
347 closing = " right " + closing;
348 if( separator == "|" ) // plain "|" would be actually "V" (logical or)
349 separator = " mline ";
350 if( opening.isEmpty())
351 opening = "left none ";
352 if( closing.isEmpty())
353 closing = " right none";
354 OUStringBuffer ret;
355 ret.append( opening );
356 bool first = true;
357 while( m_rStream.findTag( OPENING( M_TOKEN( e ))))
359 if( !first )
360 ret.append( separator );
361 first = false;
362 ret.append( readOMathArgInElement( M_TOKEN( e )));
364 ret.append( closing );
365 m_rStream.ensureClosingTag( M_TOKEN( d ));
366 return ret.makeStringAndClear();
369 OUString SmOoxmlImport::handleEqArr()
371 m_rStream.ensureOpeningTag( M_TOKEN( eqArr ));
372 OUStringBuffer ret;
374 { // there must be at least one m:e
375 if( !ret.isEmpty())
376 ret.append("#");
377 ret.append(" ");
378 ret.append(readOMathArgInElement( M_TOKEN( e )));
379 ret.append(" ");
380 } while( !m_rStream.atEnd() && m_rStream.findTag( OPENING( M_TOKEN( e ))));
381 m_rStream.ensureClosingTag( M_TOKEN( eqArr ));
382 return "stack {" + ret.makeStringAndClear() + "}";
385 OUString SmOoxmlImport::handleF()
387 m_rStream.ensureOpeningTag( M_TOKEN( f ));
388 enum operation_t { bar, lin, noBar } operation = bar;
389 if( m_rStream.checkOpeningTag( M_TOKEN( fPr )))
391 if( XmlStream::Tag type = m_rStream.checkOpeningTag( M_TOKEN( type )))
393 if( type.attribute( M_TOKEN( val )) == "bar" )
394 operation = bar;
395 else if( type.attribute( M_TOKEN( val )) == "lin" )
396 operation = lin;
397 else if( type.attribute( M_TOKEN( val )) == "noBar" )
398 operation = noBar;
399 m_rStream.ensureClosingTag( M_TOKEN( type ));
401 m_rStream.ensureClosingTag( M_TOKEN( fPr ));
403 OUString num = readOMathArgInElement( M_TOKEN( num ));
404 OUString den = readOMathArgInElement( M_TOKEN( den ));
405 m_rStream.ensureClosingTag( M_TOKEN( f ));
406 if( operation == bar )
407 return "{" + num + "} over {" + den + "}";
408 else if( operation == lin )
409 return "{" + num + "} / {" + den + "}";
410 else // noBar
412 return "binom {" + num + "} {" + den + "}";
416 OUString SmOoxmlImport::handleFunc()
418 //lim from{x rightarrow 1} x
419 m_rStream.ensureOpeningTag( M_TOKEN( func ));
420 OUString fname = readOMathArgInElement( M_TOKEN( fName ));
421 // fix the various functions
422 if( fname.startsWith( "lim csub {" ))
423 fname = OUString::Concat("lim from {") + fname.subView( 10 );
424 OUString ret = fname + " {" + readOMathArgInElement( M_TOKEN( e )) + "}";
425 m_rStream.ensureClosingTag( M_TOKEN( func ));
426 return ret;
429 OUString SmOoxmlImport::handleLimLowUpp( LimLowUpp_t limlowupp )
431 int token = limlowupp == LimLow ? M_TOKEN( limLow ) : M_TOKEN( limUpp );
432 m_rStream.ensureOpeningTag( token );
433 OUString e = readOMathArgInElement( M_TOKEN( e ));
434 OUString lim = readOMathArgInElement( M_TOKEN( lim ));
435 m_rStream.ensureClosingTag( token );
436 // fix up overbrace/underbrace (use { }, as {} will be converted to a placeholder)
437 if( limlowupp == LimUpp && e.endsWith( " overbrace { }" ))
438 return e.subView( 0, e.getLength() - 2 ) + lim + "}";
439 if( limlowupp == LimLow && e.endsWith( " underbrace { }" ))
440 return e.subView( 0, e.getLength() - 2 ) + lim + "}";
441 return e
442 + ( limlowupp == LimLow ? OUStringLiteral( u" csub {" ) : OUStringLiteral( u" csup {" ))
443 + lim + "}";
446 OUString SmOoxmlImport::handleGroupChr()
448 m_rStream.ensureOpeningTag( M_TOKEN( groupChr ));
449 sal_Unicode chr = 0x23df;
450 enum pos_t { top, bot } pos = bot;
451 if( m_rStream.checkOpeningTag( M_TOKEN( groupChrPr )))
453 if( XmlStream::Tag chrTag = m_rStream.checkOpeningTag( M_TOKEN( chr )))
455 chr = chrTag.attribute( M_TOKEN( val ), chr );
456 m_rStream.ensureClosingTag( M_TOKEN( chr ));
458 if( XmlStream::Tag posTag = m_rStream.checkOpeningTag( M_TOKEN( pos )))
460 if( posTag.attribute( M_TOKEN( val ), OUString( "bot" )) == "top" )
461 pos = top;
462 m_rStream.ensureClosingTag( M_TOKEN( pos ));
464 m_rStream.ensureClosingTag( M_TOKEN( groupChrPr ));
466 OUString e = readOMathArgInElement( M_TOKEN( e ));
467 m_rStream.ensureClosingTag( M_TOKEN( groupChr ));
468 if( pos == top && chr == u'\x23de')
469 return "{" + e + "} overbrace { }";
470 if( pos == bot && chr == u'\x23df')
471 return "{" + e + "} underbrace { }";
472 if( pos == top )
473 return "{" + e + "} csup {" + OUStringChar( chr ) + "}";
474 else
475 return "{" + e + "} csub {" + OUStringChar( chr ) + "}";
478 OUString SmOoxmlImport::handleM()
480 m_rStream.ensureOpeningTag( M_TOKEN( m ));
481 OUStringBuffer allrows;
482 do // there must be at least one m:mr
484 m_rStream.ensureOpeningTag( M_TOKEN( mr ));
485 OUStringBuffer row;
486 do // there must be at least one m:e
488 if( !row.isEmpty())
489 row.append(" # ");
490 row.append(readOMathArgInElement( M_TOKEN( e )));
491 } while( !m_rStream.atEnd() && m_rStream.findTag( OPENING( M_TOKEN( e ))));
492 if( !allrows.isEmpty())
493 allrows.append(" ## ");
494 allrows.append(row);
495 m_rStream.ensureClosingTag( M_TOKEN( mr ));
496 } while( !m_rStream.atEnd() && m_rStream.findTag( OPENING( M_TOKEN( mr ))));
497 m_rStream.ensureClosingTag( M_TOKEN( m ));
498 return "matrix {" + allrows.makeStringAndClear() + "}";
501 OUString SmOoxmlImport::handleNary()
503 m_rStream.ensureOpeningTag( M_TOKEN( nary ));
504 sal_Unicode chr = 0x222b;
505 bool subHide = false;
506 bool supHide = false;
507 if( m_rStream.checkOpeningTag( M_TOKEN( naryPr )))
509 if( XmlStream::Tag chrTag = m_rStream.checkOpeningTag( M_TOKEN( chr )))
511 chr = chrTag.attribute( M_TOKEN( val ), chr );
512 m_rStream.ensureClosingTag( M_TOKEN( chr ));
514 if( XmlStream::Tag subHideTag = m_rStream.checkOpeningTag( M_TOKEN( subHide )))
516 subHide = subHideTag.attribute( M_TOKEN( val ), subHide );
517 m_rStream.ensureClosingTag( M_TOKEN( subHide ));
519 if( XmlStream::Tag supHideTag = m_rStream.checkOpeningTag( M_TOKEN( supHide )))
521 supHide = supHideTag.attribute( M_TOKEN( val ), supHide );
522 m_rStream.ensureClosingTag( M_TOKEN( supHide ));
524 m_rStream.ensureClosingTag( M_TOKEN( naryPr ));
526 OUString sub = readOMathArgInElement( M_TOKEN( sub ));
527 OUString sup = readOMathArgInElement( M_TOKEN( sup ));
528 OUString e = readOMathArgInElement( M_TOKEN( e ));
529 OUString ret;
530 switch( chr )
532 case MS_INT:
533 ret = "int";
534 break;
535 case MS_IINT:
536 ret = "iint";
537 break;
538 case MS_IIINT:
539 ret = "iiint";
540 break;
541 case MS_LINT:
542 ret = "lint";
543 break;
544 case MS_LLINT:
545 ret = "llint";
546 break;
547 case MS_LLLINT:
548 ret = "lllint";
549 break;
550 case MS_PROD:
551 ret = "prod";
552 break;
553 case MS_COPROD:
554 ret = "coprod";
555 break;
556 case MS_SUM:
557 ret = "sum";
558 break;
559 default:
560 SAL_WARN( "starmath.ooxml", "Unknown m:nary chr \'" << OUString(chr) << "\'" );
561 break;
563 if( !subHide )
564 ret += " from {" + sub + "}";
565 if( !supHide )
566 ret += " to {" + sup + "}";
567 ret += " {" + e + "}";
568 m_rStream.ensureClosingTag( M_TOKEN( nary ));
569 return ret;
572 // NOT complete
573 OUString SmOoxmlImport::handleR()
575 m_rStream.ensureOpeningTag( M_TOKEN( r ));
576 bool normal = false;
577 bool literal = false;
578 if( XmlStream::Tag rPr = m_rStream.checkOpeningTag( M_TOKEN( rPr )))
580 if( XmlStream::Tag litTag = m_rStream.checkOpeningTag( M_TOKEN( lit )))
582 literal = litTag.attribute( M_TOKEN( val ), true );
583 m_rStream.ensureClosingTag( M_TOKEN( lit ));
585 if( XmlStream::Tag norTag = m_rStream.checkOpeningTag( M_TOKEN( nor )))
587 normal = norTag.attribute( M_TOKEN( val ), true );
588 m_rStream.ensureClosingTag( M_TOKEN( nor ));
590 m_rStream.ensureClosingTag( M_TOKEN( rPr ));
592 OUStringBuffer text;
593 while( !m_rStream.atEnd() && m_rStream.currentToken() != CLOSING( m_rStream.currentToken()))
595 switch( m_rStream.currentToken())
597 case OPENING( M_TOKEN( t )):
599 XmlStream::Tag rtag = m_rStream.ensureOpeningTag( M_TOKEN( t ));
600 if( rtag.attribute( OOX_TOKEN( xml, space )) != "preserve" )
601 text.append(rtag.text.trim());
602 else
603 text.append(rtag.text);
604 m_rStream.ensureClosingTag( M_TOKEN( t ));
605 break;
607 default:
608 m_rStream.handleUnexpectedTag();
609 break;
612 m_rStream.ensureClosingTag( M_TOKEN( r ));
613 if( normal || literal )
615 text.insert(0, "\"");
616 text.append("\"");
618 return text.makeStringAndClear().replaceAll("{", "\\{").replaceAll("}", "\\}");
621 OUString SmOoxmlImport::handleRad()
623 m_rStream.ensureOpeningTag( M_TOKEN( rad ));
624 bool degHide = false;
625 if( m_rStream.checkOpeningTag( M_TOKEN( radPr )))
627 if( XmlStream::Tag degHideTag = m_rStream.checkOpeningTag( M_TOKEN( degHide )))
629 degHide = degHideTag.attribute( M_TOKEN( val ), degHide );
630 m_rStream.ensureClosingTag( M_TOKEN( degHide ));
632 m_rStream.ensureClosingTag( M_TOKEN( radPr ));
634 OUString deg = readOMathArgInElement( M_TOKEN( deg ));
635 OUString e = readOMathArgInElement( M_TOKEN( e ));
636 m_rStream.ensureClosingTag( M_TOKEN( rad ));
637 if( degHide )
638 return "sqrt {" + e + "}";
639 else
640 return "nroot {" + deg + "} {" + e + "}";
643 OUString SmOoxmlImport::handleSpre()
645 m_rStream.ensureOpeningTag( M_TOKEN( sPre ));
646 OUString sub = readOMathArgInElement( M_TOKEN( sub ));
647 OUString sup = readOMathArgInElement( M_TOKEN( sup ));
648 OUString e = readOMathArgInElement( M_TOKEN( e ));
649 m_rStream.ensureClosingTag( M_TOKEN( sPre ));
650 return "{" + e + "} lsub {" + sub + "} lsup {" + sup + "}";
653 OUString SmOoxmlImport::handleSsub()
655 m_rStream.ensureOpeningTag( M_TOKEN( sSub ));
656 OUString e = readOMathArgInElement( M_TOKEN( e ));
657 OUString sub = readOMathArgInElement( M_TOKEN( sub ));
658 m_rStream.ensureClosingTag( M_TOKEN( sSub ));
659 return "{" + e + "} rsub {" + sub + "}";
662 OUString SmOoxmlImport::handleSsubsup()
664 m_rStream.ensureOpeningTag( M_TOKEN( sSubSup ));
665 OUString e = readOMathArgInElement( M_TOKEN( e ));
666 OUString sub = readOMathArgInElement( M_TOKEN( sub ));
667 OUString sup = readOMathArgInElement( M_TOKEN( sup ));
668 m_rStream.ensureClosingTag( M_TOKEN( sSubSup ));
669 return "{" + e + "} rsub {" + sub + "} rsup {" + sup + "}";
672 OUString SmOoxmlImport::handleSsup()
674 m_rStream.ensureOpeningTag( M_TOKEN( sSup ));
675 OUString e = readOMathArgInElement( M_TOKEN( e ));
676 OUString sup = readOMathArgInElement( M_TOKEN( sup ));
677 m_rStream.ensureClosingTag( M_TOKEN( sSup ));
678 return "{" + e + "} ^ {" + sup + "}";
681 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */