63594c6202
Change-Id: I907e282c9e7b75abca9a4c91ba12a2c57fc45f40 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177733 Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com> Tested-by: Jenkins
3321 lines
108 KiB
C++
3321 lines
108 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include "mathtype.hxx"
|
|
#include "eqnolefilehdr.hxx"
|
|
|
|
#include <filter/msfilter/classids.hxx>
|
|
#include <osl/diagnose.h>
|
|
#include <sfx2/docfile.hxx>
|
|
#include <sot/storage.hxx>
|
|
#include <array>
|
|
|
|
//These are the default MathType sizes
|
|
constexpr std::array<sal_Int16, 7> aSizeTable {
|
|
12,
|
|
8,
|
|
6,
|
|
24,
|
|
10,
|
|
12,
|
|
12,
|
|
};
|
|
|
|
void MathType::Init()
|
|
{
|
|
/*
|
|
These are the default MathType italic/bold settings If mathtype is changed
|
|
from its defaults, there is nothing we can do, as this information is not
|
|
stored in the document
|
|
*/
|
|
MathTypeFont aFont;
|
|
aUserStyles.reserve(11);
|
|
for(sal_uInt8 i=1;i<=11;i++)
|
|
{
|
|
aFont.nTface = i+128;
|
|
switch (i)
|
|
{
|
|
default:
|
|
aFont.nStyle=0;
|
|
break;
|
|
case 3:
|
|
case 4:
|
|
aFont.nStyle=1;
|
|
break;
|
|
case 7:
|
|
aFont.nStyle=2;
|
|
break;
|
|
}
|
|
aUserStyles.insert(aFont);
|
|
}
|
|
}
|
|
|
|
|
|
/*ToDo replace with table rather than switch, returns
|
|
sal_True in the case that the char is just a char, and
|
|
sal_False if the character is an operator which must not be
|
|
placed inside the quote sequence designed to protect
|
|
against being parsed as a keyword
|
|
|
|
General solution required to force starmath to handle
|
|
unicode math chars the way it handles its own math
|
|
chars rather than handle them as text as it will do
|
|
for the default case below, i.e. incorrect spacing
|
|
between math symbols and ordinary text e.g. 1=2 rather
|
|
than 1 = 2
|
|
*/
|
|
bool MathType::LookupChar(sal_Unicode nChar,OUStringBuffer &rRet,sal_uInt8 nVersion,
|
|
sal_uInt8 nTypeFace)
|
|
{
|
|
bool bRet=false;
|
|
const char *pC = nullptr;
|
|
switch(nChar)
|
|
{
|
|
case 0x0000:
|
|
pC = " none ";
|
|
break;
|
|
case 0x00ac:
|
|
pC = " neg ";
|
|
break;
|
|
case 0x00b1:
|
|
pC = " +- ";
|
|
break;
|
|
case '(':
|
|
pC = " \\( ";
|
|
break;
|
|
case ')':
|
|
pC = " \\) ";
|
|
break;
|
|
case '[':
|
|
pC = " \\[ ";
|
|
break;
|
|
case ']':
|
|
pC = " \\] ";
|
|
break;
|
|
case '.':
|
|
pC = " \".\" ";
|
|
break;
|
|
case 0xae:
|
|
if ((nVersion < 3) && (nTypeFace == 0x86))
|
|
pC = " rightarrow ";
|
|
else
|
|
{
|
|
rRet.append(OUStringChar(nChar));
|
|
bRet=true;
|
|
}
|
|
break;
|
|
case 0x00fb:
|
|
if ((nVersion < 3) && (nTypeFace == 0x81))
|
|
nChar = 0xDF;
|
|
rRet.append(OUStringChar(nChar));
|
|
bRet=true;
|
|
break;
|
|
case 'a':
|
|
if ((nVersion < 3) && (nTypeFace == 0x84))
|
|
nChar = 0x3b1;
|
|
rRet.append(OUStringChar(nChar));
|
|
bRet=true;
|
|
break;
|
|
case 'b':
|
|
if ((nVersion < 3) && (nTypeFace == 0x84))
|
|
nChar = 0x3b2;
|
|
rRet.append(OUStringChar(nChar));
|
|
bRet=true;
|
|
break;
|
|
case 'l':
|
|
if ((nVersion < 3) && (nTypeFace == 0x84))
|
|
nChar = 0x3bb;
|
|
rRet.append(OUStringChar(nChar));
|
|
bRet=true;
|
|
break;
|
|
case 'n':
|
|
if ((nVersion < 3) && (nTypeFace == 0x84))
|
|
nChar = 0x3bd;
|
|
rRet.append(OUStringChar(nChar));
|
|
bRet=true;
|
|
break;
|
|
case 'r':
|
|
if ((nVersion < 3) && (nTypeFace == 0x84))
|
|
nChar = 0x3c1;
|
|
rRet.append(OUStringChar(nChar));
|
|
bRet=true;
|
|
break;
|
|
case 'D':
|
|
if ((nVersion < 3) && (nTypeFace == 0x84))
|
|
nChar = 0x394;
|
|
rRet.append(OUStringChar(nChar));
|
|
bRet=true;
|
|
break;
|
|
case 0xa9:
|
|
if ((nVersion < 3) && (nTypeFace == 0x82))
|
|
nChar = '\'';
|
|
rRet.append(OUStringChar(nChar));
|
|
bRet=true;
|
|
break;
|
|
case 0x00f1:
|
|
if ((nVersion < 3) && (nTypeFace == 0x86))
|
|
pC = " \\rangle ";
|
|
else
|
|
{
|
|
rRet.append(OUStringChar(nChar));
|
|
bRet=true;
|
|
}
|
|
break;
|
|
case 0x00a3:
|
|
if ((nVersion < 3) && (nTypeFace == 0x86))
|
|
pC = " <= ";
|
|
else
|
|
{
|
|
rRet.append(OUStringChar(nChar));
|
|
bRet=true;
|
|
}
|
|
break;
|
|
case 0x00de:
|
|
if ((nVersion < 3) && (nTypeFace == 0x86))
|
|
pC = " drarrow ";
|
|
else
|
|
{
|
|
rRet.append(OUStringChar(nChar));
|
|
bRet=true;
|
|
}
|
|
break;
|
|
case 0x0057:
|
|
if ((nVersion < 3) && (nTypeFace == 0x85))
|
|
pC = " %OMEGA ";
|
|
else
|
|
{
|
|
rRet.append(OUStringChar(nChar));
|
|
bRet=true;
|
|
}
|
|
break;
|
|
case 0x007b:
|
|
pC = " lbrace ";
|
|
break;
|
|
case 0x007c:
|
|
pC = " \\lline ";
|
|
break;
|
|
case 0x007d:
|
|
pC = " rbrace ";
|
|
break;
|
|
case 0x007e:
|
|
pC = " \"~\" ";
|
|
break;
|
|
case 0x2224:
|
|
pC = " ndivides ";
|
|
break;
|
|
case 0x2225:
|
|
pC = " parallel ";
|
|
break;
|
|
case 0x00d7:
|
|
if (nVersion < 3)
|
|
pC = " cdot ";
|
|
else
|
|
pC = " times ";
|
|
break;
|
|
case 0x00f7:
|
|
pC = " div ";
|
|
break;
|
|
case 0x019b:
|
|
pC = " lambdabar ";
|
|
break;
|
|
case 0x2026:
|
|
pC = " dotslow ";
|
|
break;
|
|
case 0x2022:
|
|
case 0x22c5:
|
|
pC = " cdot ";
|
|
break;
|
|
case 0x2102:
|
|
pC = " setC ";
|
|
break;
|
|
case 0x210f:
|
|
pC = " hbar ";
|
|
break;
|
|
case 0x2111:
|
|
pC = " Im ";
|
|
break;
|
|
case 0x2115:
|
|
pC = " setN ";
|
|
break;
|
|
case 0x2118:
|
|
pC = " wp ";
|
|
break;
|
|
case 0x211a:
|
|
pC = " setQ ";
|
|
break;
|
|
case 0x211c:
|
|
pC = " Re ";
|
|
break;
|
|
case 0x211d:
|
|
pC = " setR ";
|
|
break;
|
|
case 0x2124:
|
|
pC = " setZ ";
|
|
break;
|
|
case 0x2135:
|
|
pC = " aleph ";
|
|
break;
|
|
case 0x2190:
|
|
pC = " leftarrow ";
|
|
break;
|
|
case 0x2191:
|
|
pC = " uparrow ";
|
|
break;
|
|
case 0x2192:
|
|
pC = " rightarrow ";
|
|
break;
|
|
case 0x0362:
|
|
case 0xe098:
|
|
pC = " widevec ";
|
|
break;
|
|
case 0x2193:
|
|
pC = " downarrow ";
|
|
break;
|
|
case 0x21d0:
|
|
pC = " dlarrow ";
|
|
break;
|
|
case 0x21d2:
|
|
pC = " drarrow ";
|
|
break;
|
|
case 0x21d4:
|
|
pC = " dlrarrow ";
|
|
break;
|
|
case 0x2200:
|
|
pC = " forall ";
|
|
break;
|
|
case 0x2202:
|
|
pC = " partial ";
|
|
break;
|
|
case 0x2203:
|
|
pC = " exists ";
|
|
break;
|
|
case 0x2204:
|
|
pC = " notexists ";
|
|
break;
|
|
case 0x2205:
|
|
pC = " emptyset ";
|
|
break;
|
|
case 0x2207:
|
|
pC = " nabla ";
|
|
break;
|
|
case 0x2112:
|
|
pC = " laplace ";
|
|
break;
|
|
case 0x03F6:
|
|
pC = " backepsilon ";
|
|
break;
|
|
case 0x2208: // in
|
|
case 0x2209: // notin
|
|
case 0x2282: // subset
|
|
case 0x2283: // supset
|
|
case 0x2284: // nsubset
|
|
case 0x2285: // nsupset
|
|
case 0x2286: // subseteq
|
|
case 0x2287: // supseteq
|
|
case 0x2288: // nsubseteq
|
|
case 0x2289: // nsupseteq
|
|
case 0x22b2: // NORMAL SUBGROUP OF
|
|
case 0x22b3: // CONTAINS AS NORMAL SUBGROUP
|
|
rRet.append(" func " + OUStringChar(nChar) + " ");
|
|
break;
|
|
case 0x220d: // owns
|
|
rRet.append(u" func \u220b ");
|
|
break;
|
|
case 0x220f:
|
|
pC = " prod ";
|
|
break;
|
|
case 0x2210:
|
|
pC = " coprod ";
|
|
break;
|
|
case 0x2211:
|
|
pC = " sum ";
|
|
break;
|
|
case 0x2212:
|
|
pC = " - ";
|
|
break;
|
|
case 0x2213:
|
|
pC = " -+ ";
|
|
break;
|
|
case 0x2217:
|
|
pC = " * ";
|
|
break;
|
|
case 0x2218:
|
|
pC = " circ ";
|
|
break;
|
|
case 0x221d:
|
|
pC = " prop ";
|
|
break;
|
|
case 0x221e:
|
|
pC = " infinity ";
|
|
break;
|
|
case 0x2227:
|
|
pC = " and ";
|
|
break;
|
|
case 0x2228:
|
|
pC = " or ";
|
|
break;
|
|
case 0x2229:
|
|
pC = " intersection ";
|
|
break;
|
|
case 0x222a:
|
|
pC = " union ";
|
|
break;
|
|
case 0x222b:
|
|
pC = " int ";
|
|
break;
|
|
case 0x222c:
|
|
pC = " iint ";
|
|
break;
|
|
case 0x222d:
|
|
pC = " iiint ";
|
|
break;
|
|
case 0x222e:
|
|
pC = " lint ";
|
|
break;
|
|
case 0x222f:
|
|
pC = " llint ";
|
|
break;
|
|
case 0x2230:
|
|
pC = " lllint ";
|
|
break;
|
|
case 0x2245:
|
|
pC = " simeq ";
|
|
break;
|
|
case 0x2248:
|
|
pC = " approx ";
|
|
break;
|
|
case 0x2260:
|
|
pC = " <> ";
|
|
break;
|
|
case 0x2261:
|
|
pC = " equiv ";
|
|
break;
|
|
case 0x2264:
|
|
pC = " <= ";
|
|
break;
|
|
case 0x2265:
|
|
pC = " >= ";
|
|
break;
|
|
|
|
case 0x227A:
|
|
pC = " prec ";
|
|
break;
|
|
case 0x227B:
|
|
pC = " succ ";
|
|
break;
|
|
case 0x227C:
|
|
pC = " preccurlyeq ";
|
|
break;
|
|
case 0x227D:
|
|
pC = " succcurlyeq ";
|
|
break;
|
|
case 0x227E:
|
|
pC = " precsim ";
|
|
break;
|
|
case 0x227F:
|
|
pC = " succsim ";
|
|
break;
|
|
case 0x2280:
|
|
pC = " nprec ";
|
|
break;
|
|
case 0x2281:
|
|
pC = " nsucc ";
|
|
break;
|
|
case 0x22a5:
|
|
pC = " ortho ";
|
|
break;
|
|
case 0x22ee:
|
|
pC = " dotsvert ";
|
|
break;
|
|
case 0x22ef:
|
|
pC = " dotsaxis ";
|
|
break;
|
|
case 0x22f0:
|
|
pC = " dotsup ";
|
|
break;
|
|
case 0x22f1:
|
|
pC = " dotsdown ";
|
|
break;
|
|
case MS_LANGLE:
|
|
case MS_LMATHANGLE:
|
|
pC = " langle ";
|
|
break;
|
|
case MS_RANGLE:
|
|
case MS_RMATHANGLE:
|
|
pC = " rangle ";
|
|
break;
|
|
case 0x301a:
|
|
pC = " ldbracket ";
|
|
break;
|
|
case 0x301b:
|
|
pC = " rdbracket ";
|
|
break;
|
|
case 0xe083:
|
|
rRet.append("+");
|
|
bRet=true;
|
|
break;
|
|
case '^':
|
|
case 0xe091:
|
|
pC = " widehat ";
|
|
break;
|
|
case 0xe096:
|
|
pC = " widetilde ";
|
|
break;
|
|
case 0xE421:
|
|
pC = " geslant ";
|
|
break;
|
|
case 0xE425:
|
|
pC = " leslant ";
|
|
break;
|
|
case 0xeb01: //no space
|
|
case 0xeb08: //normal space
|
|
bRet=true;
|
|
break;
|
|
case 0xef04: //tiny space
|
|
case 0xef05: //tiny space
|
|
case 0xeb02: //small space
|
|
case 0xeb04: //medium space
|
|
rRet.append("`");
|
|
break;
|
|
case 0xeb05: //large space
|
|
rRet.append("~");
|
|
break;
|
|
case 0x3a9:
|
|
pC = " %OMEGA ";
|
|
break;
|
|
default:
|
|
rRet.append(OUStringChar(nChar));
|
|
bRet=true;
|
|
break;
|
|
}
|
|
if (pC)
|
|
rRet.appendAscii(pC);
|
|
return bRet;
|
|
}
|
|
|
|
void MathTypeFont::AppendStyleToText(OUString &rRet)
|
|
{
|
|
const char *pC = nullptr;
|
|
switch (nStyle)
|
|
{
|
|
default:
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
pC = " ital ";
|
|
break;
|
|
case 2:
|
|
pC = " bold ";
|
|
break;
|
|
case 3:
|
|
pC = " bold italic";
|
|
break;
|
|
}
|
|
if (pC)
|
|
rRet += OUString::createFromAscii( pC );
|
|
}
|
|
|
|
void MathType::TypeFaceToString(OUString &rTxt,sal_uInt8 nFace)
|
|
{
|
|
MathTypeFont aFont(nFace);
|
|
auto aItr = aUserStyles.find(aFont);
|
|
if (aItr != aUserStyles.end())
|
|
aFont.nStyle = aItr->nStyle;
|
|
aFont.AppendStyleToText(rTxt);
|
|
}
|
|
|
|
bool MathType::Parse(SotStorage *pStor)
|
|
{
|
|
rtl::Reference<SotStorageStream> xSrc = pStor->OpenSotStream(
|
|
u"Equation Native"_ustr,
|
|
StreamMode::STD_READ);
|
|
if ( (!xSrc.is()) || (ERRCODE_NONE != xSrc->GetError()))
|
|
return false;
|
|
return Parse(xSrc.get());
|
|
}
|
|
|
|
bool MathType::Parse(SvStream* pStream)
|
|
{
|
|
pS = pStream;
|
|
pS->SetEndian( SvStreamEndian::LITTLE );
|
|
|
|
EQNOLEFILEHDR aHdr;
|
|
aHdr.Read(pS);
|
|
sal_uInt8 nProdVersion;
|
|
sal_uInt8 nProdSubVersion;
|
|
sal_uInt8 nPlatform;
|
|
sal_uInt8 nProduct;
|
|
pS->ReadUChar( nVersion );
|
|
pS->ReadUChar( nPlatform );
|
|
pS->ReadUChar( nProduct );
|
|
pS->ReadUChar( nProdVersion );
|
|
pS->ReadUChar( nProdSubVersion );
|
|
|
|
if (!pS->good() || nVersion > 3) // allow only supported versions of MathType to be parsed
|
|
return false;
|
|
|
|
bool bRet = HandleRecords(0);
|
|
//little crude hack to close occasionally open expressions
|
|
//a sophisticated system to determine what expressions are
|
|
//opened is required, but this is as much work as rewriting
|
|
//starmaths internals.
|
|
rRet.append("{}");
|
|
|
|
return bRet;
|
|
}
|
|
|
|
static void lcl_PrependDummyTerm(OUStringBuffer &rRet, sal_Int32 &rTextStart)
|
|
{
|
|
if ((rTextStart < rRet.getLength()) &&
|
|
(rRet[rTextStart] == '=') &&
|
|
((rTextStart == 0) || (rRet[ rTextStart-1 ] == '{'))
|
|
)
|
|
{
|
|
rRet.insert(rTextStart, " {}");
|
|
rTextStart+=3;
|
|
}
|
|
}
|
|
|
|
static void lcl_AppendDummyTerm(OUStringBuffer &rRet)
|
|
{
|
|
bool bOk=false;
|
|
for(int nI=rRet.getLength()-1;nI >= 0; nI--)
|
|
{
|
|
sal_Int32 nIdx = sal::static_int_cast< sal_Int32 >(nI);
|
|
sal_Unicode nChar = rRet[nIdx];
|
|
if (nChar == ' ')
|
|
continue;
|
|
if (rRet[nIdx] != '{')
|
|
bOk=true;
|
|
break;
|
|
}
|
|
if (!bOk) //No term, use dummy
|
|
rRet.append(" {}");
|
|
}
|
|
|
|
void MathType::HandleNudge()
|
|
{
|
|
sal_uInt8 nXNudge(0);
|
|
pS->ReadUChar(nXNudge);
|
|
sal_uInt8 nYNudge(0);
|
|
pS->ReadUChar(nYNudge);
|
|
if (nXNudge == 128 && nYNudge == 128)
|
|
{
|
|
sal_uInt16 nXLongNudge(0);
|
|
sal_uInt16 nYLongNudge(0);
|
|
pS->ReadUInt16(nXLongNudge);
|
|
pS->ReadUInt16(nYLongNudge);
|
|
}
|
|
}
|
|
|
|
/* Fabulously complicated as many tokens have to be reordered and generally
|
|
* moved around from mathtypes paradigm to starmaths. */
|
|
bool MathType::HandleRecords(int nLevel, sal_uInt8 nSelector,
|
|
sal_uInt8 nVariation, int nMatrixRows, int nMatrixCols)
|
|
{
|
|
//depth-protect
|
|
if (nLevel > 1024)
|
|
return false;
|
|
|
|
sal_uInt8 nTag,nRecord;
|
|
sal_uInt8 nTabType;
|
|
sal_uInt16 nTabOffset;
|
|
int i, newline=0;
|
|
bool bSilent=false;
|
|
int nPart=0;
|
|
OUString sPush,sMainTerm;
|
|
int nSetSize=0,nSetAlign=0;
|
|
int nCurRow=0,nCurCol=0;
|
|
bool bOpenString=false;
|
|
sal_Int32 nTextStart = 0;
|
|
sal_Int32 nSubSupStartPos = 0;
|
|
sal_Int32 nLastTemplateBracket=-1;
|
|
bool bRet = true;
|
|
|
|
do
|
|
{
|
|
nTag = 0;
|
|
pS->ReadUChar( nTag );
|
|
nRecord = nTag&0x0F;
|
|
|
|
/*MathType strings can of course include words which
|
|
*are StarMath keywords, the simplest solution is
|
|
to escape strings of greater than len 1 with double
|
|
quotes to avoid scanning the TokenTable for matches
|
|
|
|
Unfortunately it may turn out that the string gets
|
|
split during the handling of a character emblishment
|
|
so this special case must be handled in the
|
|
character handler case 2:
|
|
*/
|
|
if ((nRecord == CHAR) && (!bOpenString))
|
|
{
|
|
bOpenString=true;
|
|
nTextStart = rRet.getLength();
|
|
}
|
|
else if ((nRecord != CHAR) && bOpenString)
|
|
{
|
|
bOpenString=false;
|
|
if ((rRet.getLength() - nTextStart) > 1)
|
|
{
|
|
OUString aStr;
|
|
TypeFaceToString(aStr,nTypeFace);
|
|
rRet.insert(nTextStart, aStr + "\"");
|
|
rRet.append("\"");
|
|
}
|
|
else if (nRecord == END && !rRet.isEmpty())
|
|
{
|
|
sal_Unicode cChar = 0;
|
|
sal_Int32 nI = rRet.getLength()-1;
|
|
while (nI)
|
|
{
|
|
cChar = rRet[nI];
|
|
if (cChar != ' ')
|
|
break;
|
|
--nI;
|
|
}
|
|
if ((cChar == '=') || (cChar == '+') || (cChar == '-'))
|
|
rRet.append("{}");
|
|
}
|
|
}
|
|
|
|
switch(nRecord)
|
|
{
|
|
case LINE:
|
|
{
|
|
if (xfLMOVE(nTag))
|
|
HandleNudge();
|
|
|
|
if (newline>0)
|
|
rRet.append("\nnewline\n");
|
|
if (!(xfNULL(nTag)))
|
|
{
|
|
switch (nSelector)
|
|
{
|
|
case tmANGLE:
|
|
if (nVariation==0)
|
|
rRet.append(" langle ");
|
|
else if (nVariation==1)
|
|
rRet.append(" \\langle ");
|
|
break;
|
|
case tmPAREN:
|
|
if (nVariation==0)
|
|
rRet.append(" left (");
|
|
else if (nVariation==1)
|
|
rRet.append("\\(");
|
|
break;
|
|
case tmBRACE:
|
|
if ((nVariation==0) || (nVariation==1))
|
|
rRet.append(" left lbrace ");
|
|
else
|
|
rRet.append(" left none ");
|
|
break;
|
|
case tmBRACK:
|
|
if (nVariation==0)
|
|
rRet.append(" left [");
|
|
else if (nVariation==1)
|
|
rRet.append("\\[");
|
|
break;
|
|
case tmLBLB:
|
|
case tmLBRP:
|
|
rRet.append(" \\[");
|
|
break;
|
|
case tmBAR:
|
|
if (nVariation==0)
|
|
rRet.append(" lline ");
|
|
else if (nVariation==1)
|
|
rRet.append(" \\lline ");
|
|
break;
|
|
case tmDBAR:
|
|
if (nVariation==0)
|
|
rRet.append(" ldline ");
|
|
else if (nVariation==1)
|
|
rRet.append(" \\ldline ");
|
|
break;
|
|
case tmFLOOR:
|
|
if (nVariation == 0 || nVariation & 0x01) // tvFENCE_L
|
|
rRet.append(" left lfloor ");
|
|
else
|
|
rRet.append(" left none ");
|
|
break;
|
|
case tmCEILING:
|
|
if (nVariation==0)
|
|
rRet.append(" lceil ");
|
|
else if (nVariation==1)
|
|
rRet.append(" \\lceil ");
|
|
break;
|
|
case tmRBRB:
|
|
case tmRBLB:
|
|
rRet.append(" \\]");
|
|
break;
|
|
case tmLPRB:
|
|
rRet.append(" \\(");
|
|
break;
|
|
case tmROOT:
|
|
if (nPart == 0)
|
|
{
|
|
if (nVariation == 0)
|
|
rRet.append(" sqrt");
|
|
else
|
|
{
|
|
rRet.append(" nroot");
|
|
sPush = rRet.makeStringAndClear();
|
|
}
|
|
}
|
|
rRet.append(" {");
|
|
break;
|
|
case tmFRACT:
|
|
if (nPart == 0)
|
|
rRet.append(" { ");
|
|
|
|
|
|
if (nPart == 1)
|
|
rRet.append(" over ");
|
|
rRet.append(" {");
|
|
break;
|
|
case tmSCRIPT:
|
|
nSubSupStartPos = rRet.getLength();
|
|
if ((nVariation == 0) ||
|
|
((nVariation == 2) && (nPart==1)))
|
|
{
|
|
lcl_AppendDummyTerm(rRet);
|
|
rRet.append(" rSup");
|
|
}
|
|
else if ((nVariation == 1) ||
|
|
((nVariation == 2) && (nPart==0)))
|
|
{
|
|
lcl_AppendDummyTerm(rRet);
|
|
rRet.append(" rSub");
|
|
}
|
|
rRet.append(" {");
|
|
break;
|
|
case tmUBAR:
|
|
if (nVariation == 0)
|
|
rRet.append(" {underline ");
|
|
else if (nVariation == 1)
|
|
rRet.append(" {underline underline ");
|
|
rRet.append(" {");
|
|
break;
|
|
case tmOBAR:
|
|
if (nVariation == 0)
|
|
rRet.append(" {overline ");
|
|
else if (nVariation == 1)
|
|
rRet.append(" {overline overline ");
|
|
rRet.append(" {");
|
|
break;
|
|
case tmLARROW:
|
|
case tmRARROW:
|
|
case tmBARROW:
|
|
if (nPart == 0)
|
|
{
|
|
if (nVariation == 0)
|
|
rRet.append(" widevec ");//arrow above
|
|
else if (nVariation == 1)
|
|
rRet.append(" widevec ");//arrow below
|
|
rRet.append(" {");
|
|
}
|
|
break;
|
|
case tmSINT:
|
|
if (nPart == 0)
|
|
{
|
|
if ((nVariation == 3) || (nVariation == 4))
|
|
rRet.append(" lInt");
|
|
else
|
|
rRet.append(" Int");
|
|
if ( (nVariation != 0) && (nVariation != 3))
|
|
{
|
|
sPush = rRet.makeStringAndClear();
|
|
}
|
|
}
|
|
if (((nVariation == 1) ||
|
|
(nVariation == 4)) && (nPart==1))
|
|
rRet.append(" rSub");
|
|
else if ((nVariation == 2) && (nPart==2))
|
|
rRet.append(" rSup");
|
|
else if ((nVariation == 2) && (nPart==1))
|
|
rRet.append(" rSub");
|
|
rRet.append(" {");
|
|
break;
|
|
case tmDINT:
|
|
if (nPart == 0)
|
|
{
|
|
if ((nVariation == 2) || (nVariation == 3))
|
|
rRet.append(" llInt");
|
|
else
|
|
rRet.append(" iInt");
|
|
if ( (nVariation != 0) && (nVariation != 2))
|
|
{
|
|
sPush = rRet.makeStringAndClear();
|
|
}
|
|
}
|
|
if (((nVariation == 1) ||
|
|
(nVariation == 3)) && (nPart==1))
|
|
rRet.append(" rSub");
|
|
rRet.append(" {");
|
|
break;
|
|
case tmTINT:
|
|
if (nPart == 0)
|
|
{
|
|
if ((nVariation == 2) || (nVariation == 3))
|
|
rRet.append(" lllInt");
|
|
else
|
|
rRet.append(" iiInt");
|
|
if ( (nVariation != 0) && (nVariation != 2))
|
|
{
|
|
sPush = rRet.makeStringAndClear();
|
|
}
|
|
}
|
|
if (((nVariation == 1) ||
|
|
(nVariation == 3)) && (nPart==1))
|
|
rRet.append(" rSub");
|
|
rRet.append(" {");
|
|
break;
|
|
case tmSSINT:
|
|
if (nPart == 0)
|
|
{
|
|
if (nVariation == 2)
|
|
rRet.append(" lInt");
|
|
else
|
|
rRet.append(" Int");
|
|
sPush = rRet.makeStringAndClear();
|
|
}
|
|
if (((nVariation == 1) ||
|
|
(nVariation == 2)) && (nPart==1))
|
|
rRet.append(" cSub");
|
|
else if ((nVariation == 0) && (nPart==2))
|
|
rRet.append(" cSup");
|
|
else if ((nVariation == 0) && (nPart==1))
|
|
rRet.append(" cSub");
|
|
rRet.append(" {");
|
|
break;
|
|
case tmDSINT:
|
|
if (nPart == 0)
|
|
{
|
|
if (nVariation == 0)
|
|
rRet.append(" llInt");
|
|
else
|
|
rRet.append(" iInt");
|
|
sPush = rRet.makeStringAndClear();
|
|
}
|
|
if (nPart==1)
|
|
rRet.append(" cSub");
|
|
rRet.append(" {");
|
|
break;
|
|
case tmTSINT:
|
|
if (nPart == 0)
|
|
{
|
|
if (nVariation == 0)
|
|
rRet.append(" lllInt");
|
|
else
|
|
rRet.append(" iiInt");
|
|
sPush = rRet.makeStringAndClear();
|
|
}
|
|
if (nPart==1)
|
|
rRet.append(" cSub");
|
|
rRet.append(" {");
|
|
break;
|
|
case tmUHBRACE:
|
|
case tmLHBRACE:
|
|
case tmSLFRACT:
|
|
rRet.append(" {");
|
|
break;
|
|
case tmSUM:
|
|
if (nPart == 0)
|
|
{
|
|
rRet.append(" Sum");
|
|
if (nVariation != 2)
|
|
{
|
|
sPush = rRet.makeStringAndClear();
|
|
}
|
|
}
|
|
if ((nVariation == 0) && (nPart==1))
|
|
rRet.append(" cSub");
|
|
else if ((nVariation == 1) && (nPart==2))
|
|
rRet.append(" cSup");
|
|
else if ((nVariation == 1) && (nPart==1))
|
|
rRet.append(" cSub");
|
|
rRet.append(" {");
|
|
break;
|
|
case tmISUM:
|
|
if (nPart == 0)
|
|
{
|
|
rRet.append(" Sum");
|
|
sPush = rRet.makeStringAndClear();
|
|
}
|
|
if ((nVariation == 0) && (nPart==1))
|
|
rRet.append(" rSub");
|
|
else if ((nVariation == 1) && (nPart==2))
|
|
rRet.append(" rSup");
|
|
else if ((nVariation == 1) && (nPart==1))
|
|
rRet.append(" rSub");
|
|
rRet.append(" {");
|
|
break;
|
|
case tmPROD:
|
|
if (nPart == 0)
|
|
{
|
|
rRet.append(" Prod");
|
|
if (nVariation != 2)
|
|
{
|
|
sPush = rRet.makeStringAndClear();
|
|
}
|
|
}
|
|
if ((nVariation == 0) && (nPart==1))
|
|
rRet.append(" cSub");
|
|
else if ((nVariation == 1) && (nPart==2))
|
|
rRet.append(" cSup");
|
|
else if ((nVariation == 1) && (nPart==1))
|
|
rRet.append(" cSub");
|
|
rRet.append(" {");
|
|
break;
|
|
case tmIPROD:
|
|
if (nPart == 0)
|
|
{
|
|
rRet.append(" Prod");
|
|
sPush = rRet.makeStringAndClear();
|
|
}
|
|
if ((nVariation == 0) && (nPart==1))
|
|
rRet.append(" rSub");
|
|
else if ((nVariation == 1) && (nPart==2))
|
|
rRet.append(" rSup");
|
|
else if ((nVariation == 1) && (nPart==1))
|
|
rRet.append(" rSub");
|
|
rRet.append(" {");
|
|
break;
|
|
case tmCOPROD:
|
|
if (nPart == 0)
|
|
{
|
|
rRet.append(" coProd");
|
|
if (nVariation != 2)
|
|
{
|
|
sPush = rRet.makeStringAndClear();
|
|
}
|
|
}
|
|
if ((nVariation == 0) && (nPart==1))
|
|
rRet.append(" cSub");
|
|
else if ((nVariation == 1) && (nPart==2))
|
|
rRet.append(" cSup");
|
|
else if ((nVariation == 1) && (nPart==1))
|
|
rRet.append(" cSub");
|
|
rRet.append(" {");
|
|
break;
|
|
case tmICOPROD:
|
|
if (nPart == 0)
|
|
{
|
|
rRet.append(" coProd");
|
|
sPush = rRet.makeStringAndClear();
|
|
}
|
|
if ((nVariation == 0) && (nPart==1))
|
|
rRet.append(" rSub");
|
|
else if ((nVariation == 1) && (nPart==2))
|
|
rRet.append(" rSup");
|
|
else if ((nVariation == 1) && (nPart==1))
|
|
rRet.append(" rSub");
|
|
rRet.append(" {");
|
|
break;
|
|
case tmUNION:
|
|
if (nPart == 0)
|
|
{
|
|
rRet.append(" union"); //union
|
|
if (nVariation != 2)
|
|
{
|
|
sPush = rRet.makeStringAndClear();
|
|
}
|
|
}
|
|
if ((nVariation == 0) && (nPart==1))
|
|
rRet.append(" cSub");
|
|
else if ((nVariation == 1) && (nPart==2))
|
|
rRet.append(" cSup");
|
|
else if ((nVariation == 1) && (nPart==1))
|
|
rRet.append(" cSub");
|
|
rRet.append(" {");
|
|
break;
|
|
case tmIUNION:
|
|
if (nPart == 0)
|
|
{
|
|
rRet.append(" union"); //union
|
|
sPush = rRet.makeStringAndClear();
|
|
}
|
|
if ((nVariation == 0) && (nPart==1))
|
|
rRet.append(" rSub");
|
|
else if ((nVariation == 1) && (nPart==2))
|
|
rRet.append(" rSup");
|
|
else if ((nVariation == 1) && (nPart==1))
|
|
rRet.append(" rSub");
|
|
rRet.append(" {");
|
|
break;
|
|
case tmINTER:
|
|
if (nPart == 0)
|
|
{
|
|
rRet.append(" intersect"); //intersect
|
|
if (nVariation != 2)
|
|
{
|
|
sPush = rRet.makeStringAndClear();
|
|
}
|
|
}
|
|
if ((nVariation == 0) && (nPart==1))
|
|
rRet.append(" cSub");
|
|
else if ((nVariation == 1) && (nPart==2))
|
|
rRet.append(" cSup");
|
|
else if ((nVariation == 1) && (nPart==1))
|
|
rRet.append(" cSub");
|
|
rRet.append(" {");
|
|
break;
|
|
case tmIINTER:
|
|
if (nPart == 0)
|
|
{
|
|
rRet.append(" intersect"); //intersect
|
|
sPush = rRet.makeStringAndClear();
|
|
}
|
|
if ((nVariation == 0) && (nPart==1))
|
|
rRet.append(" rSub");
|
|
else if ((nVariation == 1) && (nPart==2))
|
|
rRet.append(" rSup");
|
|
else if ((nVariation == 1) && (nPart==1))
|
|
rRet.append(" rSub");
|
|
rRet.append(" {");
|
|
break;
|
|
case tmLIM:
|
|
if ((nVariation == 0) && (nPart==1))
|
|
rRet.append(" cSup");
|
|
else if ((nVariation == 1) && (nPart==1))
|
|
rRet.append(" cSub");
|
|
else if ((nVariation == 2) && (nPart==1))
|
|
rRet.append(" cSub");
|
|
else if ((nVariation == 2) && (nPart==2))
|
|
rRet.append(" cSup");
|
|
rRet.append(" {");
|
|
break;
|
|
case tmLDIV:
|
|
if (nVariation == 0)
|
|
{
|
|
if (nPart == 0)
|
|
{
|
|
sPush = rRet.makeStringAndClear();
|
|
}
|
|
}
|
|
rRet.append(" {");
|
|
if (nVariation == 0)
|
|
{
|
|
if (nPart == 1)
|
|
rRet.append("alignr ");
|
|
}
|
|
if (nPart == 0)
|
|
rRet.append("\\lline ");
|
|
if (nVariation == 1)
|
|
rRet.append("overline ");
|
|
break;
|
|
case tmINTOP:
|
|
if (nPart == 0)
|
|
{
|
|
sPush = rRet.makeStringAndClear();
|
|
}
|
|
if ((nVariation == 0) && (nPart==0))
|
|
rRet.append(" rSup");
|
|
else if ((nVariation == 2) && (nPart==1))
|
|
rRet.append(" rSup");
|
|
else if ((nVariation == 1) && (nPart==0))
|
|
rRet.append(" rSub");
|
|
else if ((nVariation == 2) && (nPart==0))
|
|
rRet.append(" rSub");
|
|
rRet.append(" {");
|
|
break;
|
|
case tmSUMOP:
|
|
if (nPart == 0)
|
|
{
|
|
sPush = rRet.makeStringAndClear();
|
|
}
|
|
if ((nVariation == 0) && (nPart==0))
|
|
rRet.append(" cSup");
|
|
else if ((nVariation == 2) && (nPart==1))
|
|
rRet.append(" cSup");
|
|
else if ((nVariation == 1) && (nPart==0))
|
|
rRet.append(" cSub");
|
|
else if ((nVariation == 2) && (nPart==0))
|
|
rRet.append(" cSub");
|
|
rRet.append(" {");
|
|
break;
|
|
case tmLSCRIPT:
|
|
if (nPart == 0)
|
|
rRet.append("\"\"");
|
|
if ((nVariation == 0)
|
|
|| ((nVariation == 2) && (nPart==1)))
|
|
rRet.append(" lSup");
|
|
else if ((nVariation == 1)
|
|
|| ((nVariation == 2) && (nPart==0)))
|
|
rRet.append(" lSub");
|
|
rRet.append(" {");
|
|
break;
|
|
case tmDIRAC:
|
|
if (nVariation==0)
|
|
{
|
|
if (nPart == 0)
|
|
rRet.append(" langle ");
|
|
}
|
|
else if (nVariation==1)
|
|
{
|
|
rRet.append(" \\langle ");
|
|
newline--;
|
|
}
|
|
else if (nVariation==2)
|
|
{
|
|
rRet.append(" \\lline ");
|
|
newline--;
|
|
}
|
|
break;
|
|
case tmUARROW:
|
|
if (nVariation == 0)
|
|
rRet.append(" widevec ");//left below - missing functionality
|
|
else if (nVariation == 1)
|
|
rRet.append(" widevec ");//right below - missing functionality
|
|
else if (nVariation == 2)
|
|
rRet.append(" widevec ");//double headed below - missing functionality
|
|
rRet.append(" {");
|
|
break;
|
|
case tmOARROW:
|
|
if (nVariation == 0)
|
|
rRet.append(" widevec ");//left above - missing functionality
|
|
else if (nVariation == 1)
|
|
rRet.append(" widevec ");//right above
|
|
else if (nVariation == 2)
|
|
rRet.append(" widevec ");//double headed above - missing functionality
|
|
rRet.append(" {");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
sal_Int16 nOldCurSize=nCurSize;
|
|
sal_Int32 nSizeStartPos = rRet.getLength();
|
|
HandleSize( nLSize, nDSize, nSetSize );
|
|
bRet = HandleRecords( nLevel+1 );
|
|
while (nSetSize)
|
|
{
|
|
bool bOk=false;
|
|
sal_Int32 nI = rRet.lastIndexOf('{');
|
|
if (nI != -1)
|
|
{
|
|
for(nI=nI+1;nI<rRet.getLength();nI++)
|
|
if (rRet[nI] != ' ')
|
|
{
|
|
bOk=true;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
bOk=true;
|
|
|
|
if (bOk)
|
|
rRet.append("} ");
|
|
else if (rRet.getLength() > nSizeStartPos)
|
|
rRet = rRet.truncate(nSizeStartPos);
|
|
nSetSize--;
|
|
nCurSize=nOldCurSize;
|
|
}
|
|
|
|
|
|
HandleMatrixSeparator(nMatrixRows,nMatrixCols,
|
|
nCurCol,nCurRow);
|
|
|
|
switch (nSelector)
|
|
{
|
|
case tmANGLE:
|
|
if (nVariation==0)
|
|
rRet.append(" rangle ");
|
|
else if (nVariation==2)
|
|
rRet.append(" \\rangle ");
|
|
break;
|
|
case tmPAREN:
|
|
if (nVariation==0)
|
|
rRet.append(" right )");
|
|
else if (nVariation==2)
|
|
rRet.append("\\)");
|
|
break;
|
|
case tmBRACE:
|
|
if ((nVariation==0) || (nVariation==2))
|
|
rRet.append(" right rbrace ");
|
|
else
|
|
rRet.append(" right none ");
|
|
break;
|
|
case tmBRACK:
|
|
if (nVariation==0)
|
|
rRet.append(" right ]");
|
|
else if (nVariation==2)
|
|
rRet.append("\\]");
|
|
break;
|
|
case tmBAR:
|
|
if (nVariation==0)
|
|
rRet.append(" rline ");
|
|
else if (nVariation==2)
|
|
rRet.append(" \\rline ");
|
|
break;
|
|
case tmDBAR:
|
|
if (nVariation==0)
|
|
rRet.append(" rdline ");
|
|
else if (nVariation==2)
|
|
rRet.append(" \\rdline ");
|
|
break;
|
|
case tmFLOOR:
|
|
if (nVariation == 0 || nVariation & 0x02) // tvFENCE_R
|
|
rRet.append(" right rfloor ");
|
|
else
|
|
rRet.append(" right none ");
|
|
break;
|
|
case tmCEILING:
|
|
if (nVariation==0)
|
|
rRet.append(" rceil ");
|
|
else if (nVariation==2)
|
|
rRet.append(" \\rceil ");
|
|
break;
|
|
case tmLBLB:
|
|
case tmRBLB:
|
|
rRet.append("\\[");
|
|
break;
|
|
case tmRBRB:
|
|
case tmLPRB:
|
|
rRet.append("\\]");
|
|
break;
|
|
case tmROOT:
|
|
rRet.append("} ");
|
|
if (nVariation == 1)
|
|
{
|
|
if (nPart == 0)
|
|
{
|
|
newline--;
|
|
sMainTerm = rRet.makeStringAndClear();
|
|
}
|
|
else if (nPart == 1)
|
|
{
|
|
rRet.insert(0, sPush);
|
|
rRet.append(sMainTerm);
|
|
sPush.clear();
|
|
sMainTerm.clear();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (nPart == 0)
|
|
newline--;
|
|
}
|
|
nPart++;
|
|
break;
|
|
case tmLBRP:
|
|
rRet.append("\\)");
|
|
break;
|
|
case tmFRACT:
|
|
rRet.append("} ");
|
|
if (nPart == 0)
|
|
newline--;
|
|
else
|
|
rRet.append("} ");
|
|
nPart++;
|
|
break;
|
|
case tmSCRIPT:
|
|
{
|
|
if ((nPart == 0) &&
|
|
((nVariation == 2) || (nVariation == 1)))
|
|
newline--;
|
|
|
|
bool bOk=false;
|
|
sal_Int32 nI = rRet.lastIndexOf('{');
|
|
if (nI != -1)
|
|
{
|
|
for(nI=nI+1;nI<rRet.getLength();nI++)
|
|
if (rRet[nI] != ' ')
|
|
{
|
|
bOk=true;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
bOk=true;
|
|
|
|
if (bOk)
|
|
rRet.append("} ");
|
|
else if (rRet.getLength() > nSubSupStartPos)
|
|
rRet = rRet.truncate(nSubSupStartPos);
|
|
nPart++;
|
|
}
|
|
break;
|
|
case tmLSCRIPT:
|
|
if ((nPart == 0) &&
|
|
((nVariation == 2) || (nVariation == 1)))
|
|
newline--;
|
|
rRet.append("} ");
|
|
nPart++;
|
|
break;
|
|
case tmUARROW:
|
|
case tmOARROW:
|
|
rRet.append("} ");
|
|
break;
|
|
case tmUBAR:
|
|
case tmOBAR:
|
|
rRet.append("}} ");
|
|
break;
|
|
case tmLARROW:
|
|
case tmRARROW:
|
|
case tmBARROW:
|
|
if (nPart == 0)
|
|
{
|
|
newline--;
|
|
rRet.append("} ");
|
|
}
|
|
nPart++;
|
|
break;
|
|
case tmUHBRACE:
|
|
rRet.append("} ");
|
|
if (nPart == 0)
|
|
{
|
|
newline--;
|
|
rRet.append("overbrace");
|
|
}
|
|
nPart++;
|
|
break;
|
|
case tmLHBRACE:
|
|
rRet.append("} ");
|
|
if (nPart == 0)
|
|
{
|
|
newline--;
|
|
rRet.append("underbrace");
|
|
}
|
|
nPart++;
|
|
break;
|
|
case tmLIM:
|
|
if (nPart==0)
|
|
newline--;
|
|
else if ((nPart==1) &&
|
|
((nVariation == 2) || (nVariation == 1)))
|
|
newline--;
|
|
rRet.append("} ");
|
|
nPart++;
|
|
break;
|
|
case tmLDIV:
|
|
rRet.append("} ");
|
|
if (nVariation == 0)
|
|
{
|
|
if (nPart == 0)
|
|
{
|
|
sMainTerm = rRet.makeStringAndClear();
|
|
}
|
|
else if (nPart == 1)
|
|
{
|
|
rRet.insert(0, sPush);
|
|
rRet.append(" over " + sMainTerm);
|
|
sPush.clear();
|
|
sMainTerm.clear();
|
|
}
|
|
}
|
|
if (nPart == 0)
|
|
newline--;
|
|
nPart++;
|
|
break;
|
|
case tmSLFRACT:
|
|
rRet.append("} ");
|
|
if (nPart == 0)
|
|
{
|
|
newline--;
|
|
switch (nVariation)
|
|
{
|
|
case 1:
|
|
rRet.append("slash");
|
|
break;
|
|
default:
|
|
rRet.append("wideslash");
|
|
break;
|
|
}
|
|
}
|
|
nPart++;
|
|
break;
|
|
case tmSUM:
|
|
case tmISUM:
|
|
case tmPROD:
|
|
case tmIPROD:
|
|
case tmCOPROD:
|
|
case tmICOPROD:
|
|
case tmUNION:
|
|
case tmIUNION:
|
|
case tmINTER:
|
|
case tmIINTER:
|
|
rRet.append("} ");
|
|
if (nPart == 0)
|
|
{
|
|
if (nVariation != 2)
|
|
{
|
|
sMainTerm = rRet.makeStringAndClear();
|
|
}
|
|
newline--;
|
|
}
|
|
else if ((nPart == 1) && (nVariation == 0))
|
|
{
|
|
rRet.insert(0, sPush);
|
|
rRet.append(sMainTerm);
|
|
sPush.clear();
|
|
sMainTerm.clear();
|
|
newline--;
|
|
}
|
|
else if ((nPart == 1) && (nVariation == 1))
|
|
newline--;
|
|
else if ((nPart == 2) && (nVariation == 1))
|
|
{
|
|
rRet.insert(0, sPush);
|
|
rRet.append(sMainTerm);
|
|
sPush.clear();
|
|
sMainTerm.clear();
|
|
newline--;
|
|
}
|
|
nPart++;
|
|
break;
|
|
case tmSINT:
|
|
rRet.append("} ");
|
|
if (nPart == 0)
|
|
{
|
|
if ((nVariation != 0) && (nVariation != 3))
|
|
{
|
|
sMainTerm = rRet.makeStringAndClear();
|
|
}
|
|
newline--;
|
|
}
|
|
else if ((nPart == 1) &&
|
|
((nVariation == 1) || (nVariation==4)))
|
|
{
|
|
rRet.insert(0, sPush);
|
|
rRet.append(sMainTerm);
|
|
sPush.clear();
|
|
sMainTerm.clear();
|
|
newline--;
|
|
}
|
|
else if ((nPart == 1) && (nVariation == 2))
|
|
newline--;
|
|
else if ((nPart == 2) && (nVariation == 2))
|
|
{
|
|
rRet.insert(0, sPush);
|
|
rRet.append(sMainTerm);
|
|
sPush.clear();
|
|
sMainTerm.clear();
|
|
newline--;
|
|
}
|
|
nPart++;
|
|
break;
|
|
case tmDINT:
|
|
case tmTINT:
|
|
rRet.append("} ");
|
|
if (nPart == 0)
|
|
{
|
|
if ((nVariation != 0) && (nVariation != 2))
|
|
{
|
|
sMainTerm = rRet.makeStringAndClear();
|
|
}
|
|
newline--;
|
|
}
|
|
else if ((nPart == 1) &&
|
|
((nVariation == 1) || (nVariation==3)))
|
|
{
|
|
rRet.insert(0, sPush);
|
|
rRet.append(sMainTerm);
|
|
sPush.clear();
|
|
sMainTerm.clear();
|
|
newline--;
|
|
}
|
|
nPart++;
|
|
break;
|
|
case tmSSINT:
|
|
rRet.append("} ");
|
|
if (nPart == 0)
|
|
{
|
|
sMainTerm = rRet.makeStringAndClear();
|
|
newline--;
|
|
}
|
|
else if ((nPart == 1) &&
|
|
((nVariation == 1) || (nVariation==2)))
|
|
{
|
|
rRet.insert(0, sPush);
|
|
rRet.append(sMainTerm);
|
|
sPush.clear();
|
|
sMainTerm.clear();
|
|
newline--;
|
|
}
|
|
else if ((nPart == 1) && (nVariation == 0))
|
|
newline--;
|
|
else if ((nPart == 2) && (nVariation == 0))
|
|
{
|
|
rRet.insert(0, sPush);
|
|
rRet.append(sMainTerm);
|
|
sPush.clear();
|
|
sMainTerm.clear();
|
|
newline--;
|
|
}
|
|
nPart++;
|
|
break;
|
|
case tmDSINT:
|
|
case tmTSINT:
|
|
rRet.append("} ");
|
|
if (nPart == 0)
|
|
{
|
|
sMainTerm = rRet.makeStringAndClear();
|
|
newline--;
|
|
}
|
|
else if (nPart == 1)
|
|
{
|
|
rRet.insert(0, sPush);
|
|
rRet.append(sMainTerm);
|
|
sPush.clear();
|
|
sMainTerm.clear();
|
|
newline--;
|
|
}
|
|
nPart++;
|
|
break;
|
|
case tmINTOP:
|
|
case tmSUMOP:
|
|
rRet.append("} ");
|
|
|
|
if ((nPart == 0) &&
|
|
((nVariation == 0) || (nVariation == 1)))
|
|
{
|
|
sMainTerm = rRet.makeStringAndClear();
|
|
newline--;
|
|
}
|
|
else if ((nPart == 0) && (nVariation == 2))
|
|
newline--;
|
|
else if ((nPart == 1) && (nVariation == 2))
|
|
{
|
|
sMainTerm = rRet.makeStringAndClear();
|
|
newline--;
|
|
}
|
|
else if ((nPart == 2) || ((nPart == 1) &&
|
|
(nVariation == 0 || nVariation == 1)))
|
|
{
|
|
rRet.insert(0, sPush);
|
|
rRet.append(sMainTerm);
|
|
sPush.clear();
|
|
sMainTerm.clear();
|
|
}
|
|
nPart++;
|
|
break;
|
|
case tmDIRAC:
|
|
if (nVariation==0)
|
|
{
|
|
if (nPart == 0)
|
|
{
|
|
newline--; //there is another term to arrive
|
|
rRet.append(" mline ");
|
|
}
|
|
else
|
|
rRet.append(" rangle ");
|
|
}
|
|
else if (nVariation==1)
|
|
rRet.append(" \\lline ");
|
|
else if (nVariation==2)
|
|
rRet.append(" \\rangle ");
|
|
nPart++;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
bSilent = true; //Skip the optional brackets and/or
|
|
//symbols that follow some of these
|
|
//records. Foo Data.
|
|
|
|
/*In matrices and piles we cannot separate equation
|
|
*lines with the newline keyword*/
|
|
if (nMatrixCols==0)
|
|
newline++;
|
|
}
|
|
}
|
|
break;
|
|
case CHAR:
|
|
if (xfLMOVE(nTag))
|
|
HandleNudge();
|
|
bRet = HandleChar( nTextStart, nSetSize, nLevel, nTag, nSelector, nVariation, bSilent );
|
|
break;
|
|
case TMPL:
|
|
if (xfLMOVE(nTag))
|
|
HandleNudge();
|
|
bRet = HandleTemplate( nLevel, nSelector, nVariation, nLastTemplateBracket );
|
|
break;
|
|
case PILE:
|
|
if (xfLMOVE(nTag))
|
|
HandleNudge();
|
|
bRet = HandlePile( nSetAlign, nLevel, nSelector, nVariation );
|
|
HandleMatrixSeparator( nMatrixRows, nMatrixCols, nCurCol, nCurRow );
|
|
break;
|
|
case MATRIX:
|
|
if (xfLMOVE(nTag))
|
|
HandleNudge();
|
|
bRet = HandleMatrix( nLevel, nSelector, nVariation );
|
|
HandleMatrixSeparator( nMatrixRows, nMatrixCols, nCurCol, nCurRow );
|
|
break;
|
|
case EMBEL:
|
|
if (xfLMOVE(nTag))
|
|
HandleNudge();
|
|
HandleEmblishments();
|
|
break;
|
|
case RULER:
|
|
{
|
|
sal_uInt8 nTabStops(0);
|
|
pS->ReadUChar( nTabStops );
|
|
for (i=0;i<nTabStops;i++)
|
|
{
|
|
pS->ReadUChar( nTabType );
|
|
pS->ReadUInt16( nTabOffset );
|
|
}
|
|
SAL_WARN("starmath", "Not seen in the wild Equation Ruler Field");
|
|
break;
|
|
}
|
|
case FONT:
|
|
{
|
|
MathTypeFont aFont;
|
|
pS->ReadUChar( aFont.nTface );
|
|
/*
|
|
The typeface number is the negative (which makes it
|
|
positive) of the typeface value (unbiased) that appears in
|
|
CHAR records that might follow a given FONT record
|
|
*/
|
|
aFont.nTface = 128-aFont.nTface;
|
|
pS->ReadUChar( aFont.nStyle );
|
|
aUserStyles.insert(aFont);
|
|
// read font name
|
|
while(true)
|
|
{
|
|
char nChar8(0);
|
|
pS->ReadChar( nChar8 );
|
|
if (nChar8 == 0)
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case SIZE:
|
|
HandleSetSize();
|
|
break;
|
|
case 10:
|
|
case 11:
|
|
case 12:
|
|
case 13:
|
|
case 14:
|
|
nLSize=nRecord-10;
|
|
break;
|
|
case END:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
while (nRecord != END && !pS->eof());
|
|
while (nSetSize)
|
|
{
|
|
rRet.append("}");
|
|
nSetSize--;
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
/*Simply determine if we are at the end of a record or the end of a line,
|
|
*with fiddly logic to see if we are in a matrix or a pile or neither
|
|
|
|
Note we cannot tell until after the event that this is the last entry
|
|
of a pile, so we must strip the last separator of a pile after this
|
|
is detected in the PILE handler
|
|
*/
|
|
void MathType::HandleMatrixSeparator(int nMatrixRows,int nMatrixCols,
|
|
int &rCurCol,int &rCurRow)
|
|
{
|
|
if (nMatrixRows==0)
|
|
return;
|
|
|
|
if (rCurCol == nMatrixCols-1)
|
|
{
|
|
if (rCurRow != nMatrixRows-1)
|
|
rRet.append(" {} ##\n");
|
|
if (nMatrixRows!=-1)
|
|
{
|
|
rCurCol=0;
|
|
rCurRow++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rRet.append(" {} # ");
|
|
if (nMatrixRows!=-1)
|
|
rCurCol++;
|
|
else
|
|
rRet.append("\n");
|
|
}
|
|
}
|
|
|
|
/* set the alignment of the following term, but starmath currently
|
|
* cannot handle vertical alignment */
|
|
void MathType::HandleAlign(sal_uInt8 nHorAlign, int &rSetAlign)
|
|
{
|
|
switch(nHorAlign)
|
|
{
|
|
case 1:
|
|
default:
|
|
rRet.append("alignl {");
|
|
break;
|
|
case 2:
|
|
rRet.append("alignc {");
|
|
break;
|
|
case 3:
|
|
rRet.append("alignr {");
|
|
break;
|
|
}
|
|
rSetAlign++;
|
|
}
|
|
|
|
/* set size of text, complexity due to overuse of signedness as a flag
|
|
* indicator by mathtype file format*/
|
|
bool MathType::HandleSize(sal_Int16 nLstSize,sal_Int16 nDefSize, int &rSetSize)
|
|
{
|
|
bool bRet=false;
|
|
if (nLstSize < 0)
|
|
{
|
|
const sal_Int16 nDefaultSize = 12;
|
|
if ((-nLstSize/32 != nDefaultSize) && (-nLstSize/32 != nCurSize))
|
|
{
|
|
if (rSetSize)
|
|
{
|
|
rSetSize--;
|
|
rRet.append("}");
|
|
bRet=true;
|
|
}
|
|
if (-nLstSize/32 != nLastSize)
|
|
{
|
|
nLastSize = nCurSize;
|
|
rRet.append(" size ");
|
|
rRet.append(static_cast<sal_Int32>(-nLstSize/32));
|
|
rRet.append("{");
|
|
bRet=true;
|
|
rSetSize++;
|
|
}
|
|
nCurSize = -nLstSize/32;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*sizetable should theoretically be filled with the default sizes
|
|
*of the various font groupings matching starmaths equivalents
|
|
in aTypeFaces, and a test would be done to see if the new font
|
|
size would be the same as what starmath would have chosen for
|
|
itself anyway in which case the size setting could be ignored*/
|
|
nLstSize = aSizeTable.at(nLstSize);
|
|
nLstSize = nLstSize + nDefSize;
|
|
if (nLstSize != nCurSize)
|
|
{
|
|
if (rSetSize)
|
|
{
|
|
rSetSize--;
|
|
rRet.append("}");
|
|
bRet=true;
|
|
}
|
|
if (nLstSize != nLastSize)
|
|
{
|
|
nLastSize = nCurSize;
|
|
rRet.append(" size ");
|
|
rRet.append(static_cast<sal_Int32>(nLstSize));
|
|
rRet.append("{");
|
|
bRet=true;
|
|
rSetSize++;
|
|
}
|
|
nCurSize = nLstSize;
|
|
}
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
bool MathType::ConvertFromStarMath( SfxMedium& rMedium )
|
|
{
|
|
if (!pTree)
|
|
return false;
|
|
|
|
SvStream *pStream = rMedium.GetOutStream();
|
|
if ( pStream )
|
|
{
|
|
rtl::Reference<SotStorage> pStor = new SotStorage(pStream, false);
|
|
|
|
SvGlobalName aGName(MSO_EQUATION3_CLASSID);
|
|
pStor->SetClass( aGName, SotClipboardFormatId::NONE, u"Microsoft Equation 3.0"_ustr);
|
|
|
|
static sal_uInt8 const aCompObj[] = {
|
|
0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0xCE, 0x02, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x46, 0x17, 0x00, 0x00, 0x00,
|
|
0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66,
|
|
0x74, 0x20, 0x45, 0x71, 0x75, 0x61, 0x74, 0x69,
|
|
0x6F, 0x6E, 0x20, 0x33, 0x2E, 0x30, 0x00, 0x0C,
|
|
0x00, 0x00, 0x00, 0x44, 0x53, 0x20, 0x45, 0x71,
|
|
0x75, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x0B,
|
|
0x00, 0x00, 0x00, 0x45, 0x71, 0x75, 0x61, 0x74,
|
|
0x69, 0x6F, 0x6E, 0x2E, 0x33, 0x00, 0xF4, 0x39,
|
|
0xB2, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
|
};
|
|
rtl::Reference<SotStorageStream> xStor(pStor->OpenSotStream(u"\1CompObj"_ustr));
|
|
xStor->WriteBytes(aCompObj, sizeof(aCompObj));
|
|
|
|
static sal_uInt8 const aOle[] = {
|
|
0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00
|
|
};
|
|
rtl::Reference<SotStorageStream> xStor2(pStor->OpenSotStream(u"\1Ole"_ustr));
|
|
xStor2->WriteBytes(aOle, sizeof(aOle));
|
|
xStor.clear();
|
|
xStor2.clear();
|
|
|
|
rtl::Reference<SotStorageStream> xSrc = pStor->OpenSotStream(u"Equation Native"_ustr);
|
|
if ( (!xSrc.is()) || (ERRCODE_NONE != xSrc->GetError()))
|
|
return false;
|
|
|
|
pS = xSrc.get();
|
|
pS->SetEndian( SvStreamEndian::LITTLE );
|
|
|
|
pS->SeekRel(EQNOLEFILEHDR_SIZE); //Skip 28byte Header and fill it in later
|
|
pS->WriteUChar( 0x03 );
|
|
pS->WriteUChar( 0x01 );
|
|
pS->WriteUChar( 0x01 );
|
|
pS->WriteUChar( 0x03 );
|
|
pS->WriteUChar( 0x00 );
|
|
sal_uInt64 nSize = pS->Tell();
|
|
nPendingAttributes=0;
|
|
|
|
HandleNodes(pTree, 0);
|
|
pS->WriteUChar( END );
|
|
|
|
nSize = pS->Tell()-nSize;
|
|
pS->Seek(0);
|
|
EQNOLEFILEHDR aHdr(nSize+4+1);
|
|
aHdr.Write(pS);
|
|
|
|
pStor->Commit();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void MathType::HandleNodes(SmNode *pNode,int nLevel)
|
|
{
|
|
switch(pNode->GetType())
|
|
{
|
|
case SmNodeType::Attribute:
|
|
HandleAttributes(pNode,nLevel);
|
|
break;
|
|
case SmNodeType::Text:
|
|
HandleText(pNode);
|
|
break;
|
|
case SmNodeType::VerticalBrace:
|
|
HandleVerticalBrace(pNode,nLevel);
|
|
break;
|
|
case SmNodeType::Brace:
|
|
HandleBrace(pNode,nLevel);
|
|
break;
|
|
case SmNodeType::Oper:
|
|
HandleOperator(pNode,nLevel);
|
|
break;
|
|
case SmNodeType::BinVer:
|
|
HandleFractions(pNode,nLevel);
|
|
break;
|
|
case SmNodeType::Root:
|
|
HandleRoot(pNode,nLevel);
|
|
break;
|
|
case SmNodeType::Special:
|
|
{
|
|
SmTextNode *pText = static_cast<SmTextNode *>(pNode);
|
|
//if the token str and the result text are the same then this
|
|
//is to be seen as text, else assume it's a mathchar
|
|
if (pText->GetText() == pText->GetToken().aText)
|
|
HandleText(pText);
|
|
else
|
|
HandleMath(pText);
|
|
}
|
|
break;
|
|
case SmNodeType::Math:
|
|
case SmNodeType::MathIdent:
|
|
HandleMath(pNode);
|
|
break;
|
|
case SmNodeType::SubSup:
|
|
HandleSubSupScript(pNode,nLevel);
|
|
break;
|
|
case SmNodeType::Table:
|
|
//Root Node, PILE equivalent, i.e. vertical stack
|
|
HandleTable(pNode,nLevel);
|
|
break;
|
|
case SmNodeType::Matrix:
|
|
HandleSmMatrix(static_cast<SmMatrixNode *>(pNode),nLevel);
|
|
break;
|
|
case SmNodeType::Line:
|
|
{
|
|
pS->WriteUChar( 0x0a );
|
|
pS->WriteUChar( LINE );
|
|
size_t nSize = pNode->GetNumSubNodes();
|
|
for (size_t i = 0; i < nSize; ++i)
|
|
{
|
|
if (SmNode *pTemp = pNode->GetSubNode(i))
|
|
HandleNodes(pTemp,nLevel+1);
|
|
}
|
|
pS->WriteUChar( END );
|
|
break;
|
|
}
|
|
case SmNodeType::Align:
|
|
HandleMAlign(pNode,nLevel);
|
|
break;
|
|
case SmNodeType::Blank:
|
|
pS->WriteUChar( CHAR );
|
|
pS->WriteUChar( 0x98 );
|
|
if (pNode->GetToken().eType == TSBLANK)
|
|
pS->WriteUInt16( 0xEB04 );
|
|
else
|
|
pS->WriteUInt16( 0xEB05 );
|
|
break;
|
|
case SmNodeType::Expression: // same treatment as the default one
|
|
default:
|
|
{
|
|
size_t nSize = pNode->GetNumSubNodes();
|
|
for (size_t i = 0; i < nSize; ++i)
|
|
{
|
|
if (SmNode *pTemp = pNode->GetSubNode(i))
|
|
HandleNodes(pTemp,nLevel+1);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int MathType::StartTemplate(sal_uInt16 nSelector,sal_uInt16 nVariation)
|
|
{
|
|
int nOldPending=nPendingAttributes;
|
|
pS->WriteUChar( TMPL ); //Template
|
|
pS->WriteUChar( nSelector ); //selector
|
|
pS->WriteUChar( nVariation ); //variation
|
|
pS->WriteUChar( 0x00 ); //options
|
|
pS->WriteUChar( LINE );
|
|
//there's just no way we can now handle any character
|
|
//attributes (from mathtypes perspective) centered
|
|
//over an expression but above template attribute
|
|
//such as widevec and similar constructs
|
|
//we have to drop them
|
|
nPendingAttributes=0;
|
|
return nOldPending;
|
|
}
|
|
|
|
void MathType::EndTemplate(int nOldPendingAttributes)
|
|
{
|
|
pS->WriteUChar( END ); //end line
|
|
pS->WriteUChar( END ); //end template
|
|
nPendingAttributes=nOldPendingAttributes;
|
|
}
|
|
|
|
|
|
void MathType::HandleSmMatrix(SmMatrixNode *pMatrix,int nLevel)
|
|
{
|
|
pS->WriteUChar( MATRIX );
|
|
pS->WriteUChar( 0x00 ); //vAlign ?
|
|
pS->WriteUChar( 0x00 ); //h_just
|
|
pS->WriteUChar( 0x00 ); //v_just
|
|
pS->WriteUChar( pMatrix->GetNumRows() ); //v_just
|
|
pS->WriteUChar( pMatrix->GetNumCols() ); //v_just
|
|
int nBytes=(pMatrix->GetNumRows()+1)*2/8;
|
|
if (((pMatrix->GetNumRows()+1)*2)%8)
|
|
nBytes++;
|
|
for (int j = 0; j < nBytes; j++)
|
|
pS->WriteUChar( 0x00 ); //row_parts
|
|
nBytes=(pMatrix->GetNumCols()+1)*2/8;
|
|
if (((pMatrix->GetNumCols()+1)*2)%8)
|
|
nBytes++;
|
|
for (int k = 0; k < nBytes; k++)
|
|
pS->WriteUChar( 0x00 ); //col_parts
|
|
size_t nSize = pMatrix->GetNumSubNodes();
|
|
for (size_t i = 0; i < nSize; ++i)
|
|
{
|
|
if (SmNode *pTemp = pMatrix->GetSubNode(i))
|
|
{
|
|
pS->WriteUChar( LINE ); //line
|
|
HandleNodes(pTemp,nLevel+1);
|
|
pS->WriteUChar( END ); //end line
|
|
}
|
|
}
|
|
pS->WriteUChar( END );
|
|
}
|
|
|
|
|
|
//Root Node, PILE equivalent, i.e. vertical stack
|
|
void MathType::HandleTable(SmNode *pNode,int nLevel)
|
|
{
|
|
size_t nSize = pNode->GetNumSubNodes();
|
|
//The root of the starmath is a table, if
|
|
//we convert this them each iteration of
|
|
//conversion from starmath to mathtype will
|
|
//add an extra unnecessary level to the
|
|
//mathtype output stack which would grow
|
|
//without bound in a multi step conversion
|
|
|
|
if (nLevel == 0)
|
|
pS->WriteUChar( 0x0A ); //initial size
|
|
|
|
if ( nLevel || (nSize >1))
|
|
{
|
|
pS->WriteUChar( PILE );
|
|
pS->WriteUChar( nHAlign ); //vAlign ?
|
|
pS->WriteUChar( 0x01 ); //hAlign
|
|
}
|
|
|
|
for (size_t i = 0; i < nSize; ++i)
|
|
{
|
|
if (SmNode *pTemp = pNode->GetSubNode(i))
|
|
{
|
|
pS->WriteUChar( LINE );
|
|
HandleNodes(pTemp,nLevel+1);
|
|
pS->WriteUChar( END );
|
|
}
|
|
}
|
|
if (nLevel || (nSize>1))
|
|
pS->WriteUChar( END );
|
|
}
|
|
|
|
|
|
void MathType::HandleRoot(SmNode *pNode,int nLevel)
|
|
{
|
|
SmNode *pTemp;
|
|
pS->WriteUChar( TMPL ); //Template
|
|
pS->WriteUChar( 0x0D ); //selector
|
|
if (pNode->GetSubNode(0))
|
|
pS->WriteUChar( 0x01 ); //variation
|
|
else
|
|
pS->WriteUChar( 0x00 ); //variation
|
|
pS->WriteUChar( 0x00 ); //options
|
|
|
|
if (nullptr != (pTemp = pNode->GetSubNode(2)))
|
|
{
|
|
pS->WriteUChar( LINE ); //line
|
|
HandleNodes(pTemp,nLevel+1);
|
|
pS->WriteUChar( END );
|
|
}
|
|
|
|
if (nullptr != (pTemp = pNode->GetSubNode(0)))
|
|
{
|
|
pS->WriteUChar( LINE ); //line
|
|
HandleNodes(pTemp,nLevel+1);
|
|
pS->WriteUChar( END );
|
|
}
|
|
else
|
|
pS->WriteUChar( LINE|0x10 ); //dummy line
|
|
|
|
|
|
pS->WriteUChar( END );
|
|
}
|
|
|
|
sal_uInt8 MathType::HandleCScript(SmNode *pNode,SmNode *pContent,int nLevel,
|
|
sal_uInt64 *pPos,bool bTest)
|
|
{
|
|
sal_uInt8 nVariation2=0xff;
|
|
|
|
if (bTest && pNode->GetSubNode(CSUP+1))
|
|
{
|
|
nVariation2=0;
|
|
if (pNode->GetSubNode(CSUB+1))
|
|
nVariation2=2;
|
|
}
|
|
else if (pNode->GetSubNode(CSUB+1))
|
|
nVariation2=1;
|
|
|
|
if (nVariation2!=0xff)
|
|
{
|
|
if (pPos)
|
|
*pPos = pS->Tell();
|
|
pS->WriteUChar( TMPL ); //Template
|
|
pS->WriteUChar( 0x2B ); //selector
|
|
pS->WriteUChar( nVariation2 );
|
|
pS->WriteUChar( 0x00 ); //options
|
|
|
|
if (pContent)
|
|
{
|
|
pS->WriteUChar( LINE ); //line
|
|
HandleNodes(pContent,nLevel+1);
|
|
pS->WriteUChar( END ); //line
|
|
}
|
|
else
|
|
pS->WriteUChar( LINE|0x10 );
|
|
|
|
pS->WriteUChar( 0x0B );
|
|
|
|
SmNode *pTemp;
|
|
if (nullptr != (pTemp = pNode->GetSubNode(CSUB+1)))
|
|
{
|
|
pS->WriteUChar( LINE ); //line
|
|
HandleNodes(pTemp,nLevel+1);
|
|
pS->WriteUChar( END ); //line
|
|
}
|
|
else
|
|
pS->WriteUChar( LINE|0x10 );
|
|
if (bTest && nullptr != (pTemp = pNode->GetSubNode(CSUP+1)))
|
|
{
|
|
pS->WriteUChar( LINE ); //line
|
|
HandleNodes(pTemp,nLevel+1);
|
|
pS->WriteUChar( END ); //line
|
|
}
|
|
else
|
|
pS->WriteUChar( LINE|0x10 );
|
|
}
|
|
return nVariation2;
|
|
}
|
|
|
|
|
|
/*
|
|
Sub and Sup scripts and another problem area, StarMath
|
|
can have all possible options used at the same time, whereas
|
|
Mathtype cannot. The ordering of the nodes for each system
|
|
is quite different as well leading to some complexity
|
|
*/
|
|
void MathType::HandleSubSupScript(SmNode *pNode,int nLevel)
|
|
{
|
|
sal_uInt8 nVariation=0xff;
|
|
if (pNode->GetSubNode(LSUP+1))
|
|
{
|
|
nVariation=0;
|
|
if (pNode->GetSubNode(LSUB+1))
|
|
nVariation=2;
|
|
}
|
|
else if ( nullptr != pNode->GetSubNode(LSUB+1) )
|
|
nVariation=1;
|
|
|
|
SmNode *pTemp;
|
|
if (nVariation!=0xff)
|
|
{
|
|
pS->WriteUChar( TMPL ); //Template
|
|
pS->WriteUChar( 0x2c ); //selector
|
|
pS->WriteUChar( nVariation );
|
|
pS->WriteUChar( 0x00 ); //options
|
|
pS->WriteUChar( 0x0B );
|
|
|
|
if (nullptr != (pTemp = pNode->GetSubNode(LSUB+1)))
|
|
{
|
|
pS->WriteUChar( LINE ); //line
|
|
HandleNodes(pTemp,nLevel+1);
|
|
pS->WriteUChar( END ); //line
|
|
}
|
|
else
|
|
pS->WriteUChar( LINE|0x10 );
|
|
if (nullptr != (pTemp = pNode->GetSubNode(LSUP+1)))
|
|
{
|
|
pS->WriteUChar( LINE ); //line
|
|
HandleNodes(pTemp,nLevel+1);
|
|
pS->WriteUChar( END ); //line
|
|
}
|
|
else
|
|
pS->WriteUChar( LINE|0x10 );
|
|
pS->WriteUChar( END );
|
|
nVariation=0xff;
|
|
}
|
|
|
|
|
|
sal_uInt8 nVariation2=HandleCScript(pNode,nullptr,nLevel);
|
|
|
|
if (nullptr != (pTemp = pNode->GetSubNode(0)))
|
|
{
|
|
HandleNodes(pTemp,nLevel+1);
|
|
}
|
|
|
|
if (nVariation2 != 0xff)
|
|
pS->WriteUChar( END );
|
|
|
|
if (nullptr != (pNode->GetSubNode(RSUP+1)))
|
|
{
|
|
nVariation=0;
|
|
if (pNode->GetSubNode(RSUB+1))
|
|
nVariation=2;
|
|
}
|
|
else if (nullptr != pNode->GetSubNode(RSUB+1))
|
|
nVariation=1;
|
|
|
|
if (nVariation!=0xff)
|
|
{
|
|
pS->WriteUChar( TMPL ); //Template
|
|
pS->WriteUChar( 0x0F ); //selector
|
|
pS->WriteUChar( nVariation );
|
|
pS->WriteUChar( 0x00 ); //options
|
|
pS->WriteUChar( 0x0B );
|
|
|
|
if (nullptr != (pTemp = pNode->GetSubNode(RSUB+1)))
|
|
{
|
|
pS->WriteUChar( LINE ); //line
|
|
HandleNodes(pTemp,nLevel+1);
|
|
pS->WriteUChar( END ); //line
|
|
}
|
|
else
|
|
pS->WriteUChar( LINE|0x10 );
|
|
if (nullptr != (pTemp = pNode->GetSubNode(RSUP+1)))
|
|
{
|
|
pS->WriteUChar( LINE ); //line
|
|
HandleNodes(pTemp,nLevel+1);
|
|
pS->WriteUChar( END ); //line
|
|
}
|
|
else
|
|
pS->WriteUChar( LINE|0x10 );
|
|
pS->WriteUChar( END ); //line
|
|
}
|
|
|
|
//After subscript mathtype will keep the size of
|
|
//normal text at the subscript size, sigh.
|
|
pS->WriteUChar( 0x0A );
|
|
}
|
|
|
|
|
|
void MathType::HandleFractions(SmNode *pNode,int nLevel)
|
|
{
|
|
SmNode *pTemp;
|
|
pS->WriteUChar( TMPL ); //Template
|
|
pS->WriteUChar( 0x0E ); //selector
|
|
pS->WriteUChar( 0x00 ); //variation
|
|
pS->WriteUChar( 0x00 ); //options
|
|
|
|
pS->WriteUChar( 0x0A );
|
|
pS->WriteUChar( LINE ); //line
|
|
if (nullptr != (pTemp = pNode->GetSubNode(0)))
|
|
HandleNodes(pTemp,nLevel+1);
|
|
pS->WriteUChar( END );
|
|
|
|
pS->WriteUChar( 0x0A );
|
|
pS->WriteUChar( LINE ); //line
|
|
if (nullptr != (pTemp = pNode->GetSubNode(2)))
|
|
HandleNodes(pTemp,nLevel+1);
|
|
pS->WriteUChar( END );
|
|
|
|
pS->WriteUChar( END );
|
|
}
|
|
|
|
|
|
void MathType::HandleBrace(SmNode *pNode,int nLevel)
|
|
{
|
|
SmNode *pTemp;
|
|
SmNode *pLeft=pNode->GetSubNode(0);
|
|
SmNode *pRight=pNode->GetSubNode(2);
|
|
|
|
pS->WriteUChar( TMPL ); //Template
|
|
bIsReInterpBrace=false;
|
|
sal_uInt8 nBSpec=0x10;
|
|
auto nLoc = pS->Tell();
|
|
if (pLeft)
|
|
{
|
|
switch (pLeft->GetToken().eType)
|
|
{
|
|
case TLANGLE:
|
|
pS->WriteUChar( tmANGLE ); //selector
|
|
pS->WriteUChar( 0 ); //variation
|
|
pS->WriteUChar( 0 ); //options
|
|
break;
|
|
case TLBRACE:
|
|
pS->WriteUChar( tmBRACE ); //selector
|
|
pS->WriteUChar( 0 ); //variation
|
|
pS->WriteUChar( 0 ); //options
|
|
nBSpec+=3;
|
|
break;
|
|
case TLBRACKET:
|
|
pS->WriteUChar( tmBRACK ); //selector
|
|
pS->WriteUChar( 0 ); //variation
|
|
pS->WriteUChar( 0 ); //options
|
|
nBSpec+=3;
|
|
break;
|
|
case TLFLOOR:
|
|
pS->WriteUChar( tmFLOOR ); //selector
|
|
pS->WriteUChar( 0 ); //variation
|
|
pS->WriteUChar( 0 ); //options
|
|
break;
|
|
case TLLINE:
|
|
pS->WriteUChar( tmBAR ); //selector
|
|
pS->WriteUChar( 0 ); //variation
|
|
pS->WriteUChar( 0 ); //options
|
|
nBSpec+=3;
|
|
break;
|
|
case TLDLINE:
|
|
pS->WriteUChar( tmDBAR ); //selector
|
|
pS->WriteUChar( 0 ); //variation
|
|
pS->WriteUChar( 0 ); //options
|
|
break;
|
|
default:
|
|
pS->WriteUChar( tmPAREN ); //selector
|
|
pS->WriteUChar( 0 ); //variation
|
|
pS->WriteUChar( 0 ); //options
|
|
nBSpec+=3;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (nullptr != (pTemp = pNode->GetSubNode(1)))
|
|
{
|
|
pS->WriteUChar( LINE ); //line
|
|
HandleNodes(pTemp,nLevel+1);
|
|
pS->WriteUChar( END ); //options
|
|
}
|
|
nSpec=nBSpec;
|
|
if (pLeft)
|
|
HandleNodes(pLeft,nLevel+1);
|
|
if (bIsReInterpBrace)
|
|
{
|
|
auto nLoc2 = pS->Tell();
|
|
pS->Seek(nLoc);
|
|
pS->WriteUChar( 0x2D );
|
|
pS->Seek(nLoc2);
|
|
pS->WriteUChar( CHAR );
|
|
pS->WriteUChar( 0x96 );
|
|
pS->WriteUInt16( 0xEC07 );
|
|
bIsReInterpBrace=false;
|
|
}
|
|
if (pRight)
|
|
HandleNodes(pRight,nLevel+1);
|
|
nSpec=0x0;
|
|
pS->WriteUChar( END );
|
|
}
|
|
|
|
|
|
void MathType::HandleVerticalBrace(SmNode *pNode,int nLevel)
|
|
{
|
|
SmNode *pTemp;
|
|
pS->WriteUChar( TMPL ); //Template
|
|
if (pNode->GetToken().eType == TUNDERBRACE)
|
|
pS->WriteUChar( tmLHBRACE ); //selector
|
|
else
|
|
pS->WriteUChar( tmUHBRACE ); //selector
|
|
pS->WriteUChar( 0 ); //variation
|
|
pS->WriteUChar( 0 ); //options
|
|
|
|
if (nullptr != (pTemp = pNode->GetSubNode(0)))
|
|
{
|
|
pS->WriteUChar( LINE ); //line
|
|
HandleNodes(pTemp,nLevel+1);
|
|
pS->WriteUChar( END ); //options
|
|
}
|
|
|
|
if (nullptr != (pTemp = pNode->GetSubNode(2)))
|
|
{
|
|
pS->WriteUChar( LINE ); //line
|
|
HandleNodes(pTemp,nLevel+1);
|
|
pS->WriteUChar( END ); //options
|
|
}
|
|
pS->WriteUChar( END );
|
|
}
|
|
|
|
void MathType::HandleOperator(SmNode *pNode,int nLevel)
|
|
{
|
|
if (HandleLim(pNode,nLevel))
|
|
return;
|
|
|
|
sal_uInt64 nPos;
|
|
sal_uInt8 nVariation;
|
|
|
|
switch (pNode->GetToken().eType)
|
|
{
|
|
case TIINT:
|
|
case TIIINT:
|
|
case TLINT:
|
|
case TLLINT:
|
|
case TLLLINT:
|
|
nVariation=HandleCScript(pNode->GetSubNode(0),
|
|
pNode->GetSubNode(1),nLevel,&nPos,false);
|
|
break;
|
|
default:
|
|
nVariation=HandleCScript(pNode->GetSubNode(0),
|
|
pNode->GetSubNode(1),nLevel,&nPos);
|
|
break;
|
|
}
|
|
|
|
sal_uInt8 nOldVariation=nVariation;
|
|
sal_uInt8 nIntVariation=nVariation;
|
|
|
|
sal_uInt64 nPos2=0;
|
|
if (nVariation != 0xff)
|
|
{
|
|
nPos2 = pS->Tell();
|
|
pS->Seek(nPos);
|
|
if (nVariation == 2)
|
|
{
|
|
nIntVariation=0;
|
|
nVariation = 1;
|
|
}
|
|
else if (nVariation == 0)
|
|
nVariation = 1;
|
|
else if (nVariation == 1)
|
|
nVariation = 0;
|
|
}
|
|
else
|
|
{
|
|
nVariation = 2;
|
|
nIntVariation=0;
|
|
}
|
|
pS->WriteUChar( TMPL );
|
|
switch(pNode->GetToken().eType)
|
|
{
|
|
case TINT:
|
|
case TINTD:
|
|
if (nOldVariation != 0xff)
|
|
pS->WriteUChar( 0x18 ); //selector
|
|
else
|
|
pS->WriteUChar( 0x15 ); //selector
|
|
pS->WriteUChar( nIntVariation ); //variation
|
|
break;
|
|
case TIINT:
|
|
if (nOldVariation != 0xff)
|
|
{
|
|
pS->WriteUChar( 0x19 );
|
|
pS->WriteUChar( 0x01 );
|
|
}
|
|
else
|
|
{
|
|
pS->WriteUChar( 0x16 );
|
|
pS->WriteUChar( 0x00 );
|
|
}
|
|
break;
|
|
case TIIINT:
|
|
if (nOldVariation != 0xff)
|
|
{
|
|
pS->WriteUChar( 0x1a );
|
|
pS->WriteUChar( 0x01 );
|
|
}
|
|
else
|
|
{
|
|
pS->WriteUChar( 0x17 );
|
|
pS->WriteUChar( 0x00 );
|
|
}
|
|
break;
|
|
case TLINT:
|
|
if (nOldVariation != 0xff)
|
|
{
|
|
pS->WriteUChar( 0x18 );
|
|
pS->WriteUChar( 0x02 );
|
|
}
|
|
else
|
|
{
|
|
pS->WriteUChar( 0x15 );
|
|
pS->WriteUChar( 0x03 );
|
|
}
|
|
break;
|
|
case TLLINT:
|
|
if (nOldVariation != 0xff)
|
|
{
|
|
pS->WriteUChar( 0x19 );
|
|
pS->WriteUChar( 0x00 );
|
|
}
|
|
else
|
|
{
|
|
pS->WriteUChar( 0x16 );
|
|
pS->WriteUChar( 0x02 );
|
|
}
|
|
break;
|
|
case TLLLINT:
|
|
if (nOldVariation != 0xff)
|
|
{
|
|
pS->WriteUChar( 0x1a );
|
|
pS->WriteUChar( 0x00 );
|
|
}
|
|
else
|
|
{
|
|
pS->WriteUChar( 0x17 );
|
|
pS->WriteUChar( 0x02 );
|
|
}
|
|
break;
|
|
case TSUM:
|
|
default:
|
|
pS->WriteUChar( 0x1d );
|
|
pS->WriteUChar( nVariation );
|
|
break;
|
|
case TPROD:
|
|
pS->WriteUChar( 0x1f );
|
|
pS->WriteUChar( nVariation );
|
|
break;
|
|
case TCOPROD:
|
|
pS->WriteUChar( 0x21 );
|
|
pS->WriteUChar( nVariation );
|
|
break;
|
|
}
|
|
pS->WriteUChar( 0 ); //options
|
|
|
|
if (nPos2)
|
|
pS->Seek(nPos2);
|
|
else
|
|
{
|
|
pS->WriteUChar( LINE ); //line
|
|
HandleNodes(pNode->GetSubNode(1),nLevel+1);
|
|
pS->WriteUChar( END ); //line
|
|
pS->WriteUChar( LINE|0x10 );
|
|
pS->WriteUChar( LINE|0x10 );
|
|
}
|
|
|
|
pS->WriteUChar( 0x0D );
|
|
switch(pNode->GetToken().eType)
|
|
{
|
|
case TSUM:
|
|
default:
|
|
pS->WriteUChar( CHAR );
|
|
pS->WriteUChar( 0x86 );
|
|
pS->WriteUInt16( 0x2211 );
|
|
break;
|
|
case TPROD:
|
|
pS->WriteUChar( CHAR );
|
|
pS->WriteUChar( 0x86 );
|
|
pS->WriteUInt16( 0x220F );
|
|
break;
|
|
case TCOPROD:
|
|
pS->WriteUChar( CHAR );
|
|
pS->WriteUChar( 0x8B );
|
|
pS->WriteUInt16( 0x2210 );
|
|
break;
|
|
case TIIINT:
|
|
case TLLLINT:
|
|
pS->WriteUChar( CHAR );
|
|
pS->WriteUChar( 0x86 );
|
|
pS->WriteUInt16( 0x222B );
|
|
[[fallthrough]];
|
|
case TIINT:
|
|
case TLLINT:
|
|
pS->WriteUChar( CHAR );
|
|
pS->WriteUChar( 0x86 );
|
|
pS->WriteUInt16( 0x222B );
|
|
[[fallthrough]];
|
|
case TINT:
|
|
case TINTD:
|
|
case TLINT:
|
|
pS->WriteUChar( CHAR );
|
|
pS->WriteUChar( 0x86 );
|
|
pS->WriteUInt16( 0x222B );
|
|
break;
|
|
}
|
|
pS->WriteUChar( END );
|
|
pS->WriteUChar( 0x0A );
|
|
}
|
|
|
|
|
|
bool MathType::HandlePile(int &rSetAlign, int nLevel, sal_uInt8 nSelector, sal_uInt8 nVariation)
|
|
{
|
|
sal_uInt8 nVAlign;
|
|
pS->ReadUChar( nHAlign );
|
|
pS->ReadUChar( nVAlign );
|
|
|
|
HandleAlign(nHAlign, rSetAlign);
|
|
|
|
rRet.append(" stack {\n");
|
|
bool bRet = HandleRecords( nLevel+1, nSelector, nVariation, -1, -1 );
|
|
int nRemoveFrom = rRet.getLength() >= 3 ? rRet.getLength() - 3 : 0;
|
|
rRet.remove(nRemoveFrom, 2);
|
|
rRet.append("} ");
|
|
|
|
while (rSetAlign)
|
|
{
|
|
rRet.append("} ");
|
|
rSetAlign--;
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
bool MathType::HandleMatrix(int nLevel, sal_uInt8 nSelector, sal_uInt8 nVariation)
|
|
{
|
|
sal_uInt8 nH_just,nV_just,nRows,nCols,nVAlign;
|
|
pS->ReadUChar( nVAlign );
|
|
pS->ReadUChar( nH_just );
|
|
pS->ReadUChar( nV_just );
|
|
pS->ReadUChar( nRows );
|
|
pS->ReadUChar( nCols );
|
|
if (!pS->good())
|
|
return false;
|
|
int nBytes = ((nRows+1)*2)/8;
|
|
if (((nRows+1)*2)%8)
|
|
nBytes++;
|
|
pS->SeekRel(nBytes);
|
|
nBytes = ((nCols+1)*2)/8;
|
|
if (((nCols+1)*2)%8)
|
|
nBytes++;
|
|
pS->SeekRel(nBytes);
|
|
rRet.append(" matrix {\n");
|
|
bool bRet = HandleRecords( nLevel+1, nSelector, nVariation, nRows, nCols );
|
|
|
|
sal_Int32 nI = rRet.lastIndexOf('#');
|
|
if (nI > 0)
|
|
if (rRet[nI-1] != '#') //missing column
|
|
rRet.append("{}");
|
|
|
|
rRet.append("\n} ");
|
|
return bRet;
|
|
}
|
|
|
|
bool MathType::HandleTemplate(int nLevel, sal_uInt8 &rSelector,
|
|
sal_uInt8 &rVariation, sal_Int32 &rLastTemplateBracket)
|
|
{
|
|
sal_uInt8 nOption; //This appears utterly unused
|
|
pS->ReadUChar( rSelector );
|
|
pS->ReadUChar( rVariation );
|
|
pS->ReadUChar( nOption );
|
|
OSL_ENSURE(rSelector < 48,"Selector out of range");
|
|
if ((rSelector >= 21) && (rSelector <=26))
|
|
{
|
|
OSL_ENSURE(nOption < 2,"Option out of range");
|
|
}
|
|
else if (rSelector <= 12)
|
|
{
|
|
OSL_ENSURE(nOption < 3,"Option out of range");
|
|
}
|
|
|
|
//For the (broken) case where one subscript template ends, and there is
|
|
//another one after it, mathtype handles it as if the second one was
|
|
//inside the first one and renders it as sub of sub
|
|
bool bRemove=false;
|
|
if ( (rSelector == 0xf) && (rLastTemplateBracket != -1) )
|
|
{
|
|
bRemove=true;
|
|
for (sal_Int32 nI = rLastTemplateBracket+1; nI < rRet.getLength(); nI++ )
|
|
if (rRet[nI] != ' ')
|
|
{
|
|
bRemove=false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//suborderlist
|
|
bool bRet = HandleRecords( nLevel+1, rSelector, rVariation );
|
|
|
|
if (bRemove)
|
|
{
|
|
if (rLastTemplateBracket < rRet.getLength())
|
|
rRet.remove(rLastTemplateBracket, 1);
|
|
rRet.append("} ");
|
|
rLastTemplateBracket = -1;
|
|
}
|
|
if (rSelector == 0xf)
|
|
rLastTemplateBracket = rRet.lastIndexOf('}');
|
|
else
|
|
rLastTemplateBracket = -1;
|
|
|
|
rSelector = sal::static_int_cast< sal_uInt8 >(-1);
|
|
return bRet;
|
|
}
|
|
|
|
void MathType::HandleEmblishments()
|
|
{
|
|
sal_uInt8 nEmbel;
|
|
do
|
|
{
|
|
pS->ReadUChar( nEmbel );
|
|
if (!pS->good())
|
|
break;
|
|
switch (nEmbel)
|
|
{
|
|
case 0x02:
|
|
rRet.append(" dot ");
|
|
break;
|
|
case 0x03:
|
|
rRet.append(" ddot ");
|
|
break;
|
|
case 0x04:
|
|
rRet.append(" dddot ");
|
|
break;
|
|
case 0x05:
|
|
if (!nPostSup)
|
|
{
|
|
sPost.append(" sup {}");
|
|
nPostSup = sPost.getLength();
|
|
}
|
|
sPost.insert(nPostSup-1," ' ");
|
|
nPostSup += 3;
|
|
break;
|
|
case 0x06:
|
|
if (!nPostSup)
|
|
{
|
|
sPost.append(" sup {}");
|
|
nPostSup = sPost.getLength();
|
|
}
|
|
sPost.insert(nPostSup-1," '' ");
|
|
nPostSup += 4;
|
|
break;
|
|
case 0x07:
|
|
if (!nPostlSup)
|
|
{
|
|
sPost.append(" lsup {}");
|
|
nPostlSup = sPost.getLength();
|
|
}
|
|
sPost.insert(nPostlSup-1," ' ");
|
|
nPostlSup += 3;
|
|
break;
|
|
case 0x08:
|
|
rRet.append(" tilde ");
|
|
break;
|
|
case 0x09:
|
|
rRet.append(" hat ");
|
|
break;
|
|
case 0x0b:
|
|
rRet.append(" vec ");
|
|
break;
|
|
case 0x10:
|
|
rRet.append(" overstrike ");
|
|
break;
|
|
case 0x11:
|
|
rRet.append(" bar ");
|
|
break;
|
|
case 0x12:
|
|
if (!nPostSup)
|
|
{
|
|
sPost.append(" sup {}");
|
|
nPostSup = sPost.getLength();
|
|
}
|
|
sPost.insert(nPostSup-1," ''' ");
|
|
nPostSup += 5;
|
|
break;
|
|
case 0x14:
|
|
rRet.append(" breve ");
|
|
break;
|
|
default:
|
|
OSL_ENSURE(nEmbel < 21,"Embel out of range");
|
|
break;
|
|
}
|
|
if (nVersion < 3)
|
|
break;
|
|
}while (nEmbel);
|
|
}
|
|
|
|
void MathType::HandleSetSize()
|
|
{
|
|
sal_uInt8 nTemp(0);
|
|
pS->ReadUChar(nTemp);
|
|
switch (nTemp)
|
|
{
|
|
case 101:
|
|
pS->ReadInt16( nLSize );
|
|
nLSize = -nLSize;
|
|
break;
|
|
case 100:
|
|
pS->ReadUChar( nTemp );
|
|
nLSize = nTemp;
|
|
pS->ReadInt16( nDSize );
|
|
break;
|
|
default:
|
|
nLSize = nTemp;
|
|
pS->ReadUChar( nTemp );
|
|
nDSize = nTemp-128;
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool MathType::HandleChar(sal_Int32 &rTextStart, int &rSetSize, int nLevel,
|
|
sal_uInt8 nTag, sal_uInt8 nSelector, sal_uInt8 nVariation, bool bSilent)
|
|
{
|
|
sal_Unicode nChar(0);
|
|
bool bRet = true;
|
|
|
|
if (xfAUTO(nTag))
|
|
{
|
|
//This is a candidate for function recognition, whatever
|
|
//that is!
|
|
}
|
|
|
|
sal_uInt8 nOldTypeFace = nTypeFace;
|
|
pS->ReadUChar( nTypeFace );
|
|
if (nVersion < 3)
|
|
{
|
|
sal_uInt8 nChar8(0);
|
|
pS->ReadUChar( nChar8 );
|
|
nChar = nChar8;
|
|
}
|
|
else
|
|
pS->ReadUtf16( nChar );
|
|
|
|
/*
|
|
bad character, old mathtype < 3 has these
|
|
*/
|
|
if (nChar < 0x20)
|
|
return bRet;
|
|
|
|
if (xfEMBELL(nTag))
|
|
{
|
|
//A bit tricky, the character emblishments for
|
|
//mathtype can all be listed after each other, in
|
|
//starmath some must go before the character and some
|
|
//must go after. In addition some of the emblishments
|
|
//may repeated and in starmath some of these groups
|
|
//must be gathered together. sPost is the portion that
|
|
//follows the char and nPostSup and nPostlSup are the
|
|
//indexes at which this class of emblishment is
|
|
//collated together
|
|
sPost = "";
|
|
nPostSup = nPostlSup = 0;
|
|
int nOriglen=rRet.getLength()-rTextStart;
|
|
rRet.append(" {"); // #i24340# make what would be "vec {A}_n" become "{vec {A}}_n"
|
|
if ((!bSilent) && (nOriglen > 1))
|
|
rRet.append("\"");
|
|
bRet = HandleRecords( nLevel+1, nSelector, nVariation );
|
|
if (!bSilent)
|
|
{
|
|
if (nOriglen > 1)
|
|
{
|
|
OUString aStr;
|
|
TypeFaceToString(aStr,nOldTypeFace);
|
|
rRet.insert(std::min(rTextStart, rRet.getLength()), aStr + "\"");
|
|
|
|
aStr.clear();
|
|
TypeFaceToString(aStr,nTypeFace);
|
|
rRet.append(aStr + "{");
|
|
}
|
|
else
|
|
rRet.append(" {");
|
|
rTextStart = rRet.getLength();
|
|
}
|
|
}
|
|
|
|
if (!bSilent)
|
|
{
|
|
sal_Int32 nOldLen = rRet.getLength();
|
|
if (
|
|
HandleSize(nLSize,nDSize,rSetSize) ||
|
|
(nOldTypeFace != nTypeFace)
|
|
)
|
|
{
|
|
if ((nOldLen - rTextStart) > 1)
|
|
{
|
|
rRet.insert(nOldLen, "\"");
|
|
OUString aStr;
|
|
TypeFaceToString(aStr,nOldTypeFace);
|
|
rRet.insert(rTextStart, aStr + "\"");
|
|
}
|
|
rTextStart = rRet.getLength();
|
|
}
|
|
nOldLen = rRet.getLength();
|
|
if (!LookupChar(nChar,rRet,nVersion,nTypeFace))
|
|
{
|
|
if (nOldLen - rTextStart > 1)
|
|
{
|
|
rRet.insert(nOldLen, "\"");
|
|
OUString aStr;
|
|
TypeFaceToString(aStr,nOldTypeFace);
|
|
rRet.insert(rTextStart, aStr + "\"");
|
|
}
|
|
rTextStart = rRet.getLength();
|
|
}
|
|
lcl_PrependDummyTerm(rRet, rTextStart);
|
|
}
|
|
|
|
if ((xfEMBELL(nTag)) && (!bSilent))
|
|
{
|
|
rRet.append("}}" + sPost); // #i24340# make what would be "vec {A}_n" become "{vec {A}}_n"
|
|
rTextStart = rRet.getLength();
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
bool MathType::HandleLim(SmNode *pNode,int nLevel)
|
|
{
|
|
bool bRet=false;
|
|
//Special case for the "lim" option in StarMath
|
|
if ((pNode->GetToken().eType == TLIM)
|
|
|| (pNode->GetToken().eType == TLIMSUP)
|
|
|| (pNode->GetToken().eType == TLIMINF)
|
|
)
|
|
{
|
|
if (pNode->GetSubNode(1))
|
|
{
|
|
sal_uInt8 nVariation2=HandleCScript(pNode->GetSubNode(0),nullptr,
|
|
nLevel);
|
|
|
|
pS->WriteUChar( 0x0A );
|
|
pS->WriteUChar( LINE ); //line
|
|
pS->WriteUChar( CHAR|0x10 );
|
|
pS->WriteUChar( 0x82 );
|
|
pS->WriteUInt16( 'l' );
|
|
pS->WriteUChar( CHAR|0x10 );
|
|
pS->WriteUChar( 0x82 );
|
|
pS->WriteUInt16( 'i' );
|
|
pS->WriteUChar( CHAR|0x10 );
|
|
pS->WriteUChar( 0x82 );
|
|
pS->WriteUInt16( 'm' );
|
|
|
|
if (pNode->GetToken().eType == TLIMSUP)
|
|
{
|
|
pS->WriteUChar( CHAR ); //some space
|
|
pS->WriteUChar( 0x98 );
|
|
pS->WriteUInt16( 0xEB04 );
|
|
|
|
pS->WriteUChar( CHAR|0x10 );
|
|
pS->WriteUChar( 0x82 );
|
|
pS->WriteUInt16( 's' );
|
|
pS->WriteUChar( CHAR|0x10 );
|
|
pS->WriteUChar( 0x82 );
|
|
pS->WriteUInt16( 'u' );
|
|
pS->WriteUChar( CHAR|0x10 );
|
|
pS->WriteUChar( 0x82 );
|
|
pS->WriteUInt16( 'p' );
|
|
}
|
|
else if (pNode->GetToken().eType == TLIMINF)
|
|
{
|
|
pS->WriteUChar( CHAR ); //some space
|
|
pS->WriteUChar( 0x98 );
|
|
pS->WriteUInt16( 0xEB04 );
|
|
|
|
pS->WriteUChar( CHAR|0x10 );
|
|
pS->WriteUChar( 0x82 );
|
|
pS->WriteUInt16( 'i' );
|
|
pS->WriteUChar( CHAR|0x10 );
|
|
pS->WriteUChar( 0x82 );
|
|
pS->WriteUInt16( 'n' );
|
|
pS->WriteUChar( CHAR|0x10 );
|
|
pS->WriteUChar( 0x82 );
|
|
pS->WriteUInt16( 'f' );
|
|
}
|
|
|
|
|
|
pS->WriteUChar( CHAR ); //some space
|
|
pS->WriteUChar( 0x98 );
|
|
pS->WriteUInt16( 0xEB04 );
|
|
|
|
if (nVariation2 != 0xff)
|
|
{
|
|
pS->WriteUChar( END );
|
|
pS->WriteUChar( END );
|
|
}
|
|
HandleNodes(pNode->GetSubNode(1),nLevel+1);
|
|
bRet = true;
|
|
}
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
void MathType::HandleMAlign(SmNode *pNode,int nLevel)
|
|
{
|
|
sal_uInt8 nPushedHAlign=nHAlign;
|
|
switch(pNode->GetToken().eType)
|
|
{
|
|
case TALIGNC:
|
|
nHAlign=2;
|
|
break;
|
|
case TALIGNR:
|
|
nHAlign=3;
|
|
break;
|
|
default:
|
|
nHAlign=1;
|
|
break;
|
|
}
|
|
size_t nSize = pNode->GetNumSubNodes();
|
|
for (size_t i = 0; i < nSize; ++i)
|
|
{
|
|
if (SmNode *pTemp = pNode->GetSubNode(i))
|
|
HandleNodes(pTemp,nLevel+1);
|
|
}
|
|
nHAlign=nPushedHAlign;
|
|
}
|
|
|
|
void MathType::HandleMath(SmNode *pNode)
|
|
{
|
|
if (pNode->GetToken().eType == TMLINE)
|
|
{
|
|
pS->WriteUChar( END );
|
|
pS->WriteUChar( LINE );
|
|
bIsReInterpBrace=true;
|
|
return;
|
|
}
|
|
SmMathSymbolNode *pTemp = static_cast<SmMathSymbolNode *>(pNode);
|
|
for(sal_Int32 i=0;i<pTemp->GetText().getLength();i++)
|
|
{
|
|
sal_Unicode nArse = SmTextNode::ConvertSymbolToUnicode(pTemp->GetText()[i]);
|
|
if ((nArse == 0x2224) || (nArse == 0x2288) || (nArse == 0x2285) ||
|
|
(nArse == 0x2289))
|
|
{
|
|
pS->WriteUChar( CHAR|0x20 );
|
|
}
|
|
else if (nPendingAttributes &&
|
|
(i == ((pTemp->GetText().getLength()+1)/2)-1))
|
|
{
|
|
pS->WriteUChar( 0x22 );
|
|
}
|
|
else
|
|
pS->WriteUChar( CHAR ); //char without formula recognition
|
|
//The typeface seems to be MTEXTRA for unicode characters,
|
|
//though how to determine when mathtype chooses one over
|
|
//the other is unknown. This should do the trick
|
|
//nevertheless.
|
|
sal_uInt8 nBias;
|
|
if ( (nArse == 0x2213) || (nArse == 0x2218) ||
|
|
(nArse == 0x210F) || (
|
|
(nArse >= 0x22EE) && (nArse <= 0x22FF)
|
|
))
|
|
{
|
|
nBias = 0xB; //typeface
|
|
}
|
|
else if ((nArse == 0x2F) || (nArse == 0x2225))
|
|
nBias = 0x2; //typeface
|
|
else if ((nArse > 0x2000) || (nArse == 0x00D7))
|
|
nBias = 0x6; //typeface
|
|
else if (nArse == 0x3d1)
|
|
nBias = 0x4;
|
|
else if ((nArse > 0xFF) && ((nArse < 0x393) || (nArse > 0x3c9)))
|
|
nBias = 0xB; //typeface
|
|
else
|
|
nBias = 0x3; //typeface
|
|
|
|
pS->WriteUChar( nSpec+nBias+128 ); //typeface
|
|
|
|
if (nArse == 0x2224)
|
|
{
|
|
pS->WriteUInt16( 0x7C );
|
|
pS->WriteUChar( EMBEL );
|
|
pS->WriteUChar( 0x0A );
|
|
pS->WriteUChar( END ); //end embel
|
|
pS->WriteUChar( END ); //end embel
|
|
}
|
|
else if (nArse == 0x2225)
|
|
pS->WriteUInt16( 0xEC09 );
|
|
else if (nArse == 0xE421)
|
|
pS->WriteUInt16( 0x2265 );
|
|
else if (nArse == 0x230A)
|
|
pS->WriteUInt16( 0xF8F0 );
|
|
else if (nArse == 0x230B)
|
|
pS->WriteUInt16( 0xF8FB );
|
|
else if (nArse == 0xE425)
|
|
pS->WriteUInt16( 0x2264 );
|
|
else if (nArse == 0x226A)
|
|
{
|
|
pS->WriteUInt16( 0x3C );
|
|
pS->WriteUChar( CHAR );
|
|
pS->WriteUChar( 0x98 );
|
|
pS->WriteUInt16( 0xEB01 );
|
|
pS->WriteUChar( CHAR );
|
|
pS->WriteUChar( 0x86 );
|
|
pS->WriteUInt16( 0x3c );
|
|
}
|
|
else if (nArse == 0x2288)
|
|
{
|
|
pS->WriteUInt16( 0x2286 );
|
|
pS->WriteUChar( EMBEL );
|
|
pS->WriteUChar( 0x0A );
|
|
pS->WriteUChar( END ); //end embel
|
|
pS->WriteUChar( END ); //end embel
|
|
}
|
|
else if (nArse == 0x2289)
|
|
{
|
|
pS->WriteUInt16( 0x2287 );
|
|
pS->WriteUChar( EMBEL );
|
|
pS->WriteUChar( 0x0A );
|
|
pS->WriteUChar( END ); //end embel
|
|
pS->WriteUChar( END ); //end embel
|
|
}
|
|
else if (nArse == 0x2285)
|
|
{
|
|
pS->WriteUInt16( 0x2283 );
|
|
pS->WriteUChar( EMBEL );
|
|
pS->WriteUChar( 0x0A );
|
|
pS->WriteUChar( END ); //end embel
|
|
pS->WriteUChar( END ); //end embel
|
|
}
|
|
else
|
|
pS->WriteUInt16( nArse );
|
|
}
|
|
nPendingAttributes = 0;
|
|
}
|
|
|
|
void MathType::HandleAttributes(SmNode *pNode,int nLevel)
|
|
{
|
|
sal_uInt64 nOldInsertion = nInsertion;
|
|
int nOldPending = 0;
|
|
SmNode *pTemp = nullptr;
|
|
SmTextNode *pIsText = nullptr;
|
|
|
|
if (nullptr != (pTemp = pNode->GetSubNode(0)))
|
|
{
|
|
pIsText = static_cast<SmTextNode *>(pNode->GetSubNode(1));
|
|
|
|
switch (pTemp->GetToken().eType)
|
|
{
|
|
case TWIDEVEC:
|
|
//there's just no way we can now handle any character
|
|
//attributes (from mathtypes perspective) centered
|
|
//over an expression but above template attributes
|
|
//such as widevec and similar constructs
|
|
//we have to drop them
|
|
nOldPending = StartTemplate(0x2f,0x01);
|
|
break;
|
|
case TCHECK: //Not Exportable
|
|
case TACUTE: //Not Exportable
|
|
case TGRAVE: //Not Exportable
|
|
case TCIRCLE: //Not Exportable
|
|
case TWIDEHARPOON: //Not Exportable
|
|
case TWIDETILDE: //Not Exportable
|
|
case TWIDEHAT: //Not Exportable
|
|
break;
|
|
case TUNDERLINE:
|
|
nOldPending = StartTemplate(0x10);
|
|
break;
|
|
case TOVERLINE: //If the next node is not text
|
|
//or text with more than one char
|
|
if (!pIsText ||
|
|
pIsText->GetToken().eType != TTEXT ||
|
|
pIsText->GetText().getLength() > 1)
|
|
nOldPending = StartTemplate(0x11);
|
|
break;
|
|
default:
|
|
nPendingAttributes++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pIsText)
|
|
HandleNodes(pIsText,nLevel+1);
|
|
|
|
if (pTemp)
|
|
{
|
|
switch (pTemp->GetToken().eType)
|
|
{
|
|
case TWIDEVEC:
|
|
case TUNDERLINE:
|
|
EndTemplate(nOldPending);
|
|
break;
|
|
case TOVERLINE:
|
|
if (!pIsText ||
|
|
pIsText->GetToken().eType != TTEXT ||
|
|
pIsText->GetText().getLength() > 1)
|
|
EndTemplate(nOldPending);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
//if there was no suitable place to put the attribute,
|
|
//then we have to just give up on it
|
|
if (nPendingAttributes)
|
|
nPendingAttributes--;
|
|
else
|
|
{
|
|
if ((nInsertion != 0) && nullptr != (pTemp = pNode->GetSubNode(0)))
|
|
{
|
|
auto nPos = pS->Tell();
|
|
pS->Seek(nInsertion - 1);
|
|
switch(pTemp->GetToken().eType)
|
|
{
|
|
case TACUTE: //Not Exportable
|
|
case TGRAVE: //Not Exportable
|
|
case TCIRCLE: //Not Exportable
|
|
break;
|
|
case TCDOT:
|
|
pS->WriteUChar( 2 );
|
|
break;
|
|
case TDDOT:
|
|
pS->WriteUChar( 3 );
|
|
break;
|
|
case TDDDOT:
|
|
pS->WriteUChar( 4 );
|
|
break;
|
|
case TTILDE:
|
|
pS->WriteUChar( 8 );
|
|
break;
|
|
case THAT:
|
|
pS->WriteUChar( 9 );
|
|
break;
|
|
case TVEC:
|
|
pS->WriteUChar( 11 );
|
|
break;
|
|
case TOVERSTRIKE:
|
|
pS->WriteUChar( 16 );
|
|
break;
|
|
case TOVERLINE:
|
|
if (pIsText &&
|
|
(pIsText->GetToken().eType == TTEXT &&
|
|
pIsText->GetText().getLength() == 1))
|
|
pS->WriteUChar( 17 );
|
|
break;
|
|
case TBREVE:
|
|
pS->WriteUChar( 20 );
|
|
break;
|
|
case TWIDEVEC:
|
|
case TWIDEHARPOON:
|
|
case TUNDERLINE:
|
|
case TWIDETILDE:
|
|
case TWIDEHAT:
|
|
break;
|
|
case TBAR:
|
|
pS->WriteUChar( 17 );
|
|
break;
|
|
default:
|
|
pS->WriteUChar( 2 );
|
|
break;
|
|
}
|
|
pS->Seek(nPos);
|
|
}
|
|
}
|
|
nInsertion = nOldInsertion;
|
|
}
|
|
|
|
void MathType::HandleText(SmNode *pNode)
|
|
{
|
|
SmTextNode *pTemp = static_cast<SmTextNode *>(pNode);
|
|
for(sal_Int32 i=0;i<pTemp->GetText().getLength();i++)
|
|
{
|
|
if (nPendingAttributes &&
|
|
(i == ((pTemp->GetText().getLength()+1)/2)-1))
|
|
{
|
|
pS->WriteUChar( 0x22 ); //char, with attributes right
|
|
//after the character
|
|
}
|
|
else
|
|
pS->WriteUChar( CHAR );
|
|
|
|
sal_uInt8 nFace = 0x1;
|
|
if (pNode->GetFont().GetItalic() == ITALIC_NORMAL)
|
|
nFace = 0x3;
|
|
else if (pNode->GetFont().GetWeight() == WEIGHT_BOLD)
|
|
nFace = 0x7;
|
|
pS->WriteUChar( nFace+128 ); //typeface
|
|
sal_uInt16 nChar = pTemp->GetText()[i];
|
|
pS->WriteUInt16( SmTextNode::ConvertSymbolToUnicode(nChar) );
|
|
|
|
//Mathtype can only have these sort of character
|
|
//attributes on a single character, starmath can put them
|
|
//anywhere, when the entity involved is a text run this is
|
|
//a large effort to place the character attribute on the
|
|
//central mathtype character so that it does pretty much
|
|
//what the user probably has in mind. The attributes
|
|
//filled in here are dummy ones which are replaced in the
|
|
//ATTRIBUTE handler if a suitable location for the
|
|
//attributes was found here. Unfortunately it is
|
|
//possible for starmath to place character attributes on
|
|
//entities which cannot occur in mathtype e.g. a Summation
|
|
//symbol so these attributes may be lost
|
|
if (nPendingAttributes &&
|
|
(i == ((pTemp->GetText().getLength()+1)/2)-1))
|
|
{
|
|
pS->WriteUChar( EMBEL );
|
|
while (nPendingAttributes)
|
|
{
|
|
pS->WriteUChar( 2 );
|
|
//wedge the attributes in here and clear
|
|
//the pending stack
|
|
nPendingAttributes--;
|
|
}
|
|
nInsertion=pS->Tell();
|
|
pS->WriteUChar( END ); //end embel
|
|
pS->WriteUChar( END ); //end embel
|
|
}
|
|
}
|
|
}
|
|
|
|
extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportMathType(SvStream &rStream)
|
|
{
|
|
OUStringBuffer sText;
|
|
MathType aEquation(sText);
|
|
bool bRet = false;
|
|
try
|
|
{
|
|
bRet = aEquation.Parse(&rStream);
|
|
}
|
|
catch (const std::out_of_range&)
|
|
{
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|