1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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"
21 #include "eqnolefilehdr.hxx"
23 #include <filter/msfilter/classids.hxx>
24 #include <osl/diagnose.h>
25 #include <sfx2/docfile.hxx>
26 #include <sot/storage.hxx>
29 //These are the default MathType sizes
30 constexpr std::array
<sal_Int16
, 7> aSizeTable
{
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
48 aUserStyles
.reserve(11);
49 for(sal_uInt8 i
=1;i
<=11;i
++)
65 aUserStyles
.insert(aFont
);
70 /*ToDo replace with table rather than switch, returns
71 sal_True in the case that the char is just a char, and
72 sal_False if the character is an operator which must not be
73 placed inside the quote sequence designed to protect
74 against being parsed as a keyword
76 General solution required to force starmath to handle
77 unicode math chars the way it handles its own math
78 chars rather than handle them as text as it will do
79 for the default case below, i.e. incorrect spacing
80 between math symbols and ordinary text e.g. 1=2 rather
83 bool MathType::LookupChar(sal_Unicode nChar
,OUStringBuffer
&rRet
,sal_uInt8 nVersion
,
87 const char *pC
= nullptr;
115 if ((nVersion
< 3) && (nTypeFace
== 0x86))
119 rRet
.append(OUStringChar(nChar
));
124 if ((nVersion
< 3) && (nTypeFace
== 0x81))
126 rRet
.append(OUStringChar(nChar
));
130 if ((nVersion
< 3) && (nTypeFace
== 0x84))
132 rRet
.append(OUStringChar(nChar
));
136 if ((nVersion
< 3) && (nTypeFace
== 0x84))
138 rRet
.append(OUStringChar(nChar
));
142 if ((nVersion
< 3) && (nTypeFace
== 0x84))
144 rRet
.append(OUStringChar(nChar
));
148 if ((nVersion
< 3) && (nTypeFace
== 0x84))
150 rRet
.append(OUStringChar(nChar
));
154 if ((nVersion
< 3) && (nTypeFace
== 0x84))
156 rRet
.append(OUStringChar(nChar
));
160 if ((nVersion
< 3) && (nTypeFace
== 0x84))
162 rRet
.append(OUStringChar(nChar
));
166 if ((nVersion
< 3) && (nTypeFace
== 0x82))
168 rRet
.append(OUStringChar(nChar
));
172 if ((nVersion
< 3) && (nTypeFace
== 0x86))
176 rRet
.append(OUStringChar(nChar
));
181 if ((nVersion
< 3) && (nTypeFace
== 0x86))
185 rRet
.append(OUStringChar(nChar
));
190 if ((nVersion
< 3) && (nTypeFace
== 0x86))
194 rRet
.append(OUStringChar(nChar
));
199 if ((nVersion
< 3) && (nTypeFace
== 0x85))
203 rRet
.append(OUStringChar(nChar
));
319 pC
= " backepsilon ";
322 case 0x2209: // notin
323 rRet
.append(" func " + OUStringChar(nChar
) + " ");
326 rRet
.append(u
" func \u220b ");
362 pC
= " intersection ";
411 pC
= " preccurlyeq ";
414 pC
= " succcurlyeq ";
429 case 0x2282: // subset
430 case 0x2283: // supset
431 case 0x2284: // nsubset
432 case 0x2285: // nsupset
433 case 0x2286: // subseteq
434 case 0x2287: // supseteq
435 case 0x2288: // nsubseteq
436 case 0x2289: // nsupseteq
437 case 0x22b2: // NORMAL SUBGROUP OF
438 case 0x22b3: // CONTAINS AS NORMAL SUBGROUP
439 rRet
.append(" func " + OUStringChar(nChar
) + " ");
493 case 0xeb01: //no space
494 case 0xeb08: //normal space
497 case 0xef04: //tiny space
498 case 0xef05: //tiny space
499 case 0xeb02: //small space
500 case 0xeb04: //medium space
503 case 0xeb05: //large space
510 rRet
.append(OUStringChar(nChar
));
515 rRet
.appendAscii(pC
);
519 void MathTypeFont::AppendStyleToText(OUString
&rRet
)
521 const char *pC
= nullptr;
538 rRet
+= OUString::createFromAscii( pC
);
541 void MathType::TypeFaceToString(OUString
&rTxt
,sal_uInt8 nFace
)
543 MathTypeFont
aFont(nFace
);
544 auto aItr
= aUserStyles
.find(aFont
);
545 if (aItr
!= aUserStyles
.end())
546 aFont
.nStyle
= aItr
->nStyle
;
547 aFont
.AppendStyleToText(rTxt
);
550 bool MathType::Parse(SotStorage
*pStor
)
552 rtl::Reference
<SotStorageStream
> xSrc
= pStor
->OpenSotStream(
553 u
"Equation Native"_ustr
,
554 StreamMode::STD_READ
);
555 if ( (!xSrc
.is()) || (ERRCODE_NONE
!= xSrc
->GetError()))
557 return Parse(xSrc
.get());
560 bool MathType::Parse(SvStream
* pStream
)
563 pS
->SetEndian( SvStreamEndian::LITTLE
);
567 sal_uInt8 nProdVersion
;
568 sal_uInt8 nProdSubVersion
;
571 pS
->ReadUChar( nVersion
);
572 pS
->ReadUChar( nPlatform
);
573 pS
->ReadUChar( nProduct
);
574 pS
->ReadUChar( nProdVersion
);
575 pS
->ReadUChar( nProdSubVersion
);
577 if (!pS
->good() || nVersion
> 3) // allow only supported versions of MathType to be parsed
580 bool bRet
= HandleRecords(0);
581 //little crude hack to close occasionally open expressions
582 //a sophisticated system to determine what expressions are
583 //opened is required, but this is as much work as rewriting
584 //starmaths internals.
590 static void lcl_PrependDummyTerm(OUStringBuffer
&rRet
, sal_Int32
&rTextStart
)
592 if ((rTextStart
< rRet
.getLength()) &&
593 (rRet
[rTextStart
] == '=') &&
594 ((rTextStart
== 0) || (rRet
[ rTextStart
-1 ] == '{'))
597 rRet
.insert(rTextStart
, " {}");
602 static void lcl_AppendDummyTerm(OUStringBuffer
&rRet
)
605 for(int nI
=rRet
.getLength()-1;nI
>= 0; nI
--)
607 sal_Int32 nIdx
= sal::static_int_cast
< sal_Int32
>(nI
);
608 sal_Unicode nChar
= rRet
[nIdx
];
611 if (rRet
[nIdx
] != '{')
615 if (!bOk
) //No term, use dummy
619 void MathType::HandleNudge()
621 sal_uInt8
nXNudge(0);
622 pS
->ReadUChar(nXNudge
);
623 sal_uInt8
nYNudge(0);
624 pS
->ReadUChar(nYNudge
);
625 if (nXNudge
== 128 && nYNudge
== 128)
627 sal_uInt16
nXLongNudge(0);
628 sal_uInt16
nYLongNudge(0);
629 pS
->ReadUInt16(nXLongNudge
);
630 pS
->ReadUInt16(nYLongNudge
);
634 /* Fabulously complicated as many tokens have to be reordered and generally
635 * moved around from mathtypes paradigm to starmaths. */
636 bool MathType::HandleRecords(int nLevel
, sal_uInt8 nSelector
,
637 sal_uInt8 nVariation
, int nMatrixRows
, int nMatrixCols
)
643 sal_uInt8 nTag
,nRecord
;
645 sal_uInt16 nTabOffset
;
649 OUString sPush
,sMainTerm
;
650 int nSetSize
=0,nSetAlign
=0;
651 int nCurRow
=0,nCurCol
=0;
652 bool bOpenString
=false;
653 sal_Int32 nTextStart
= 0;
654 sal_Int32 nSubSupStartPos
= 0;
655 sal_Int32 nLastTemplateBracket
=-1;
661 pS
->ReadUChar( nTag
);
664 /*MathType strings can of course include words which
665 *are StarMath keywords, the simplest solution is
666 to escape strings of greater than len 1 with double
667 quotes to avoid scanning the TokenTable for matches
669 Unfortunately it may turn out that the string gets
670 split during the handling of a character emblishment
671 so this special case must be handled in the
672 character handler case 2:
674 if ((nRecord
== CHAR
) && (!bOpenString
))
677 nTextStart
= rRet
.getLength();
679 else if ((nRecord
!= CHAR
) && bOpenString
)
682 if ((rRet
.getLength() - nTextStart
) > 1)
685 TypeFaceToString(aStr
,nTypeFace
);
686 rRet
.insert(nTextStart
, aStr
+ "\"");
689 else if (nRecord
== END
&& !rRet
.isEmpty())
691 sal_Unicode cChar
= 0;
692 sal_Int32 nI
= rRet
.getLength()-1;
700 if ((cChar
== '=') || (cChar
== '+') || (cChar
== '-'))
713 rRet
.append("\nnewline\n");
720 rRet
.append(" langle ");
721 else if (nVariation
==1)
722 rRet
.append(" \\langle ");
726 rRet
.append(" left (");
727 else if (nVariation
==1)
731 if ((nVariation
==0) || (nVariation
==1))
732 rRet
.append(" left lbrace ");
734 rRet
.append(" left none ");
738 rRet
.append(" left [");
739 else if (nVariation
==1)
748 rRet
.append(" lline ");
749 else if (nVariation
==1)
750 rRet
.append(" \\lline ");
754 rRet
.append(" ldline ");
755 else if (nVariation
==1)
756 rRet
.append(" \\ldline ");
759 if (nVariation
== 0 || nVariation
& 0x01) // tvFENCE_L
760 rRet
.append(" left lfloor ");
762 rRet
.append(" left none ");
766 rRet
.append(" lceil ");
767 else if (nVariation
==1)
768 rRet
.append(" \\lceil ");
781 rRet
.append(" sqrt");
784 rRet
.append(" nroot");
785 sPush
= rRet
.makeStringAndClear();
796 rRet
.append(" over ");
800 nSubSupStartPos
= rRet
.getLength();
801 if ((nVariation
== 0) ||
802 ((nVariation
== 2) && (nPart
==1)))
804 lcl_AppendDummyTerm(rRet
);
805 rRet
.append(" rSup");
807 else if ((nVariation
== 1) ||
808 ((nVariation
== 2) && (nPart
==0)))
810 lcl_AppendDummyTerm(rRet
);
811 rRet
.append(" rSub");
817 rRet
.append(" {underline ");
818 else if (nVariation
== 1)
819 rRet
.append(" {underline underline ");
824 rRet
.append(" {overline ");
825 else if (nVariation
== 1)
826 rRet
.append(" {overline overline ");
833 rRet
.append(" widevec ");//left arrow above
834 else if (nVariation
== 1)
835 rRet
.append(" widevec ");//left arrow below
843 rRet
.append(" widevec ");//right arrow above
844 else if (nVariation
== 1)
845 rRet
.append(" widevec ");//right arrow below
853 rRet
.append(" widevec ");//double arrow above
854 else if (nVariation
== 1)
855 rRet
.append(" widevec ");//double arrow below
862 if ((nVariation
== 3) || (nVariation
== 4))
863 rRet
.append(" lInt");
866 if ( (nVariation
!= 0) && (nVariation
!= 3))
868 sPush
= rRet
.makeStringAndClear();
871 if (((nVariation
== 1) ||
872 (nVariation
== 4)) && (nPart
==1))
873 rRet
.append(" rSub");
874 else if ((nVariation
== 2) && (nPart
==2))
875 rRet
.append(" rSup");
876 else if ((nVariation
== 2) && (nPart
==1))
877 rRet
.append(" rSub");
883 if ((nVariation
== 2) || (nVariation
== 3))
884 rRet
.append(" llInt");
886 rRet
.append(" iInt");
887 if ( (nVariation
!= 0) && (nVariation
!= 2))
889 sPush
= rRet
.makeStringAndClear();
892 if (((nVariation
== 1) ||
893 (nVariation
== 3)) && (nPart
==1))
894 rRet
.append(" rSub");
900 if ((nVariation
== 2) || (nVariation
== 3))
901 rRet
.append(" lllInt");
903 rRet
.append(" iiInt");
904 if ( (nVariation
!= 0) && (nVariation
!= 2))
906 sPush
= rRet
.makeStringAndClear();
909 if (((nVariation
== 1) ||
910 (nVariation
== 3)) && (nPart
==1))
911 rRet
.append(" rSub");
918 rRet
.append(" lInt");
921 sPush
= rRet
.makeStringAndClear();
923 if (((nVariation
== 1) ||
924 (nVariation
== 2)) && (nPart
==1))
925 rRet
.append(" cSub");
926 else if ((nVariation
== 0) && (nPart
==2))
927 rRet
.append(" cSup");
928 else if ((nVariation
== 0) && (nPart
==1))
929 rRet
.append(" cSub");
936 rRet
.append(" llInt");
938 rRet
.append(" iInt");
939 sPush
= rRet
.makeStringAndClear();
942 rRet
.append(" cSub");
949 rRet
.append(" lllInt");
951 rRet
.append(" iiInt");
952 sPush
= rRet
.makeStringAndClear();
955 rRet
.append(" cSub");
968 sPush
= rRet
.makeStringAndClear();
971 if ((nVariation
== 0) && (nPart
==1))
972 rRet
.append(" cSub");
973 else if ((nVariation
== 1) && (nPart
==2))
974 rRet
.append(" cSup");
975 else if ((nVariation
== 1) && (nPart
==1))
976 rRet
.append(" cSub");
983 sPush
= rRet
.makeStringAndClear();
985 if ((nVariation
== 0) && (nPart
==1))
986 rRet
.append(" rSub");
987 else if ((nVariation
== 1) && (nPart
==2))
988 rRet
.append(" rSup");
989 else if ((nVariation
== 1) && (nPart
==1))
990 rRet
.append(" rSub");
996 rRet
.append(" Prod");
999 sPush
= rRet
.makeStringAndClear();
1002 if ((nVariation
== 0) && (nPart
==1))
1003 rRet
.append(" cSub");
1004 else if ((nVariation
== 1) && (nPart
==2))
1005 rRet
.append(" cSup");
1006 else if ((nVariation
== 1) && (nPart
==1))
1007 rRet
.append(" cSub");
1013 rRet
.append(" Prod");
1014 sPush
= rRet
.makeStringAndClear();
1016 if ((nVariation
== 0) && (nPart
==1))
1017 rRet
.append(" rSub");
1018 else if ((nVariation
== 1) && (nPart
==2))
1019 rRet
.append(" rSup");
1020 else if ((nVariation
== 1) && (nPart
==1))
1021 rRet
.append(" rSub");
1027 rRet
.append(" coProd");
1028 if (nVariation
!= 2)
1030 sPush
= rRet
.makeStringAndClear();
1033 if ((nVariation
== 0) && (nPart
==1))
1034 rRet
.append(" cSub");
1035 else if ((nVariation
== 1) && (nPart
==2))
1036 rRet
.append(" cSup");
1037 else if ((nVariation
== 1) && (nPart
==1))
1038 rRet
.append(" cSub");
1044 rRet
.append(" coProd");
1045 sPush
= rRet
.makeStringAndClear();
1047 if ((nVariation
== 0) && (nPart
==1))
1048 rRet
.append(" rSub");
1049 else if ((nVariation
== 1) && (nPart
==2))
1050 rRet
.append(" rSup");
1051 else if ((nVariation
== 1) && (nPart
==1))
1052 rRet
.append(" rSub");
1058 rRet
.append(" union"); //union
1059 if (nVariation
!= 2)
1061 sPush
= rRet
.makeStringAndClear();
1064 if ((nVariation
== 0) && (nPart
==1))
1065 rRet
.append(" cSub");
1066 else if ((nVariation
== 1) && (nPart
==2))
1067 rRet
.append(" cSup");
1068 else if ((nVariation
== 1) && (nPart
==1))
1069 rRet
.append(" cSub");
1075 rRet
.append(" union"); //union
1076 sPush
= rRet
.makeStringAndClear();
1078 if ((nVariation
== 0) && (nPart
==1))
1079 rRet
.append(" rSub");
1080 else if ((nVariation
== 1) && (nPart
==2))
1081 rRet
.append(" rSup");
1082 else if ((nVariation
== 1) && (nPart
==1))
1083 rRet
.append(" rSub");
1089 rRet
.append(" intersect"); //intersect
1090 if (nVariation
!= 2)
1092 sPush
= rRet
.makeStringAndClear();
1095 if ((nVariation
== 0) && (nPart
==1))
1096 rRet
.append(" cSub");
1097 else if ((nVariation
== 1) && (nPart
==2))
1098 rRet
.append(" cSup");
1099 else if ((nVariation
== 1) && (nPart
==1))
1100 rRet
.append(" cSub");
1106 rRet
.append(" intersect"); //intersect
1107 sPush
= rRet
.makeStringAndClear();
1109 if ((nVariation
== 0) && (nPart
==1))
1110 rRet
.append(" rSub");
1111 else if ((nVariation
== 1) && (nPart
==2))
1112 rRet
.append(" rSup");
1113 else if ((nVariation
== 1) && (nPart
==1))
1114 rRet
.append(" rSub");
1118 if ((nVariation
== 0) && (nPart
==1))
1119 rRet
.append(" cSup");
1120 else if ((nVariation
== 1) && (nPart
==1))
1121 rRet
.append(" cSub");
1122 else if ((nVariation
== 2) && (nPart
==1))
1123 rRet
.append(" cSub");
1124 else if ((nVariation
== 2) && (nPart
==2))
1125 rRet
.append(" cSup");
1129 if (nVariation
== 0)
1133 sPush
= rRet
.makeStringAndClear();
1137 if (nVariation
== 0)
1140 rRet
.append("alignr ");
1143 rRet
.append("\\lline ");
1144 if (nVariation
== 1)
1145 rRet
.append("overline ");
1153 sPush
= rRet
.makeStringAndClear();
1155 if ((nVariation
== 0) && (nPart
==0))
1156 rRet
.append(" rSup");
1157 else if ((nVariation
== 2) && (nPart
==1))
1158 rRet
.append(" rSup");
1159 else if ((nVariation
== 1) && (nPart
==0))
1160 rRet
.append(" rSub");
1161 else if ((nVariation
== 2) && (nPart
==0))
1162 rRet
.append(" rSub");
1168 sPush
= rRet
.makeStringAndClear();
1170 if ((nVariation
== 0) && (nPart
==0))
1171 rRet
.append(" cSup");
1172 else if ((nVariation
== 2) && (nPart
==1))
1173 rRet
.append(" cSup");
1174 else if ((nVariation
== 1) && (nPart
==0))
1175 rRet
.append(" cSub");
1176 else if ((nVariation
== 2) && (nPart
==0))
1177 rRet
.append(" cSub");
1182 rRet
.append("\"\"");
1183 if ((nVariation
== 0)
1184 || ((nVariation
== 2) && (nPart
==1)))
1185 rRet
.append(" lSup");
1186 else if ((nVariation
== 1)
1187 || ((nVariation
== 2) && (nPart
==0)))
1188 rRet
.append(" lSub");
1195 rRet
.append(" langle ");
1197 else if (nVariation
==1)
1199 rRet
.append(" \\langle ");
1202 else if (nVariation
==2)
1204 rRet
.append(" \\lline ");
1209 if (nVariation
== 0)
1210 rRet
.append(" widevec ");//left below
1211 else if (nVariation
== 1)
1212 rRet
.append(" widevec ");//right below
1213 else if (nVariation
== 2)
1214 rRet
.append(" widevec ");//double headed below
1218 if (nVariation
== 0)
1219 rRet
.append(" widevec ");//left above
1220 else if (nVariation
== 1)
1221 rRet
.append(" widevec ");//right above
1222 else if (nVariation
== 2)
1223 rRet
.append(" widevec ");//double headed above
1229 sal_Int16 nOldCurSize
=nCurSize
;
1230 sal_Int32 nSizeStartPos
= rRet
.getLength();
1231 HandleSize( nLSize
, nDSize
, nSetSize
);
1232 bRet
= HandleRecords( nLevel
+1 );
1236 sal_Int32 nI
= rRet
.lastIndexOf('{');
1239 for(nI
=nI
+1;nI
<rRet
.getLength();nI
++)
1240 if (rRet
[nI
] != ' ')
1251 else if (rRet
.getLength() > nSizeStartPos
)
1252 rRet
= rRet
.truncate(nSizeStartPos
);
1254 nCurSize
=nOldCurSize
;
1258 HandleMatrixSeparator(nMatrixRows
,nMatrixCols
,
1265 rRet
.append(" rangle ");
1266 else if (nVariation
==2)
1267 rRet
.append(" \\rangle ");
1271 rRet
.append(" right )");
1272 else if (nVariation
==2)
1276 if ((nVariation
==0) || (nVariation
==2))
1277 rRet
.append(" right rbrace ");
1279 rRet
.append(" right none ");
1283 rRet
.append(" right ]");
1284 else if (nVariation
==2)
1289 rRet
.append(" rline ");
1290 else if (nVariation
==2)
1291 rRet
.append(" \\rline ");
1295 rRet
.append(" rdline ");
1296 else if (nVariation
==2)
1297 rRet
.append(" \\rdline ");
1300 if (nVariation
== 0 || nVariation
& 0x02) // tvFENCE_R
1301 rRet
.append(" right rfloor ");
1303 rRet
.append(" right none ");
1307 rRet
.append(" rceil ");
1308 else if (nVariation
==2)
1309 rRet
.append(" \\rceil ");
1321 if (nVariation
== 1)
1326 sMainTerm
= rRet
.makeStringAndClear();
1328 else if (nPart
== 1)
1330 rRet
.insert(0, sPush
);
1331 rRet
.append(sMainTerm
);
1357 ((nVariation
== 2) || (nVariation
== 1)))
1361 sal_Int32 nI
= rRet
.lastIndexOf('{');
1364 for(nI
=nI
+1;nI
<rRet
.getLength();nI
++)
1365 if (rRet
[nI
] != ' ')
1376 else if (rRet
.getLength() > nSubSupStartPos
)
1377 rRet
= rRet
.truncate(nSubSupStartPos
);
1383 ((nVariation
== 2) || (nVariation
== 1)))
1411 rRet
.append("overbrace");
1420 rRet
.append("underbrace");
1427 else if ((nPart
==1) &&
1428 ((nVariation
== 2) || (nVariation
== 1)))
1435 if (nVariation
== 0)
1439 sMainTerm
= rRet
.makeStringAndClear();
1441 else if (nPart
== 1)
1443 rRet
.insert(0, sPush
);
1444 rRet
.append(" over " + sMainTerm
);
1461 rRet
.append("slash");
1464 rRet
.append("wideslash");
1483 if (nVariation
!= 2)
1485 sMainTerm
= rRet
.makeStringAndClear();
1489 else if ((nPart
== 1) && (nVariation
== 0))
1491 rRet
.insert(0, sPush
);
1492 rRet
.append(sMainTerm
);
1497 else if ((nPart
== 1) && (nVariation
== 1))
1499 else if ((nPart
== 2) && (nVariation
== 1))
1501 rRet
.insert(0, sPush
);
1502 rRet
.append(sMainTerm
);
1513 if ((nVariation
!= 0) && (nVariation
!= 3))
1515 sMainTerm
= rRet
.makeStringAndClear();
1519 else if ((nPart
== 1) &&
1520 ((nVariation
== 1) || (nVariation
==4)))
1522 rRet
.insert(0, sPush
);
1523 rRet
.append(sMainTerm
);
1528 else if ((nPart
== 1) && (nVariation
== 2))
1530 else if ((nPart
== 2) && (nVariation
== 2))
1532 rRet
.insert(0, sPush
);
1533 rRet
.append(sMainTerm
);
1545 if ((nVariation
!= 0) && (nVariation
!= 2))
1547 sMainTerm
= rRet
.makeStringAndClear();
1551 else if ((nPart
== 1) &&
1552 ((nVariation
== 1) || (nVariation
==3)))
1554 rRet
.insert(0, sPush
);
1555 rRet
.append(sMainTerm
);
1566 sMainTerm
= rRet
.makeStringAndClear();
1569 else if ((nPart
== 1) &&
1570 ((nVariation
== 1) || (nVariation
==2)))
1572 rRet
.insert(0, sPush
);
1573 rRet
.append(sMainTerm
);
1578 else if ((nPart
== 1) && (nVariation
== 0))
1580 else if ((nPart
== 2) && (nVariation
== 0))
1582 rRet
.insert(0, sPush
);
1583 rRet
.append(sMainTerm
);
1595 sMainTerm
= rRet
.makeStringAndClear();
1598 else if (nPart
== 1)
1600 rRet
.insert(0, sPush
);
1601 rRet
.append(sMainTerm
);
1613 ((nVariation
== 0) || (nVariation
== 1)))
1615 sMainTerm
= rRet
.makeStringAndClear();
1618 else if ((nPart
== 0) && (nVariation
== 2))
1620 else if ((nPart
== 1) && (nVariation
== 2))
1622 sMainTerm
= rRet
.makeStringAndClear();
1625 else if ((nPart
== 2) || ((nPart
== 1) &&
1626 (nVariation
== 0 || nVariation
== 1)))
1628 rRet
.insert(0, sPush
);
1629 rRet
.append(sMainTerm
);
1640 newline
--; //there is another term to arrive
1641 rRet
.append(" mline ");
1644 rRet
.append(" rangle ");
1646 else if (nVariation
==1)
1647 rRet
.append(" \\lline ");
1648 else if (nVariation
==2)
1649 rRet
.append(" \\rangle ");
1655 bSilent
= true; //Skip the optional brackets and/or
1656 //symbols that follow some of these
1657 //records. Foo Data.
1659 /*In matrices and piles we cannot separate equation
1660 *lines with the newline keyword*/
1669 bRet
= HandleChar( nTextStart
, nSetSize
, nLevel
, nTag
, nSelector
, nVariation
, bSilent
);
1674 bRet
= HandleTemplate( nLevel
, nSelector
, nVariation
, nLastTemplateBracket
);
1679 bRet
= HandlePile( nSetAlign
, nLevel
, nSelector
, nVariation
);
1680 HandleMatrixSeparator( nMatrixRows
, nMatrixCols
, nCurCol
, nCurRow
);
1685 bRet
= HandleMatrix( nLevel
, nSelector
, nVariation
);
1686 HandleMatrixSeparator( nMatrixRows
, nMatrixCols
, nCurCol
, nCurRow
);
1691 HandleEmblishments();
1695 sal_uInt8
nTabStops(0);
1696 pS
->ReadUChar( nTabStops
);
1697 for (i
=0;i
<nTabStops
;i
++)
1699 pS
->ReadUChar( nTabType
);
1700 pS
->ReadUInt16( nTabOffset
);
1702 SAL_WARN("starmath", "Not seen in the wild Equation Ruler Field");
1708 pS
->ReadUChar( aFont
.nTface
);
1710 The typeface number is the negative (which makes it
1711 positive) of the typeface value (unbiased) that appears in
1712 CHAR records that might follow a given FONT record
1714 aFont
.nTface
= 128-aFont
.nTface
;
1715 pS
->ReadUChar( aFont
.nStyle
);
1716 aUserStyles
.insert(aFont
);
1721 pS
->ReadChar( nChar8
);
1742 while (nRecord
!= END
&& !pS
->eof());
1751 /*Simply determine if we are at the end of a record or the end of a line,
1752 *with fiddly logic to see if we are in a matrix or a pile or neither
1754 Note we cannot tell until after the event that this is the last entry
1755 of a pile, so we must strip the last separator of a pile after this
1756 is detected in the PILE handler
1758 void MathType::HandleMatrixSeparator(int nMatrixRows
,int nMatrixCols
,
1759 int &rCurCol
,int &rCurRow
)
1764 if (rCurCol
== nMatrixCols
-1)
1766 if (rCurRow
!= nMatrixRows
-1)
1767 rRet
.append(" {} ##\n");
1768 if (nMatrixRows
!=-1)
1776 rRet
.append(" {} # ");
1777 if (nMatrixRows
!=-1)
1784 /* set the alignment of the following term, but starmath currently
1785 * cannot handle vertical alignment */
1786 void MathType::HandleAlign(sal_uInt8 nHorAlign
, int &rSetAlign
)
1792 rRet
.append("alignl {");
1795 rRet
.append("alignc {");
1798 rRet
.append("alignr {");
1804 /* set size of text, complexity due to overuse of signedness as a flag
1805 * indicator by mathtype file format*/
1806 bool MathType::HandleSize(sal_Int16 nLstSize
,sal_Int16 nDefSize
, int &rSetSize
)
1811 const sal_Int16 nDefaultSize
= 12;
1812 if ((-nLstSize
/32 != nDefaultSize
) && (-nLstSize
/32 != nCurSize
))
1820 if (-nLstSize
/32 != nLastSize
)
1822 nLastSize
= nCurSize
;
1823 rRet
.append(" size ");
1824 rRet
.append(static_cast<sal_Int32
>(-nLstSize
/32));
1829 nCurSize
= -nLstSize
/32;
1834 /*sizetable should theoretically be filled with the default sizes
1835 *of the various font groupings matching starmaths equivalents
1836 in aTypeFaces, and a test would be done to see if the new font
1837 size would be the same as what starmath would have chosen for
1838 itself anyway in which case the size setting could be ignored*/
1839 nLstSize
= aSizeTable
.at(nLstSize
);
1840 nLstSize
= nLstSize
+ nDefSize
;
1841 if (nLstSize
!= nCurSize
)
1849 if (nLstSize
!= nLastSize
)
1851 nLastSize
= nCurSize
;
1852 rRet
.append(" size ");
1853 rRet
.append(static_cast<sal_Int32
>(nLstSize
));
1858 nCurSize
= nLstSize
;
1864 bool MathType::ConvertFromStarMath( SfxMedium
& rMedium
)
1869 SvStream
*pStream
= rMedium
.GetOutStream();
1872 rtl::Reference
<SotStorage
> pStor
= new SotStorage(pStream
, false);
1874 SvGlobalName
aGName(MSO_EQUATION3_CLASSID
);
1875 pStor
->SetClass( aGName
, SotClipboardFormatId::NONE
, u
"Microsoft Equation 3.0"_ustr
);
1877 static sal_uInt8
const aCompObj
[] = {
1878 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
1879 0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0xCE, 0x02, 0x00,
1880 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00,
1881 0x00, 0x00, 0x00, 0x46, 0x17, 0x00, 0x00, 0x00,
1882 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66,
1883 0x74, 0x20, 0x45, 0x71, 0x75, 0x61, 0x74, 0x69,
1884 0x6F, 0x6E, 0x20, 0x33, 0x2E, 0x30, 0x00, 0x0C,
1885 0x00, 0x00, 0x00, 0x44, 0x53, 0x20, 0x45, 0x71,
1886 0x75, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x0B,
1887 0x00, 0x00, 0x00, 0x45, 0x71, 0x75, 0x61, 0x74,
1888 0x69, 0x6F, 0x6E, 0x2E, 0x33, 0x00, 0xF4, 0x39,
1889 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1890 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1892 rtl::Reference
<SotStorageStream
> xStor(pStor
->OpenSotStream(u
"\1CompObj"_ustr
));
1893 xStor
->WriteBytes(aCompObj
, sizeof(aCompObj
));
1895 static sal_uInt8
const aOle
[] = {
1896 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
1897 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1898 0x00, 0x00, 0x00, 0x00
1900 rtl::Reference
<SotStorageStream
> xStor2(pStor
->OpenSotStream(u
"\1Ole"_ustr
));
1901 xStor2
->WriteBytes(aOle
, sizeof(aOle
));
1905 rtl::Reference
<SotStorageStream
> xSrc
= pStor
->OpenSotStream(u
"Equation Native"_ustr
);
1906 if ( (!xSrc
.is()) || (ERRCODE_NONE
!= xSrc
->GetError()))
1910 pS
->SetEndian( SvStreamEndian::LITTLE
);
1912 pS
->SeekRel(EQNOLEFILEHDR_SIZE
); //Skip 28byte Header and fill it in later
1913 pS
->WriteUChar( 0x03 );
1914 pS
->WriteUChar( 0x01 );
1915 pS
->WriteUChar( 0x01 );
1916 pS
->WriteUChar( 0x03 );
1917 pS
->WriteUChar( 0x00 );
1918 sal_uInt64 nSize
= pS
->Tell();
1919 nPendingAttributes
=0;
1921 HandleNodes(pTree
, 0);
1922 pS
->WriteUChar( END
);
1924 nSize
= pS
->Tell()-nSize
;
1926 EQNOLEFILEHDR
aHdr(nSize
+4+1);
1936 void MathType::HandleNodes(SmNode
*pNode
,int nLevel
)
1938 switch(pNode
->GetType())
1940 case SmNodeType::Attribute
:
1941 HandleAttributes(pNode
,nLevel
);
1943 case SmNodeType::Text
:
1946 case SmNodeType::VerticalBrace
:
1947 HandleVerticalBrace(pNode
,nLevel
);
1949 case SmNodeType::Brace
:
1950 HandleBrace(pNode
,nLevel
);
1952 case SmNodeType::Oper
:
1953 HandleOperator(pNode
,nLevel
);
1955 case SmNodeType::BinVer
:
1956 HandleFractions(pNode
,nLevel
);
1958 case SmNodeType::Root
:
1959 HandleRoot(pNode
,nLevel
);
1961 case SmNodeType::Special
:
1963 SmTextNode
*pText
= static_cast<SmTextNode
*>(pNode
);
1964 //if the token str and the result text are the same then this
1965 //is to be seen as text, else assume it's a mathchar
1966 if (pText
->GetText() == pText
->GetToken().aText
)
1972 case SmNodeType::Math
:
1973 case SmNodeType::MathIdent
:
1976 case SmNodeType::SubSup
:
1977 HandleSubSupScript(pNode
,nLevel
);
1979 case SmNodeType::Table
:
1980 //Root Node, PILE equivalent, i.e. vertical stack
1981 HandleTable(pNode
,nLevel
);
1983 case SmNodeType::Matrix
:
1984 HandleSmMatrix(static_cast<SmMatrixNode
*>(pNode
),nLevel
);
1986 case SmNodeType::Line
:
1988 pS
->WriteUChar( 0x0a );
1989 pS
->WriteUChar( LINE
);
1990 size_t nSize
= pNode
->GetNumSubNodes();
1991 for (size_t i
= 0; i
< nSize
; ++i
)
1993 if (SmNode
*pTemp
= pNode
->GetSubNode(i
))
1994 HandleNodes(pTemp
,nLevel
+1);
1996 pS
->WriteUChar( END
);
1999 case SmNodeType::Align
:
2000 HandleMAlign(pNode
,nLevel
);
2002 case SmNodeType::Blank
:
2003 pS
->WriteUChar( CHAR
);
2004 pS
->WriteUChar( 0x98 );
2005 if (pNode
->GetToken().eType
== TSBLANK
)
2006 pS
->WriteUInt16( 0xEB04 );
2008 pS
->WriteUInt16( 0xEB05 );
2010 case SmNodeType::Expression
: // same treatment as the default one
2013 size_t nSize
= pNode
->GetNumSubNodes();
2014 for (size_t i
= 0; i
< nSize
; ++i
)
2016 if (SmNode
*pTemp
= pNode
->GetSubNode(i
))
2017 HandleNodes(pTemp
,nLevel
+1);
2025 int MathType::StartTemplate(sal_uInt16 nSelector
,sal_uInt16 nVariation
)
2027 int nOldPending
=nPendingAttributes
;
2028 pS
->WriteUChar( TMPL
); //Template
2029 pS
->WriteUChar( nSelector
); //selector
2030 pS
->WriteUChar( nVariation
); //variation
2031 pS
->WriteUChar( 0x00 ); //options
2032 pS
->WriteUChar( LINE
);
2033 //there's just no way we can now handle any character
2034 //attributes (from mathtypes perspective) centered
2035 //over an expression but above template attribute
2036 //such as widevec and similar constructs
2037 //we have to drop them
2038 nPendingAttributes
=0;
2042 void MathType::EndTemplate(int nOldPendingAttributes
)
2044 pS
->WriteUChar( END
); //end line
2045 pS
->WriteUChar( END
); //end template
2046 nPendingAttributes
=nOldPendingAttributes
;
2050 void MathType::HandleSmMatrix(SmMatrixNode
*pMatrix
,int nLevel
)
2052 pS
->WriteUChar( MATRIX
);
2053 pS
->WriteUChar( 0x00 ); //vAlign ?
2054 pS
->WriteUChar( 0x00 ); //h_just
2055 pS
->WriteUChar( 0x00 ); //v_just
2056 pS
->WriteUChar( pMatrix
->GetNumRows() ); //v_just
2057 pS
->WriteUChar( pMatrix
->GetNumCols() ); //v_just
2058 int nBytes
=(pMatrix
->GetNumRows()+1)*2/8;
2059 if (((pMatrix
->GetNumRows()+1)*2)%8)
2061 for (int j
= 0; j
< nBytes
; j
++)
2062 pS
->WriteUChar( 0x00 ); //row_parts
2063 nBytes
=(pMatrix
->GetNumCols()+1)*2/8;
2064 if (((pMatrix
->GetNumCols()+1)*2)%8)
2066 for (int k
= 0; k
< nBytes
; k
++)
2067 pS
->WriteUChar( 0x00 ); //col_parts
2068 size_t nSize
= pMatrix
->GetNumSubNodes();
2069 for (size_t i
= 0; i
< nSize
; ++i
)
2071 if (SmNode
*pTemp
= pMatrix
->GetSubNode(i
))
2073 pS
->WriteUChar( LINE
); //line
2074 HandleNodes(pTemp
,nLevel
+1);
2075 pS
->WriteUChar( END
); //end line
2078 pS
->WriteUChar( END
);
2082 //Root Node, PILE equivalent, i.e. vertical stack
2083 void MathType::HandleTable(SmNode
*pNode
,int nLevel
)
2085 size_t nSize
= pNode
->GetNumSubNodes();
2086 //The root of the starmath is a table, if
2087 //we convert this them each iteration of
2088 //conversion from starmath to mathtype will
2089 //add an extra unnecessary level to the
2090 //mathtype output stack which would grow
2091 //without bound in a multi step conversion
2094 pS
->WriteUChar( 0x0A ); //initial size
2096 if ( nLevel
|| (nSize
>1))
2098 pS
->WriteUChar( PILE
);
2099 pS
->WriteUChar( nHAlign
); //vAlign ?
2100 pS
->WriteUChar( 0x01 ); //hAlign
2103 for (size_t i
= 0; i
< nSize
; ++i
)
2105 if (SmNode
*pTemp
= pNode
->GetSubNode(i
))
2107 pS
->WriteUChar( LINE
);
2108 HandleNodes(pTemp
,nLevel
+1);
2109 pS
->WriteUChar( END
);
2112 if (nLevel
|| (nSize
>1))
2113 pS
->WriteUChar( END
);
2117 void MathType::HandleRoot(SmNode
*pNode
,int nLevel
)
2120 pS
->WriteUChar( TMPL
); //Template
2121 pS
->WriteUChar( 0x0D ); //selector
2122 if (pNode
->GetSubNode(0))
2123 pS
->WriteUChar( 0x01 ); //variation
2125 pS
->WriteUChar( 0x00 ); //variation
2126 pS
->WriteUChar( 0x00 ); //options
2128 if (nullptr != (pTemp
= pNode
->GetSubNode(2)))
2130 pS
->WriteUChar( LINE
); //line
2131 HandleNodes(pTemp
,nLevel
+1);
2132 pS
->WriteUChar( END
);
2135 if (nullptr != (pTemp
= pNode
->GetSubNode(0)))
2137 pS
->WriteUChar( LINE
); //line
2138 HandleNodes(pTemp
,nLevel
+1);
2139 pS
->WriteUChar( END
);
2142 pS
->WriteUChar( LINE
|0x10 ); //dummy line
2145 pS
->WriteUChar( END
);
2148 sal_uInt8
MathType::HandleCScript(SmNode
*pNode
,SmNode
*pContent
,int nLevel
,
2149 sal_uInt64
*pPos
,bool bTest
)
2151 sal_uInt8 nVariation2
=0xff;
2153 if (bTest
&& pNode
->GetSubNode(CSUP
+1))
2156 if (pNode
->GetSubNode(CSUB
+1))
2159 else if (pNode
->GetSubNode(CSUB
+1))
2162 if (nVariation2
!=0xff)
2166 pS
->WriteUChar( TMPL
); //Template
2167 pS
->WriteUChar( 0x2B ); //selector
2168 pS
->WriteUChar( nVariation2
);
2169 pS
->WriteUChar( 0x00 ); //options
2173 pS
->WriteUChar( LINE
); //line
2174 HandleNodes(pContent
,nLevel
+1);
2175 pS
->WriteUChar( END
); //line
2178 pS
->WriteUChar( LINE
|0x10 );
2180 pS
->WriteUChar( 0x0B );
2183 if (nullptr != (pTemp
= pNode
->GetSubNode(CSUB
+1)))
2185 pS
->WriteUChar( LINE
); //line
2186 HandleNodes(pTemp
,nLevel
+1);
2187 pS
->WriteUChar( END
); //line
2190 pS
->WriteUChar( LINE
|0x10 );
2191 if (bTest
&& nullptr != (pTemp
= pNode
->GetSubNode(CSUP
+1)))
2193 pS
->WriteUChar( LINE
); //line
2194 HandleNodes(pTemp
,nLevel
+1);
2195 pS
->WriteUChar( END
); //line
2198 pS
->WriteUChar( LINE
|0x10 );
2205 Sub and Sup scripts and another problem area, StarMath
2206 can have all possible options used at the same time, whereas
2207 Mathtype cannot. The ordering of the nodes for each system
2208 is quite different as well leading to some complexity
2210 void MathType::HandleSubSupScript(SmNode
*pNode
,int nLevel
)
2212 sal_uInt8 nVariation
=0xff;
2213 if (pNode
->GetSubNode(LSUP
+1))
2216 if (pNode
->GetSubNode(LSUB
+1))
2219 else if ( nullptr != pNode
->GetSubNode(LSUB
+1) )
2223 if (nVariation
!=0xff)
2225 pS
->WriteUChar( TMPL
); //Template
2226 pS
->WriteUChar( 0x2c ); //selector
2227 pS
->WriteUChar( nVariation
);
2228 pS
->WriteUChar( 0x00 ); //options
2229 pS
->WriteUChar( 0x0B );
2231 if (nullptr != (pTemp
= pNode
->GetSubNode(LSUB
+1)))
2233 pS
->WriteUChar( LINE
); //line
2234 HandleNodes(pTemp
,nLevel
+1);
2235 pS
->WriteUChar( END
); //line
2238 pS
->WriteUChar( LINE
|0x10 );
2239 if (nullptr != (pTemp
= pNode
->GetSubNode(LSUP
+1)))
2241 pS
->WriteUChar( LINE
); //line
2242 HandleNodes(pTemp
,nLevel
+1);
2243 pS
->WriteUChar( END
); //line
2246 pS
->WriteUChar( LINE
|0x10 );
2247 pS
->WriteUChar( END
);
2252 sal_uInt8 nVariation2
=HandleCScript(pNode
,nullptr,nLevel
);
2254 if (nullptr != (pTemp
= pNode
->GetSubNode(0)))
2256 HandleNodes(pTemp
,nLevel
+1);
2259 if (nVariation2
!= 0xff)
2260 pS
->WriteUChar( END
);
2262 if (nullptr != (pNode
->GetSubNode(RSUP
+1)))
2265 if (pNode
->GetSubNode(RSUB
+1))
2268 else if (nullptr != pNode
->GetSubNode(RSUB
+1))
2271 if (nVariation
!=0xff)
2273 pS
->WriteUChar( TMPL
); //Template
2274 pS
->WriteUChar( 0x0F ); //selector
2275 pS
->WriteUChar( nVariation
);
2276 pS
->WriteUChar( 0x00 ); //options
2277 pS
->WriteUChar( 0x0B );
2279 if (nullptr != (pTemp
= pNode
->GetSubNode(RSUB
+1)))
2281 pS
->WriteUChar( LINE
); //line
2282 HandleNodes(pTemp
,nLevel
+1);
2283 pS
->WriteUChar( END
); //line
2286 pS
->WriteUChar( LINE
|0x10 );
2287 if (nullptr != (pTemp
= pNode
->GetSubNode(RSUP
+1)))
2289 pS
->WriteUChar( LINE
); //line
2290 HandleNodes(pTemp
,nLevel
+1);
2291 pS
->WriteUChar( END
); //line
2294 pS
->WriteUChar( LINE
|0x10 );
2295 pS
->WriteUChar( END
); //line
2298 //After subscript mathtype will keep the size of
2299 //normal text at the subscript size, sigh.
2300 pS
->WriteUChar( 0x0A );
2304 void MathType::HandleFractions(SmNode
*pNode
,int nLevel
)
2307 pS
->WriteUChar( TMPL
); //Template
2308 pS
->WriteUChar( 0x0E ); //selector
2309 pS
->WriteUChar( 0x00 ); //variation
2310 pS
->WriteUChar( 0x00 ); //options
2312 pS
->WriteUChar( 0x0A );
2313 pS
->WriteUChar( LINE
); //line
2314 if (nullptr != (pTemp
= pNode
->GetSubNode(0)))
2315 HandleNodes(pTemp
,nLevel
+1);
2316 pS
->WriteUChar( END
);
2318 pS
->WriteUChar( 0x0A );
2319 pS
->WriteUChar( LINE
); //line
2320 if (nullptr != (pTemp
= pNode
->GetSubNode(2)))
2321 HandleNodes(pTemp
,nLevel
+1);
2322 pS
->WriteUChar( END
);
2324 pS
->WriteUChar( END
);
2328 void MathType::HandleBrace(SmNode
*pNode
,int nLevel
)
2331 SmNode
*pLeft
=pNode
->GetSubNode(0);
2332 SmNode
*pRight
=pNode
->GetSubNode(2);
2334 pS
->WriteUChar( TMPL
); //Template
2335 bIsReInterpBrace
=false;
2336 sal_uInt8 nBSpec
=0x10;
2337 auto nLoc
= pS
->Tell();
2340 switch (pLeft
->GetToken().eType
)
2343 pS
->WriteUChar( tmANGLE
); //selector
2344 pS
->WriteUChar( 0 ); //variation
2345 pS
->WriteUChar( 0 ); //options
2348 pS
->WriteUChar( tmBRACE
); //selector
2349 pS
->WriteUChar( 0 ); //variation
2350 pS
->WriteUChar( 0 ); //options
2354 pS
->WriteUChar( tmBRACK
); //selector
2355 pS
->WriteUChar( 0 ); //variation
2356 pS
->WriteUChar( 0 ); //options
2360 pS
->WriteUChar( tmFLOOR
); //selector
2361 pS
->WriteUChar( 0 ); //variation
2362 pS
->WriteUChar( 0 ); //options
2365 pS
->WriteUChar( tmBAR
); //selector
2366 pS
->WriteUChar( 0 ); //variation
2367 pS
->WriteUChar( 0 ); //options
2371 pS
->WriteUChar( tmDBAR
); //selector
2372 pS
->WriteUChar( 0 ); //variation
2373 pS
->WriteUChar( 0 ); //options
2376 pS
->WriteUChar( tmPAREN
); //selector
2377 pS
->WriteUChar( 0 ); //variation
2378 pS
->WriteUChar( 0 ); //options
2384 if (nullptr != (pTemp
= pNode
->GetSubNode(1)))
2386 pS
->WriteUChar( LINE
); //line
2387 HandleNodes(pTemp
,nLevel
+1);
2388 pS
->WriteUChar( END
); //options
2392 HandleNodes(pLeft
,nLevel
+1);
2393 if (bIsReInterpBrace
)
2395 auto nLoc2
= pS
->Tell();
2397 pS
->WriteUChar( 0x2D );
2399 pS
->WriteUChar( CHAR
);
2400 pS
->WriteUChar( 0x96 );
2401 pS
->WriteUInt16( 0xEC07 );
2402 bIsReInterpBrace
=false;
2405 HandleNodes(pRight
,nLevel
+1);
2407 pS
->WriteUChar( END
);
2411 void MathType::HandleVerticalBrace(SmNode
*pNode
,int nLevel
)
2414 pS
->WriteUChar( TMPL
); //Template
2415 if (pNode
->GetToken().eType
== TUNDERBRACE
)
2416 pS
->WriteUChar( tmLHBRACE
); //selector
2418 pS
->WriteUChar( tmUHBRACE
); //selector
2419 pS
->WriteUChar( 0 ); //variation
2420 pS
->WriteUChar( 0 ); //options
2422 if (nullptr != (pTemp
= pNode
->GetSubNode(0)))
2424 pS
->WriteUChar( LINE
); //line
2425 HandleNodes(pTemp
,nLevel
+1);
2426 pS
->WriteUChar( END
); //options
2429 if (nullptr != (pTemp
= pNode
->GetSubNode(2)))
2431 pS
->WriteUChar( LINE
); //line
2432 HandleNodes(pTemp
,nLevel
+1);
2433 pS
->WriteUChar( END
); //options
2435 pS
->WriteUChar( END
);
2438 void MathType::HandleOperator(SmNode
*pNode
,int nLevel
)
2440 if (HandleLim(pNode
,nLevel
))
2444 sal_uInt8 nVariation
;
2446 switch (pNode
->GetToken().eType
)
2453 nVariation
=HandleCScript(pNode
->GetSubNode(0),
2454 pNode
->GetSubNode(1),nLevel
,&nPos
,false);
2457 nVariation
=HandleCScript(pNode
->GetSubNode(0),
2458 pNode
->GetSubNode(1),nLevel
,&nPos
);
2462 sal_uInt8 nOldVariation
=nVariation
;
2463 sal_uInt8 nIntVariation
=nVariation
;
2466 if (nVariation
!= 0xff)
2470 if (nVariation
== 2)
2475 else if (nVariation
== 0)
2477 else if (nVariation
== 1)
2485 pS
->WriteUChar( TMPL
);
2486 switch(pNode
->GetToken().eType
)
2490 if (nOldVariation
!= 0xff)
2491 pS
->WriteUChar( 0x18 ); //selector
2493 pS
->WriteUChar( 0x15 ); //selector
2494 pS
->WriteUChar( nIntVariation
); //variation
2497 if (nOldVariation
!= 0xff)
2499 pS
->WriteUChar( 0x19 );
2500 pS
->WriteUChar( 0x01 );
2504 pS
->WriteUChar( 0x16 );
2505 pS
->WriteUChar( 0x00 );
2509 if (nOldVariation
!= 0xff)
2511 pS
->WriteUChar( 0x1a );
2512 pS
->WriteUChar( 0x01 );
2516 pS
->WriteUChar( 0x17 );
2517 pS
->WriteUChar( 0x00 );
2521 if (nOldVariation
!= 0xff)
2523 pS
->WriteUChar( 0x18 );
2524 pS
->WriteUChar( 0x02 );
2528 pS
->WriteUChar( 0x15 );
2529 pS
->WriteUChar( 0x03 );
2533 if (nOldVariation
!= 0xff)
2535 pS
->WriteUChar( 0x19 );
2536 pS
->WriteUChar( 0x00 );
2540 pS
->WriteUChar( 0x16 );
2541 pS
->WriteUChar( 0x02 );
2545 if (nOldVariation
!= 0xff)
2547 pS
->WriteUChar( 0x1a );
2548 pS
->WriteUChar( 0x00 );
2552 pS
->WriteUChar( 0x17 );
2553 pS
->WriteUChar( 0x02 );
2558 pS
->WriteUChar( 0x1d );
2559 pS
->WriteUChar( nVariation
);
2562 pS
->WriteUChar( 0x1f );
2563 pS
->WriteUChar( nVariation
);
2566 pS
->WriteUChar( 0x21 );
2567 pS
->WriteUChar( nVariation
);
2570 pS
->WriteUChar( 0 ); //options
2576 pS
->WriteUChar( LINE
); //line
2577 HandleNodes(pNode
->GetSubNode(1),nLevel
+1);
2578 pS
->WriteUChar( END
); //line
2579 pS
->WriteUChar( LINE
|0x10 );
2580 pS
->WriteUChar( LINE
|0x10 );
2583 pS
->WriteUChar( 0x0D );
2584 switch(pNode
->GetToken().eType
)
2588 pS
->WriteUChar( CHAR
);
2589 pS
->WriteUChar( 0x86 );
2590 pS
->WriteUInt16( 0x2211 );
2593 pS
->WriteUChar( CHAR
);
2594 pS
->WriteUChar( 0x86 );
2595 pS
->WriteUInt16( 0x220F );
2598 pS
->WriteUChar( CHAR
);
2599 pS
->WriteUChar( 0x8B );
2600 pS
->WriteUInt16( 0x2210 );
2604 pS
->WriteUChar( CHAR
);
2605 pS
->WriteUChar( 0x86 );
2606 pS
->WriteUInt16( 0x222B );
2610 pS
->WriteUChar( CHAR
);
2611 pS
->WriteUChar( 0x86 );
2612 pS
->WriteUInt16( 0x222B );
2617 pS
->WriteUChar( CHAR
);
2618 pS
->WriteUChar( 0x86 );
2619 pS
->WriteUInt16( 0x222B );
2622 pS
->WriteUChar( END
);
2623 pS
->WriteUChar( 0x0A );
2627 bool MathType::HandlePile(int &rSetAlign
, int nLevel
, sal_uInt8 nSelector
, sal_uInt8 nVariation
)
2630 pS
->ReadUChar( nHAlign
);
2631 pS
->ReadUChar( nVAlign
);
2633 HandleAlign(nHAlign
, rSetAlign
);
2635 rRet
.append(" stack {\n");
2636 bool bRet
= HandleRecords( nLevel
+1, nSelector
, nVariation
, -1, -1 );
2637 int nRemoveFrom
= rRet
.getLength() >= 3 ? rRet
.getLength() - 3 : 0;
2638 rRet
.remove(nRemoveFrom
, 2);
2649 bool MathType::HandleMatrix(int nLevel
, sal_uInt8 nSelector
, sal_uInt8 nVariation
)
2651 sal_uInt8 nH_just
,nV_just
,nRows
,nCols
,nVAlign
;
2652 pS
->ReadUChar( nVAlign
);
2653 pS
->ReadUChar( nH_just
);
2654 pS
->ReadUChar( nV_just
);
2655 pS
->ReadUChar( nRows
);
2656 pS
->ReadUChar( nCols
);
2659 int nBytes
= ((nRows
+1)*2)/8;
2660 if (((nRows
+1)*2)%8)
2662 pS
->SeekRel(nBytes
);
2663 nBytes
= ((nCols
+1)*2)/8;
2664 if (((nCols
+1)*2)%8)
2666 pS
->SeekRel(nBytes
);
2667 rRet
.append(" matrix {\n");
2668 bool bRet
= HandleRecords( nLevel
+1, nSelector
, nVariation
, nRows
, nCols
);
2670 sal_Int32 nI
= rRet
.lastIndexOf('#');
2672 if (rRet
[nI
-1] != '#') //missing column
2675 rRet
.append("\n} ");
2679 bool MathType::HandleTemplate(int nLevel
, sal_uInt8
&rSelector
,
2680 sal_uInt8
&rVariation
, sal_Int32
&rLastTemplateBracket
)
2682 sal_uInt8 nOption
; //This appears utterly unused
2683 pS
->ReadUChar( rSelector
);
2684 pS
->ReadUChar( rVariation
);
2685 pS
->ReadUChar( nOption
);
2686 OSL_ENSURE(rSelector
< 48,"Selector out of range");
2687 if ((rSelector
>= 21) && (rSelector
<=26))
2689 OSL_ENSURE(nOption
< 2,"Option out of range");
2691 else if (rSelector
<= 12)
2693 OSL_ENSURE(nOption
< 3,"Option out of range");
2696 //For the (broken) case where one subscript template ends, and there is
2697 //another one after it, mathtype handles it as if the second one was
2698 //inside the first one and renders it as sub of sub
2700 if ( (rSelector
== 0xf) && (rLastTemplateBracket
!= -1) )
2703 for (sal_Int32 nI
= rLastTemplateBracket
+1; nI
< rRet
.getLength(); nI
++ )
2704 if (rRet
[nI
] != ' ')
2712 bool bRet
= HandleRecords( nLevel
+1, rSelector
, rVariation
);
2716 if (rLastTemplateBracket
< rRet
.getLength())
2717 rRet
.remove(rLastTemplateBracket
, 1);
2719 rLastTemplateBracket
= -1;
2721 if (rSelector
== 0xf)
2722 rLastTemplateBracket
= rRet
.lastIndexOf('}');
2724 rLastTemplateBracket
= -1;
2726 rSelector
= sal::static_int_cast
< sal_uInt8
>(-1);
2730 void MathType::HandleEmblishments()
2735 pS
->ReadUChar( nEmbel
);
2741 rRet
.append(" dot ");
2744 rRet
.append(" ddot ");
2747 rRet
.append(" dddot ");
2752 sPost
.append(" sup {}");
2753 nPostSup
= sPost
.getLength();
2755 sPost
.insert(nPostSup
-1," ' ");
2761 sPost
.append(" sup {}");
2762 nPostSup
= sPost
.getLength();
2764 sPost
.insert(nPostSup
-1," '' ");
2770 sPost
.append(" lsup {}");
2771 nPostlSup
= sPost
.getLength();
2773 sPost
.insert(nPostlSup
-1," ' ");
2777 rRet
.append(" tilde ");
2780 rRet
.append(" hat ");
2783 rRet
.append(" vec ");
2786 rRet
.append(" overstrike ");
2789 rRet
.append(" bar ");
2794 sPost
.append(" sup {}");
2795 nPostSup
= sPost
.getLength();
2797 sPost
.insert(nPostSup
-1," ''' ");
2801 rRet
.append(" breve ");
2804 OSL_ENSURE(nEmbel
< 21,"Embel out of range");
2812 void MathType::HandleSetSize()
2815 pS
->ReadUChar(nTemp
);
2819 pS
->ReadInt16( nLSize
);
2823 pS
->ReadUChar( nTemp
);
2825 pS
->ReadInt16( nDSize
);
2829 pS
->ReadUChar( nTemp
);
2835 bool MathType::HandleChar(sal_Int32
&rTextStart
, int &rSetSize
, int nLevel
,
2836 sal_uInt8 nTag
, sal_uInt8 nSelector
, sal_uInt8 nVariation
, bool bSilent
)
2838 sal_Unicode
nChar(0);
2843 //This is a candidate for function recognition, whatever
2847 sal_uInt8 nOldTypeFace
= nTypeFace
;
2848 pS
->ReadUChar( nTypeFace
);
2851 sal_uInt8
nChar8(0);
2852 pS
->ReadUChar( nChar8
);
2856 pS
->ReadUtf16( nChar
);
2859 bad character, old mathtype < 3 has these
2866 //A bit tricky, the character emblishments for
2867 //mathtype can all be listed after each other, in
2868 //starmath some must go before the character and some
2869 //must go after. In addition some of the emblishments
2870 //may repeated and in starmath some of these groups
2871 //must be gathered together. sPost is the portion that
2872 //follows the char and nPostSup and nPostlSup are the
2873 //indexes at which this class of emblishment is
2876 nPostSup
= nPostlSup
= 0;
2877 int nOriglen
=rRet
.getLength()-rTextStart
;
2878 rRet
.append(" {"); // #i24340# make what would be "vec {A}_n" become "{vec {A}}_n"
2879 if ((!bSilent
) && (nOriglen
> 1))
2881 bRet
= HandleRecords( nLevel
+1, nSelector
, nVariation
);
2887 TypeFaceToString(aStr
,nOldTypeFace
);
2888 rRet
.insert(std::min(rTextStart
, rRet
.getLength()), aStr
+ "\"");
2891 TypeFaceToString(aStr
,nTypeFace
);
2892 rRet
.append(aStr
+ "{");
2896 rTextStart
= rRet
.getLength();
2902 sal_Int32 nOldLen
= rRet
.getLength();
2904 HandleSize(nLSize
,nDSize
,rSetSize
) ||
2905 (nOldTypeFace
!= nTypeFace
)
2908 if ((nOldLen
- rTextStart
) > 1)
2910 rRet
.insert(nOldLen
, "\"");
2912 TypeFaceToString(aStr
,nOldTypeFace
);
2913 rRet
.insert(rTextStart
, aStr
+ "\"");
2915 rTextStart
= rRet
.getLength();
2917 nOldLen
= rRet
.getLength();
2918 if (!LookupChar(nChar
,rRet
,nVersion
,nTypeFace
))
2920 if (nOldLen
- rTextStart
> 1)
2922 rRet
.insert(nOldLen
, "\"");
2924 TypeFaceToString(aStr
,nOldTypeFace
);
2925 rRet
.insert(rTextStart
, aStr
+ "\"");
2927 rTextStart
= rRet
.getLength();
2929 lcl_PrependDummyTerm(rRet
, rTextStart
);
2932 if ((xfEMBELL(nTag
)) && (!bSilent
))
2934 rRet
.append("}}" + sPost
); // #i24340# make what would be "vec {A}_n" become "{vec {A}}_n"
2935 rTextStart
= rRet
.getLength();
2940 bool MathType::HandleLim(SmNode
*pNode
,int nLevel
)
2943 //Special case for the "lim" option in StarMath
2944 if ((pNode
->GetToken().eType
== TLIM
)
2945 || (pNode
->GetToken().eType
== TLIMSUP
)
2946 || (pNode
->GetToken().eType
== TLIMINF
)
2949 if (pNode
->GetSubNode(1))
2951 sal_uInt8 nVariation2
=HandleCScript(pNode
->GetSubNode(0),nullptr,
2954 pS
->WriteUChar( 0x0A );
2955 pS
->WriteUChar( LINE
); //line
2956 pS
->WriteUChar( CHAR
|0x10 );
2957 pS
->WriteUChar( 0x82 );
2958 pS
->WriteUInt16( 'l' );
2959 pS
->WriteUChar( CHAR
|0x10 );
2960 pS
->WriteUChar( 0x82 );
2961 pS
->WriteUInt16( 'i' );
2962 pS
->WriteUChar( CHAR
|0x10 );
2963 pS
->WriteUChar( 0x82 );
2964 pS
->WriteUInt16( 'm' );
2966 if (pNode
->GetToken().eType
== TLIMSUP
)
2968 pS
->WriteUChar( CHAR
); //some space
2969 pS
->WriteUChar( 0x98 );
2970 pS
->WriteUInt16( 0xEB04 );
2972 pS
->WriteUChar( CHAR
|0x10 );
2973 pS
->WriteUChar( 0x82 );
2974 pS
->WriteUInt16( 's' );
2975 pS
->WriteUChar( CHAR
|0x10 );
2976 pS
->WriteUChar( 0x82 );
2977 pS
->WriteUInt16( 'u' );
2978 pS
->WriteUChar( CHAR
|0x10 );
2979 pS
->WriteUChar( 0x82 );
2980 pS
->WriteUInt16( 'p' );
2982 else if (pNode
->GetToken().eType
== TLIMINF
)
2984 pS
->WriteUChar( CHAR
); //some space
2985 pS
->WriteUChar( 0x98 );
2986 pS
->WriteUInt16( 0xEB04 );
2988 pS
->WriteUChar( CHAR
|0x10 );
2989 pS
->WriteUChar( 0x82 );
2990 pS
->WriteUInt16( 'i' );
2991 pS
->WriteUChar( CHAR
|0x10 );
2992 pS
->WriteUChar( 0x82 );
2993 pS
->WriteUInt16( 'n' );
2994 pS
->WriteUChar( CHAR
|0x10 );
2995 pS
->WriteUChar( 0x82 );
2996 pS
->WriteUInt16( 'f' );
3000 pS
->WriteUChar( CHAR
); //some space
3001 pS
->WriteUChar( 0x98 );
3002 pS
->WriteUInt16( 0xEB04 );
3004 if (nVariation2
!= 0xff)
3006 pS
->WriteUChar( END
);
3007 pS
->WriteUChar( END
);
3009 HandleNodes(pNode
->GetSubNode(1),nLevel
+1);
3016 void MathType::HandleMAlign(SmNode
*pNode
,int nLevel
)
3018 sal_uInt8 nPushedHAlign
=nHAlign
;
3019 switch(pNode
->GetToken().eType
)
3031 size_t nSize
= pNode
->GetNumSubNodes();
3032 for (size_t i
= 0; i
< nSize
; ++i
)
3034 if (SmNode
*pTemp
= pNode
->GetSubNode(i
))
3035 HandleNodes(pTemp
,nLevel
+1);
3037 nHAlign
=nPushedHAlign
;
3040 void MathType::HandleMath(SmNode
*pNode
)
3042 if (pNode
->GetToken().eType
== TMLINE
)
3044 pS
->WriteUChar( END
);
3045 pS
->WriteUChar( LINE
);
3046 bIsReInterpBrace
=true;
3049 SmMathSymbolNode
*pTemp
= static_cast<SmMathSymbolNode
*>(pNode
);
3050 for(sal_Int32 i
=0;i
<pTemp
->GetText().getLength();i
++)
3052 sal_Unicode nArse
= SmTextNode::ConvertSymbolToUnicode(pTemp
->GetText()[i
]);
3053 if ((nArse
== 0x2224) || (nArse
== 0x2288) || (nArse
== 0x2285) ||
3056 pS
->WriteUChar( CHAR
|0x20 );
3058 else if (nPendingAttributes
&&
3059 (i
== ((pTemp
->GetText().getLength()+1)/2)-1))
3061 pS
->WriteUChar( 0x22 );
3064 pS
->WriteUChar( CHAR
); //char without formula recognition
3065 //The typeface seems to be MTEXTRA for unicode characters,
3066 //though how to determine when mathtype chooses one over
3067 //the other is unknown. This should do the trick
3070 if ( (nArse
== 0x2213) || (nArse
== 0x2218) ||
3071 (nArse
== 0x210F) || (
3072 (nArse
>= 0x22EE) && (nArse
<= 0x22FF)
3075 nBias
= 0xB; //typeface
3077 else if ((nArse
== 0x2F) || (nArse
== 0x2225))
3078 nBias
= 0x2; //typeface
3079 else if ((nArse
> 0x2000) || (nArse
== 0x00D7))
3080 nBias
= 0x6; //typeface
3081 else if (nArse
== 0x3d1)
3083 else if ((nArse
> 0xFF) && ((nArse
< 0x393) || (nArse
> 0x3c9)))
3084 nBias
= 0xB; //typeface
3086 nBias
= 0x3; //typeface
3088 pS
->WriteUChar( nSpec
+nBias
+128 ); //typeface
3090 if (nArse
== 0x2224)
3092 pS
->WriteUInt16( 0x7C );
3093 pS
->WriteUChar( EMBEL
);
3094 pS
->WriteUChar( 0x0A );
3095 pS
->WriteUChar( END
); //end embel
3096 pS
->WriteUChar( END
); //end embel
3098 else if (nArse
== 0x2225)
3099 pS
->WriteUInt16( 0xEC09 );
3100 else if (nArse
== 0xE421)
3101 pS
->WriteUInt16( 0x2265 );
3102 else if (nArse
== 0x230A)
3103 pS
->WriteUInt16( 0xF8F0 );
3104 else if (nArse
== 0x230B)
3105 pS
->WriteUInt16( 0xF8FB );
3106 else if (nArse
== 0xE425)
3107 pS
->WriteUInt16( 0x2264 );
3108 else if (nArse
== 0x226A)
3110 pS
->WriteUInt16( 0x3C );
3111 pS
->WriteUChar( CHAR
);
3112 pS
->WriteUChar( 0x98 );
3113 pS
->WriteUInt16( 0xEB01 );
3114 pS
->WriteUChar( CHAR
);
3115 pS
->WriteUChar( 0x86 );
3116 pS
->WriteUInt16( 0x3c );
3118 else if (nArse
== 0x2288)
3120 pS
->WriteUInt16( 0x2286 );
3121 pS
->WriteUChar( EMBEL
);
3122 pS
->WriteUChar( 0x0A );
3123 pS
->WriteUChar( END
); //end embel
3124 pS
->WriteUChar( END
); //end embel
3126 else if (nArse
== 0x2289)
3128 pS
->WriteUInt16( 0x2287 );
3129 pS
->WriteUChar( EMBEL
);
3130 pS
->WriteUChar( 0x0A );
3131 pS
->WriteUChar( END
); //end embel
3132 pS
->WriteUChar( END
); //end embel
3134 else if (nArse
== 0x2285)
3136 pS
->WriteUInt16( 0x2283 );
3137 pS
->WriteUChar( EMBEL
);
3138 pS
->WriteUChar( 0x0A );
3139 pS
->WriteUChar( END
); //end embel
3140 pS
->WriteUChar( END
); //end embel
3143 pS
->WriteUInt16( nArse
);
3145 nPendingAttributes
= 0;
3148 void MathType::HandleAttributes(SmNode
*pNode
,int nLevel
)
3150 int nOldPending
= 0;
3151 SmNode
*pTemp
= nullptr;
3152 SmTextNode
*pIsText
= nullptr;
3154 if (nullptr != (pTemp
= pNode
->GetSubNode(0)))
3156 pIsText
= static_cast<SmTextNode
*>(pNode
->GetSubNode(1));
3158 switch (pTemp
->GetToken().eType
)
3161 //there's just no way we can now handle any character
3162 //attributes (from mathtypes perspective) centered
3163 //over an expression but above template attributes
3164 //such as widevec and similar constructs
3165 //we have to drop them
3166 nOldPending
= StartTemplate(0x2f,0x01);
3168 case TCHECK
: //Not Exportable
3169 case TACUTE
: //Not Exportable
3170 case TGRAVE
: //Not Exportable
3171 case TCIRCLE
: //Not Exportable
3172 case TWIDEHARPOON
: //Not Exportable
3173 case TWIDETILDE
: //Not Exportable
3174 case TWIDEHAT
: //Not Exportable
3177 nOldPending
= StartTemplate(0x10);
3179 case TOVERLINE
: //If the next node is not text
3180 //or text with more than one char
3182 pIsText
->GetToken().eType
!= TTEXT
||
3183 pIsText
->GetText().getLength() > 1)
3184 nOldPending
= StartTemplate(0x11);
3187 nPendingAttributes
++;
3193 HandleNodes(pIsText
,nLevel
+1);
3197 switch (pTemp
->GetToken().eType
)
3201 EndTemplate(nOldPending
);
3205 pIsText
->GetToken().eType
!= TTEXT
||
3206 pIsText
->GetText().getLength() > 1)
3207 EndTemplate(nOldPending
);
3214 //if there was no suitable place to put the attribute,
3215 //then we have to just give up on it
3216 if (nPendingAttributes
)
3217 nPendingAttributes
--;
3220 if ((nInsertion
!= 0) && nullptr != (pTemp
= pNode
->GetSubNode(0)))
3222 auto nPos
= pS
->Tell();
3224 pS
->Seek(nInsertion
);
3225 switch(pTemp
->GetToken().eType
)
3227 case TACUTE
: //Not Exportable
3228 case TGRAVE
: //Not Exportable
3229 case TCIRCLE
: //Not Exportable
3232 pS
->WriteUChar( 2 );
3235 pS
->WriteUChar( 3 );
3238 pS
->WriteUChar( 4 );
3241 pS
->WriteUChar( 8 );
3244 pS
->WriteUChar( 9 );
3247 pS
->WriteUChar( 11 );
3250 pS
->WriteUChar( 16 );
3254 (pIsText
->GetToken().eType
== TTEXT
&&
3255 pIsText
->GetText().getLength() == 1))
3256 pS
->WriteUChar( 17 );
3259 pS
->WriteUChar( 20 );
3268 pS
->WriteUChar( 17 );
3271 pS
->WriteUChar( 2 );
3279 void MathType::HandleText(SmNode
*pNode
)
3281 SmTextNode
*pTemp
= static_cast<SmTextNode
*>(pNode
);
3282 for(sal_Int32 i
=0;i
<pTemp
->GetText().getLength();i
++)
3284 if (nPendingAttributes
&&
3285 (i
== ((pTemp
->GetText().getLength()+1)/2)-1))
3287 pS
->WriteUChar( 0x22 ); //char, with attributes right
3288 //after the character
3291 pS
->WriteUChar( CHAR
);
3293 sal_uInt8 nFace
= 0x1;
3294 if (pNode
->GetFont().GetItalic() == ITALIC_NORMAL
)
3296 else if (pNode
->GetFont().GetWeight() == WEIGHT_BOLD
)
3298 pS
->WriteUChar( nFace
+128 ); //typeface
3299 sal_uInt16 nChar
= pTemp
->GetText()[i
];
3300 pS
->WriteUInt16( SmTextNode::ConvertSymbolToUnicode(nChar
) );
3302 //Mathtype can only have these sort of character
3303 //attributes on a single character, starmath can put them
3304 //anywhere, when the entity involved is a text run this is
3305 //a large effort to place the character attribute on the
3306 //central mathtype character so that it does pretty much
3307 //what the user probably has in mind. The attributes
3308 //filled in here are dummy ones which are replaced in the
3309 //ATTRIBUTE handler if a suitable location for the
3310 //attributes was found here. Unfortunately it is
3311 //possible for starmath to place character attributes on
3312 //entities which cannot occur in mathtype e.g. a Summation
3313 //symbol so these attributes may be lost
3314 if (nPendingAttributes
&&
3315 (i
== ((pTemp
->GetText().getLength()+1)/2)-1))
3317 pS
->WriteUChar( EMBEL
);
3318 while (nPendingAttributes
)
3320 pS
->WriteUChar( 2 );
3321 //wedge the attributes in here and clear
3323 nPendingAttributes
--;
3325 nInsertion
=pS
->Tell();
3326 pS
->WriteUChar( END
); //end embel
3327 pS
->WriteUChar( END
); //end embel
3332 extern "C" SAL_DLLPUBLIC_EXPORT
bool TestImportMathType(SvStream
&rStream
)
3334 OUStringBuffer sText
;
3335 MathType
aEquation(sText
);
3339 bRet
= aEquation
.Parse(&rStream
);
3341 catch (const std::out_of_range
&)
3347 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */