1/*
2 *
3 * (C) Copyright IBM Corp.  and others 1998-2014 - All Rights Reserved
4 *
5 */
6
7#include "LETypes.h"
8#include "MorphTables.h"
9#include "StateTables.h"
10#include "MorphStateTables.h"
11#include "SubtableProcessor2.h"
12#include "StateTableProcessor2.h"
13#include "LEGlyphStorage.h"
14#include "LESwaps.h"
15#include "LookupTables.h"
16
17U_NAMESPACE_BEGIN
18
19StateTableProcessor2::StateTableProcessor2()
20{
21}
22
23StateTableProcessor2::StateTableProcessor2(const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success)
24  : SubtableProcessor2(morphSubtableHeader, success),
25    dir(1),
26    format(0),
27    nClasses(0),
28    classTableOffset(0),
29    stateArrayOffset(0),
30    entryTableOffset(0),
31    classTable(),
32    stateArray(),
33    stateTableHeader(morphSubtableHeader, success),
34    stHeader(stateTableHeader, success, (const StateTableHeader2*)&stateTableHeader->stHeader)
35{
36  if (LE_FAILURE(success)) {
37    return;
38  }
39  nClasses = SWAPL(stHeader->nClasses);
40  classTableOffset = SWAPL(stHeader->classTableOffset);
41  stateArrayOffset = SWAPL(stHeader->stateArrayOffset);
42  entryTableOffset = SWAPL(stHeader->entryTableOffset);
43
44  classTable = LEReferenceTo<LookupTable>(stHeader, success, classTableOffset);
45  format = SWAPW(classTable->format);
46
47  stateArray = LEReferenceToArrayOf<EntryTableIndex2>(stHeader, success, stateArrayOffset, LE_UNBOUNDED_ARRAY);
48}
49
50StateTableProcessor2::~StateTableProcessor2()
51{
52}
53
54void StateTableProcessor2::process(LEGlyphStorage &glyphStorage, LEErrorCode &success)
55{
56    if (LE_FAILURE(success)) return;
57    // Start at state 0
58    // XXX: How do we know when to start at state 1?
59    le_uint16 currentState = 0;
60    le_int32 glyphCount = glyphStorage.getGlyphCount();
61
62    LE_STATE_PATIENCE_INIT();
63
64    le_int32 currGlyph = 0;
65    if ((coverage & scfReverse2) != 0) {  // process glyphs in descending order
66        currGlyph = glyphCount - 1;
67        dir = -1;
68    } else {
69        dir = 1;
70    }
71
72    beginStateTable();
73    switch (format) {
74        case ltfSimpleArray: {
75#ifdef TEST_FORMAT
76          LEReferenceTo<SimpleArrayLookupTable> lookupTable0(classTable, success);
77          if(LE_FAILURE(success)) break;
78            while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) {
79                if (LE_FAILURE(success)) break;
80                if (LE_STATE_PATIENCE_DECR()) {
81                  LE_DEBUG_BAD_FONT("patience exceeded - state table not moving")
82                  break; // patience exceeded.
83                }
84                LookupValue classCode = classCodeOOB;
85                if (currGlyph == glyphCount || currGlyph == -1) {
86                    // XXX: How do we handle EOT vs. EOL?
87                    classCode = classCodeEOT;
88                } else {
89                    LEGlyphID gid = glyphStorage[currGlyph];
90                    TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid);
91
92                    if (glyphCode == 0xFFFF) {
93                        classCode = classCodeDEL;
94                    } else {
95                        classCode = SWAPW(lookupTable0->valueArray[gid]);
96                    }
97                }
98                EntryTableIndex2 entryTableIndex = SWAPW(stateArray(classCode + currentState * nClasses, success));
99                LE_STATE_PATIENCE_CURR(le_int32, currGlyph);
100                currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); // return a zero-based index instead of a byte offset
101                LE_STATE_PATIENCE_INCR(currGlyph);
102            }
103#endif
104            break;
105        }
106        case ltfSegmentSingle: {
107          LEReferenceTo<SegmentSingleLookupTable> lookupTable2(classTable, success);
108          if(LE_FAILURE(success)) break;
109            while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) {
110                if (LE_FAILURE(success)) break;
111                if (LE_STATE_PATIENCE_DECR()) {
112                  LE_DEBUG_BAD_FONT("patience exceeded  - state table not moving")
113                  break; // patience exceeded.
114                }
115                LookupValue classCode = classCodeOOB;
116                if (currGlyph == glyphCount || currGlyph == -1) {
117                    // XXX: How do we handle EOT vs. EOL?
118                    classCode = classCodeEOT;
119                } else {
120                    LEGlyphID gid = glyphStorage[currGlyph];
121                    TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid);
122
123                    if (glyphCode == 0xFFFF) {
124                        classCode = classCodeDEL;
125                    } else {
126                      const LookupSegment *segment =
127                        lookupTable2->lookupSegment(lookupTable2, lookupTable2->segments, gid, success);
128                        if (segment != NULL && LE_SUCCESS(success)) {
129                            classCode = SWAPW(segment->value);
130                        }
131                    }
132                }
133                EntryTableIndex2 entryTableIndex = SWAPW(stateArray(classCode + currentState * nClasses,success));
134                LE_STATE_PATIENCE_CURR(le_int32, currGlyph);
135                currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex, success);
136                LE_STATE_PATIENCE_INCR(currGlyph);
137            }
138            break;
139        }
140        case ltfSegmentArray: {
141          //printf("Lookup Table Format4: specific interpretation needed!\n");
142            break;
143        }
144        case ltfSingleTable: {
145            LEReferenceTo<SingleTableLookupTable> lookupTable6(classTable, success);
146            while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) {
147                if (LE_FAILURE(success)) break;
148                if (LE_STATE_PATIENCE_DECR()) {
149                  LE_DEBUG_BAD_FONT("patience exceeded - state table not moving")
150                  break; // patience exceeded.
151                }
152                LookupValue classCode = classCodeOOB;
153                if (currGlyph == glyphCount || currGlyph == -1) {
154                    // XXX: How do we handle EOT vs. EOL?
155                    classCode = classCodeEOT;
156                } else if(currGlyph > glyphCount) {
157                  // note if > glyphCount, we've run off the end (bad font)
158                  currGlyph = glyphCount;
159                  classCode = classCodeEOT;
160                } else {
161                    LEGlyphID gid = glyphStorage[currGlyph];
162                    TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid);
163
164                    if (glyphCode == 0xFFFF) {
165                        classCode = classCodeDEL;
166                    } else {
167                      const LookupSingle *segment = lookupTable6->lookupSingle(lookupTable6, lookupTable6->entries, gid, success);
168                        if (segment != NULL) {
169                            classCode = SWAPW(segment->value);
170                        }
171                    }
172                }
173                EntryTableIndex2 entryTableIndex = SWAPW(stateArray(classCode + currentState * nClasses, success));
174                LE_STATE_PATIENCE_CURR(le_int32, currGlyph);
175                currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex, success);
176                LE_STATE_PATIENCE_INCR(currGlyph);
177            }
178            break;
179        }
180        case ltfTrimmedArray: {
181            LEReferenceTo<TrimmedArrayLookupTable> lookupTable8(classTable, success);
182            if (LE_FAILURE(success)) break;
183            TTGlyphID firstGlyph = SWAPW(lookupTable8->firstGlyph);
184            TTGlyphID lastGlyph  = firstGlyph + SWAPW(lookupTable8->glyphCount);
185
186            while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) {
187                if(LE_STATE_PATIENCE_DECR()) {
188                  LE_DEBUG_BAD_FONT("patience exceeded - state table not moving")
189                  break; // patience exceeded.
190                }
191
192                LookupValue classCode = classCodeOOB;
193                if (currGlyph == glyphCount || currGlyph == -1) {
194                    // XXX: How do we handle EOT vs. EOL?
195                    classCode = classCodeEOT;
196                } else {
197                    TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(glyphStorage[currGlyph]);
198                    if (glyphCode == 0xFFFF) {
199                        classCode = classCodeDEL;
200                    } else if ((glyphCode >= firstGlyph) && (glyphCode < lastGlyph)) {
201                        classCode = SWAPW(lookupTable8->valueArray[glyphCode - firstGlyph]);
202                    }
203                }
204                EntryTableIndex2 entryTableIndex = SWAPW(stateArray(classCode + currentState * nClasses, success));
205                LE_STATE_PATIENCE_CURR(le_int32, currGlyph);
206                currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex, success);
207                LE_STATE_PATIENCE_INCR(currGlyph);
208            }
209            break;
210        }
211        default:
212            break;
213    }
214
215    endStateTable();
216}
217
218U_NAMESPACE_END
219