1/*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation.  Oracle designates this
7 * particular file as subject to the "Classpath" exception as provided
8 * by Oracle in the LICENSE file that accompanied this code.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 *
24 */
25
26/*
27 *
28 * (C) Copyright IBM Corp.  and others 1998-2013 - All Rights Reserved
29 *
30 */
31
32#include "LETypes.h"
33#include "MorphTables.h"
34#include "StateTables.h"
35#include "MorphStateTables.h"
36#include "SubtableProcessor2.h"
37#include "StateTableProcessor2.h"
38#include "LEGlyphStorage.h"
39#include "LESwaps.h"
40#include "LookupTables.h"
41
42U_NAMESPACE_BEGIN
43
44StateTableProcessor2::StateTableProcessor2()
45{
46}
47
48StateTableProcessor2::StateTableProcessor2(const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success)
49  : SubtableProcessor2(morphSubtableHeader, success), stateTableHeader(morphSubtableHeader, success),
50    stHeader(stateTableHeader, success, (const StateTableHeader2*)&stateTableHeader->stHeader),
51    nClasses(0), classTableOffset(0), stateArrayOffset(0), entryTableOffset(0), classTable(), format(0),
52    stateArray()
53{
54  if (LE_FAILURE(success)) {
55    return;
56  }
57  nClasses = SWAPL(stHeader->nClasses);
58  classTableOffset = SWAPL(stHeader->classTableOffset);
59  stateArrayOffset = SWAPL(stHeader->stateArrayOffset);
60  entryTableOffset = SWAPL(stHeader->entryTableOffset);
61
62  classTable = LEReferenceTo<LookupTable>(stHeader, success, classTableOffset);
63  if (LE_FAILURE(success)) return;
64  format = SWAPW(classTable->format);
65
66  stateArray = LEReferenceToArrayOf<EntryTableIndex2>(stHeader, success, stateArrayOffset, LE_UNBOUNDED_ARRAY);
67}
68
69StateTableProcessor2::~StateTableProcessor2()
70{
71}
72
73void StateTableProcessor2::process(LEGlyphStorage &glyphStorage, LEErrorCode &success)
74{
75    if (LE_FAILURE(success)) return;
76    // Start at state 0
77    // XXX: How do we know when to start at state 1?
78    le_uint16 currentState = 0;
79    le_int32 glyphCount = glyphStorage.getGlyphCount();
80
81    LE_STATE_PATIENCE_INIT();
82
83    le_int32 currGlyph = 0;
84    if ((coverage & scfReverse2) != 0) {  // process glyphs in descending order
85        currGlyph = glyphCount - 1;
86        dir = -1;
87    } else {
88        dir = 1;
89    }
90
91    beginStateTable();
92    switch (format) {
93        case ltfSimpleArray: {
94#ifdef TEST_FORMAT
95          LEReferenceTo<SimpleArrayLookupTable> lookupTable0(classTable, success);
96          if(LE_FAILURE(success)) break;
97            while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) {
98                if (LE_FAILURE(success)) break;
99                if (LE_STATE_PATIENCE_DECR()) {
100                  LE_DEBUG_BAD_FONT("patience exceeded - state table not moving")
101                  break; // patience exceeded.
102                }
103                LookupValue classCode = classCodeOOB;
104                if (currGlyph == glyphCount || currGlyph == -1) {
105                    // XXX: How do we handle EOT vs. EOL?
106                    classCode = classCodeEOT;
107                    break;
108                } else {
109                    LEGlyphID gid = glyphStorage[currGlyph];
110                    TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid);
111
112                    if (glyphCode == 0xFFFF) {
113                        classCode = classCodeDEL;
114                    } else {
115                        classCode = SWAPW(lookupTable0->valueArray[gid]);
116                    }
117                }
118                EntryTableIndex2 entryTableIndex = SWAPW(stateArray(classCode + currentState * nClasses, success));
119                LE_STATE_PATIENCE_CURR(le_int32, currGlyph);
120                currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); // return a zero-based index instead of a byte offset
121                LE_STATE_PATIENCE_INCR(currGlyph);
122            }
123#endif
124            break;
125        }
126        case ltfSegmentSingle: {
127          LEReferenceTo<SegmentSingleLookupTable> lookupTable2(classTable, success);
128          if(LE_FAILURE(success)) break;
129            while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) {
130                if (LE_FAILURE(success)) break;
131                if (LE_STATE_PATIENCE_DECR()) {
132                  LE_DEBUG_BAD_FONT("patience exceeded  - state table not moving")
133                  break; // patience exceeded.
134                }
135                LookupValue classCode = classCodeOOB;
136                if (currGlyph == glyphCount || currGlyph == -1) {
137                    // XXX: How do we handle EOT vs. EOL?
138                    classCode = classCodeEOT;
139                    break;
140                } else {
141                    LEGlyphID gid = glyphStorage[currGlyph];
142                    TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid);
143
144                    if (glyphCode == 0xFFFF) {
145                        classCode = classCodeDEL;
146                    } else {
147                      const LookupSegment *segment =
148                        lookupTable2->lookupSegment(lookupTable2, lookupTable2->segments, gid, success);
149                        if (segment != NULL && LE_SUCCESS(success)) {
150                            classCode = SWAPW(segment->value);
151                        }
152                    }
153                }
154                EntryTableIndex2 entryTableIndex = SWAPW(stateArray(classCode + currentState * nClasses,success));
155                LE_STATE_PATIENCE_CURR(le_int32, currGlyph);
156                currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex, success);
157                LE_STATE_PATIENCE_INCR(currGlyph);
158            }
159            break;
160        }
161        case ltfSegmentArray: {
162          //printf("Lookup Table Format4: specific interpretation needed!\n");
163            break;
164        }
165        case ltfSingleTable: {
166            LEReferenceTo<SingleTableLookupTable> lookupTable6(classTable, success);
167            while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) {
168                if (LE_FAILURE(success)) break;
169                if (LE_STATE_PATIENCE_DECR()) {
170                  LE_DEBUG_BAD_FONT("patience exceeded - state table not moving")
171                  break; // patience exceeded.
172                }
173                LookupValue classCode = classCodeOOB;
174                if (currGlyph == glyphCount || currGlyph == -1) {
175                    // XXX: How do we handle EOT vs. EOL?
176                    classCode = classCodeEOT;
177                    break;
178                } else if(currGlyph > glyphCount) {
179                  // note if > glyphCount, we've run off the end (bad font)
180                  currGlyph = glyphCount;
181                  classCode = classCodeEOT;
182                } else {
183                    LEGlyphID gid = glyphStorage[currGlyph];
184                    TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid);
185
186                    if (glyphCode == 0xFFFF) {
187                        classCode = classCodeDEL;
188                    } else {
189                      const LookupSingle *segment = lookupTable6->lookupSingle(lookupTable6, lookupTable6->entries, gid, success);
190                        if (segment != NULL) {
191                            classCode = SWAPW(segment->value);
192                        }
193                    }
194                }
195                EntryTableIndex2 entryTableIndex = SWAPW(stateArray(classCode + currentState * nClasses, success));
196                LE_STATE_PATIENCE_CURR(le_int32, currGlyph);
197                currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex, success);
198                LE_STATE_PATIENCE_INCR(currGlyph);
199            }
200            break;
201        }
202        case ltfTrimmedArray: {
203            LEReferenceTo<TrimmedArrayLookupTable> lookupTable8(classTable, success);
204            if (LE_FAILURE(success)) break;
205            TTGlyphID firstGlyph = SWAPW(lookupTable8->firstGlyph);
206            TTGlyphID lastGlyph  = firstGlyph + SWAPW(lookupTable8->glyphCount);
207
208            while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) {
209                if(LE_STATE_PATIENCE_DECR()) {
210                  LE_DEBUG_BAD_FONT("patience exceeded - state table not moving")
211                  break; // patience exceeded.
212                }
213
214                LookupValue classCode = classCodeOOB;
215                if (currGlyph == glyphCount || currGlyph == -1) {
216                    // XXX: How do we handle EOT vs. EOL?
217                    classCode = classCodeEOT;
218                    break;
219                } else {
220                    TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(glyphStorage[currGlyph]);
221                    if (glyphCode == 0xFFFF) {
222                        classCode = classCodeDEL;
223                    } else if ((glyphCode >= firstGlyph) && (glyphCode < lastGlyph)) {
224                        classCode = SWAPW(lookupTable8->valueArray[glyphCode - firstGlyph]);
225                    }
226                }
227                EntryTableIndex2 entryTableIndex = SWAPW(stateArray(classCode + currentState * nClasses, success));
228                LE_STATE_PATIENCE_CURR(le_int32, currGlyph);
229                currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex, success);
230                LE_STATE_PATIENCE_INCR(currGlyph);
231            }
232            break;
233        }
234        default:
235            break;
236    }
237
238    endStateTable();
239}
240
241U_NAMESPACE_END
242