2013-02-06 07:01:19 +00:00
|
|
|
/*
|
|
|
|
*
|
2014-01-10 02:24:54 +00:00
|
|
|
* (C) Copyright IBM Corp. and others 1998-2014 - All Rights Reserved
|
2013-02-06 07:01:19 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "LETypes.h"
|
|
|
|
#include "MorphTables.h"
|
|
|
|
#include "StateTables.h"
|
|
|
|
#include "MorphStateTables.h"
|
|
|
|
#include "SubtableProcessor2.h"
|
|
|
|
#include "StateTableProcessor2.h"
|
|
|
|
#include "LEGlyphStorage.h"
|
|
|
|
#include "LESwaps.h"
|
|
|
|
#include "LookupTables.h"
|
|
|
|
|
|
|
|
U_NAMESPACE_BEGIN
|
|
|
|
|
|
|
|
StateTableProcessor2::StateTableProcessor2()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-04-18 21:24:51 +00:00
|
|
|
StateTableProcessor2::StateTableProcessor2(const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success)
|
2014-01-10 02:24:54 +00:00
|
|
|
: SubtableProcessor2(morphSubtableHeader, success),
|
|
|
|
dir(1),
|
|
|
|
format(0),
|
|
|
|
nClasses(0),
|
|
|
|
classTableOffset(0),
|
|
|
|
stateArrayOffset(0),
|
|
|
|
entryTableOffset(0),
|
|
|
|
classTable(),
|
|
|
|
stateArray(),
|
|
|
|
stateTableHeader(morphSubtableHeader, success),
|
|
|
|
stHeader(stateTableHeader, success, (const StateTableHeader2*)&stateTableHeader->stHeader)
|
2013-02-06 07:01:19 +00:00
|
|
|
{
|
2013-04-18 21:24:51 +00:00
|
|
|
if (LE_FAILURE(success)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
nClasses = SWAPL(stHeader->nClasses);
|
|
|
|
classTableOffset = SWAPL(stHeader->classTableOffset);
|
|
|
|
stateArrayOffset = SWAPL(stHeader->stateArrayOffset);
|
|
|
|
entryTableOffset = SWAPL(stHeader->entryTableOffset);
|
|
|
|
|
|
|
|
classTable = LEReferenceTo<LookupTable>(stHeader, success, classTableOffset);
|
|
|
|
format = SWAPW(classTable->format);
|
|
|
|
|
|
|
|
stateArray = LEReferenceToArrayOf<EntryTableIndex2>(stHeader, success, stateArrayOffset, LE_UNBOUNDED_ARRAY);
|
2013-02-06 07:01:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
StateTableProcessor2::~StateTableProcessor2()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-04-18 21:24:51 +00:00
|
|
|
void StateTableProcessor2::process(LEGlyphStorage &glyphStorage, LEErrorCode &success)
|
2013-02-06 07:01:19 +00:00
|
|
|
{
|
2013-04-18 21:24:51 +00:00
|
|
|
if (LE_FAILURE(success)) return;
|
2013-02-06 07:01:19 +00:00
|
|
|
// Start at state 0
|
|
|
|
// XXX: How do we know when to start at state 1?
|
|
|
|
le_uint16 currentState = 0;
|
|
|
|
le_int32 glyphCount = glyphStorage.getGlyphCount();
|
2013-04-18 21:24:51 +00:00
|
|
|
|
|
|
|
LE_STATE_PATIENCE_INIT();
|
|
|
|
|
2013-02-06 07:01:19 +00:00
|
|
|
le_int32 currGlyph = 0;
|
|
|
|
if ((coverage & scfReverse2) != 0) { // process glyphs in descending order
|
|
|
|
currGlyph = glyphCount - 1;
|
|
|
|
dir = -1;
|
|
|
|
} else {
|
|
|
|
dir = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
beginStateTable();
|
|
|
|
switch (format) {
|
|
|
|
case ltfSimpleArray: {
|
2013-02-07 01:08:41 +00:00
|
|
|
#ifdef TEST_FORMAT
|
2013-04-18 21:24:51 +00:00
|
|
|
LEReferenceTo<SimpleArrayLookupTable> lookupTable0(classTable, success);
|
|
|
|
if(LE_FAILURE(success)) break;
|
2013-02-06 07:01:19 +00:00
|
|
|
while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) {
|
2013-04-18 21:24:51 +00:00
|
|
|
if (LE_FAILURE(success)) break;
|
|
|
|
if (LE_STATE_PATIENCE_DECR()) {
|
|
|
|
LE_DEBUG_BAD_FONT("patience exceeded - state table not moving")
|
|
|
|
break; // patience exceeded.
|
|
|
|
}
|
2013-02-06 07:01:19 +00:00
|
|
|
LookupValue classCode = classCodeOOB;
|
|
|
|
if (currGlyph == glyphCount || currGlyph == -1) {
|
|
|
|
// XXX: How do we handle EOT vs. EOL?
|
|
|
|
classCode = classCodeEOT;
|
|
|
|
} else {
|
|
|
|
LEGlyphID gid = glyphStorage[currGlyph];
|
|
|
|
TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid);
|
|
|
|
|
|
|
|
if (glyphCode == 0xFFFF) {
|
|
|
|
classCode = classCodeDEL;
|
|
|
|
} else {
|
|
|
|
classCode = SWAPW(lookupTable0->valueArray[gid]);
|
|
|
|
}
|
|
|
|
}
|
2013-04-18 21:24:51 +00:00
|
|
|
EntryTableIndex2 entryTableIndex = SWAPW(stateArray(classCode + currentState * nClasses, success));
|
|
|
|
LE_STATE_PATIENCE_CURR(le_int32, currGlyph);
|
2013-02-06 07:01:19 +00:00
|
|
|
currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); // return a zero-based index instead of a byte offset
|
2013-04-18 21:24:51 +00:00
|
|
|
LE_STATE_PATIENCE_INCR(currGlyph);
|
2013-02-06 07:01:19 +00:00
|
|
|
}
|
2013-02-07 01:08:41 +00:00
|
|
|
#endif
|
2013-02-06 07:01:19 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ltfSegmentSingle: {
|
2013-04-18 21:24:51 +00:00
|
|
|
LEReferenceTo<SegmentSingleLookupTable> lookupTable2(classTable, success);
|
|
|
|
if(LE_FAILURE(success)) break;
|
2013-02-06 07:01:19 +00:00
|
|
|
while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) {
|
2013-04-18 21:24:51 +00:00
|
|
|
if (LE_FAILURE(success)) break;
|
|
|
|
if (LE_STATE_PATIENCE_DECR()) {
|
|
|
|
LE_DEBUG_BAD_FONT("patience exceeded - state table not moving")
|
|
|
|
break; // patience exceeded.
|
|
|
|
}
|
2013-02-06 07:01:19 +00:00
|
|
|
LookupValue classCode = classCodeOOB;
|
|
|
|
if (currGlyph == glyphCount || currGlyph == -1) {
|
|
|
|
// XXX: How do we handle EOT vs. EOL?
|
|
|
|
classCode = classCodeEOT;
|
|
|
|
} else {
|
|
|
|
LEGlyphID gid = glyphStorage[currGlyph];
|
|
|
|
TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid);
|
|
|
|
|
|
|
|
if (glyphCode == 0xFFFF) {
|
|
|
|
classCode = classCodeDEL;
|
|
|
|
} else {
|
2013-04-18 21:24:51 +00:00
|
|
|
const LookupSegment *segment =
|
|
|
|
lookupTable2->lookupSegment(lookupTable2, lookupTable2->segments, gid, success);
|
|
|
|
if (segment != NULL && LE_SUCCESS(success)) {
|
2013-02-06 07:01:19 +00:00
|
|
|
classCode = SWAPW(segment->value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-04-18 21:24:51 +00:00
|
|
|
EntryTableIndex2 entryTableIndex = SWAPW(stateArray(classCode + currentState * nClasses,success));
|
|
|
|
LE_STATE_PATIENCE_CURR(le_int32, currGlyph);
|
|
|
|
currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex, success);
|
|
|
|
LE_STATE_PATIENCE_INCR(currGlyph);
|
2013-02-06 07:01:19 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ltfSegmentArray: {
|
2013-04-18 21:24:51 +00:00
|
|
|
//printf("Lookup Table Format4: specific interpretation needed!\n");
|
2013-02-06 07:01:19 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ltfSingleTable: {
|
2013-04-18 21:24:51 +00:00
|
|
|
LEReferenceTo<SingleTableLookupTable> lookupTable6(classTable, success);
|
2013-02-06 07:01:19 +00:00
|
|
|
while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) {
|
2013-04-18 21:24:51 +00:00
|
|
|
if (LE_FAILURE(success)) break;
|
|
|
|
if (LE_STATE_PATIENCE_DECR()) {
|
|
|
|
LE_DEBUG_BAD_FONT("patience exceeded - state table not moving")
|
|
|
|
break; // patience exceeded.
|
|
|
|
}
|
2013-02-06 07:01:19 +00:00
|
|
|
LookupValue classCode = classCodeOOB;
|
|
|
|
if (currGlyph == glyphCount || currGlyph == -1) {
|
|
|
|
// XXX: How do we handle EOT vs. EOL?
|
|
|
|
classCode = classCodeEOT;
|
2013-04-18 21:24:51 +00:00
|
|
|
} else if(currGlyph > glyphCount) {
|
|
|
|
// note if > glyphCount, we've run off the end (bad font)
|
|
|
|
currGlyph = glyphCount;
|
|
|
|
classCode = classCodeEOT;
|
2013-02-06 07:01:19 +00:00
|
|
|
} else {
|
|
|
|
LEGlyphID gid = glyphStorage[currGlyph];
|
|
|
|
TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid);
|
|
|
|
|
|
|
|
if (glyphCode == 0xFFFF) {
|
|
|
|
classCode = classCodeDEL;
|
|
|
|
} else {
|
2013-04-18 21:24:51 +00:00
|
|
|
const LookupSingle *segment = lookupTable6->lookupSingle(lookupTable6, lookupTable6->entries, gid, success);
|
2013-02-06 07:01:19 +00:00
|
|
|
if (segment != NULL) {
|
|
|
|
classCode = SWAPW(segment->value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-04-18 21:24:51 +00:00
|
|
|
EntryTableIndex2 entryTableIndex = SWAPW(stateArray(classCode + currentState * nClasses, success));
|
|
|
|
LE_STATE_PATIENCE_CURR(le_int32, currGlyph);
|
|
|
|
currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex, success);
|
|
|
|
LE_STATE_PATIENCE_INCR(currGlyph);
|
2013-02-06 07:01:19 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ltfTrimmedArray: {
|
2013-04-18 21:24:51 +00:00
|
|
|
LEReferenceTo<TrimmedArrayLookupTable> lookupTable8(classTable, success);
|
|
|
|
if (LE_FAILURE(success)) break;
|
2013-02-06 07:01:19 +00:00
|
|
|
TTGlyphID firstGlyph = SWAPW(lookupTable8->firstGlyph);
|
|
|
|
TTGlyphID lastGlyph = firstGlyph + SWAPW(lookupTable8->glyphCount);
|
|
|
|
|
|
|
|
while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) {
|
2013-04-18 21:24:51 +00:00
|
|
|
if(LE_STATE_PATIENCE_DECR()) {
|
|
|
|
LE_DEBUG_BAD_FONT("patience exceeded - state table not moving")
|
|
|
|
break; // patience exceeded.
|
|
|
|
}
|
|
|
|
|
2013-02-06 07:01:19 +00:00
|
|
|
LookupValue classCode = classCodeOOB;
|
|
|
|
if (currGlyph == glyphCount || currGlyph == -1) {
|
|
|
|
// XXX: How do we handle EOT vs. EOL?
|
|
|
|
classCode = classCodeEOT;
|
|
|
|
} else {
|
|
|
|
TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(glyphStorage[currGlyph]);
|
|
|
|
if (glyphCode == 0xFFFF) {
|
|
|
|
classCode = classCodeDEL;
|
|
|
|
} else if ((glyphCode >= firstGlyph) && (glyphCode < lastGlyph)) {
|
|
|
|
classCode = SWAPW(lookupTable8->valueArray[glyphCode - firstGlyph]);
|
|
|
|
}
|
|
|
|
}
|
2013-04-18 21:24:51 +00:00
|
|
|
EntryTableIndex2 entryTableIndex = SWAPW(stateArray(classCode + currentState * nClasses, success));
|
|
|
|
LE_STATE_PATIENCE_CURR(le_int32, currGlyph);
|
|
|
|
currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex, success);
|
|
|
|
LE_STATE_PATIENCE_INCR(currGlyph);
|
2013-02-06 07:01:19 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
endStateTable();
|
|
|
|
}
|
|
|
|
|
|
|
|
U_NAMESPACE_END
|