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>
22 #include <filter/msfilter/classids.hxx>
23 #include <osl/diagnose.h>
24 #include <sfx2/docfile.hxx>
28 //These are the default MathType sizes
29 aSizeTable
.push_back(12);
30 aSizeTable
.push_back(8);
31 aSizeTable
.push_back(6);
32 aSizeTable
.push_back(24);
33 aSizeTable
.push_back(10);
34 aSizeTable
.push_back(12);
35 aSizeTable
.push_back(12);
38 These are the default MathType italic/bold settings If mathtype is changed
39 from its defaults, there is nothing we can do, as this information is not
40 stored in the document
43 for(sal_uInt8 i
=1;i
<=11;i
++)
59 aUserStyles
.insert(aFont
);
64 /*ToDo replace with table rather than switch, returns
65 sal_True in the case that the char is just a char, and
66 sal_False if the character is an operator which must not be
67 placed inside the quote sequence designed to protect
68 against being parsed as a keyword
70 General solution required to force starmath to handle
71 unicode math chars the way it handles its own math
72 chars rather than handle them as text as it will do
73 for the default case below, i.e. incorrect spacing
74 between math symbols and ordinary text e.g. 1=2 rather
77 bool MathType::LookupChar(sal_Unicode nChar
,OUString
&rRet
,sal_uInt8 nVersion
,
81 const char *pC
= nullptr;
109 if ((nVersion
< 3) && (nTypeFace
== 0x86))
113 rRet
+= OUStringLiteral1( nChar
);
118 if ((nVersion
< 3) && (nTypeFace
== 0x81))
120 rRet
+= OUStringLiteral1( nChar
);
124 if ((nVersion
< 3) && (nTypeFace
== 0x84))
126 rRet
+= OUStringLiteral1( nChar
);
130 if ((nVersion
< 3) && (nTypeFace
== 0x84))
132 rRet
+= OUStringLiteral1( nChar
);
136 if ((nVersion
< 3) && (nTypeFace
== 0x84))
138 rRet
+= OUStringLiteral1( nChar
);
142 if ((nVersion
< 3) && (nTypeFace
== 0x84))
144 rRet
+= OUStringLiteral1( nChar
);
148 if ((nVersion
< 3) && (nTypeFace
== 0x84))
150 rRet
+= OUStringLiteral1( nChar
);
154 if ((nVersion
< 3) && (nTypeFace
== 0x84))
156 rRet
+= OUStringLiteral1( nChar
);
160 if ((nVersion
< 3) && (nTypeFace
== 0x82))
162 rRet
+= OUStringLiteral1( nChar
);
166 if ((nVersion
< 3) && (nTypeFace
== 0x86))
170 rRet
+= OUStringLiteral1( nChar
);
175 if ((nVersion
< 3) && (nTypeFace
== 0x86))
179 rRet
+= OUStringLiteral1( nChar
);
184 if ((nVersion
< 3) && (nTypeFace
== 0x86))
188 rRet
+= OUStringLiteral1( nChar
);
193 if ((nVersion
< 3) && (nTypeFace
== 0x85))
197 rRet
+= OUStringLiteral1( nChar
);
352 pC
= " intersection ";
401 pC
= " preccurlyeq ";
404 pC
= " succcurlyeq ";
445 rRet
+= " " + OUStringLiteral1( nChar
) + " ";
499 case 0xeb01: //no space
500 case 0xeb08: //normal space
503 case 0xef04: //tiny space
504 case 0xef05: //tiny space
505 case 0xeb02: //small space
506 case 0xeb04: //medium space
509 case 0xeb05: //large space
516 rRet
+= OUStringLiteral1( nChar
);
521 rRet
+= OUString::createFromAscii( pC
);
525 void MathTypeFont::AppendStyleToText(OUString
&rRet
)
527 const char *pC
= nullptr;
544 rRet
+= OUString::createFromAscii( pC
);
547 void MathType::TypeFaceToString(OUString
&rTxt
,sal_uInt8 nFace
)
549 MathTypeFont
aFont(nFace
);
550 MathTypeFontSet::iterator aItr
= aUserStyles
.find(aFont
);
551 if (aItr
!= aUserStyles
.end())
552 aFont
.nStyle
= aItr
->nStyle
;
553 aFont
.AppendStyleToText(rTxt
);
556 bool MathType::Parse(SotStorage
*pStor
)
558 tools::SvRef
<SotStorageStream
> xSrc
= pStor
->OpenSotStream(
560 StreamMode::STD_READ
);
561 if ( (!xSrc
.Is()) || (SVSTREAM_OK
!= xSrc
->GetError()))
564 pS
->SetEndian( SvStreamEndian::LITTLE
);
568 pS
->ReadUChar( nVersion
);
569 pS
->ReadUChar( nPlatform
);
570 pS
->ReadUChar( nProduct
);
571 pS
->ReadUChar( nProdVersion
);
572 pS
->ReadUChar( nProdSubVersion
);
574 if (nVersion
> 3) // allow only supported versions of MathType to be parsed
577 bool bRet
= HandleRecords(0);
578 //little crude hack to close occasionally open expressions
579 //a sophisticated system to determine what expressions are
580 //opened is required, but this is as much work as rewriting
581 //starmaths internals.
587 //sigh, theres no point! MathType (in some bizarre subvarient) pads
588 //the end of the formula with ENDs (0)'s
589 sal_uLong nEnd
= pS
->Tell();
590 SAL_WARN_IF(nEnd
== pS
->Seek(STREAM_SEEK_TO_END
), "starmath", "Possibly unfully parsed formula");
595 static void lcl_PrependDummyTerm(OUString
&rRet
, sal_Int32
&rTextStart
)
597 if ((rTextStart
< rRet
.getLength()) &&
598 (rRet
[rTextStart
] == '=') &&
599 ((rTextStart
== 0) || (rRet
[ rTextStart
-1 ] == '{'))
602 rRet
= rRet
.replaceAt(rTextStart
,0," {}");
607 static void lcl_AppendDummyTerm(OUString
&rRet
)
610 for(int nI
=rRet
.getLength()-1;nI
>= 0; nI
--)
612 sal_Int32 nIdx
= sal::static_int_cast
< sal_Int32
>(nI
);
613 sal_Unicode nChar
= rRet
[nIdx
];
616 if (rRet
[nIdx
] != '{')
620 if (!bOk
) //No term, use dummy
624 void MathType::HandleNudge()
627 pS
->ReadUChar( nXNudge
);
629 pS
->ReadUChar( nYNudge
);
630 if (nXNudge
== 128 && nYNudge
== 128)
632 sal_uInt16 nXLongNudge
;
633 sal_uInt16 nYLongNudge
;
634 pS
->ReadUInt16( nXLongNudge
);
635 pS
->ReadUInt16( nYLongNudge
);
639 /* Fabulously complicated as many tokens have to be reordered and generally
640 * moved around from mathtypes paradigm to starmaths. */
641 bool MathType::HandleRecords(int nLevel
, sal_uInt8 nSelector
,
642 sal_uInt8 nVariation
, int nMatrixRows
, int nMatrixCols
)
644 sal_uInt8 nTag
,nRecord
;
645 sal_uInt8 nTabType
,nTabStops
;
646 sal_uInt16 nTabOffset
;
650 OUString sPush
,sMainTerm
;
651 int nSetSize
=0,nSetAlign
=0;
652 int nCurRow
=0,nCurCol
=0;
653 bool bOpenString
=false;
654 sal_Int32 nTextStart
= 0;
655 sal_Int32 nSubSupStartPos
= 0;
656 sal_Int32 nLastTemplateBracket
=-1;
662 pS
->ReadUChar( nTag
);
665 /*MathType strings can of course include words which
666 *are StarMath keywords, the simplest solution is
667 to escape strings of greater than len 1 with double
668 quotes to avoid scanning the TokenTable for matches
670 Unfortunately it may turn out that the string gets
671 split during the handling of a character emblishment
672 so this special case must be handled in the
673 character handler case 2:
675 if ((nRecord
== CHAR
) && (!bOpenString
))
678 nTextStart
= rRet
.getLength();
680 else if ((nRecord
!= CHAR
) && (bOpenString
))
683 if ((rRet
.getLength() - nTextStart
) > 1)
686 TypeFaceToString(aStr
,nTypeFace
);
688 rRet
= rRet
.replaceAt(nTextStart
,0,aStr
);
691 else if (nRecord
== END
&& !rRet
.isEmpty())
693 sal_Unicode cChar
= 0;
694 sal_Int32 nI
= rRet
.getLength()-1;
695 while (nI
&& ((cChar
= rRet
[nI
]) == ' '))
697 if ((cChar
== '=') || (cChar
== '+') || (cChar
== '-'))
710 rRet
+= "\nnewline\n";
718 else if (nVariation
==1)
719 rRet
+= " \\langle ";
724 else if (nVariation
==1)
728 if ((nVariation
==0) || (nVariation
==1))
729 rRet
+= " left lbrace ";
731 rRet
+= " left none ";
736 else if (nVariation
==1)
746 else if (nVariation
==1)
752 else if (nVariation
==1)
753 rRet
+= " \\ldline ";
756 if (nVariation
== 0 || nVariation
== 1)
757 rRet
+= " left lfloor ";
758 else if (nVariation
==1)
759 rRet
+= " left none ";
764 else if (nVariation
==1)
798 nSubSupStartPos
= rRet
.getLength();
799 if ((nVariation
== 0) ||
800 ((nVariation
== 2) && (nPart
==1)))
802 lcl_AppendDummyTerm(rRet
);
805 else if ((nVariation
== 1) ||
806 ((nVariation
== 2) && (nPart
==0)))
808 lcl_AppendDummyTerm(rRet
);
815 rRet
+= " {underline ";
816 else if (nVariation
== 1)
817 rRet
+= " {underline underline ";
822 rRet
+= " {overline ";
823 else if (nVariation
== 1)
824 rRet
+= " {overline overline ";
831 rRet
+= " widevec ";//left arrow above
832 else if (nVariation
== 1)
833 rRet
+= " widevec ";//left arrow below
841 rRet
+= " widevec ";//right arrow above
842 else if (nVariation
== 1)
843 rRet
+= " widevec ";//right arrow below
851 rRet
+= " widevec ";//double arrow above
852 else if (nVariation
== 1)
853 rRet
+= " widevec ";//double arrow below
860 if ((nVariation
== 3) || (nVariation
== 4))
864 if ( (nVariation
!= 0) && (nVariation
!= 3))
870 if (((nVariation
== 1) ||
871 (nVariation
== 4)) && (nPart
==1))
873 else if ((nVariation
== 2) && (nPart
==2))
875 else if ((nVariation
== 2) && (nPart
==1))
882 if ((nVariation
== 2) || (nVariation
== 3))
886 if ( (nVariation
!= 0) && (nVariation
!= 2))
892 if (((nVariation
== 1) ||
893 (nVariation
== 3)) && (nPart
==1))
900 if ((nVariation
== 2) || (nVariation
== 3))
904 if ( (nVariation
!= 0) && (nVariation
!= 2))
910 if (((nVariation
== 1) ||
911 (nVariation
== 3)) && (nPart
==1))
925 if (((nVariation
== 1) ||
926 (nVariation
== 2)) && (nPart
==1))
928 else if ((nVariation
== 0) && (nPart
==2))
930 else if ((nVariation
== 0) && (nPart
==1))
976 if ((nVariation
== 0) && (nPart
==1))
978 else if ((nVariation
== 1) && (nPart
==2))
980 else if ((nVariation
== 1) && (nPart
==1))
991 if ((nVariation
== 0) && (nPart
==1))
993 else if ((nVariation
== 1) && (nPart
==2))
995 else if ((nVariation
== 1) && (nPart
==1))
1003 if (nVariation
!= 2)
1009 if ((nVariation
== 0) && (nPart
==1))
1011 else if ((nVariation
== 1) && (nPart
==2))
1013 else if ((nVariation
== 1) && (nPart
==1))
1024 if ((nVariation
== 0) && (nPart
==1))
1026 else if ((nVariation
== 1) && (nPart
==2))
1028 else if ((nVariation
== 1) && (nPart
==1))
1036 if (nVariation
!= 2)
1042 if ((nVariation
== 0) && (nPart
==1))
1044 else if ((nVariation
== 1) && (nPart
==2))
1046 else if ((nVariation
== 1) && (nPart
==1))
1057 if ((nVariation
== 0) && (nPart
==1))
1059 else if ((nVariation
== 1) && (nPart
==2))
1061 else if ((nVariation
== 1) && (nPart
==1))
1068 rRet
+= " union"; //union
1069 if (nVariation
!= 2)
1075 if ((nVariation
== 0) && (nPart
==1))
1077 else if ((nVariation
== 1) && (nPart
==2))
1079 else if ((nVariation
== 1) && (nPart
==1))
1086 rRet
+= " union"; //union
1090 if ((nVariation
== 0) && (nPart
==1))
1092 else if ((nVariation
== 1) && (nPart
==2))
1094 else if ((nVariation
== 1) && (nPart
==1))
1101 rRet
+= " intersect"; //intersect
1102 if (nVariation
!= 2)
1108 if ((nVariation
== 0) && (nPart
==1))
1110 else if ((nVariation
== 1) && (nPart
==2))
1112 else if ((nVariation
== 1) && (nPart
==1))
1119 rRet
+= " intersect"; //intersect
1123 if ((nVariation
== 0) && (nPart
==1))
1125 else if ((nVariation
== 1) && (nPart
==2))
1127 else if ((nVariation
== 1) && (nPart
==1))
1132 if ((nVariation
== 0) && (nPart
==1))
1134 else if ((nVariation
== 1) && (nPart
==1))
1136 else if ((nVariation
== 2) && (nPart
==1))
1138 else if ((nVariation
== 2) && (nPart
==2))
1143 if (nVariation
== 0)
1152 if (nVariation
== 0)
1159 if (nVariation
== 1)
1160 rRet
+= "overline ";
1171 if ((nVariation
== 0) && (nPart
==0))
1173 else if ((nVariation
== 2) && (nPart
==1))
1175 else if ((nVariation
== 1) && (nPart
==0))
1177 else if ((nVariation
== 2) && (nPart
==0))
1187 if ((nVariation
== 0) && (nPart
==0))
1189 else if ((nVariation
== 2) && (nPart
==1))
1191 else if ((nVariation
== 1) && (nPart
==0))
1193 else if ((nVariation
== 2) && (nPart
==0))
1200 if ((nVariation
== 0)
1201 || ((nVariation
== 2) && (nPart
==1)))
1203 else if ((nVariation
== 1)
1204 || ((nVariation
== 2) && (nPart
==0)))
1214 else if (nVariation
==1)
1216 rRet
+= " \\langle ";
1219 else if (nVariation
==2)
1221 rRet
+= " \\lline ";
1226 if (nVariation
== 0)
1227 rRet
+= " widevec ";//left below
1228 else if (nVariation
== 1)
1229 rRet
+= " widevec ";//right below
1230 else if (nVariation
== 2)
1231 rRet
+= " widevec ";//double headed below
1235 if (nVariation
== 0)
1236 rRet
+= " widevec ";//left above
1237 else if (nVariation
== 1)
1238 rRet
+= " widevec ";//right above
1239 else if (nVariation
== 2)
1240 rRet
+= " widevec ";//double headed above
1246 sal_Int16 nOldCurSize
=nCurSize
;
1247 sal_Int32 nSizeStartPos
= rRet
.getLength();
1248 HandleSize( nLSize
, nDSize
, nSetSize
);
1249 bRet
= HandleRecords( nLevel
+1 );
1253 sal_Int32 nI
= rRet
.lastIndexOf('{');
1256 for(nI
=nI
+1;nI
<rRet
.getLength();nI
++)
1257 if (rRet
[nI
] != ' ')
1269 rRet
= rRet
.replaceAt( nSizeStartPos
, rRet
.getLength(), "" );
1271 nCurSize
=nOldCurSize
;
1275 HandleMatrixSeparator(nMatrixRows
,nMatrixCols
,
1283 else if (nVariation
==2)
1284 rRet
+= " \\rangle ";
1289 else if (nVariation
==2)
1293 if ((nVariation
==0) || (nVariation
==2))
1294 rRet
+= " right rbrace ";
1296 rRet
+= " right none ";
1301 else if (nVariation
==2)
1307 else if (nVariation
==2)
1308 rRet
+= " \\rline ";
1313 else if (nVariation
==2)
1314 rRet
+= " \\rdline ";
1317 if (nVariation
== 0 || nVariation
== 2)
1318 rRet
+= " right rfloor ";
1319 else if (nVariation
==2)
1320 rRet
+= " right none ";
1325 else if (nVariation
==2)
1326 rRet
+= " \\rceil ";
1338 if (nVariation
== 1)
1374 ((nVariation
== 2) || (nVariation
== 1)))
1378 sal_Int32 nI
= rRet
.lastIndexOf('{');
1381 for(nI
=nI
+1;nI
<rRet
.getLength();nI
++)
1382 if (rRet
[nI
] != ' ')
1394 rRet
= rRet
.replaceAt(nSubSupStartPos
, rRet
.getLength(), "");
1400 ((nVariation
== 2) || (nVariation
== 1)))
1428 rRet
+= "overbrace";
1437 rRet
+= "underbrace";
1444 else if ((nPart
==1) &&
1445 ((nVariation
== 2) || (nVariation
== 1)))
1452 if (nVariation
== 0)
1482 rRet
+= "wideslash";
1501 if (nVariation
!= 2)
1508 else if ((nPart
== 1) && (nVariation
== 0))
1515 else if ((nPart
== 1) && (nVariation
== 1))
1517 else if ((nPart
== 2) && (nVariation
== 1))
1530 if ((nVariation
!= 0) && (nVariation
!= 3))
1537 else if ((nPart
== 1) &&
1538 ((nVariation
== 1) || (nVariation
==4)))
1545 else if ((nPart
== 1) && (nVariation
== 2))
1547 else if ((nPart
== 2) && (nVariation
== 2))
1561 if ((nVariation
!= 0) && (nVariation
!= 2))
1568 else if ((nPart
== 1) &&
1569 ((nVariation
== 1) || (nVariation
==3)))
1586 else if ((nPart
== 1) &&
1587 ((nVariation
== 1) || (nVariation
==2)))
1594 else if ((nPart
== 1) && (nVariation
== 0))
1596 else if ((nPart
== 2) && (nVariation
== 0))
1614 else if (nPart
== 1)
1628 ((nVariation
== 0) || (nVariation
== 1)))
1634 else if ((nPart
== 0) && (nVariation
== 2))
1636 else if ((nPart
== 1) && (nVariation
== 2))
1642 else if ((nPart
== 2) || ((((nPart
== 1) &&
1643 (nVariation
== 0)) || (nVariation
== 1))))
1656 newline
--; //there is another term to arrive
1662 else if (nVariation
==1)
1663 rRet
+= " \\lline ";
1664 else if (nVariation
==2)
1665 rRet
+= " \\rangle ";
1671 bSilent
= true; //Skip the optional brackets and/or
1672 //symbols that follow some of these
1673 //records. Foo Data.
1675 /*In matrices and piles we cannot separate equation
1676 *lines with the newline keyword*/
1685 bRet
= HandleChar( nTextStart
, nSetSize
, nLevel
, nTag
, nSelector
, nVariation
, bSilent
);
1690 bRet
= HandleTemplate( nLevel
, nSelector
, nVariation
, nLastTemplateBracket
);
1695 bRet
= HandlePile( nSetAlign
, nLevel
, nSelector
, nVariation
);
1696 HandleMatrixSeparator( nMatrixRows
, nMatrixCols
, nCurCol
, nCurRow
);
1701 bRet
= HandleMatrix( nLevel
, nSelector
, nVariation
);
1702 HandleMatrixSeparator( nMatrixRows
, nMatrixCols
, nCurCol
, nCurRow
);
1707 HandleEmblishments();
1710 pS
->ReadUChar( nTabStops
);
1711 for (i
=0;i
<nTabStops
;i
++)
1713 pS
->ReadUChar( nTabType
);
1714 pS
->ReadUInt16( nTabOffset
);
1716 SAL_WARN("starmath", "Not seen in the wild Equation Ruler Field");
1721 pS
->ReadUChar( aFont
.nTface
);
1723 The typeface number is the negative (which makes it
1724 positive) of the typeface value (unbiased) that appears in
1725 CHAR records that might follow a given FONT record
1727 aFont
.nTface
= 128-aFont
.nTface
;
1728 pS
->ReadUChar( aFont
.nStyle
);
1729 aUserStyles
.insert(aFont
);
1730 std::vector
<sal_Char
> aSeq
;
1734 pS
->ReadChar( nChar8
);
1737 aSeq
.push_back(nChar8
);
1739 // Do nothing to the font name now in aSeq!?
1757 while (nRecord
!= END
&& !pS
->IsEof());
1766 /*Simply determine if we are at the end of a record or the end of a line,
1767 *with fiddley logic to see if we are in a matrix or a pile or neither
1769 Note we cannot tell until after the event that this is the last entry
1770 of a pile, so we must strip the last separator of a pile after this
1771 is detected in the PILE handler
1773 void MathType::HandleMatrixSeparator(int nMatrixRows
,int nMatrixCols
,
1774 int &rCurCol
,int &rCurRow
)
1778 if (rCurCol
== nMatrixCols
-1)
1780 if (rCurRow
!= nMatrixRows
-1)
1782 if (nMatrixRows
!=-1)
1791 if (nMatrixRows
!=-1)
1799 /* set the alignment of the following term, but starmath currently
1800 * cannot handle vertical alignment */
1801 void MathType::HandleAlign(sal_uInt8 nHorAlign
, sal_uInt8
/*nVAlign*/, int &rSetAlign
)
1819 /* set size of text, complexity due to overuse of signedness as a flag
1820 * indicator by mathtype file format*/
1821 bool MathType::HandleSize(sal_Int16 nLstSize
,sal_Int16 nDefSize
, int &rSetSize
)
1823 const sal_Int16 nDefaultSize
= 12;
1827 if ((-nLstSize
/32 != nDefaultSize
) && (-nLstSize
/32 != nCurSize
))
1835 if (-nLstSize
/32 != nLastSize
)
1837 nLastSize
= nCurSize
;
1839 rRet
+= OUString::number(-nLstSize
/32);
1844 nCurSize
= -nLstSize
/32;
1849 /*sizetable should theoreticaly be filled with the default sizes
1850 *of the various font groupings matching starmaths equivalents
1851 in aTypeFaces, and a test would be done to see if the new font
1852 size would be the same as what starmath would have chosen for
1853 itself anyway in which case the size setting could be ignored*/
1854 nLstSize
= aSizeTable
.at(nLstSize
);
1855 nLstSize
= nLstSize
+ nDefSize
;
1856 if (nLstSize
!= nCurSize
)
1864 if (nLstSize
!= nLastSize
)
1866 nLastSize
= nCurSize
;
1868 rRet
+= OUString::number(nLstSize
);
1873 nCurSize
= nLstSize
;
1879 bool MathType::ConvertFromStarMath( SfxMedium
& rMedium
)
1884 SvStream
*pStream
= rMedium
.GetOutStream();
1887 tools::SvRef
<SotStorage
> pStor
= new SotStorage( pStream
, false );
1889 SvGlobalName
aGName(MSO_EQUATION3_CLASSID
);
1890 pStor
->SetClass( aGName
, SotClipboardFormatId::NONE
, "Microsoft Equation 3.0");
1892 static sal_uInt8
const aCompObj
[] = {
1893 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
1894 0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0xCE, 0x02, 0x00,
1895 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00,
1896 0x00, 0x00, 0x00, 0x46, 0x17, 0x00, 0x00, 0x00,
1897 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66,
1898 0x74, 0x20, 0x45, 0x71, 0x75, 0x61, 0x74, 0x69,
1899 0x6F, 0x6E, 0x20, 0x33, 0x2E, 0x30, 0x00, 0x0C,
1900 0x00, 0x00, 0x00, 0x44, 0x53, 0x20, 0x45, 0x71,
1901 0x75, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x0B,
1902 0x00, 0x00, 0x00, 0x45, 0x71, 0x75, 0x61, 0x74,
1903 0x69, 0x6F, 0x6E, 0x2E, 0x33, 0x00, 0xF4, 0x39,
1904 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1905 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1907 tools::SvRef
<SotStorageStream
> xStor( pStor
->OpenSotStream("\1CompObj"));
1908 xStor
->WriteBytes(aCompObj
, sizeof(aCompObj
));
1910 static sal_uInt8
const aOle
[] = {
1911 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
1912 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1913 0x00, 0x00, 0x00, 0x00
1915 tools::SvRef
<SotStorageStream
> xStor2( pStor
->OpenSotStream("\1Ole"));
1916 xStor2
->WriteBytes(aOle
, sizeof(aOle
));
1920 tools::SvRef
<SotStorageStream
> xSrc
= pStor
->OpenSotStream("Equation Native");
1921 if ( (!xSrc
.Is()) || (SVSTREAM_OK
!= xSrc
->GetError()))
1925 pS
->SetEndian( SvStreamEndian::LITTLE
);
1927 pS
->SeekRel(EQNOLEFILEHDR_SIZE
); //Skip 28byte Header and fill it in later
1928 pS
->WriteUChar( 0x03 );
1929 pS
->WriteUChar( 0x01 );
1930 pS
->WriteUChar( 0x01 );
1931 pS
->WriteUChar( 0x03 );
1932 pS
->WriteUChar( 0x00 );
1933 sal_uInt32 nSize
= pS
->Tell();
1934 nPendingAttributes
=0;
1936 HandleNodes(pTree
, 0);
1937 pS
->WriteUChar( END
);
1939 nSize
= pS
->Tell()-nSize
;
1941 EQNOLEFILEHDR
aHdr(nSize
+4+1);
1951 void MathType::HandleNodes(SmNode
*pNode
,int nLevel
)
1953 switch(pNode
->GetType())
1956 HandleAttributes(pNode
,nLevel
);
1959 HandleText(pNode
,nLevel
);
1961 case NVERTICAL_BRACE
:
1962 HandleVerticalBrace(pNode
,nLevel
);
1965 HandleBrace(pNode
,nLevel
);
1968 HandleOperator(pNode
,nLevel
);
1971 HandleFractions(pNode
,nLevel
);
1974 HandleRoot(pNode
,nLevel
);
1978 SmTextNode
*pText
= static_cast<SmTextNode
*>(pNode
);
1979 //if the token str and the result text are the same then this
1980 //is to be seen as text, else assume it's a mathchar
1981 if (pText
->GetText() == pText
->GetToken().aText
)
1982 HandleText(pText
,nLevel
);
1984 HandleMath(pText
,nLevel
);
1989 HandleMath(pNode
,nLevel
);
1992 HandleSubSupScript(pNode
,nLevel
);
1996 sal_uInt16 nSize
= pNode
->GetNumSubNodes();
1997 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
1998 if (SmNode
*pTemp
= pNode
->GetSubNode(i
))
1999 HandleNodes(pTemp
,nLevel
+1);
2003 //Root Node, PILE equivalent, i.e. vertical stack
2004 HandleTable(pNode
,nLevel
);
2007 HandleSmMatrix(static_cast<SmMatrixNode
*>(pNode
),nLevel
);
2011 pS
->WriteUChar( 0x0a );
2012 pS
->WriteUChar( LINE
);
2013 sal_uInt16 nSize
= pNode
->GetNumSubNodes();
2014 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
2015 if (SmNode
*pTemp
= pNode
->GetSubNode(i
))
2016 HandleNodes(pTemp
,nLevel
+1);
2017 pS
->WriteUChar( END
);
2021 HandleMAlign(pNode
,nLevel
);
2024 pS
->WriteUChar( CHAR
);
2025 pS
->WriteUChar( 0x98 );
2026 if (pNode
->GetToken().eType
== TSBLANK
)
2027 pS
->WriteUInt16( 0xEB04 );
2029 pS
->WriteUInt16( 0xEB05 );
2033 sal_uInt16 nSize
= pNode
->GetNumSubNodes();
2034 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
2035 if (SmNode
*pTemp
= pNode
->GetSubNode(i
))
2036 HandleNodes(pTemp
,nLevel
+1);
2043 int MathType::StartTemplate(sal_uInt16 nSelector
,sal_uInt16 nVariation
)
2045 int nOldPending
=nPendingAttributes
;
2046 pS
->WriteUChar( TMPL
); //Template
2047 pS
->WriteUChar( nSelector
); //selector
2048 pS
->WriteUChar( nVariation
); //variation
2049 pS
->WriteUChar( 0x00 ); //options
2050 pS
->WriteUChar( LINE
);
2051 //theres just no way we can now handle any character
2052 //attributes (from mathtypes perspective) centered
2053 //over an expression but above template attribute
2054 //such as widevec and similar constructs
2055 //we have to drop them
2056 nPendingAttributes
=0;
2060 void MathType::EndTemplate(int nOldPendingAttributes
)
2062 pS
->WriteUChar( END
); //end line
2063 pS
->WriteUChar( END
); //end template
2064 nPendingAttributes
=nOldPendingAttributes
;
2068 void MathType::HandleSmMatrix(SmMatrixNode
*pMatrix
,int nLevel
)
2070 pS
->WriteUChar( MATRIX
);
2071 pS
->WriteUChar( 0x00 ); //vAlign ?
2072 pS
->WriteUChar( 0x00 ); //h_just
2073 pS
->WriteUChar( 0x00 ); //v_just
2074 pS
->WriteUChar( pMatrix
->GetNumRows() ); //v_just
2075 pS
->WriteUChar( pMatrix
->GetNumCols() ); //v_just
2076 int nBytes
=(pMatrix
->GetNumRows()+1)*2/8;
2077 if (((pMatrix
->GetNumRows()+1)*2)%8)
2079 for (int j
= 0; j
< nBytes
; j
++)
2080 pS
->WriteUChar( 0x00 ); //row_parts
2081 nBytes
=(pMatrix
->GetNumCols()+1)*2/8;
2082 if (((pMatrix
->GetNumCols()+1)*2)%8)
2084 for (int k
= 0; k
< nBytes
; k
++)
2085 pS
->WriteUChar( 0x00 ); //col_parts
2086 sal_uInt16 nSize
= pMatrix
->GetNumSubNodes();
2087 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
2088 if (SmNode
*pTemp
= pMatrix
->GetSubNode(i
))
2090 pS
->WriteUChar( LINE
); //line
2091 HandleNodes(pTemp
,nLevel
+1);
2092 pS
->WriteUChar( END
); //end line
2094 pS
->WriteUChar( END
);
2098 //Root Node, PILE equivalent, i.e. vertical stack
2099 void MathType::HandleTable(SmNode
*pNode
,int nLevel
)
2101 sal_uInt16 nSize
= pNode
->GetNumSubNodes();
2102 //The root of the starmath is a table, if
2103 //we convert this them each iteration of
2104 //conversion from starmath to mathtype will
2105 //add an extra unnecessary level to the
2106 //mathtype output stack which would grow
2107 //without bound in a multi step conversion
2110 pS
->WriteUChar( 0x0A ); //initial size
2112 if ( nLevel
|| (nSize
>1))
2114 pS
->WriteUChar( PILE
);
2115 pS
->WriteUChar( nHAlign
); //vAlign ?
2116 pS
->WriteUChar( 0x01 ); //hAlign
2119 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
2120 if (SmNode
*pTemp
= pNode
->GetSubNode(i
))
2122 pS
->WriteUChar( LINE
);
2123 HandleNodes(pTemp
,nLevel
+1);
2124 pS
->WriteUChar( END
);
2126 if (nLevel
|| (nSize
>1))
2127 pS
->WriteUChar( END
);
2131 void MathType::HandleRoot(SmNode
*pNode
,int nLevel
)
2134 pS
->WriteUChar( TMPL
); //Template
2135 pS
->WriteUChar( 0x0D ); //selector
2136 if (pNode
->GetSubNode(0))
2137 pS
->WriteUChar( 0x01 ); //variation
2139 pS
->WriteUChar( 0x00 ); //variation
2140 pS
->WriteUChar( 0x00 ); //options
2142 if (nullptr != (pTemp
= pNode
->GetSubNode(2)))
2144 pS
->WriteUChar( LINE
); //line
2145 HandleNodes(pTemp
,nLevel
+1);
2146 pS
->WriteUChar( END
);
2149 if (nullptr != (pTemp
= pNode
->GetSubNode(0)))
2151 pS
->WriteUChar( LINE
); //line
2152 HandleNodes(pTemp
,nLevel
+1);
2153 pS
->WriteUChar( END
);
2156 pS
->WriteUChar( LINE
|0x10 ); //dummy line
2159 pS
->WriteUChar( END
);
2162 sal_uInt8
MathType::HandleCScript(SmNode
*pNode
,SmNode
*pContent
,int nLevel
,
2163 sal_uLong
*pPos
,bool bTest
)
2165 sal_uInt8 nVariation2
=0xff;
2167 if (bTest
&& pNode
->GetSubNode(CSUP
+1))
2170 if (pNode
->GetSubNode(CSUB
+1))
2173 else if (pNode
->GetSubNode(CSUB
+1))
2176 if (nVariation2
!=0xff)
2180 pS
->WriteUChar( TMPL
); //Template
2181 pS
->WriteUChar( 0x2B ); //selector
2182 pS
->WriteUChar( nVariation2
);
2183 pS
->WriteUChar( 0x00 ); //options
2187 pS
->WriteUChar( LINE
); //line
2188 HandleNodes(pContent
,nLevel
+1);
2189 pS
->WriteUChar( END
); //line
2192 pS
->WriteUChar( LINE
|0x10 );
2194 pS
->WriteUChar( 0x0B );
2197 if (nullptr != (pTemp
= pNode
->GetSubNode(CSUB
+1)))
2199 pS
->WriteUChar( LINE
); //line
2200 HandleNodes(pTemp
,nLevel
+1);
2201 pS
->WriteUChar( END
); //line
2204 pS
->WriteUChar( LINE
|0x10 );
2205 if (bTest
&& nullptr != (pTemp
= pNode
->GetSubNode(CSUP
+1)))
2207 pS
->WriteUChar( LINE
); //line
2208 HandleNodes(pTemp
,nLevel
+1);
2209 pS
->WriteUChar( END
); //line
2212 pS
->WriteUChar( LINE
|0x10 );
2219 Sub and Sup scripts and another problem area, StarMath
2220 can have all possible options used at the same time, whereas
2221 Mathtype cannot. The ordering of the nodes for each system
2222 is quite different as well leading to some complexity
2224 void MathType::HandleSubSupScript(SmNode
*pNode
,int nLevel
)
2226 sal_uInt8 nVariation
=0xff;
2227 if (pNode
->GetSubNode(LSUP
+1))
2230 if (pNode
->GetSubNode(LSUB
+1))
2233 else if ( nullptr != pNode
->GetSubNode(LSUB
+1) )
2237 if (nVariation
!=0xff)
2239 pS
->WriteUChar( TMPL
); //Template
2240 pS
->WriteUChar( 0x2c ); //selector
2241 pS
->WriteUChar( nVariation
);
2242 pS
->WriteUChar( 0x00 ); //options
2243 pS
->WriteUChar( 0x0B );
2245 if (nullptr != (pTemp
= pNode
->GetSubNode(LSUB
+1)))
2247 pS
->WriteUChar( LINE
); //line
2248 HandleNodes(pTemp
,nLevel
+1);
2249 pS
->WriteUChar( END
); //line
2252 pS
->WriteUChar( LINE
|0x10 );
2253 if (nullptr != (pTemp
= pNode
->GetSubNode(LSUP
+1)))
2255 pS
->WriteUChar( LINE
); //line
2256 HandleNodes(pTemp
,nLevel
+1);
2257 pS
->WriteUChar( END
); //line
2260 pS
->WriteUChar( LINE
|0x10 );
2261 pS
->WriteUChar( END
);
2266 sal_uInt8 nVariation2
=HandleCScript(pNode
,nullptr,nLevel
);
2268 if (nullptr != (pTemp
= pNode
->GetSubNode(0)))
2270 HandleNodes(pTemp
,nLevel
+1);
2273 if (nVariation2
!= 0xff)
2274 pS
->WriteUChar( END
);
2276 if (nullptr != (pNode
->GetSubNode(RSUP
+1)))
2279 if (pNode
->GetSubNode(RSUB
+1))
2282 else if (nullptr != pNode
->GetSubNode(RSUB
+1))
2285 if (nVariation
!=0xff)
2287 pS
->WriteUChar( TMPL
); //Template
2288 pS
->WriteUChar( 0x0F ); //selector
2289 pS
->WriteUChar( nVariation
);
2290 pS
->WriteUChar( 0x00 ); //options
2291 pS
->WriteUChar( 0x0B );
2293 if (nullptr != (pTemp
= pNode
->GetSubNode(RSUB
+1)))
2295 pS
->WriteUChar( LINE
); //line
2296 HandleNodes(pTemp
,nLevel
+1);
2297 pS
->WriteUChar( END
); //line
2300 pS
->WriteUChar( LINE
|0x10 );
2301 if (nullptr != (pTemp
= pNode
->GetSubNode(RSUP
+1)))
2303 pS
->WriteUChar( LINE
); //line
2304 HandleNodes(pTemp
,nLevel
+1);
2305 pS
->WriteUChar( END
); //line
2308 pS
->WriteUChar( LINE
|0x10 );
2309 pS
->WriteUChar( END
); //line
2312 //After subscript mathtype will keep the size of
2313 //normal text at the subscript size, sigh.
2314 pS
->WriteUChar( 0x0A );
2318 void MathType::HandleFractions(SmNode
*pNode
,int nLevel
)
2321 pS
->WriteUChar( TMPL
); //Template
2322 pS
->WriteUChar( 0x0E ); //selector
2323 pS
->WriteUChar( 0x00 ); //variation
2324 pS
->WriteUChar( 0x00 ); //options
2326 pS
->WriteUChar( 0x0A );
2327 pS
->WriteUChar( LINE
); //line
2328 if (nullptr != (pTemp
= pNode
->GetSubNode(0)))
2329 HandleNodes(pTemp
,nLevel
+1);
2330 pS
->WriteUChar( END
);
2332 pS
->WriteUChar( 0x0A );
2333 pS
->WriteUChar( LINE
); //line
2334 if (nullptr != (pTemp
= pNode
->GetSubNode(2)))
2335 HandleNodes(pTemp
,nLevel
+1);
2336 pS
->WriteUChar( END
);
2338 pS
->WriteUChar( END
);
2342 void MathType::HandleBrace(SmNode
*pNode
,int nLevel
)
2345 SmNode
*pLeft
=pNode
->GetSubNode(0);
2346 SmNode
*pRight
=pNode
->GetSubNode(2);
2348 pS
->WriteUChar( TMPL
); //Template
2349 bIsReInterpBrace
=false;
2350 sal_uInt8 nBSpec
=0x10;
2351 sal_uLong nLoc
= pS
->Tell();
2354 switch (pLeft
->GetToken().eType
)
2357 pS
->WriteUChar( tmANGLE
); //selector
2358 pS
->WriteUChar( 0 ); //variation
2359 pS
->WriteUChar( 0 ); //options
2362 pS
->WriteUChar( tmBRACE
); //selector
2363 pS
->WriteUChar( 0 ); //variation
2364 pS
->WriteUChar( 0 ); //options
2368 pS
->WriteUChar( tmBRACK
); //selector
2369 pS
->WriteUChar( 0 ); //variation
2370 pS
->WriteUChar( 0 ); //options
2374 pS
->WriteUChar( tmFLOOR
); //selector
2375 pS
->WriteUChar( 0 ); //variation
2376 pS
->WriteUChar( 0 ); //options
2379 pS
->WriteUChar( tmBAR
); //selector
2380 pS
->WriteUChar( 0 ); //variation
2381 pS
->WriteUChar( 0 ); //options
2385 pS
->WriteUChar( tmDBAR
); //selector
2386 pS
->WriteUChar( 0 ); //variation
2387 pS
->WriteUChar( 0 ); //options
2390 pS
->WriteUChar( tmPAREN
); //selector
2391 pS
->WriteUChar( 0 ); //variation
2392 pS
->WriteUChar( 0 ); //options
2398 if (nullptr != (pTemp
= pNode
->GetSubNode(1)))
2400 pS
->WriteUChar( LINE
); //line
2401 HandleNodes(pTemp
,nLevel
+1);
2402 pS
->WriteUChar( END
); //options
2406 HandleNodes(pLeft
,nLevel
+1);
2407 if (bIsReInterpBrace
)
2409 sal_uLong nLoc2
= pS
->Tell();
2411 pS
->WriteUChar( 0x2D );
2413 pS
->WriteUChar( CHAR
);
2414 pS
->WriteUChar( 0x96 );
2415 pS
->WriteUInt16( 0xEC07 );
2416 bIsReInterpBrace
=false;
2419 HandleNodes(pRight
,nLevel
+1);
2421 pS
->WriteUChar( END
);
2425 void MathType::HandleVerticalBrace(SmNode
*pNode
,int nLevel
)
2428 pS
->WriteUChar( TMPL
); //Template
2429 if (pNode
->GetToken().eType
== TUNDERBRACE
)
2430 pS
->WriteUChar( tmLHBRACE
); //selector
2432 pS
->WriteUChar( tmUHBRACE
); //selector
2433 pS
->WriteUChar( 0 ); //variation
2434 pS
->WriteUChar( 0 ); //options
2436 if (nullptr != (pTemp
= pNode
->GetSubNode(0)))
2438 pS
->WriteUChar( LINE
); //line
2439 HandleNodes(pTemp
,nLevel
+1);
2440 pS
->WriteUChar( END
); //options
2443 if (nullptr != (pTemp
= pNode
->GetSubNode(2)))
2445 pS
->WriteUChar( LINE
); //line
2446 HandleNodes(pTemp
,nLevel
+1);
2447 pS
->WriteUChar( END
); //options
2449 pS
->WriteUChar( END
);
2452 void MathType::HandleOperator(SmNode
*pNode
,int nLevel
)
2454 if (HandleLim(pNode
,nLevel
))
2458 sal_uInt8 nVariation
;
2460 switch (pNode
->GetToken().eType
)
2467 nVariation
=HandleCScript(pNode
->GetSubNode(0),
2468 pNode
->GetSubNode(1),nLevel
,&nPos
,false);
2471 nVariation
=HandleCScript(pNode
->GetSubNode(0),
2472 pNode
->GetSubNode(1),nLevel
,&nPos
);
2476 sal_uInt8 nOldVariation
=nVariation
;
2477 sal_uInt8 nIntVariation
=nVariation
;
2480 if (nVariation
!= 0xff)
2484 if (nVariation
== 2)
2489 else if (nVariation
== 0)
2491 else if (nVariation
== 1)
2499 pS
->WriteUChar( TMPL
);
2500 switch(pNode
->GetToken().eType
)
2504 if (nOldVariation
!= 0xff)
2505 pS
->WriteUChar( 0x18 ); //selector
2507 pS
->WriteUChar( 0x15 ); //selector
2508 pS
->WriteUChar( nIntVariation
); //variation
2511 if (nOldVariation
!= 0xff)
2513 pS
->WriteUChar( 0x19 );
2514 pS
->WriteUChar( 0x01 );
2518 pS
->WriteUChar( 0x16 );
2519 pS
->WriteUChar( 0x00 );
2523 if (nOldVariation
!= 0xff)
2525 pS
->WriteUChar( 0x1a );
2526 pS
->WriteUChar( 0x01 );
2530 pS
->WriteUChar( 0x17 );
2531 pS
->WriteUChar( 0x00 );
2535 if (nOldVariation
!= 0xff)
2537 pS
->WriteUChar( 0x18 );
2538 pS
->WriteUChar( 0x02 );
2542 pS
->WriteUChar( 0x15 );
2543 pS
->WriteUChar( 0x03 );
2547 if (nOldVariation
!= 0xff)
2549 pS
->WriteUChar( 0x19 );
2550 pS
->WriteUChar( 0x00 );
2554 pS
->WriteUChar( 0x16 );
2555 pS
->WriteUChar( 0x02 );
2559 if (nOldVariation
!= 0xff)
2561 pS
->WriteUChar( 0x1a );
2562 pS
->WriteUChar( 0x00 );
2566 pS
->WriteUChar( 0x17 );
2567 pS
->WriteUChar( 0x02 );
2572 pS
->WriteUChar( 0x1d );
2573 pS
->WriteUChar( nVariation
);
2576 pS
->WriteUChar( 0x1f );
2577 pS
->WriteUChar( nVariation
);
2580 pS
->WriteUChar( 0x21 );
2581 pS
->WriteUChar( nVariation
);
2584 pS
->WriteUChar( 0 ); //options
2590 pS
->WriteUChar( LINE
); //line
2591 HandleNodes(pNode
->GetSubNode(1),nLevel
+1);
2592 pS
->WriteUChar( END
); //line
2593 pS
->WriteUChar( LINE
|0x10 );
2594 pS
->WriteUChar( LINE
|0x10 );
2597 pS
->WriteUChar( 0x0D );
2598 switch(pNode
->GetToken().eType
)
2602 pS
->WriteUChar( CHAR
);
2603 pS
->WriteUChar( 0x86 );
2604 pS
->WriteUInt16( 0x2211 );
2607 pS
->WriteUChar( CHAR
);
2608 pS
->WriteUChar( 0x86 );
2609 pS
->WriteUInt16( 0x220F );
2612 pS
->WriteUChar( CHAR
);
2613 pS
->WriteUChar( 0x8B );
2614 pS
->WriteUInt16( 0x2210 );
2618 pS
->WriteUChar( CHAR
);
2619 pS
->WriteUChar( 0x86 );
2620 pS
->WriteUInt16( 0x222B );
2624 pS
->WriteUChar( CHAR
);
2625 pS
->WriteUChar( 0x86 );
2626 pS
->WriteUInt16( 0x222B );
2631 pS
->WriteUChar( CHAR
);
2632 pS
->WriteUChar( 0x86 );
2633 pS
->WriteUInt16( 0x222B );
2636 pS
->WriteUChar( END
);
2637 pS
->WriteUChar( 0x0A );
2641 bool MathType::HandlePile(int &rSetAlign
, int nLevel
, sal_uInt8 nSelector
, sal_uInt8 nVariation
)
2643 pS
->ReadUChar( nHAlign
);
2644 pS
->ReadUChar( nVAlign
);
2646 HandleAlign(nHAlign
,nVAlign
,rSetAlign
);
2648 rRet
+= " stack {\n";
2649 bool bRet
= HandleRecords( nLevel
+1, nSelector
, nVariation
, -1, -1 );
2650 rRet
= rRet
.replaceAt(rRet
.getLength()-3,2,"");
2661 bool MathType::HandleMatrix(int nLevel
, sal_uInt8 nSelector
, sal_uInt8 nVariation
)
2663 sal_uInt8 nH_just
,nV_just
,nRows
,nCols
;
2664 pS
->ReadUChar( nVAlign
);
2665 pS
->ReadUChar( nH_just
);
2666 pS
->ReadUChar( nV_just
);
2667 pS
->ReadUChar( nRows
);
2668 pS
->ReadUChar( nCols
);
2669 int nBytes
= ((nRows
+1)*2)/8;
2670 if (((nRows
+1)*2)%8)
2672 pS
->SeekRel(nBytes
);
2673 nBytes
= ((nCols
+1)*2)/8;
2674 if (((nCols
+1)*2)%8)
2676 pS
->SeekRel(nBytes
);
2677 rRet
+= " matrix {\n";
2678 bool bRet
= HandleRecords( nLevel
+1, nSelector
, nVariation
, nRows
, nCols
);
2680 sal_Int32 nI
= rRet
.lastIndexOf('#');
2682 if (rRet
[nI
-1] != '#') //missing column
2689 bool MathType::HandleTemplate(int nLevel
, sal_uInt8
&rSelector
,
2690 sal_uInt8
&rVariation
, sal_Int32
&rLastTemplateBracket
)
2692 sal_uInt8 nOption
; //This appears utterly unused
2693 pS
->ReadUChar( rSelector
);
2694 pS
->ReadUChar( rVariation
);
2695 pS
->ReadUChar( nOption
);
2696 OSL_ENSURE(rSelector
< 48,"Selector out of range");
2697 if ((rSelector
>= 21) && (rSelector
<=26))
2699 OSL_ENSURE(nOption
< 2,"Option out of range");
2701 else if (/*(rSelector >= 0) &&*/ (rSelector
<=12))
2703 OSL_ENSURE(nOption
< 3,"Option out of range");
2706 //For the (broken) case where one subscript template ends, and there is
2707 //another one after it, mathtype handles it as if the second one was
2708 //inside the first one and renders it as sub of sub
2710 if ( (rSelector
== 0xf) && (rLastTemplateBracket
!= -1) )
2713 for (sal_Int32 nI
= rLastTemplateBracket
+1; nI
< rRet
.getLength(); nI
++ )
2714 if (rRet
[nI
] != ' ')
2722 bool bRet
= HandleRecords( nLevel
+1, rSelector
, rVariation
);
2726 rRet
= rRet
.replaceAt(rLastTemplateBracket
,1,"");
2728 rLastTemplateBracket
= -1;
2730 if (rSelector
== 0xf)
2731 rLastTemplateBracket
= rRet
.lastIndexOf('}');
2733 rLastTemplateBracket
= -1;
2735 rSelector
= sal::static_int_cast
< sal_uInt8
>(-1);
2739 void MathType::HandleEmblishments()
2744 pS
->ReadUChar( nEmbel
);
2760 nPostSup
= sPost
.getLength();
2762 sPost
= sPost
.replaceAt(nPostSup
-1,0," ' ");
2769 nPostSup
= sPost
.getLength();
2771 sPost
= sPost
.replaceAt(nPostSup
-1,0," '' ");
2777 sPost
+= " lsup {}";
2778 nPostlSup
= sPost
.getLength();
2780 sPost
= sPost
.replaceAt(nPostlSup
-1,0," ' ");
2793 rRet
+= " overstrike ";
2802 nPostSup
= sPost
.getLength();
2804 sPost
= sPost
.replaceAt(nPostSup
-1,0," ''' ");
2811 OSL_ENSURE(nEmbel
< 21,"Embel out of range");
2819 void MathType::HandleSetSize()
2822 pS
->ReadUChar( nTemp
);
2826 pS
->ReadInt16( nLSize
);
2830 pS
->ReadUChar( nTemp
);
2832 pS
->ReadInt16( nDSize
);
2836 pS
->ReadUChar( nTemp
);
2842 bool MathType::HandleChar(sal_Int32
&rTextStart
, int &rSetSize
, int nLevel
,
2843 sal_uInt8 nTag
, sal_uInt8 nSelector
, sal_uInt8 nVariation
, bool bSilent
)
2850 //This is a candidate for function recognition, whatever
2854 sal_uInt8 nOldTypeFace
= nTypeFace
;
2855 pS
->ReadUChar( nTypeFace
);
2859 pS
->ReadUChar( nChar8
);
2863 pS
->ReadUtf16( nChar
);
2866 bad character, old mathtype < 3 has these
2873 //A bit tricky, the character emblishments for
2874 //mathtype can all be listed after eachother, in
2875 //starmath some must go before the character and some
2876 //must go after. In addition some of the emblishments
2877 //may repeated and in starmath some of these groups
2878 //must be gathered together. sPost is the portion that
2879 //follows the char and nPostSup and nPostlSup are the
2880 //indexes at which this class of emblishment is
2883 nPostSup
= nPostlSup
= 0;
2884 int nOriglen
=rRet
.getLength()-rTextStart
;
2885 rRet
+= " {"; // #i24340# make what would be "vec {A}_n" become "{vec {A}}_n"
2886 if ((!bSilent
) && ((nOriglen
) > 1))
2888 bRet
= HandleRecords( nLevel
+1, nSelector
, nVariation
);
2894 TypeFaceToString(aStr
,nOldTypeFace
);
2896 rRet
= rRet
.replaceAt(rTextStart
,0,aStr
);
2899 TypeFaceToString(aStr
,nTypeFace
);
2904 rTextStart
= rRet
.getLength();
2910 sal_Int32 nOldLen
= rRet
.getLength();
2912 HandleSize(nLSize
,nDSize
,rSetSize
) ||
2913 (nOldTypeFace
!= nTypeFace
)
2916 if ((nOldLen
- rTextStart
) > 1)
2918 rRet
= rRet
.replaceAt(nOldLen
, 0, "\"");
2920 TypeFaceToString(aStr
,nOldTypeFace
);
2922 rRet
= rRet
.replaceAt(rTextStart
,0,aStr
);
2924 rTextStart
= rRet
.getLength();
2926 nOldLen
= rRet
.getLength();
2927 if (!LookupChar(nChar
,rRet
,nVersion
,nTypeFace
))
2929 if (nOldLen
- rTextStart
> 1)
2931 rRet
= rRet
.replaceAt(nOldLen
,0,"\"");
2933 TypeFaceToString(aStr
,nOldTypeFace
);
2935 rRet
= rRet
.replaceAt(rTextStart
, 0, aStr
);
2937 rTextStart
= rRet
.getLength();
2939 lcl_PrependDummyTerm(rRet
, rTextStart
);
2942 if ((xfEMBELL(nTag
)) && (!bSilent
))
2944 rRet
+= "}}" + sPost
; // #i24340# make what would be "vec {A}_n" become "{vec {A}}_n"
2945 rTextStart
= rRet
.getLength();
2950 bool MathType::HandleLim(SmNode
*pNode
,int nLevel
)
2953 //Special case for the "lim" option in StarMath
2954 if ((pNode
->GetToken().eType
== TLIM
)
2955 || (pNode
->GetToken().eType
== TLIMSUP
)
2956 || (pNode
->GetToken().eType
== TLIMINF
)
2959 if (pNode
->GetSubNode(1))
2961 sal_uInt8 nVariation2
=HandleCScript(pNode
->GetSubNode(0),nullptr,
2964 pS
->WriteUChar( 0x0A );
2965 pS
->WriteUChar( LINE
); //line
2966 pS
->WriteUChar( CHAR
|0x10 );
2967 pS
->WriteUChar( 0x82 );
2968 pS
->WriteUInt16( 'l' );
2969 pS
->WriteUChar( CHAR
|0x10 );
2970 pS
->WriteUChar( 0x82 );
2971 pS
->WriteUInt16( 'i' );
2972 pS
->WriteUChar( CHAR
|0x10 );
2973 pS
->WriteUChar( 0x82 );
2974 pS
->WriteUInt16( 'm' );
2976 if (pNode
->GetToken().eType
== TLIMSUP
)
2978 pS
->WriteUChar( CHAR
); //some space
2979 pS
->WriteUChar( 0x98 );
2980 pS
->WriteUInt16( 0xEB04 );
2982 pS
->WriteUChar( CHAR
|0x10 );
2983 pS
->WriteUChar( 0x82 );
2984 pS
->WriteUInt16( 's' );
2985 pS
->WriteUChar( CHAR
|0x10 );
2986 pS
->WriteUChar( 0x82 );
2987 pS
->WriteUInt16( 'u' );
2988 pS
->WriteUChar( CHAR
|0x10 );
2989 pS
->WriteUChar( 0x82 );
2990 pS
->WriteUInt16( 'p' );
2992 else if (pNode
->GetToken().eType
== TLIMINF
)
2994 pS
->WriteUChar( CHAR
); //some space
2995 pS
->WriteUChar( 0x98 );
2996 pS
->WriteUInt16( 0xEB04 );
2998 pS
->WriteUChar( CHAR
|0x10 );
2999 pS
->WriteUChar( 0x82 );
3000 pS
->WriteUInt16( 'i' );
3001 pS
->WriteUChar( CHAR
|0x10 );
3002 pS
->WriteUChar( 0x82 );
3003 pS
->WriteUInt16( 'n' );
3004 pS
->WriteUChar( CHAR
|0x10 );
3005 pS
->WriteUChar( 0x82 );
3006 pS
->WriteUInt16( 'f' );
3010 pS
->WriteUChar( CHAR
); //some space
3011 pS
->WriteUChar( 0x98 );
3012 pS
->WriteUInt16( 0xEB04 );
3014 if (nVariation2
!= 0xff)
3016 pS
->WriteUChar( END
);
3017 pS
->WriteUChar( END
);
3019 HandleNodes(pNode
->GetSubNode(1),nLevel
+1);
3026 void MathType::HandleMAlign(SmNode
*pNode
,int nLevel
)
3028 sal_uInt8 nPushedHAlign
=nHAlign
;
3029 switch(pNode
->GetToken().eType
)
3041 sal_uInt16 nSize
= pNode
->GetNumSubNodes();
3042 for (sal_uInt16 i
= 0; i
< nSize
; i
++)
3043 if (SmNode
*pTemp
= pNode
->GetSubNode(i
))
3044 HandleNodes(pTemp
,nLevel
+1);
3045 nHAlign
=nPushedHAlign
;
3048 void MathType::HandleMath(SmNode
*pNode
, int /*nLevel*/)
3050 if (pNode
->GetToken().eType
== TMLINE
)
3052 pS
->WriteUChar( END
);
3053 pS
->WriteUChar( LINE
);
3054 bIsReInterpBrace
=true;
3057 SmMathSymbolNode
*pTemp
= static_cast<SmMathSymbolNode
*>(pNode
);
3058 for(sal_Int32 i
=0;i
<pTemp
->GetText().getLength();i
++)
3060 sal_Unicode nArse
= SmTextNode::ConvertSymbolToUnicode(pTemp
->GetText()[i
]);
3061 if ((nArse
== 0x2224) || (nArse
== 0x2288) || (nArse
== 0x2285) ||
3064 pS
->WriteUChar( CHAR
|0x20 );
3066 else if ((nPendingAttributes
) &&
3067 (i
== ((pTemp
->GetText().getLength()+1)/2)-1))
3069 pS
->WriteUChar( 0x22 );
3072 pS
->WriteUChar( CHAR
); //char without formula recognition
3073 //The typeface seems to be MTEXTRA for unicode characters,
3074 //though how to determine when mathtype chooses one over
3075 //the other is unknown. This should do the trick
3078 if ( (nArse
== 0x2213) || (nArse
== 0x2218) ||
3079 (nArse
== 0x210F) || (
3080 (nArse
>= 0x22EE) && (nArse
<= 0x22FF)
3083 nBias
= 0xB; //typeface
3085 else if ((nArse
> 0x2000) || (nArse
== 0x00D7))
3086 nBias
= 0x6; //typeface
3087 else if (nArse
== 0x3d1)
3089 else if ((nArse
> 0xFF) && ((nArse
< 0x393) || (nArse
> 0x3c9)))
3090 nBias
= 0xB; //typeface
3091 else if ((nArse
== 0x2F) || (nArse
== 0x2225))
3092 nBias
= 0x2; //typeface
3094 nBias
= 0x3; //typeface
3096 pS
->WriteUChar( nSpec
+nBias
+128 ); //typeface
3098 if (nArse
== 0x2224)
3100 pS
->WriteUInt16( 0x7C );
3101 pS
->WriteUChar( EMBEL
);
3102 pS
->WriteUChar( 0x0A );
3103 pS
->WriteUChar( END
); //end embel
3104 pS
->WriteUChar( END
); //end embel
3106 else if (nArse
== 0x2225)
3107 pS
->WriteUInt16( 0xEC09 );
3108 else if (nArse
== 0xE421)
3109 pS
->WriteUInt16( 0x2265 );
3110 else if (nArse
== 0x230A)
3111 pS
->WriteUInt16( 0xF8F0 );
3112 else if (nArse
== 0x230B)
3113 pS
->WriteUInt16( 0xF8FB );
3114 else if (nArse
== 0xE425)
3115 pS
->WriteUInt16( 0x2264 );
3116 else if (nArse
== 0x226A)
3118 pS
->WriteUInt16( 0x3C );
3119 pS
->WriteUChar( CHAR
);
3120 pS
->WriteUChar( 0x98 );
3121 pS
->WriteUInt16( 0xEB01 );
3122 pS
->WriteUChar( CHAR
);
3123 pS
->WriteUChar( 0x86 );
3124 pS
->WriteUInt16( 0x3c );
3126 else if (nArse
== 0x2288)
3128 pS
->WriteUInt16( 0x2286 );
3129 pS
->WriteUChar( EMBEL
);
3130 pS
->WriteUChar( 0x0A );
3131 pS
->WriteUChar( END
); //end embel
3132 pS
->WriteUChar( END
); //end embel
3134 else if (nArse
== 0x2289)
3136 pS
->WriteUInt16( 0x2287 );
3137 pS
->WriteUChar( EMBEL
);
3138 pS
->WriteUChar( 0x0A );
3139 pS
->WriteUChar( END
); //end embel
3140 pS
->WriteUChar( END
); //end embel
3142 else if (nArse
== 0x2285)
3144 pS
->WriteUInt16( 0x2283 );
3145 pS
->WriteUChar( EMBEL
);
3146 pS
->WriteUChar( 0x0A );
3147 pS
->WriteUChar( END
); //end embel
3148 pS
->WriteUChar( END
); //end embel
3151 pS
->WriteUInt16( nArse
);
3153 nPendingAttributes
= 0;
3156 void MathType::HandleAttributes(SmNode
*pNode
,int nLevel
)
3158 int nOldPending
= 0;
3159 SmNode
*pTemp
= nullptr;
3160 SmTextNode
*pIsText
= nullptr;
3162 if (nullptr != (pTemp
= pNode
->GetSubNode(0)))
3164 pIsText
= static_cast<SmTextNode
*>(pNode
->GetSubNode(1));
3166 switch (pTemp
->GetToken().eType
)
3169 //theres just no way we can now handle any character
3170 //attributes (from mathtypes perspective) centered
3171 //over an expression but above template attributes
3172 //such as widevec and similar constructs
3173 //we have to drop them
3174 nOldPending
= StartTemplate(0x2f,0x01);
3176 case TCHECK
: //Not Exportable
3177 case TACUTE
: //Not Exportable
3178 case TGRAVE
: //Not Exportable
3179 case TCIRCLE
: //Not Exportable
3180 case TWIDETILDE
: //Not Exportable
3181 case TWIDEHAT
: //Not Exportable
3184 nOldPending
= StartTemplate(0x10);
3186 case TOVERLINE
: //If the next node is not text
3187 //or text with more than one char
3188 if ((pIsText
->GetToken().eType
!= TTEXT
) ||
3189 (pIsText
->GetText().getLength() > 1))
3190 nOldPending
= StartTemplate(0x11);
3193 nPendingAttributes
++;
3199 HandleNodes(pIsText
,nLevel
+1);
3201 switch (pTemp
->GetToken().eType
)
3205 EndTemplate(nOldPending
);
3208 if ((pIsText
->GetToken().eType
!= TTEXT
) ||
3209 (pIsText
->GetText().getLength() > 1))
3210 EndTemplate(nOldPending
);
3216 //if there was no suitable place to put the attribute,
3217 //then we have to just give up on it
3218 if (nPendingAttributes
)
3219 nPendingAttributes
--;
3222 if ((nInsertion
!= 0) && nullptr != (pTemp
= pNode
->GetSubNode(0)))
3224 sal_uLong nPos
= pS
->Tell();
3226 pS
->Seek(nInsertion
);
3227 switch(pTemp
->GetToken().eType
)
3229 case TACUTE
: //Not Exportable
3230 case TGRAVE
: //Not Exportable
3231 case TCIRCLE
: //Not Exportable
3234 pS
->WriteUChar( 2 );
3237 pS
->WriteUChar( 3 );
3240 pS
->WriteUChar( 4 );
3243 pS
->WriteUChar( 8 );
3246 pS
->WriteUChar( 9 );
3249 pS
->WriteUChar( 11 );
3252 pS
->WriteUChar( 16 );
3255 if ((pIsText
->GetToken().eType
== TTEXT
) &&
3256 (pIsText
->GetText().getLength() == 1))
3257 pS
->WriteUChar( 17 );
3260 pS
->WriteUChar( 20 );
3268 pS
->WriteUChar( 17 );
3271 pS
->WriteUChar( 2 );
3279 void MathType::HandleText(SmNode
*pNode
, int /*nLevel*/)
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 //ATTRIBUT 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 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */