Bump version to 21.06.18.1
[LibreOffice.git] / starmath / source / mathtype.cxx
blobc81433267e01dc6ea8e591a1c4f34fcee5ca72cf
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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "mathtype.hxx"
22 #include <filter/msfilter/classids.hxx>
23 #include <osl/diagnose.h>
24 #include <sfx2/docfile.hxx>
25 #include <sot/storage.hxx>
26 #include <sal/log.hxx>
28 #include "eqnolefilehdr.hxx"
29 #include <node.hxx>
31 void MathType::Init()
33 //These are the default MathType sizes
34 aSizeTable.push_back(12);
35 aSizeTable.push_back(8);
36 aSizeTable.push_back(6);
37 aSizeTable.push_back(24);
38 aSizeTable.push_back(10);
39 aSizeTable.push_back(12);
40 aSizeTable.push_back(12);
43 These are the default MathType italic/bold settings If mathtype is changed
44 from its defaults, there is nothing we can do, as this information is not
45 stored in the document
47 MathTypeFont aFont;
48 for(sal_uInt8 i=1;i<=11;i++)
50 aFont.nTface = i+128;
51 switch (i)
53 default:
54 aFont.nStyle=0;
55 break;
56 case 3:
57 case 4:
58 aFont.nStyle=1;
59 break;
60 case 7:
61 aFont.nStyle=2;
62 break;
64 aUserStyles.insert(aFont);
69 /*ToDo replace with table rather than switch, returns
70 sal_True in the case that the char is just a char, and
71 sal_False if the character is an operator which must not be
72 placed inside the quote sequence designed to protect
73 against being parsed as a keyword
75 General solution required to force starmath to handle
76 unicode math chars the way it handles its own math
77 chars rather than handle them as text as it will do
78 for the default case below, i.e. incorrect spacing
79 between math symbols and ordinary text e.g. 1=2 rather
80 than 1 = 2
82 bool MathType::LookupChar(sal_Unicode nChar,OUStringBuffer &rRet,sal_uInt8 nVersion,
83 sal_uInt8 nTypeFace)
85 bool bRet=false;
86 const char *pC = nullptr;
87 switch(nChar)
89 case 0x0000:
90 pC = " none ";
91 break;
92 case 0x00ac:
93 pC = " neg ";
94 break;
95 case 0x00b1:
96 pC = " +- ";
97 break;
98 case '(':
99 pC = " \\( ";
100 break;
101 case ')':
102 pC = " \\) ";
103 break;
104 case '[':
105 pC = " \\[ ";
106 break;
107 case ']':
108 pC = " \\] ";
109 break;
110 case '.':
111 pC = " \".\" ";
112 break;
113 case 0xae:
114 if ((nVersion < 3) && (nTypeFace == 0x86))
115 pC = " rightarrow ";
116 else
118 rRet.append(OUStringChar(nChar));
119 bRet=true;
121 break;
122 case 0x00fb:
123 if ((nVersion < 3) && (nTypeFace == 0x81))
124 nChar = 0xDF;
125 rRet.append(OUStringChar(nChar));
126 bRet=true;
127 break;
128 case 'a':
129 if ((nVersion < 3) && (nTypeFace == 0x84))
130 nChar = 0x3b1;
131 rRet.append(OUStringChar(nChar));
132 bRet=true;
133 break;
134 case 'b':
135 if ((nVersion < 3) && (nTypeFace == 0x84))
136 nChar = 0x3b2;
137 rRet.append(OUStringChar(nChar));
138 bRet=true;
139 break;
140 case 'l':
141 if ((nVersion < 3) && (nTypeFace == 0x84))
142 nChar = 0x3bb;
143 rRet.append(OUStringChar(nChar));
144 bRet=true;
145 break;
146 case 'n':
147 if ((nVersion < 3) && (nTypeFace == 0x84))
148 nChar = 0x3bd;
149 rRet.append(OUStringChar(nChar));
150 bRet=true;
151 break;
152 case 'r':
153 if ((nVersion < 3) && (nTypeFace == 0x84))
154 nChar = 0x3c1;
155 rRet.append(OUStringChar(nChar));
156 bRet=true;
157 break;
158 case 'D':
159 if ((nVersion < 3) && (nTypeFace == 0x84))
160 nChar = 0x394;
161 rRet.append(OUStringChar(nChar));
162 bRet=true;
163 break;
164 case 0xa9:
165 if ((nVersion < 3) && (nTypeFace == 0x82))
166 nChar = '\'';
167 rRet.append(OUStringChar(nChar));
168 bRet=true;
169 break;
170 case 0x00f1:
171 if ((nVersion < 3) && (nTypeFace == 0x86))
172 pC = " \\rangle ";
173 else
175 rRet.append(OUStringChar(nChar));
176 bRet=true;
178 break;
179 case 0x00a3:
180 if ((nVersion < 3) && (nTypeFace == 0x86))
181 pC = " <= ";
182 else
184 rRet.append(OUStringChar(nChar));
185 bRet=true;
187 break;
188 case 0x00de:
189 if ((nVersion < 3) && (nTypeFace == 0x86))
190 pC = " drarrow ";
191 else
193 rRet.append(OUStringChar(nChar));
194 bRet=true;
196 break;
197 case 0x0057:
198 if ((nVersion < 3) && (nTypeFace == 0x85))
199 pC = " %OMEGA ";
200 else
202 rRet.append(OUStringChar(nChar));
203 bRet=true;
205 break;
206 case 0x007b:
207 pC = " lbrace ";
208 break;
209 case 0x007c:
210 pC = " \\lline ";
211 break;
212 case 0x007d:
213 pC = " rbrace ";
214 break;
215 case 0x007e:
216 pC = " \"~\" ";
217 break;
218 case 0x2224:
219 pC = " ndivides ";
220 break;
221 case 0x2225:
222 pC = " parallel ";
223 break;
224 case 0x00d7:
225 if (nVersion < 3)
226 pC = " cdot ";
227 else
228 pC = " times ";
229 break;
230 case 0x00f7:
231 pC = " div ";
232 break;
233 case 0x019b:
234 pC = " lambdabar ";
235 break;
236 case 0x2026:
237 pC = " dotslow ";
238 break;
239 case 0x2022:
240 pC = " cdot ";
241 break;
242 case 0x2102:
243 pC = " setC ";
244 break;
245 case 0x210f:
246 pC = " hbar ";
247 break;
248 case 0x2111:
249 pC = " Im ";
250 break;
251 case 0x2115:
252 pC = " setN ";
253 break;
254 case 0x2118:
255 pC = " wp ";
256 break;
257 case 0x211a:
258 pC = " setQ ";
259 break;
260 case 0x211c:
261 pC = " Re ";
262 break;
263 case 0x211d:
264 pC = " setR ";
265 break;
266 case 0x2124:
267 pC = " setZ ";
268 break;
269 case 0x2135:
270 pC = " aleph ";
271 break;
272 case 0x2190:
273 pC = " leftarrow ";
274 break;
275 case 0x2191:
276 pC = " uparrow ";
277 break;
278 case 0x2192:
279 pC = " rightarrow ";
280 break;
281 case 0x0362:
282 pC = " widevec ";
283 break;
284 case 0x2193:
285 pC = " downarrow ";
286 break;
287 case 0x21d0:
288 pC = " dlarrow ";
289 break;
290 case 0x21d2:
291 pC = " drarrow ";
292 break;
293 case 0x21d4:
294 pC = " dlrarrow ";
295 break;
296 case 0x2200:
297 pC = " forall ";
298 break;
299 case 0x2202:
300 pC = " partial ";
301 break;
302 case 0x2203:
303 pC = " exists ";
304 break;
305 case 0x2204:
306 pC = " notexists ";
307 break;
308 case 0x2205:
309 pC = " emptyset ";
310 break;
311 case 0x2207:
312 pC = " nabla ";
313 break;
314 case 0x2112:
315 pC = " laplace ";
316 break;
317 case 0x2208: // in
318 case 0x2209: // notin
319 rRet.append(" func ").append(OUStringChar(nChar)).append(" ");
320 break;
321 case 0x220d: // owns
322 rRet.append(u" func \u220b ");
323 break;
324 case 0x220f:
325 pC = " prod ";
326 break;
327 case 0x2210:
328 pC = " coprod ";
329 break;
330 case 0x2211:
331 pC = " sum ";
332 break;
333 case 0x2212:
334 pC = " - ";
335 break;
336 case 0x2213:
337 pC = " -+ ";
338 break;
339 case 0x2217:
340 pC = " * ";
341 break;
342 case 0x2218:
343 pC = " circ ";
344 break;
345 case 0x221d:
346 pC = " prop ";
347 break;
348 case 0x221e:
349 pC = " infinity ";
350 break;
351 case 0x2227:
352 pC = " and ";
353 break;
354 case 0x2228:
355 pC = " or ";
356 break;
357 case 0x2229:
358 pC = " intersection ";
359 break;
360 case 0x222a:
361 pC = " union ";
362 break;
363 case 0x222b:
364 pC = " int ";
365 break;
366 case 0x222c:
367 pC = " iint ";
368 break;
369 case 0x222d:
370 pC = " iiint ";
371 break;
372 case 0x222e:
373 pC = " lint ";
374 break;
375 case 0x222f:
376 pC = " llint ";
377 break;
378 case 0x2230:
379 pC = " lllint ";
380 break;
381 case 0x2245:
382 pC = " simeq ";
383 break;
384 case 0x2248:
385 pC = " approx ";
386 break;
387 case 0x2260:
388 pC = " <> ";
389 break;
390 case 0x2261:
391 pC = " equiv ";
392 break;
393 case 0x2264:
394 pC = " <= ";
395 break;
396 case 0x2265:
397 pC = " >= ";
398 break;
400 case 0x227A:
401 pC = " prec ";
402 break;
403 case 0x227B:
404 pC = " succ ";
405 break;
406 case 0x227C:
407 pC = " preccurlyeq ";
408 break;
409 case 0x227D:
410 pC = " succcurlyeq ";
411 break;
412 case 0x227E:
413 pC = " precsim ";
414 break;
415 case 0x227F:
416 pC = " succsim ";
417 break;
418 case 0x2280:
419 pC = " nprec ";
420 break;
421 case 0x2281:
422 pC = " nsucc ";
423 break;
425 case 0x2282: // subset
426 case 0x2283: // supset
427 case 0x2284: // nsubset
428 case 0x2285: // nsupset
429 case 0x2286: // subseteq
430 case 0x2287: // supseteq
431 case 0x2288: // nsubseteq
432 case 0x2289: // nsupseteq
433 case 0x22b2: // NORMAL SUBGROUP OF
434 case 0x22b3: // CONTAINS AS NORMAL SUBGROUP
435 rRet.append(" func ").append(OUStringChar(nChar)).append(" ");
436 break;
437 case 0x22a5:
438 pC = " ortho ";
439 break;
440 case 0x22c5:
441 pC = " cdot ";
442 break;
443 case 0x22ee:
444 pC = " dotsvert ";
445 break;
446 case 0x22ef:
447 pC = " dotsaxis ";
448 break;
449 case 0x22f0:
450 pC = " dotsup ";
451 break;
452 case 0x22f1:
453 pC = " dotsdown ";
454 break;
455 case MS_LANGLE:
456 case MS_LMATHANGLE:
457 pC = " langle ";
458 break;
459 case MS_RANGLE:
460 case MS_RMATHANGLE:
461 pC = " rangle ";
462 break;
463 case 0x301a:
464 pC = " ldbracket ";
465 break;
466 case 0x301b:
467 pC = " rdbracket ";
468 break;
469 case 0xe083:
470 rRet.append("+");
471 bRet=true;
472 break;
473 case '^':
474 case 0xe091:
475 pC = " widehat ";
476 break;
477 case 0xe096:
478 pC = " widetilde ";
479 break;
480 case 0xe098:
481 pC = " widevec ";
482 break;
483 case 0xE421:
484 pC = " geslant ";
485 break;
486 case 0xE425:
487 pC = " leslant ";
488 break;
489 case 0xeb01: //no space
490 case 0xeb08: //normal space
491 bRet=true;
492 break;
493 case 0xef04: //tiny space
494 case 0xef05: //tiny space
495 case 0xeb02: //small space
496 case 0xeb04: //medium space
497 rRet.append("`");
498 break;
499 case 0xeb05: //large space
500 rRet.append("~");
501 break;
502 case 0x3a9:
503 pC = " %OMEGA ";
504 break;
505 default:
506 rRet.append(OUStringChar(nChar));
507 bRet=true;
508 break;
510 if (pC)
511 rRet.appendAscii(pC);
512 return bRet;
515 void MathTypeFont::AppendStyleToText(OUString &rRet)
517 const char *pC = nullptr;
518 switch (nStyle)
520 default:
521 case 0:
522 break;
523 case 1:
524 pC = " ital ";
525 break;
526 case 2:
527 pC = " bold ";
528 break;
529 case 3:
530 pC = " bold italic";
531 break;
533 if (pC)
534 rRet += OUString::createFromAscii( pC );
537 void MathType::TypeFaceToString(OUString &rTxt,sal_uInt8 nFace)
539 MathTypeFont aFont(nFace);
540 MathTypeFontSet::iterator aItr = aUserStyles.find(aFont);
541 if (aItr != aUserStyles.end())
542 aFont.nStyle = aItr->nStyle;
543 aFont.AppendStyleToText(rTxt);
546 bool MathType::Parse(SotStorage *pStor)
548 tools::SvRef<SotStorageStream> xSrc = pStor->OpenSotStream(
549 "Equation Native",
550 StreamMode::STD_READ);
551 if ( (!xSrc.is()) || (ERRCODE_NONE != xSrc->GetError()))
552 return false;
553 return Parse(xSrc.get());
556 bool MathType::Parse(SvStream* pStream)
558 pS = pStream;
559 pS->SetEndian( SvStreamEndian::LITTLE );
561 EQNOLEFILEHDR aHdr;
562 aHdr.Read(pS);
563 sal_uInt8 nProdVersion;
564 sal_uInt8 nProdSubVersion;
565 sal_uInt8 nPlatform;
566 sal_uInt8 nProduct;
567 pS->ReadUChar( nVersion );
568 pS->ReadUChar( nPlatform );
569 pS->ReadUChar( nProduct );
570 pS->ReadUChar( nProdVersion );
571 pS->ReadUChar( nProdSubVersion );
573 if (nVersion > 3) // allow only supported versions of MathType to be parsed
574 return false;
576 bool bRet = HandleRecords(0);
577 //little crude hack to close occasionally open expressions
578 //a sophisticated system to determine what expressions are
579 //opened is required, but this is as much work as rewriting
580 //starmaths internals.
581 rRet.append("{}");
583 return bRet;
586 static void lcl_PrependDummyTerm(OUStringBuffer &rRet, sal_Int32 &rTextStart)
588 if ((rTextStart < rRet.getLength()) &&
589 (rRet[rTextStart] == '=') &&
590 ((rTextStart == 0) || (rRet[ rTextStart-1 ] == '{'))
593 rRet.insert(rTextStart, " {}");
594 rTextStart+=3;
598 static void lcl_AppendDummyTerm(OUStringBuffer &rRet)
600 bool bOk=false;
601 for(int nI=rRet.getLength()-1;nI >= 0; nI--)
603 sal_Int32 nIdx = sal::static_int_cast< sal_Int32 >(nI);
604 sal_Unicode nChar = rRet[nIdx];
605 if (nChar == ' ')
606 continue;
607 if (rRet[nIdx] != '{')
608 bOk=true;
609 break;
611 if (!bOk) //No term, use dummy
612 rRet.append(" {}");
615 void MathType::HandleNudge()
617 sal_uInt8 nXNudge(0);
618 pS->ReadUChar(nXNudge);
619 sal_uInt8 nYNudge(0);
620 pS->ReadUChar(nYNudge);
621 if (nXNudge == 128 && nYNudge == 128)
623 sal_uInt16 nXLongNudge(0);
624 sal_uInt16 nYLongNudge(0);
625 pS->ReadUInt16(nXLongNudge);
626 pS->ReadUInt16(nYLongNudge);
630 /* Fabulously complicated as many tokens have to be reordered and generally
631 * moved around from mathtypes paradigm to starmaths. */
632 bool MathType::HandleRecords(int nLevel, sal_uInt8 nSelector,
633 sal_uInt8 nVariation, int nMatrixRows, int nMatrixCols)
635 //depth-protect
636 if (nLevel > 1024)
637 return false;
639 sal_uInt8 nTag,nRecord;
640 sal_uInt8 nTabType,nTabStops;
641 sal_uInt16 nTabOffset;
642 int i, newline=0;
643 bool bSilent=false;
644 int nPart=0;
645 OUString sPush,sMainTerm;
646 int nSetSize=0,nSetAlign=0;
647 int nCurRow=0,nCurCol=0;
648 bool bOpenString=false;
649 sal_Int32 nTextStart = 0;
650 sal_Int32 nSubSupStartPos = 0;
651 sal_Int32 nLastTemplateBracket=-1;
652 bool bRet = true;
656 nTag = 0;
657 pS->ReadUChar( nTag );
658 nRecord = nTag&0x0F;
660 /*MathType strings can of course include words which
661 *are StarMath keywords, the simplest solution is
662 to escape strings of greater than len 1 with double
663 quotes to avoid scanning the TokenTable for matches
665 Unfortunately it may turn out that the string gets
666 split during the handling of a character emblishment
667 so this special case must be handled in the
668 character handler case 2:
670 if ((nRecord == CHAR) && (!bOpenString))
672 bOpenString=true;
673 nTextStart = rRet.getLength();
675 else if ((nRecord != CHAR) && bOpenString)
677 bOpenString=false;
678 if ((rRet.getLength() - nTextStart) > 1)
680 OUString aStr;
681 TypeFaceToString(aStr,nTypeFace);
682 aStr += "\"";
683 rRet.insert(nTextStart,aStr);
684 rRet.append("\"");
686 else if (nRecord == END && !rRet.isEmpty())
688 sal_Unicode cChar = 0;
689 sal_Int32 nI = rRet.getLength()-1;
690 while (nI)
692 cChar = rRet[nI];
693 if (cChar != ' ')
694 break;
695 --nI;
697 if ((cChar == '=') || (cChar == '+') || (cChar == '-'))
698 rRet.append("{}");
702 switch(nRecord)
704 case LINE:
706 if (xfLMOVE(nTag))
707 HandleNudge();
709 if (newline>0)
710 rRet.append("\nnewline\n");
711 if (!(xfNULL(nTag)))
713 switch (nSelector)
715 case tmANGLE:
716 if (nVariation==0)
717 rRet.append(" langle ");
718 else if (nVariation==1)
719 rRet.append(" \\langle ");
720 break;
721 case tmPAREN:
722 if (nVariation==0)
723 rRet.append(" left (");
724 else if (nVariation==1)
725 rRet.append("\\(");
726 break;
727 case tmBRACE:
728 if ((nVariation==0) || (nVariation==1))
729 rRet.append(" left lbrace ");
730 else
731 rRet.append(" left none ");
732 break;
733 case tmBRACK:
734 if (nVariation==0)
735 rRet.append(" left [");
736 else if (nVariation==1)
737 rRet.append("\\[");
738 break;
739 case tmLBLB:
740 case tmLBRP:
741 rRet.append(" \\[");
742 break;
743 case tmBAR:
744 if (nVariation==0)
745 rRet.append(" lline ");
746 else if (nVariation==1)
747 rRet.append(" \\lline ");
748 break;
749 case tmDBAR:
750 if (nVariation==0)
751 rRet.append(" ldline ");
752 else if (nVariation==1)
753 rRet.append(" \\ldline ");
754 break;
755 case tmFLOOR:
756 if (nVariation == 0 || nVariation & 0x01) // tvFENCE_L
757 rRet.append(" left lfloor ");
758 else
759 rRet.append(" left none ");
760 break;
761 case tmCEILING:
762 if (nVariation==0)
763 rRet.append(" lceil ");
764 else if (nVariation==1)
765 rRet.append(" \\lceil ");
766 break;
767 case tmRBRB:
768 case tmRBLB:
769 rRet.append(" \\]");
770 break;
771 case tmLPRB:
772 rRet.append(" \\(");
773 break;
774 case tmROOT:
775 if (nPart == 0)
777 if (nVariation == 0)
778 rRet.append(" sqrt");
779 else
781 rRet.append(" nroot");
782 sPush = rRet.makeStringAndClear();
785 rRet.append(" {");
786 break;
787 case tmFRACT:
788 if (nPart == 0)
789 rRet.append(" { ");
792 if (nPart == 1)
793 rRet.append(" over ");
794 rRet.append(" {");
795 break;
796 case tmSCRIPT:
797 nSubSupStartPos = rRet.getLength();
798 if ((nVariation == 0) ||
799 ((nVariation == 2) && (nPart==1)))
801 lcl_AppendDummyTerm(rRet);
802 rRet.append(" rSup");
804 else if ((nVariation == 1) ||
805 ((nVariation == 2) && (nPart==0)))
807 lcl_AppendDummyTerm(rRet);
808 rRet.append(" rSub");
810 rRet.append(" {");
811 break;
812 case tmUBAR:
813 if (nVariation == 0)
814 rRet.append(" {underline ");
815 else if (nVariation == 1)
816 rRet.append(" {underline underline ");
817 rRet.append(" {");
818 break;
819 case tmOBAR:
820 if (nVariation == 0)
821 rRet.append(" {overline ");
822 else if (nVariation == 1)
823 rRet.append(" {overline overline ");
824 rRet.append(" {");
825 break;
826 case tmLARROW:
827 if (nPart == 0)
829 if (nVariation == 0)
830 rRet.append(" widevec ");//left arrow above
831 else if (nVariation == 1)
832 rRet.append(" widevec ");//left arrow below
833 rRet.append(" {");
835 break;
836 case tmRARROW:
837 if (nPart == 0)
839 if (nVariation == 0)
840 rRet.append(" widevec ");//right arrow above
841 else if (nVariation == 1)
842 rRet.append(" widevec ");//right arrow below
843 rRet.append(" {");
845 break;
846 case tmBARROW:
847 if (nPart == 0)
849 if (nVariation == 0)
850 rRet.append(" widevec ");//double arrow above
851 else if (nVariation == 1)
852 rRet.append(" widevec ");//double arrow below
853 rRet.append(" {");
855 break;
856 case tmSINT:
857 if (nPart == 0)
859 if ((nVariation == 3) || (nVariation == 4))
860 rRet.append(" lInt");
861 else
862 rRet.append(" Int");
863 if ( (nVariation != 0) && (nVariation != 3))
865 sPush = rRet.makeStringAndClear();
868 if (((nVariation == 1) ||
869 (nVariation == 4)) && (nPart==1))
870 rRet.append(" rSub");
871 else if ((nVariation == 2) && (nPart==2))
872 rRet.append(" rSup");
873 else if ((nVariation == 2) && (nPart==1))
874 rRet.append(" rSub");
875 rRet.append(" {");
876 break;
877 case tmDINT:
878 if (nPart == 0)
880 if ((nVariation == 2) || (nVariation == 3))
881 rRet.append(" llInt");
882 else
883 rRet.append(" iInt");
884 if ( (nVariation != 0) && (nVariation != 2))
886 sPush = rRet.makeStringAndClear();
889 if (((nVariation == 1) ||
890 (nVariation == 3)) && (nPart==1))
891 rRet.append(" rSub");
892 rRet.append(" {");
893 break;
894 case tmTINT:
895 if (nPart == 0)
897 if ((nVariation == 2) || (nVariation == 3))
898 rRet.append(" lllInt");
899 else
900 rRet.append(" iiInt");
901 if ( (nVariation != 0) && (nVariation != 2))
903 sPush = rRet.makeStringAndClear();
906 if (((nVariation == 1) ||
907 (nVariation == 3)) && (nPart==1))
908 rRet.append(" rSub");
909 rRet.append(" {");
910 break;
911 case tmSSINT:
912 if (nPart == 0)
914 if (nVariation == 2)
915 rRet.append(" lInt");
916 else
917 rRet.append(" Int");
918 sPush = rRet.makeStringAndClear();
920 if (((nVariation == 1) ||
921 (nVariation == 2)) && (nPart==1))
922 rRet.append(" cSub");
923 else if ((nVariation == 0) && (nPart==2))
924 rRet.append(" cSup");
925 else if ((nVariation == 0) && (nPart==1))
926 rRet.append(" cSub");
927 rRet.append(" {");
928 break;
929 case tmDSINT:
930 if (nPart == 0)
932 if (nVariation == 0)
933 rRet.append(" llInt");
934 else
935 rRet.append(" iInt");
936 sPush = rRet.makeStringAndClear();
938 if (nPart==1)
939 rRet.append(" cSub");
940 rRet.append(" {");
941 break;
942 case tmTSINT:
943 if (nPart == 0)
945 if (nVariation == 0)
946 rRet.append(" lllInt");
947 else
948 rRet.append(" iiInt");
949 sPush = rRet.makeStringAndClear();
951 if (nPart==1)
952 rRet.append(" cSub");
953 rRet.append(" {");
954 break;
955 case tmUHBRACE:
956 case tmLHBRACE:
957 rRet.append(" {");
958 break;
959 case tmSUM:
960 if (nPart == 0)
962 rRet.append(" Sum");
963 if (nVariation != 2)
965 sPush = rRet.makeStringAndClear();
968 if ((nVariation == 0) && (nPart==1))
969 rRet.append(" cSub");
970 else if ((nVariation == 1) && (nPart==2))
971 rRet.append(" cSup");
972 else if ((nVariation == 1) && (nPart==1))
973 rRet.append(" cSub");
974 rRet.append(" {");
975 break;
976 case tmISUM:
977 if (nPart == 0)
979 rRet.append(" Sum");
980 sPush = rRet.makeStringAndClear();
982 if ((nVariation == 0) && (nPart==1))
983 rRet.append(" rSub");
984 else if ((nVariation == 1) && (nPart==2))
985 rRet.append(" rSup");
986 else if ((nVariation == 1) && (nPart==1))
987 rRet.append(" rSub");
988 rRet.append(" {");
989 break;
990 case tmPROD:
991 if (nPart == 0)
993 rRet.append(" Prod");
994 if (nVariation != 2)
996 sPush = rRet.makeStringAndClear();
999 if ((nVariation == 0) && (nPart==1))
1000 rRet.append(" cSub");
1001 else if ((nVariation == 1) && (nPart==2))
1002 rRet.append(" cSup");
1003 else if ((nVariation == 1) && (nPart==1))
1004 rRet.append(" cSub");
1005 rRet.append(" {");
1006 break;
1007 case tmIPROD:
1008 if (nPart == 0)
1010 rRet.append(" Prod");
1011 sPush = rRet.makeStringAndClear();
1013 if ((nVariation == 0) && (nPart==1))
1014 rRet.append(" rSub");
1015 else if ((nVariation == 1) && (nPart==2))
1016 rRet.append(" rSup");
1017 else if ((nVariation == 1) && (nPart==1))
1018 rRet.append(" rSub");
1019 rRet.append(" {");
1020 break;
1021 case tmCOPROD:
1022 if (nPart == 0)
1024 rRet.append(" coProd");
1025 if (nVariation != 2)
1027 sPush = rRet.makeStringAndClear();
1030 if ((nVariation == 0) && (nPart==1))
1031 rRet.append(" cSub");
1032 else if ((nVariation == 1) && (nPart==2))
1033 rRet.append(" cSup");
1034 else if ((nVariation == 1) && (nPart==1))
1035 rRet.append(" cSub");
1036 rRet.append(" {");
1037 break;
1038 case tmICOPROD:
1039 if (nPart == 0)
1041 rRet.append(" coProd");
1042 sPush = rRet.makeStringAndClear();
1044 if ((nVariation == 0) && (nPart==1))
1045 rRet.append(" rSub");
1046 else if ((nVariation == 1) && (nPart==2))
1047 rRet.append(" rSup");
1048 else if ((nVariation == 1) && (nPart==1))
1049 rRet.append(" rSub");
1050 rRet.append(" {");
1051 break;
1052 case tmUNION:
1053 if (nPart == 0)
1055 rRet.append(" union"); //union
1056 if (nVariation != 2)
1058 sPush = rRet.makeStringAndClear();
1061 if ((nVariation == 0) && (nPart==1))
1062 rRet.append(" cSub");
1063 else if ((nVariation == 1) && (nPart==2))
1064 rRet.append(" cSup");
1065 else if ((nVariation == 1) && (nPart==1))
1066 rRet.append(" cSub");
1067 rRet.append(" {");
1068 break;
1069 case tmIUNION:
1070 if (nPart == 0)
1072 rRet.append(" union"); //union
1073 sPush = rRet.makeStringAndClear();
1075 if ((nVariation == 0) && (nPart==1))
1076 rRet.append(" rSub");
1077 else if ((nVariation == 1) && (nPart==2))
1078 rRet.append(" rSup");
1079 else if ((nVariation == 1) && (nPart==1))
1080 rRet.append(" rSub");
1081 rRet.append(" {");
1082 break;
1083 case tmINTER:
1084 if (nPart == 0)
1086 rRet.append(" intersect"); //intersect
1087 if (nVariation != 2)
1089 sPush = rRet.makeStringAndClear();
1092 if ((nVariation == 0) && (nPart==1))
1093 rRet.append(" cSub");
1094 else if ((nVariation == 1) && (nPart==2))
1095 rRet.append(" cSup");
1096 else if ((nVariation == 1) && (nPart==1))
1097 rRet.append(" cSub");
1098 rRet.append(" {");
1099 break;
1100 case tmIINTER:
1101 if (nPart == 0)
1103 rRet.append(" intersect"); //intersect
1104 sPush = rRet.makeStringAndClear();
1106 if ((nVariation == 0) && (nPart==1))
1107 rRet.append(" rSub");
1108 else if ((nVariation == 1) && (nPart==2))
1109 rRet.append(" rSup");
1110 else if ((nVariation == 1) && (nPart==1))
1111 rRet.append(" rSub");
1112 rRet.append(" {");
1113 break;
1114 case tmLIM:
1115 if ((nVariation == 0) && (nPart==1))
1116 rRet.append(" cSup");
1117 else if ((nVariation == 1) && (nPart==1))
1118 rRet.append(" cSub");
1119 else if ((nVariation == 2) && (nPart==1))
1120 rRet.append(" cSub");
1121 else if ((nVariation == 2) && (nPart==2))
1122 rRet.append(" cSup");
1123 rRet.append(" {");
1124 break;
1125 case tmLDIV:
1126 if (nVariation == 0)
1128 if (nPart == 0)
1130 sPush = rRet.makeStringAndClear();
1133 rRet.append(" {");
1134 if (nVariation == 0)
1136 if (nPart == 1)
1137 rRet.append("alignr ");
1139 if (nPart == 0)
1140 rRet.append("\\lline ");
1141 if (nVariation == 1)
1142 rRet.append("overline ");
1143 break;
1144 case tmSLFRACT:
1145 rRet.append(" {");
1146 break;
1147 case tmINTOP:
1148 if (nPart == 0)
1150 sPush = rRet.makeStringAndClear();
1152 if ((nVariation == 0) && (nPart==0))
1153 rRet.append(" rSup");
1154 else if ((nVariation == 2) && (nPart==1))
1155 rRet.append(" rSup");
1156 else if ((nVariation == 1) && (nPart==0))
1157 rRet.append(" rSub");
1158 else if ((nVariation == 2) && (nPart==0))
1159 rRet.append(" rSub");
1160 rRet.append(" {");
1161 break;
1162 case tmSUMOP:
1163 if (nPart == 0)
1165 sPush = rRet.makeStringAndClear();
1167 if ((nVariation == 0) && (nPart==0))
1168 rRet.append(" cSup");
1169 else if ((nVariation == 2) && (nPart==1))
1170 rRet.append(" cSup");
1171 else if ((nVariation == 1) && (nPart==0))
1172 rRet.append(" cSub");
1173 else if ((nVariation == 2) && (nPart==0))
1174 rRet.append(" cSub");
1175 rRet.append(" {");
1176 break;
1177 case tmLSCRIPT:
1178 if (nPart == 0)
1179 rRet.append("\"\"");
1180 if ((nVariation == 0)
1181 || ((nVariation == 2) && (nPart==1)))
1182 rRet.append(" lSup");
1183 else if ((nVariation == 1)
1184 || ((nVariation == 2) && (nPart==0)))
1185 rRet.append(" lSub");
1186 rRet.append(" {");
1187 break;
1188 case tmDIRAC:
1189 if (nVariation==0)
1191 if (nPart == 0)
1192 rRet.append(" langle ");
1194 else if (nVariation==1)
1196 rRet.append(" \\langle ");
1197 newline--;
1199 else if (nVariation==2)
1201 rRet.append(" \\lline ");
1202 newline--;
1204 break;
1205 case tmUARROW:
1206 if (nVariation == 0)
1207 rRet.append(" widevec ");//left below
1208 else if (nVariation == 1)
1209 rRet.append(" widevec ");//right below
1210 else if (nVariation == 2)
1211 rRet.append(" widevec ");//double headed below
1212 rRet.append(" {");
1213 break;
1214 case tmOARROW:
1215 if (nVariation == 0)
1216 rRet.append(" widevec ");//left above
1217 else if (nVariation == 1)
1218 rRet.append(" widevec ");//right above
1219 else if (nVariation == 2)
1220 rRet.append(" widevec ");//double headed above
1221 rRet.append(" {");
1222 break;
1223 default:
1224 break;
1226 sal_Int16 nOldCurSize=nCurSize;
1227 sal_Int32 nSizeStartPos = rRet.getLength();
1228 HandleSize( nLSize, nDSize, nSetSize );
1229 bRet = HandleRecords( nLevel+1 );
1230 while (nSetSize)
1232 bool bOk=false;
1233 sal_Int32 nI = rRet.lastIndexOf('{');
1234 if (nI != -1)
1236 for(nI=nI+1;nI<rRet.getLength();nI++)
1237 if (rRet[nI] != ' ')
1239 bOk=true;
1240 break;
1243 else
1244 bOk=true;
1246 if (bOk)
1247 rRet.append("} ");
1248 else if (rRet.getLength() > nSizeStartPos)
1249 rRet = rRet.truncate(nSizeStartPos);
1250 nSetSize--;
1251 nCurSize=nOldCurSize;
1255 HandleMatrixSeparator(nMatrixRows,nMatrixCols,
1256 nCurCol,nCurRow);
1258 switch (nSelector)
1260 case tmANGLE:
1261 if (nVariation==0)
1262 rRet.append(" rangle ");
1263 else if (nVariation==2)
1264 rRet.append(" \\rangle ");
1265 break;
1266 case tmPAREN:
1267 if (nVariation==0)
1268 rRet.append(" right )");
1269 else if (nVariation==2)
1270 rRet.append("\\)");
1271 break;
1272 case tmBRACE:
1273 if ((nVariation==0) || (nVariation==2))
1274 rRet.append(" right rbrace ");
1275 else
1276 rRet.append(" right none ");
1277 break;
1278 case tmBRACK:
1279 if (nVariation==0)
1280 rRet.append(" right ]");
1281 else if (nVariation==2)
1282 rRet.append("\\]");
1283 break;
1284 case tmBAR:
1285 if (nVariation==0)
1286 rRet.append(" rline ");
1287 else if (nVariation==2)
1288 rRet.append(" \\rline ");
1289 break;
1290 case tmDBAR:
1291 if (nVariation==0)
1292 rRet.append(" rdline ");
1293 else if (nVariation==2)
1294 rRet.append(" \\rdline ");
1295 break;
1296 case tmFLOOR:
1297 if (nVariation == 0 || nVariation & 0x02) // tvFENCE_R
1298 rRet.append(" right rfloor ");
1299 else
1300 rRet.append(" right none ");
1301 break;
1302 case tmCEILING:
1303 if (nVariation==0)
1304 rRet.append(" rceil ");
1305 else if (nVariation==2)
1306 rRet.append(" \\rceil ");
1307 break;
1308 case tmLBLB:
1309 case tmRBLB:
1310 rRet.append("\\[");
1311 break;
1312 case tmRBRB:
1313 case tmLPRB:
1314 rRet.append("\\]");
1315 break;
1316 case tmROOT:
1317 rRet.append("} ");
1318 if (nVariation == 1)
1320 if (nPart == 0)
1322 newline--;
1323 sMainTerm = rRet.makeStringAndClear();
1325 else if (nPart == 1)
1327 rRet.insert(0, sPush);
1328 rRet.append(sMainTerm);
1329 sPush.clear();
1330 sMainTerm.clear();
1333 else
1335 if (nPart == 0)
1336 newline--;
1338 nPart++;
1339 break;
1340 case tmLBRP:
1341 rRet.append("\\)");
1342 break;
1343 case tmFRACT:
1344 rRet.append("} ");
1345 if (nPart == 0)
1346 newline--;
1347 else
1348 rRet.append("} ");
1349 nPart++;
1350 break;
1351 case tmSCRIPT:
1353 if ((nPart == 0) &&
1354 ((nVariation == 2) || (nVariation == 1)))
1355 newline--;
1357 bool bOk=false;
1358 sal_Int32 nI = rRet.lastIndexOf('{');
1359 if (nI != -1)
1361 for(nI=nI+1;nI<rRet.getLength();nI++)
1362 if (rRet[nI] != ' ')
1364 bOk=true;
1365 break;
1368 else
1369 bOk=true;
1371 if (bOk)
1372 rRet.append("} ");
1373 else if (rRet.getLength() > nSubSupStartPos)
1374 rRet = rRet.truncate(nSubSupStartPos);
1375 nPart++;
1377 break;
1378 case tmLSCRIPT:
1379 if ((nPart == 0) &&
1380 ((nVariation == 2) || (nVariation == 1)))
1381 newline--;
1382 rRet.append("} ");
1383 nPart++;
1384 break;
1385 case tmUARROW:
1386 case tmOARROW:
1387 rRet.append("} ");
1388 break;
1389 case tmUBAR:
1390 case tmOBAR:
1391 rRet.append("}} ");
1392 break;
1393 case tmLARROW:
1394 case tmRARROW:
1395 case tmBARROW:
1396 if (nPart == 0)
1398 newline--;
1399 rRet.append("} ");
1401 nPart++;
1402 break;
1403 case tmUHBRACE:
1404 rRet.append("} ");
1405 if (nPart == 0)
1407 newline--;
1408 rRet.append("overbrace");
1410 nPart++;
1411 break;
1412 case tmLHBRACE:
1413 rRet.append("} ");
1414 if (nPart == 0)
1416 newline--;
1417 rRet.append("underbrace");
1419 nPart++;
1420 break;
1421 case tmLIM:
1422 if (nPart==0)
1423 newline--;
1424 else if ((nPart==1) &&
1425 ((nVariation == 2) || (nVariation == 1)))
1426 newline--;
1427 rRet.append("} ");
1428 nPart++;
1429 break;
1430 case tmLDIV:
1431 rRet.append("} ");
1432 if (nVariation == 0)
1434 if (nPart == 0)
1436 sMainTerm = rRet.makeStringAndClear();
1438 else if (nPart == 1)
1440 rRet.insert(0, sPush);
1441 rRet.append(" over ").append(sMainTerm);
1442 sPush.clear();
1443 sMainTerm.clear();
1446 if (nPart == 0)
1447 newline--;
1448 nPart++;
1449 break;
1450 case tmSLFRACT:
1451 rRet.append("} ");
1452 if (nPart == 0)
1454 newline--;
1455 switch (nVariation)
1457 case 1:
1458 rRet.append("slash");
1459 break;
1460 default:
1461 rRet.append("wideslash");
1462 break;
1465 nPart++;
1466 break;
1467 case tmSUM:
1468 case tmISUM:
1469 case tmPROD:
1470 case tmIPROD:
1471 case tmCOPROD:
1472 case tmICOPROD:
1473 case tmUNION:
1474 case tmIUNION:
1475 case tmINTER:
1476 case tmIINTER:
1477 rRet.append("} ");
1478 if (nPart == 0)
1480 if (nVariation != 2)
1482 sMainTerm = rRet.makeStringAndClear();
1484 newline--;
1486 else if ((nPart == 1) && (nVariation == 0))
1488 rRet.insert(0, sPush);
1489 rRet.append(sMainTerm);
1490 sPush.clear();
1491 sMainTerm.clear();
1492 newline--;
1494 else if ((nPart == 1) && (nVariation == 1))
1495 newline--;
1496 else if ((nPart == 2) && (nVariation == 1))
1498 rRet.insert(0, sPush);
1499 rRet.append(sMainTerm);
1500 sPush.clear();
1501 sMainTerm.clear();
1502 newline--;
1504 nPart++;
1505 break;
1506 case tmSINT:
1507 rRet.append("} ");
1508 if (nPart == 0)
1510 if ((nVariation != 0) && (nVariation != 3))
1512 sMainTerm = rRet.makeStringAndClear();
1514 newline--;
1516 else if ((nPart == 1) &&
1517 ((nVariation == 1) || (nVariation==4)))
1519 rRet.insert(0, sPush);
1520 rRet.append(sMainTerm);
1521 sPush.clear();
1522 sMainTerm.clear();
1523 newline--;
1525 else if ((nPart == 1) && (nVariation == 2))
1526 newline--;
1527 else if ((nPart == 2) && (nVariation == 2))
1529 rRet.insert(0, sPush);
1530 rRet.append(sMainTerm);
1531 sPush.clear();
1532 sMainTerm.clear();
1533 newline--;
1535 nPart++;
1536 break;
1537 case tmDINT:
1538 case tmTINT:
1539 rRet.append("} ");
1540 if (nPart == 0)
1542 if ((nVariation != 0) && (nVariation != 2))
1544 sMainTerm = rRet.makeStringAndClear();
1546 newline--;
1548 else if ((nPart == 1) &&
1549 ((nVariation == 1) || (nVariation==3)))
1551 rRet.insert(0, sPush);
1552 rRet.append(sMainTerm);
1553 sPush.clear();
1554 sMainTerm.clear();
1555 newline--;
1557 nPart++;
1558 break;
1559 case tmSSINT:
1560 rRet.append("} ");
1561 if (nPart == 0)
1563 sMainTerm = rRet.makeStringAndClear();
1564 newline--;
1566 else if ((nPart == 1) &&
1567 ((nVariation == 1) || (nVariation==2)))
1569 rRet.insert(0, sPush);
1570 rRet.append(sMainTerm);
1571 sPush.clear();
1572 sMainTerm.clear();
1573 newline--;
1575 else if ((nPart == 1) && (nVariation == 0))
1576 newline--;
1577 else if ((nPart == 2) && (nVariation == 0))
1579 rRet.insert(0, sPush);
1580 rRet.append(sMainTerm);
1581 sPush.clear();
1582 sMainTerm.clear();
1583 newline--;
1585 nPart++;
1586 break;
1587 case tmDSINT:
1588 case tmTSINT:
1589 rRet.append("} ");
1590 if (nPart == 0)
1592 sMainTerm = rRet.makeStringAndClear();
1593 newline--;
1595 else if (nPart == 1)
1597 rRet.insert(0, sPush);
1598 rRet.append(sMainTerm);
1599 sPush.clear();
1600 sMainTerm.clear();
1601 newline--;
1603 nPart++;
1604 break;
1605 case tmINTOP:
1606 case tmSUMOP:
1607 rRet.append("} ");
1609 if ((nPart == 0) &&
1610 ((nVariation == 0) || (nVariation == 1)))
1612 sMainTerm = rRet.makeStringAndClear();
1613 newline--;
1615 else if ((nPart == 0) && (nVariation == 2))
1616 newline--;
1617 else if ((nPart == 1) && (nVariation == 2))
1619 sMainTerm = rRet.makeStringAndClear();
1620 newline--;
1622 else if ((nPart == 2) || ((nPart == 1) &&
1623 (nVariation == 0 || nVariation == 1)))
1625 rRet.insert(0, sPush);
1626 rRet.append(sMainTerm);
1627 sPush.clear();
1628 sMainTerm.clear();
1630 nPart++;
1631 break;
1632 case tmDIRAC:
1633 if (nVariation==0)
1635 if (nPart == 0)
1637 newline--; //there is another term to arrive
1638 rRet.append(" mline ");
1640 else
1641 rRet.append(" rangle ");
1643 else if (nVariation==1)
1644 rRet.append(" \\lline ");
1645 else if (nVariation==2)
1646 rRet.append(" \\rangle ");
1647 nPart++;
1648 break;
1649 default:
1650 break;
1652 bSilent = true; //Skip the optional brackets and/or
1653 //symbols that follow some of these
1654 //records. Foo Data.
1656 /*In matrices and piles we cannot separate equation
1657 *lines with the newline keyword*/
1658 if (nMatrixCols==0)
1659 newline++;
1662 break;
1663 case CHAR:
1664 if (xfLMOVE(nTag))
1665 HandleNudge();
1666 bRet = HandleChar( nTextStart, nSetSize, nLevel, nTag, nSelector, nVariation, bSilent );
1667 break;
1668 case TMPL:
1669 if (xfLMOVE(nTag))
1670 HandleNudge();
1671 bRet = HandleTemplate( nLevel, nSelector, nVariation, nLastTemplateBracket );
1672 break;
1673 case PILE:
1674 if (xfLMOVE(nTag))
1675 HandleNudge();
1676 bRet = HandlePile( nSetAlign, nLevel, nSelector, nVariation );
1677 HandleMatrixSeparator( nMatrixRows, nMatrixCols, nCurCol, nCurRow );
1678 break;
1679 case MATRIX:
1680 if (xfLMOVE(nTag))
1681 HandleNudge();
1682 bRet = HandleMatrix( nLevel, nSelector, nVariation );
1683 HandleMatrixSeparator( nMatrixRows, nMatrixCols, nCurCol, nCurRow );
1684 break;
1685 case EMBEL:
1686 if (xfLMOVE(nTag))
1687 HandleNudge();
1688 HandleEmblishments();
1689 break;
1690 case RULER:
1691 pS->ReadUChar( nTabStops );
1692 for (i=0;i<nTabStops;i++)
1694 pS->ReadUChar( nTabType );
1695 pS->ReadUInt16( nTabOffset );
1697 SAL_WARN("starmath", "Not seen in the wild Equation Ruler Field");
1698 break;
1699 case FONT:
1701 MathTypeFont aFont;
1702 pS->ReadUChar( aFont.nTface );
1704 The typeface number is the negative (which makes it
1705 positive) of the typeface value (unbiased) that appears in
1706 CHAR records that might follow a given FONT record
1708 aFont.nTface = 128-aFont.nTface;
1709 pS->ReadUChar( aFont.nStyle );
1710 aUserStyles.insert(aFont);
1711 // read font name
1712 while(true)
1714 char nChar8(0);
1715 pS->ReadChar( nChar8 );
1716 if (nChar8 == 0)
1717 break;
1720 break;
1721 case SIZE:
1722 HandleSetSize();
1723 break;
1724 case 10:
1725 case 11:
1726 case 12:
1727 case 13:
1728 case 14:
1729 nLSize=nRecord-10;
1730 break;
1731 case END:
1732 default:
1733 break;
1736 while (nRecord != END && !pS->eof());
1737 while (nSetSize)
1739 rRet.append("}");
1740 nSetSize--;
1742 return bRet;
1745 /*Simply determine if we are at the end of a record or the end of a line,
1746 *with fiddly logic to see if we are in a matrix or a pile or neither
1748 Note we cannot tell until after the event that this is the last entry
1749 of a pile, so we must strip the last separator of a pile after this
1750 is detected in the PILE handler
1752 void MathType::HandleMatrixSeparator(int nMatrixRows,int nMatrixCols,
1753 int &rCurCol,int &rCurRow)
1755 if (nMatrixRows==0)
1756 return;
1758 if (rCurCol == nMatrixCols-1)
1760 if (rCurRow != nMatrixRows-1)
1761 rRet.append(" {} ##\n");
1762 if (nMatrixRows!=-1)
1764 rCurCol=0;
1765 rCurRow++;
1768 else
1770 rRet.append(" {} # ");
1771 if (nMatrixRows!=-1)
1772 rCurCol++;
1773 else
1774 rRet.append("\n");
1778 /* set the alignment of the following term, but starmath currently
1779 * cannot handle vertical alignment */
1780 void MathType::HandleAlign(sal_uInt8 nHorAlign, int &rSetAlign)
1782 switch(nHorAlign)
1784 case 1:
1785 default:
1786 rRet.append("alignl {");
1787 break;
1788 case 2:
1789 rRet.append("alignc {");
1790 break;
1791 case 3:
1792 rRet.append("alignr {");
1793 break;
1795 rSetAlign++;
1798 /* set size of text, complexity due to overuse of signedness as a flag
1799 * indicator by mathtype file format*/
1800 bool MathType::HandleSize(sal_Int16 nLstSize,sal_Int16 nDefSize, int &rSetSize)
1802 bool bRet=false;
1803 if (nLstSize < 0)
1805 const sal_Int16 nDefaultSize = 12;
1806 if ((-nLstSize/32 != nDefaultSize) && (-nLstSize/32 != nCurSize))
1808 if (rSetSize)
1810 rSetSize--;
1811 rRet.append("}");
1812 bRet=true;
1814 if (-nLstSize/32 != nLastSize)
1816 nLastSize = nCurSize;
1817 rRet.append(" size ");
1818 rRet.append(OUString::number(-nLstSize/32));
1819 rRet.append("{");
1820 bRet=true;
1821 rSetSize++;
1823 nCurSize = -nLstSize/32;
1826 else
1828 /*sizetable should theoretically be filled with the default sizes
1829 *of the various font groupings matching starmaths equivalents
1830 in aTypeFaces, and a test would be done to see if the new font
1831 size would be the same as what starmath would have chosen for
1832 itself anyway in which case the size setting could be ignored*/
1833 nLstSize = aSizeTable.at(nLstSize);
1834 nLstSize = nLstSize + nDefSize;
1835 if (nLstSize != nCurSize)
1837 if (rSetSize)
1839 rSetSize--;
1840 rRet.append("}");
1841 bRet=true;
1843 if (nLstSize != nLastSize)
1845 nLastSize = nCurSize;
1846 rRet.append(" size ");
1847 rRet.append(OUString::number(nLstSize));
1848 rRet.append("{");
1849 bRet=true;
1850 rSetSize++;
1852 nCurSize = nLstSize;
1855 return bRet;
1858 bool MathType::ConvertFromStarMath( SfxMedium& rMedium )
1860 if (!pTree)
1861 return false;
1863 SvStream *pStream = rMedium.GetOutStream();
1864 if ( pStream )
1866 tools::SvRef<SotStorage> pStor = new SotStorage( pStream, false );
1868 SvGlobalName aGName(MSO_EQUATION3_CLASSID);
1869 pStor->SetClass( aGName, SotClipboardFormatId::NONE, "Microsoft Equation 3.0");
1871 static sal_uInt8 const aCompObj[] = {
1872 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
1873 0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0xCE, 0x02, 0x00,
1874 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00,
1875 0x00, 0x00, 0x00, 0x46, 0x17, 0x00, 0x00, 0x00,
1876 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66,
1877 0x74, 0x20, 0x45, 0x71, 0x75, 0x61, 0x74, 0x69,
1878 0x6F, 0x6E, 0x20, 0x33, 0x2E, 0x30, 0x00, 0x0C,
1879 0x00, 0x00, 0x00, 0x44, 0x53, 0x20, 0x45, 0x71,
1880 0x75, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x0B,
1881 0x00, 0x00, 0x00, 0x45, 0x71, 0x75, 0x61, 0x74,
1882 0x69, 0x6F, 0x6E, 0x2E, 0x33, 0x00, 0xF4, 0x39,
1883 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1884 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1886 tools::SvRef<SotStorageStream> xStor( pStor->OpenSotStream("\1CompObj"));
1887 xStor->WriteBytes(aCompObj, sizeof(aCompObj));
1889 static sal_uInt8 const aOle[] = {
1890 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
1891 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1892 0x00, 0x00, 0x00, 0x00
1894 tools::SvRef<SotStorageStream> xStor2( pStor->OpenSotStream("\1Ole"));
1895 xStor2->WriteBytes(aOle, sizeof(aOle));
1896 xStor.clear();
1897 xStor2.clear();
1899 tools::SvRef<SotStorageStream> xSrc = pStor->OpenSotStream("Equation Native");
1900 if ( (!xSrc.is()) || (ERRCODE_NONE != xSrc->GetError()))
1901 return false;
1903 pS = xSrc.get();
1904 pS->SetEndian( SvStreamEndian::LITTLE );
1906 pS->SeekRel(EQNOLEFILEHDR_SIZE); //Skip 28byte Header and fill it in later
1907 pS->WriteUChar( 0x03 );
1908 pS->WriteUChar( 0x01 );
1909 pS->WriteUChar( 0x01 );
1910 pS->WriteUChar( 0x03 );
1911 pS->WriteUChar( 0x00 );
1912 sal_uInt32 nSize = pS->Tell();
1913 nPendingAttributes=0;
1915 HandleNodes(pTree, 0);
1916 pS->WriteUChar( END );
1918 nSize = pS->Tell()-nSize;
1919 pS->Seek(0);
1920 EQNOLEFILEHDR aHdr(nSize+4+1);
1921 aHdr.Write(pS);
1923 pStor->Commit();
1926 return true;
1930 void MathType::HandleNodes(SmNode *pNode,int nLevel)
1932 switch(pNode->GetType())
1934 case SmNodeType::Attribut:
1935 HandleAttributes(pNode,nLevel);
1936 break;
1937 case SmNodeType::Text:
1938 HandleText(pNode);
1939 break;
1940 case SmNodeType::VerticalBrace:
1941 HandleVerticalBrace(pNode,nLevel);
1942 break;
1943 case SmNodeType::Brace:
1944 HandleBrace(pNode,nLevel);
1945 break;
1946 case SmNodeType::Oper:
1947 HandleOperator(pNode,nLevel);
1948 break;
1949 case SmNodeType::BinVer:
1950 HandleFractions(pNode,nLevel);
1951 break;
1952 case SmNodeType::Root:
1953 HandleRoot(pNode,nLevel);
1954 break;
1955 case SmNodeType::Special:
1957 SmTextNode *pText = static_cast<SmTextNode *>(pNode);
1958 //if the token str and the result text are the same then this
1959 //is to be seen as text, else assume it's a mathchar
1960 if (pText->GetText() == pText->GetToken().aText)
1961 HandleText(pText);
1962 else
1963 HandleMath(pText);
1965 break;
1966 case SmNodeType::Math:
1967 case SmNodeType::MathIdent:
1968 HandleMath(pNode);
1969 break;
1970 case SmNodeType::SubSup:
1971 HandleSubSupScript(pNode,nLevel);
1972 break;
1973 case SmNodeType::Expression:
1975 size_t nSize = pNode->GetNumSubNodes();
1976 for (size_t i = 0; i < nSize; ++i)
1978 if (SmNode *pTemp = pNode->GetSubNode(i))
1979 HandleNodes(pTemp,nLevel+1);
1981 break;
1983 case SmNodeType::Table:
1984 //Root Node, PILE equivalent, i.e. vertical stack
1985 HandleTable(pNode,nLevel);
1986 break;
1987 case SmNodeType::Matrix:
1988 HandleSmMatrix(static_cast<SmMatrixNode *>(pNode),nLevel);
1989 break;
1990 case SmNodeType::Line:
1992 pS->WriteUChar( 0x0a );
1993 pS->WriteUChar( LINE );
1994 size_t nSize = pNode->GetNumSubNodes();
1995 for (size_t i = 0; i < nSize; ++i)
1997 if (SmNode *pTemp = pNode->GetSubNode(i))
1998 HandleNodes(pTemp,nLevel+1);
2000 pS->WriteUChar( END );
2001 break;
2003 case SmNodeType::Align:
2004 HandleMAlign(pNode,nLevel);
2005 break;
2006 case SmNodeType::Blank:
2007 pS->WriteUChar( CHAR );
2008 pS->WriteUChar( 0x98 );
2009 if (pNode->GetToken().eType == TSBLANK)
2010 pS->WriteUInt16( 0xEB04 );
2011 else
2012 pS->WriteUInt16( 0xEB05 );
2013 break;
2014 default:
2016 size_t nSize = pNode->GetNumSubNodes();
2017 for (size_t i = 0; i < nSize; ++i)
2019 if (SmNode *pTemp = pNode->GetSubNode(i))
2020 HandleNodes(pTemp,nLevel+1);
2022 break;
2028 int MathType::StartTemplate(sal_uInt16 nSelector,sal_uInt16 nVariation)
2030 int nOldPending=nPendingAttributes;
2031 pS->WriteUChar( TMPL ); //Template
2032 pS->WriteUChar( nSelector ); //selector
2033 pS->WriteUChar( nVariation ); //variation
2034 pS->WriteUChar( 0x00 ); //options
2035 pS->WriteUChar( LINE );
2036 //there's just no way we can now handle any character
2037 //attributes (from mathtypes perspective) centered
2038 //over an expression but above template attribute
2039 //such as widevec and similar constructs
2040 //we have to drop them
2041 nPendingAttributes=0;
2042 return nOldPending;
2045 void MathType::EndTemplate(int nOldPendingAttributes)
2047 pS->WriteUChar( END ); //end line
2048 pS->WriteUChar( END ); //end template
2049 nPendingAttributes=nOldPendingAttributes;
2053 void MathType::HandleSmMatrix(SmMatrixNode *pMatrix,int nLevel)
2055 pS->WriteUChar( MATRIX );
2056 pS->WriteUChar( 0x00 ); //vAlign ?
2057 pS->WriteUChar( 0x00 ); //h_just
2058 pS->WriteUChar( 0x00 ); //v_just
2059 pS->WriteUChar( pMatrix->GetNumRows() ); //v_just
2060 pS->WriteUChar( pMatrix->GetNumCols() ); //v_just
2061 int nBytes=(pMatrix->GetNumRows()+1)*2/8;
2062 if (((pMatrix->GetNumRows()+1)*2)%8)
2063 nBytes++;
2064 for (int j = 0; j < nBytes; j++)
2065 pS->WriteUChar( 0x00 ); //row_parts
2066 nBytes=(pMatrix->GetNumCols()+1)*2/8;
2067 if (((pMatrix->GetNumCols()+1)*2)%8)
2068 nBytes++;
2069 for (int k = 0; k < nBytes; k++)
2070 pS->WriteUChar( 0x00 ); //col_parts
2071 size_t nSize = pMatrix->GetNumSubNodes();
2072 for (size_t i = 0; i < nSize; ++i)
2074 if (SmNode *pTemp = pMatrix->GetSubNode(i))
2076 pS->WriteUChar( LINE ); //line
2077 HandleNodes(pTemp,nLevel+1);
2078 pS->WriteUChar( END ); //end line
2081 pS->WriteUChar( END );
2085 //Root Node, PILE equivalent, i.e. vertical stack
2086 void MathType::HandleTable(SmNode *pNode,int nLevel)
2088 size_t nSize = pNode->GetNumSubNodes();
2089 //The root of the starmath is a table, if
2090 //we convert this them each iteration of
2091 //conversion from starmath to mathtype will
2092 //add an extra unnecessary level to the
2093 //mathtype output stack which would grow
2094 //without bound in a multi step conversion
2096 if (nLevel == 0)
2097 pS->WriteUChar( 0x0A ); //initial size
2099 if ( nLevel || (nSize >1))
2101 pS->WriteUChar( PILE );
2102 pS->WriteUChar( nHAlign ); //vAlign ?
2103 pS->WriteUChar( 0x01 ); //hAlign
2106 for (size_t i = 0; i < nSize; ++i)
2108 if (SmNode *pTemp = pNode->GetSubNode(i))
2110 pS->WriteUChar( LINE );
2111 HandleNodes(pTemp,nLevel+1);
2112 pS->WriteUChar( END );
2115 if (nLevel || (nSize>1))
2116 pS->WriteUChar( END );
2120 void MathType::HandleRoot(SmNode *pNode,int nLevel)
2122 SmNode *pTemp;
2123 pS->WriteUChar( TMPL ); //Template
2124 pS->WriteUChar( 0x0D ); //selector
2125 if (pNode->GetSubNode(0))
2126 pS->WriteUChar( 0x01 ); //variation
2127 else
2128 pS->WriteUChar( 0x00 ); //variation
2129 pS->WriteUChar( 0x00 ); //options
2131 if (nullptr != (pTemp = pNode->GetSubNode(2)))
2133 pS->WriteUChar( LINE ); //line
2134 HandleNodes(pTemp,nLevel+1);
2135 pS->WriteUChar( END );
2138 if (nullptr != (pTemp = pNode->GetSubNode(0)))
2140 pS->WriteUChar( LINE ); //line
2141 HandleNodes(pTemp,nLevel+1);
2142 pS->WriteUChar( END );
2144 else
2145 pS->WriteUChar( LINE|0x10 ); //dummy line
2148 pS->WriteUChar( END );
2151 sal_uInt8 MathType::HandleCScript(SmNode *pNode,SmNode *pContent,int nLevel,
2152 sal_uInt64 *pPos,bool bTest)
2154 sal_uInt8 nVariation2=0xff;
2156 if (bTest && pNode->GetSubNode(CSUP+1))
2158 nVariation2=0;
2159 if (pNode->GetSubNode(CSUB+1))
2160 nVariation2=2;
2162 else if (pNode->GetSubNode(CSUB+1))
2163 nVariation2=1;
2165 if (nVariation2!=0xff)
2167 if (pPos)
2168 *pPos = pS->Tell();
2169 pS->WriteUChar( TMPL ); //Template
2170 pS->WriteUChar( 0x2B ); //selector
2171 pS->WriteUChar( nVariation2 );
2172 pS->WriteUChar( 0x00 ); //options
2174 if (pContent)
2176 pS->WriteUChar( LINE ); //line
2177 HandleNodes(pContent,nLevel+1);
2178 pS->WriteUChar( END ); //line
2180 else
2181 pS->WriteUChar( LINE|0x10 );
2183 pS->WriteUChar( 0x0B );
2185 SmNode *pTemp;
2186 if (nullptr != (pTemp = pNode->GetSubNode(CSUB+1)))
2188 pS->WriteUChar( LINE ); //line
2189 HandleNodes(pTemp,nLevel+1);
2190 pS->WriteUChar( END ); //line
2192 else
2193 pS->WriteUChar( LINE|0x10 );
2194 if (bTest && nullptr != (pTemp = pNode->GetSubNode(CSUP+1)))
2196 pS->WriteUChar( LINE ); //line
2197 HandleNodes(pTemp,nLevel+1);
2198 pS->WriteUChar( END ); //line
2200 else
2201 pS->WriteUChar( LINE|0x10 );
2203 return nVariation2;
2208 Sub and Sup scripts and another problem area, StarMath
2209 can have all possible options used at the same time, whereas
2210 Mathtype cannot. The ordering of the nodes for each system
2211 is quite different as well leading to some complexity
2213 void MathType::HandleSubSupScript(SmNode *pNode,int nLevel)
2215 sal_uInt8 nVariation=0xff;
2216 if (pNode->GetSubNode(LSUP+1))
2218 nVariation=0;
2219 if (pNode->GetSubNode(LSUB+1))
2220 nVariation=2;
2222 else if ( nullptr != pNode->GetSubNode(LSUB+1) )
2223 nVariation=1;
2225 SmNode *pTemp;
2226 if (nVariation!=0xff)
2228 pS->WriteUChar( TMPL ); //Template
2229 pS->WriteUChar( 0x2c ); //selector
2230 pS->WriteUChar( nVariation );
2231 pS->WriteUChar( 0x00 ); //options
2232 pS->WriteUChar( 0x0B );
2234 if (nullptr != (pTemp = pNode->GetSubNode(LSUB+1)))
2236 pS->WriteUChar( LINE ); //line
2237 HandleNodes(pTemp,nLevel+1);
2238 pS->WriteUChar( END ); //line
2240 else
2241 pS->WriteUChar( LINE|0x10 );
2242 if (nullptr != (pTemp = pNode->GetSubNode(LSUP+1)))
2244 pS->WriteUChar( LINE ); //line
2245 HandleNodes(pTemp,nLevel+1);
2246 pS->WriteUChar( END ); //line
2248 else
2249 pS->WriteUChar( LINE|0x10 );
2250 pS->WriteUChar( END );
2251 nVariation=0xff;
2255 sal_uInt8 nVariation2=HandleCScript(pNode,nullptr,nLevel);
2257 if (nullptr != (pTemp = pNode->GetSubNode(0)))
2259 HandleNodes(pTemp,nLevel+1);
2262 if (nVariation2 != 0xff)
2263 pS->WriteUChar( END );
2265 if (nullptr != (pNode->GetSubNode(RSUP+1)))
2267 nVariation=0;
2268 if (pNode->GetSubNode(RSUB+1))
2269 nVariation=2;
2271 else if (nullptr != pNode->GetSubNode(RSUB+1))
2272 nVariation=1;
2274 if (nVariation!=0xff)
2276 pS->WriteUChar( TMPL ); //Template
2277 pS->WriteUChar( 0x0F ); //selector
2278 pS->WriteUChar( nVariation );
2279 pS->WriteUChar( 0x00 ); //options
2280 pS->WriteUChar( 0x0B );
2282 if (nullptr != (pTemp = pNode->GetSubNode(RSUB+1)))
2284 pS->WriteUChar( LINE ); //line
2285 HandleNodes(pTemp,nLevel+1);
2286 pS->WriteUChar( END ); //line
2288 else
2289 pS->WriteUChar( LINE|0x10 );
2290 if (nullptr != (pTemp = pNode->GetSubNode(RSUP+1)))
2292 pS->WriteUChar( LINE ); //line
2293 HandleNodes(pTemp,nLevel+1);
2294 pS->WriteUChar( END ); //line
2296 else
2297 pS->WriteUChar( LINE|0x10 );
2298 pS->WriteUChar( END ); //line
2301 //After subscript mathtype will keep the size of
2302 //normal text at the subscript size, sigh.
2303 pS->WriteUChar( 0x0A );
2307 void MathType::HandleFractions(SmNode *pNode,int nLevel)
2309 SmNode *pTemp;
2310 pS->WriteUChar( TMPL ); //Template
2311 pS->WriteUChar( 0x0E ); //selector
2312 pS->WriteUChar( 0x00 ); //variation
2313 pS->WriteUChar( 0x00 ); //options
2315 pS->WriteUChar( 0x0A );
2316 pS->WriteUChar( LINE ); //line
2317 if (nullptr != (pTemp = pNode->GetSubNode(0)))
2318 HandleNodes(pTemp,nLevel+1);
2319 pS->WriteUChar( END );
2321 pS->WriteUChar( 0x0A );
2322 pS->WriteUChar( LINE ); //line
2323 if (nullptr != (pTemp = pNode->GetSubNode(2)))
2324 HandleNodes(pTemp,nLevel+1);
2325 pS->WriteUChar( END );
2327 pS->WriteUChar( END );
2331 void MathType::HandleBrace(SmNode *pNode,int nLevel)
2333 SmNode *pTemp;
2334 SmNode *pLeft=pNode->GetSubNode(0);
2335 SmNode *pRight=pNode->GetSubNode(2);
2337 pS->WriteUChar( TMPL ); //Template
2338 bIsReInterpBrace=false;
2339 sal_uInt8 nBSpec=0x10;
2340 auto nLoc = pS->Tell();
2341 if (pLeft)
2343 switch (pLeft->GetToken().eType)
2345 case TLANGLE:
2346 pS->WriteUChar( tmANGLE ); //selector
2347 pS->WriteUChar( 0 ); //variation
2348 pS->WriteUChar( 0 ); //options
2349 break;
2350 case TLBRACE:
2351 pS->WriteUChar( tmBRACE ); //selector
2352 pS->WriteUChar( 0 ); //variation
2353 pS->WriteUChar( 0 ); //options
2354 nBSpec+=3;
2355 break;
2356 case TLBRACKET:
2357 pS->WriteUChar( tmBRACK ); //selector
2358 pS->WriteUChar( 0 ); //variation
2359 pS->WriteUChar( 0 ); //options
2360 nBSpec+=3;
2361 break;
2362 case TLFLOOR:
2363 pS->WriteUChar( tmFLOOR ); //selector
2364 pS->WriteUChar( 0 ); //variation
2365 pS->WriteUChar( 0 ); //options
2366 break;
2367 case TLLINE:
2368 pS->WriteUChar( tmBAR ); //selector
2369 pS->WriteUChar( 0 ); //variation
2370 pS->WriteUChar( 0 ); //options
2371 nBSpec+=3;
2372 break;
2373 case TLDLINE:
2374 pS->WriteUChar( tmDBAR ); //selector
2375 pS->WriteUChar( 0 ); //variation
2376 pS->WriteUChar( 0 ); //options
2377 break;
2378 default:
2379 pS->WriteUChar( tmPAREN ); //selector
2380 pS->WriteUChar( 0 ); //variation
2381 pS->WriteUChar( 0 ); //options
2382 nBSpec+=3;
2383 break;
2387 if (nullptr != (pTemp = pNode->GetSubNode(1)))
2389 pS->WriteUChar( LINE ); //line
2390 HandleNodes(pTemp,nLevel+1);
2391 pS->WriteUChar( END ); //options
2393 nSpec=nBSpec;
2394 if (pLeft)
2395 HandleNodes(pLeft,nLevel+1);
2396 if (bIsReInterpBrace)
2398 auto nLoc2 = pS->Tell();
2399 pS->Seek(nLoc);
2400 pS->WriteUChar( 0x2D );
2401 pS->Seek(nLoc2);
2402 pS->WriteUChar( CHAR );
2403 pS->WriteUChar( 0x96 );
2404 pS->WriteUInt16( 0xEC07 );
2405 bIsReInterpBrace=false;
2407 if (pRight)
2408 HandleNodes(pRight,nLevel+1);
2409 nSpec=0x0;
2410 pS->WriteUChar( END );
2414 void MathType::HandleVerticalBrace(SmNode *pNode,int nLevel)
2416 SmNode *pTemp;
2417 pS->WriteUChar( TMPL ); //Template
2418 if (pNode->GetToken().eType == TUNDERBRACE)
2419 pS->WriteUChar( tmLHBRACE ); //selector
2420 else
2421 pS->WriteUChar( tmUHBRACE ); //selector
2422 pS->WriteUChar( 0 ); //variation
2423 pS->WriteUChar( 0 ); //options
2425 if (nullptr != (pTemp = pNode->GetSubNode(0)))
2427 pS->WriteUChar( LINE ); //line
2428 HandleNodes(pTemp,nLevel+1);
2429 pS->WriteUChar( END ); //options
2432 if (nullptr != (pTemp = pNode->GetSubNode(2)))
2434 pS->WriteUChar( LINE ); //line
2435 HandleNodes(pTemp,nLevel+1);
2436 pS->WriteUChar( END ); //options
2438 pS->WriteUChar( END );
2441 void MathType::HandleOperator(SmNode *pNode,int nLevel)
2443 if (HandleLim(pNode,nLevel))
2444 return;
2446 sal_uInt64 nPos;
2447 sal_uInt8 nVariation;
2449 switch (pNode->GetToken().eType)
2451 case TIINT:
2452 case TIIINT:
2453 case TLINT:
2454 case TLLINT:
2455 case TLLLINT:
2456 nVariation=HandleCScript(pNode->GetSubNode(0),
2457 pNode->GetSubNode(1),nLevel,&nPos,false);
2458 break;
2459 default:
2460 nVariation=HandleCScript(pNode->GetSubNode(0),
2461 pNode->GetSubNode(1),nLevel,&nPos);
2462 break;
2465 sal_uInt8 nOldVariation=nVariation;
2466 sal_uInt8 nIntVariation=nVariation;
2468 sal_uInt64 nPos2=0;
2469 if (nVariation != 0xff)
2471 nPos2 = pS->Tell();
2472 pS->Seek(nPos);
2473 if (nVariation == 2)
2475 nIntVariation=0;
2476 nVariation = 1;
2478 else if (nVariation == 0)
2479 nVariation = 1;
2480 else if (nVariation == 1)
2481 nVariation = 0;
2483 else
2485 nVariation = 2;
2486 nIntVariation=0;
2488 pS->WriteUChar( TMPL );
2489 switch(pNode->GetToken().eType)
2491 case TINT:
2492 case TINTD:
2493 if (nOldVariation != 0xff)
2494 pS->WriteUChar( 0x18 ); //selector
2495 else
2496 pS->WriteUChar( 0x15 ); //selector
2497 pS->WriteUChar( nIntVariation ); //variation
2498 break;
2499 case TIINT:
2500 if (nOldVariation != 0xff)
2502 pS->WriteUChar( 0x19 );
2503 pS->WriteUChar( 0x01 );
2505 else
2507 pS->WriteUChar( 0x16 );
2508 pS->WriteUChar( 0x00 );
2510 break;
2511 case TIIINT:
2512 if (nOldVariation != 0xff)
2514 pS->WriteUChar( 0x1a );
2515 pS->WriteUChar( 0x01 );
2517 else
2519 pS->WriteUChar( 0x17 );
2520 pS->WriteUChar( 0x00 );
2522 break;
2523 case TLINT:
2524 if (nOldVariation != 0xff)
2526 pS->WriteUChar( 0x18 );
2527 pS->WriteUChar( 0x02 );
2529 else
2531 pS->WriteUChar( 0x15 );
2532 pS->WriteUChar( 0x03 );
2534 break;
2535 case TLLINT:
2536 if (nOldVariation != 0xff)
2538 pS->WriteUChar( 0x19 );
2539 pS->WriteUChar( 0x00 );
2541 else
2543 pS->WriteUChar( 0x16 );
2544 pS->WriteUChar( 0x02 );
2546 break;
2547 case TLLLINT:
2548 if (nOldVariation != 0xff)
2550 pS->WriteUChar( 0x1a );
2551 pS->WriteUChar( 0x00 );
2553 else
2555 pS->WriteUChar( 0x17 );
2556 pS->WriteUChar( 0x02 );
2558 break;
2559 case TSUM:
2560 default:
2561 pS->WriteUChar( 0x1d );
2562 pS->WriteUChar( nVariation );
2563 break;
2564 case TPROD:
2565 pS->WriteUChar( 0x1f );
2566 pS->WriteUChar( nVariation );
2567 break;
2568 case TCOPROD:
2569 pS->WriteUChar( 0x21 );
2570 pS->WriteUChar( nVariation );
2571 break;
2573 pS->WriteUChar( 0 ); //options
2575 if (nPos2)
2576 pS->Seek(nPos2);
2577 else
2579 pS->WriteUChar( LINE ); //line
2580 HandleNodes(pNode->GetSubNode(1),nLevel+1);
2581 pS->WriteUChar( END ); //line
2582 pS->WriteUChar( LINE|0x10 );
2583 pS->WriteUChar( LINE|0x10 );
2586 pS->WriteUChar( 0x0D );
2587 switch(pNode->GetToken().eType)
2589 case TSUM:
2590 default:
2591 pS->WriteUChar( CHAR );
2592 pS->WriteUChar( 0x86 );
2593 pS->WriteUInt16( 0x2211 );
2594 break;
2595 case TPROD:
2596 pS->WriteUChar( CHAR );
2597 pS->WriteUChar( 0x86 );
2598 pS->WriteUInt16( 0x220F );
2599 break;
2600 case TCOPROD:
2601 pS->WriteUChar( CHAR );
2602 pS->WriteUChar( 0x8B );
2603 pS->WriteUInt16( 0x2210 );
2604 break;
2605 case TIIINT:
2606 case TLLLINT:
2607 pS->WriteUChar( CHAR );
2608 pS->WriteUChar( 0x86 );
2609 pS->WriteUInt16( 0x222B );
2610 [[fallthrough]];
2611 case TIINT:
2612 case TLLINT:
2613 pS->WriteUChar( CHAR );
2614 pS->WriteUChar( 0x86 );
2615 pS->WriteUInt16( 0x222B );
2616 [[fallthrough]];
2617 case TINT:
2618 case TINTD:
2619 case TLINT:
2620 pS->WriteUChar( CHAR );
2621 pS->WriteUChar( 0x86 );
2622 pS->WriteUInt16( 0x222B );
2623 break;
2625 pS->WriteUChar( END );
2626 pS->WriteUChar( 0x0A );
2630 bool MathType::HandlePile(int &rSetAlign, int nLevel, sal_uInt8 nSelector, sal_uInt8 nVariation)
2632 sal_uInt8 nVAlign;
2633 pS->ReadUChar( nHAlign );
2634 pS->ReadUChar( nVAlign );
2636 HandleAlign(nHAlign, rSetAlign);
2638 rRet.append(" stack {\n");
2639 bool bRet = HandleRecords( nLevel+1, nSelector, nVariation, -1, -1 );
2640 int nRemoveFrom = rRet.getLength() >= 3 ? rRet.getLength() - 3 : 0;
2641 rRet.remove(nRemoveFrom, 2);
2642 rRet.append("} ");
2644 while (rSetAlign)
2646 rRet.append("} ");
2647 rSetAlign--;
2649 return bRet;
2652 bool MathType::HandleMatrix(int nLevel, sal_uInt8 nSelector, sal_uInt8 nVariation)
2654 sal_uInt8 nH_just,nV_just,nRows,nCols,nVAlign;
2655 pS->ReadUChar( nVAlign );
2656 pS->ReadUChar( nH_just );
2657 pS->ReadUChar( nV_just );
2658 pS->ReadUChar( nRows );
2659 pS->ReadUChar( nCols );
2660 int nBytes = ((nRows+1)*2)/8;
2661 if (((nRows+1)*2)%8)
2662 nBytes++;
2663 pS->SeekRel(nBytes);
2664 nBytes = ((nCols+1)*2)/8;
2665 if (((nCols+1)*2)%8)
2666 nBytes++;
2667 pS->SeekRel(nBytes);
2668 rRet.append(" matrix {\n");
2669 bool bRet = HandleRecords( nLevel+1, nSelector, nVariation, nRows, nCols );
2671 sal_Int32 nI = rRet.lastIndexOf('#');
2672 if (nI > 0)
2673 if (rRet[nI-1] != '#') //missing column
2674 rRet.append("{}");
2676 rRet.append("\n} ");
2677 return bRet;
2680 bool MathType::HandleTemplate(int nLevel, sal_uInt8 &rSelector,
2681 sal_uInt8 &rVariation, sal_Int32 &rLastTemplateBracket)
2683 sal_uInt8 nOption; //This appears utterly unused
2684 pS->ReadUChar( rSelector );
2685 pS->ReadUChar( rVariation );
2686 pS->ReadUChar( nOption );
2687 OSL_ENSURE(rSelector < 48,"Selector out of range");
2688 if ((rSelector >= 21) && (rSelector <=26))
2690 OSL_ENSURE(nOption < 2,"Option out of range");
2692 else if (rSelector <= 12)
2694 OSL_ENSURE(nOption < 3,"Option out of range");
2697 //For the (broken) case where one subscript template ends, and there is
2698 //another one after it, mathtype handles it as if the second one was
2699 //inside the first one and renders it as sub of sub
2700 bool bRemove=false;
2701 if ( (rSelector == 0xf) && (rLastTemplateBracket != -1) )
2703 bRemove=true;
2704 for (sal_Int32 nI = rLastTemplateBracket+1; nI < rRet.getLength(); nI++ )
2705 if (rRet[nI] != ' ')
2707 bRemove=false;
2708 break;
2712 //suborderlist
2713 bool bRet = HandleRecords( nLevel+1, rSelector, rVariation );
2715 if (bRemove)
2717 if (rLastTemplateBracket < rRet.getLength())
2718 rRet.remove(rLastTemplateBracket, 1);
2719 rRet.append("} ");
2720 rLastTemplateBracket = -1;
2722 if (rSelector == 0xf)
2723 rLastTemplateBracket = rRet.lastIndexOf('}');
2724 else
2725 rLastTemplateBracket = -1;
2727 rSelector = sal::static_int_cast< sal_uInt8 >(-1);
2728 return bRet;
2731 void MathType::HandleEmblishments()
2733 sal_uInt8 nEmbel;
2736 pS->ReadUChar( nEmbel );
2737 if (!pS->good())
2738 break;
2739 switch (nEmbel)
2741 case 0x02:
2742 rRet.append(" dot ");
2743 break;
2744 case 0x03:
2745 rRet.append(" ddot ");
2746 break;
2747 case 0x04:
2748 rRet.append(" dddot ");
2749 break;
2750 case 0x05:
2751 if (!nPostSup)
2753 sPost.append(" sup {}");
2754 nPostSup = sPost.getLength();
2756 sPost.insert(nPostSup-1," ' ");
2757 nPostSup += 3;
2758 break;
2759 case 0x06:
2760 if (!nPostSup)
2762 sPost.append(" sup {}");
2763 nPostSup = sPost.getLength();
2765 sPost.insert(nPostSup-1," '' ");
2766 nPostSup += 4;
2767 break;
2768 case 0x07:
2769 if (!nPostlSup)
2771 sPost.append(" lsup {}");
2772 nPostlSup = sPost.getLength();
2774 sPost.insert(nPostlSup-1," ' ");
2775 nPostlSup += 3;
2776 break;
2777 case 0x08:
2778 rRet.append(" tilde ");
2779 break;
2780 case 0x09:
2781 rRet.append(" hat ");
2782 break;
2783 case 0x0b:
2784 rRet.append(" vec ");
2785 break;
2786 case 0x10:
2787 rRet.append(" overstrike ");
2788 break;
2789 case 0x11:
2790 rRet.append(" bar ");
2791 break;
2792 case 0x12:
2793 if (!nPostSup)
2795 sPost.append(" sup {}");
2796 nPostSup = sPost.getLength();
2798 sPost.insert(nPostSup-1," ''' ");
2799 nPostSup += 5;
2800 break;
2801 case 0x14:
2802 rRet.append(" breve ");
2803 break;
2804 default:
2805 OSL_ENSURE(nEmbel < 21,"Embel out of range");
2806 break;
2808 if (nVersion < 3)
2809 break;
2810 }while (nEmbel);
2813 void MathType::HandleSetSize()
2815 sal_uInt8 nTemp(0);
2816 pS->ReadUChar(nTemp);
2817 switch (nTemp)
2819 case 101:
2820 pS->ReadInt16( nLSize );
2821 nLSize = -nLSize;
2822 break;
2823 case 100:
2824 pS->ReadUChar( nTemp );
2825 nLSize = nTemp;
2826 pS->ReadInt16( nDSize );
2827 break;
2828 default:
2829 nLSize = nTemp;
2830 pS->ReadUChar( nTemp );
2831 nDSize = nTemp-128;
2832 break;
2836 bool MathType::HandleChar(sal_Int32 &rTextStart, int &rSetSize, int nLevel,
2837 sal_uInt8 nTag, sal_uInt8 nSelector, sal_uInt8 nVariation, bool bSilent)
2839 sal_Unicode nChar(0);
2840 bool bRet = true;
2842 if (xfAUTO(nTag))
2844 //This is a candidate for function recognition, whatever
2845 //that is!
2848 sal_uInt8 nOldTypeFace = nTypeFace;
2849 pS->ReadUChar( nTypeFace );
2850 if (nVersion < 3)
2852 sal_uInt8 nChar8(0);
2853 pS->ReadUChar( nChar8 );
2854 nChar = nChar8;
2856 else
2857 pS->ReadUtf16( nChar );
2860 bad character, old mathtype < 3 has these
2862 if (nChar < 0x20)
2863 return bRet;
2865 if (xfEMBELL(nTag))
2867 //A bit tricky, the character emblishments for
2868 //mathtype can all be listed after each other, in
2869 //starmath some must go before the character and some
2870 //must go after. In addition some of the emblishments
2871 //may repeated and in starmath some of these groups
2872 //must be gathered together. sPost is the portion that
2873 //follows the char and nPostSup and nPostlSup are the
2874 //indexes at which this class of emblishment is
2875 //collated together
2876 sPost = "";
2877 nPostSup = nPostlSup = 0;
2878 int nOriglen=rRet.getLength()-rTextStart;
2879 rRet.append(" {"); // #i24340# make what would be "vec {A}_n" become "{vec {A}}_n"
2880 if ((!bSilent) && (nOriglen > 1))
2881 rRet.append("\"");
2882 bRet = HandleRecords( nLevel+1, nSelector, nVariation );
2883 if (!bSilent)
2885 if (nOriglen > 1)
2887 OUString aStr;
2888 TypeFaceToString(aStr,nOldTypeFace);
2889 aStr += "\"";
2890 rRet.insert(std::min(rTextStart, rRet.getLength()), aStr);
2892 aStr.clear();
2893 TypeFaceToString(aStr,nTypeFace);
2894 rRet.append(aStr).append("{");
2896 else
2897 rRet.append(" {");
2898 rTextStart = rRet.getLength();
2902 if (!bSilent)
2904 sal_Int32 nOldLen = rRet.getLength();
2905 if (
2906 HandleSize(nLSize,nDSize,rSetSize) ||
2907 (nOldTypeFace != nTypeFace)
2910 if ((nOldLen - rTextStart) > 1)
2912 rRet.insert(nOldLen, "\"");
2913 OUString aStr;
2914 TypeFaceToString(aStr,nOldTypeFace);
2915 aStr += "\"";
2916 rRet.insert(rTextStart,aStr);
2918 rTextStart = rRet.getLength();
2920 nOldLen = rRet.getLength();
2921 if (!LookupChar(nChar,rRet,nVersion,nTypeFace))
2923 if (nOldLen - rTextStart > 1)
2925 rRet.insert(nOldLen, "\"");
2926 OUString aStr;
2927 TypeFaceToString(aStr,nOldTypeFace);
2928 aStr += "\"";
2929 rRet.insert(rTextStart, aStr);
2931 rTextStart = rRet.getLength();
2933 lcl_PrependDummyTerm(rRet, rTextStart);
2936 if ((xfEMBELL(nTag)) && (!bSilent))
2938 rRet.append("}}").append(sPost); // #i24340# make what would be "vec {A}_n" become "{vec {A}}_n"
2939 rTextStart = rRet.getLength();
2941 return bRet;
2944 bool MathType::HandleLim(SmNode *pNode,int nLevel)
2946 bool bRet=false;
2947 //Special case for the "lim" option in StarMath
2948 if ((pNode->GetToken().eType == TLIM)
2949 || (pNode->GetToken().eType == TLIMSUP)
2950 || (pNode->GetToken().eType == TLIMINF)
2953 if (pNode->GetSubNode(1))
2955 sal_uInt8 nVariation2=HandleCScript(pNode->GetSubNode(0),nullptr,
2956 nLevel);
2958 pS->WriteUChar( 0x0A );
2959 pS->WriteUChar( LINE ); //line
2960 pS->WriteUChar( CHAR|0x10 );
2961 pS->WriteUChar( 0x82 );
2962 pS->WriteUInt16( 'l' );
2963 pS->WriteUChar( CHAR|0x10 );
2964 pS->WriteUChar( 0x82 );
2965 pS->WriteUInt16( 'i' );
2966 pS->WriteUChar( CHAR|0x10 );
2967 pS->WriteUChar( 0x82 );
2968 pS->WriteUInt16( 'm' );
2970 if (pNode->GetToken().eType == TLIMSUP)
2972 pS->WriteUChar( CHAR ); //some space
2973 pS->WriteUChar( 0x98 );
2974 pS->WriteUInt16( 0xEB04 );
2976 pS->WriteUChar( CHAR|0x10 );
2977 pS->WriteUChar( 0x82 );
2978 pS->WriteUInt16( 's' );
2979 pS->WriteUChar( CHAR|0x10 );
2980 pS->WriteUChar( 0x82 );
2981 pS->WriteUInt16( 'u' );
2982 pS->WriteUChar( CHAR|0x10 );
2983 pS->WriteUChar( 0x82 );
2984 pS->WriteUInt16( 'p' );
2986 else if (pNode->GetToken().eType == TLIMINF)
2988 pS->WriteUChar( CHAR ); //some space
2989 pS->WriteUChar( 0x98 );
2990 pS->WriteUInt16( 0xEB04 );
2992 pS->WriteUChar( CHAR|0x10 );
2993 pS->WriteUChar( 0x82 );
2994 pS->WriteUInt16( 'i' );
2995 pS->WriteUChar( CHAR|0x10 );
2996 pS->WriteUChar( 0x82 );
2997 pS->WriteUInt16( 'n' );
2998 pS->WriteUChar( CHAR|0x10 );
2999 pS->WriteUChar( 0x82 );
3000 pS->WriteUInt16( 'f' );
3004 pS->WriteUChar( CHAR ); //some space
3005 pS->WriteUChar( 0x98 );
3006 pS->WriteUInt16( 0xEB04 );
3008 if (nVariation2 != 0xff)
3010 pS->WriteUChar( END );
3011 pS->WriteUChar( END );
3013 HandleNodes(pNode->GetSubNode(1),nLevel+1);
3014 bRet = true;
3017 return bRet;
3020 void MathType::HandleMAlign(SmNode *pNode,int nLevel)
3022 sal_uInt8 nPushedHAlign=nHAlign;
3023 switch(pNode->GetToken().eType)
3025 case TALIGNC:
3026 nHAlign=2;
3027 break;
3028 case TALIGNR:
3029 nHAlign=3;
3030 break;
3031 default:
3032 nHAlign=1;
3033 break;
3035 size_t nSize = pNode->GetNumSubNodes();
3036 for (size_t i = 0; i < nSize; ++i)
3038 if (SmNode *pTemp = pNode->GetSubNode(i))
3039 HandleNodes(pTemp,nLevel+1);
3041 nHAlign=nPushedHAlign;
3044 void MathType::HandleMath(SmNode *pNode)
3046 if (pNode->GetToken().eType == TMLINE)
3048 pS->WriteUChar( END );
3049 pS->WriteUChar( LINE );
3050 bIsReInterpBrace=true;
3051 return;
3053 SmMathSymbolNode *pTemp = static_cast<SmMathSymbolNode *>(pNode);
3054 for(sal_Int32 i=0;i<pTemp->GetText().getLength();i++)
3056 sal_Unicode nArse = SmTextNode::ConvertSymbolToUnicode(pTemp->GetText()[i]);
3057 if ((nArse == 0x2224) || (nArse == 0x2288) || (nArse == 0x2285) ||
3058 (nArse == 0x2289))
3060 pS->WriteUChar( CHAR|0x20 );
3062 else if (nPendingAttributes &&
3063 (i == ((pTemp->GetText().getLength()+1)/2)-1))
3065 pS->WriteUChar( 0x22 );
3067 else
3068 pS->WriteUChar( CHAR ); //char without formula recognition
3069 //The typeface seems to be MTEXTRA for unicode characters,
3070 //though how to determine when mathtype chooses one over
3071 //the other is unknown. This should do the trick
3072 //nevertheless.
3073 sal_uInt8 nBias;
3074 if ( (nArse == 0x2213) || (nArse == 0x2218) ||
3075 (nArse == 0x210F) || (
3076 (nArse >= 0x22EE) && (nArse <= 0x22FF)
3079 nBias = 0xB; //typeface
3081 else if ((nArse == 0x2F) || (nArse == 0x2225))
3082 nBias = 0x2; //typeface
3083 else if ((nArse > 0x2000) || (nArse == 0x00D7))
3084 nBias = 0x6; //typeface
3085 else if (nArse == 0x3d1)
3086 nBias = 0x4;
3087 else if ((nArse > 0xFF) && ((nArse < 0x393) || (nArse > 0x3c9)))
3088 nBias = 0xB; //typeface
3089 else
3090 nBias = 0x3; //typeface
3092 pS->WriteUChar( nSpec+nBias+128 ); //typeface
3094 if (nArse == 0x2224)
3096 pS->WriteUInt16( 0x7C );
3097 pS->WriteUChar( EMBEL );
3098 pS->WriteUChar( 0x0A );
3099 pS->WriteUChar( END ); //end embel
3100 pS->WriteUChar( END ); //end embel
3102 else if (nArse == 0x2225)
3103 pS->WriteUInt16( 0xEC09 );
3104 else if (nArse == 0xE421)
3105 pS->WriteUInt16( 0x2265 );
3106 else if (nArse == 0x230A)
3107 pS->WriteUInt16( 0xF8F0 );
3108 else if (nArse == 0x230B)
3109 pS->WriteUInt16( 0xF8FB );
3110 else if (nArse == 0xE425)
3111 pS->WriteUInt16( 0x2264 );
3112 else if (nArse == 0x226A)
3114 pS->WriteUInt16( 0x3C );
3115 pS->WriteUChar( CHAR );
3116 pS->WriteUChar( 0x98 );
3117 pS->WriteUInt16( 0xEB01 );
3118 pS->WriteUChar( CHAR );
3119 pS->WriteUChar( 0x86 );
3120 pS->WriteUInt16( 0x3c );
3122 else if (nArse == 0x2288)
3124 pS->WriteUInt16( 0x2286 );
3125 pS->WriteUChar( EMBEL );
3126 pS->WriteUChar( 0x0A );
3127 pS->WriteUChar( END ); //end embel
3128 pS->WriteUChar( END ); //end embel
3130 else if (nArse == 0x2289)
3132 pS->WriteUInt16( 0x2287 );
3133 pS->WriteUChar( EMBEL );
3134 pS->WriteUChar( 0x0A );
3135 pS->WriteUChar( END ); //end embel
3136 pS->WriteUChar( END ); //end embel
3138 else if (nArse == 0x2285)
3140 pS->WriteUInt16( 0x2283 );
3141 pS->WriteUChar( EMBEL );
3142 pS->WriteUChar( 0x0A );
3143 pS->WriteUChar( END ); //end embel
3144 pS->WriteUChar( END ); //end embel
3146 else
3147 pS->WriteUInt16( nArse );
3149 nPendingAttributes = 0;
3152 void MathType::HandleAttributes(SmNode *pNode,int nLevel)
3154 int nOldPending = 0;
3155 SmNode *pTemp = nullptr;
3156 SmTextNode *pIsText = nullptr;
3158 if (nullptr != (pTemp = pNode->GetSubNode(0)))
3160 pIsText = static_cast<SmTextNode *>(pNode->GetSubNode(1));
3162 switch (pTemp->GetToken().eType)
3164 case TWIDEVEC:
3165 //there's just no way we can now handle any character
3166 //attributes (from mathtypes perspective) centered
3167 //over an expression but above template attributes
3168 //such as widevec and similar constructs
3169 //we have to drop them
3170 nOldPending = StartTemplate(0x2f,0x01);
3171 break;
3172 case TCHECK: //Not Exportable
3173 case TACUTE: //Not Exportable
3174 case TGRAVE: //Not Exportable
3175 case TCIRCLE: //Not Exportable
3176 case TWIDEHARPOON: //Not Exportable
3177 case TWIDETILDE: //Not Exportable
3178 case TWIDEHAT: //Not Exportable
3179 break;
3180 case TUNDERLINE:
3181 nOldPending = StartTemplate(0x10);
3182 break;
3183 case TOVERLINE: //If the next node is not text
3184 //or text with more than one char
3185 if ((pIsText->GetToken().eType != TTEXT) ||
3186 (pIsText->GetText().getLength() > 1))
3187 nOldPending = StartTemplate(0x11);
3188 break;
3189 default:
3190 nPendingAttributes++;
3191 break;
3195 if (pIsText)
3196 HandleNodes(pIsText,nLevel+1);
3198 switch (pTemp->GetToken().eType)
3200 case TWIDEVEC:
3201 case TUNDERLINE:
3202 EndTemplate(nOldPending);
3203 break;
3204 case TOVERLINE:
3205 if ((pIsText->GetToken().eType != TTEXT) ||
3206 (pIsText->GetText().getLength() > 1))
3207 EndTemplate(nOldPending);
3208 break;
3209 default:
3210 break;
3213 //if there was no suitable place to put the attribute,
3214 //then we have to just give up on it
3215 if (nPendingAttributes)
3216 nPendingAttributes--;
3217 else
3219 if ((nInsertion != 0) && nullptr != (pTemp = pNode->GetSubNode(0)))
3221 auto nPos = pS->Tell();
3222 nInsertion--;
3223 pS->Seek(nInsertion);
3224 switch(pTemp->GetToken().eType)
3226 case TACUTE: //Not Exportable
3227 case TGRAVE: //Not Exportable
3228 case TCIRCLE: //Not Exportable
3229 break;
3230 case TCDOT:
3231 pS->WriteUChar( 2 );
3232 break;
3233 case TDDOT:
3234 pS->WriteUChar( 3 );
3235 break;
3236 case TDDDOT:
3237 pS->WriteUChar( 4 );
3238 break;
3239 case TTILDE:
3240 pS->WriteUChar( 8 );
3241 break;
3242 case THAT:
3243 pS->WriteUChar( 9 );
3244 break;
3245 case TVEC:
3246 pS->WriteUChar( 11 );
3247 break;
3248 case TOVERSTRIKE:
3249 pS->WriteUChar( 16 );
3250 break;
3251 case TOVERLINE:
3252 if ((pIsText->GetToken().eType == TTEXT) &&
3253 (pIsText->GetText().getLength() == 1))
3254 pS->WriteUChar( 17 );
3255 break;
3256 case TBREVE:
3257 pS->WriteUChar( 20 );
3258 break;
3259 case TWIDEVEC:
3260 case TWIDEHARPOON:
3261 case TUNDERLINE:
3262 case TWIDETILDE:
3263 case TWIDEHAT:
3264 break;
3265 case TBAR:
3266 pS->WriteUChar( 17 );
3267 break;
3268 default:
3269 pS->WriteUChar( 2 );
3270 break;
3272 pS->Seek(nPos);
3277 void MathType::HandleText(SmNode *pNode)
3279 SmTextNode *pTemp = static_cast<SmTextNode *>(pNode);
3280 for(sal_Int32 i=0;i<pTemp->GetText().getLength();i++)
3282 if (nPendingAttributes &&
3283 (i == ((pTemp->GetText().getLength()+1)/2)-1))
3285 pS->WriteUChar( 0x22 ); //char, with attributes right
3286 //after the character
3288 else
3289 pS->WriteUChar( CHAR );
3291 sal_uInt8 nFace = 0x1;
3292 if (pNode->GetFont().GetItalic() == ITALIC_NORMAL)
3293 nFace = 0x3;
3294 else if (pNode->GetFont().GetWeight() == WEIGHT_BOLD)
3295 nFace = 0x7;
3296 pS->WriteUChar( nFace+128 ); //typeface
3297 sal_uInt16 nChar = pTemp->GetText()[i];
3298 pS->WriteUInt16( SmTextNode::ConvertSymbolToUnicode(nChar) );
3300 //Mathtype can only have these sort of character
3301 //attributes on a single character, starmath can put them
3302 //anywhere, when the entity involved is a text run this is
3303 //a large effort to place the character attribute on the
3304 //central mathtype character so that it does pretty much
3305 //what the user probably has in mind. The attributes
3306 //filled in here are dummy ones which are replaced in the
3307 //ATTRIBUT handler if a suitable location for the
3308 //attributes was found here. Unfortunately it is
3309 //possible for starmath to place character attributes on
3310 //entities which cannot occur in mathtype e.g. a Summation
3311 //symbol so these attributes may be lost
3312 if (nPendingAttributes &&
3313 (i == ((pTemp->GetText().getLength()+1)/2)-1))
3315 pS->WriteUChar( EMBEL );
3316 while (nPendingAttributes)
3318 pS->WriteUChar( 2 );
3319 //wedge the attributes in here and clear
3320 //the pending stack
3321 nPendingAttributes--;
3323 nInsertion=pS->Tell();
3324 pS->WriteUChar( END ); //end embel
3325 pS->WriteUChar( END ); //end embel
3330 extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportMathType(SvStream &rStream)
3332 OUStringBuffer sText;
3333 MathType aEquation(sText);
3334 bool bRet = false;
3337 bRet = aEquation.Parse(&rStream);
3339 catch (const std::out_of_range&)
3342 return bRet;
3345 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */