1 /*
2  *
3  * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved
4  *
5  */
6 
7 #include "LETypes.h"
8 #include "MorphTables.h"
9 #include "StateTables.h"
10 #include "MorphStateTables.h"
11 #include "SubtableProcessor.h"
12 #include "StateTableProcessor.h"
13 #include "LigatureSubstProc.h"
14 #include "LEGlyphStorage.h"
15 #include "LESwaps.h"
16 
17 U_NAMESPACE_BEGIN
18 
19 #define ExtendedComplement(m) ((le_int32) (~((le_uint32) (m))))
20 #define SignBit(m) ((ExtendedComplement(m) >> 1) & (le_int32)(m))
21 #define SignExtend(v,m) (((v) & SignBit(m))? ((v) | ExtendedComplement(m)): (v))
22 
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LigatureSubstitutionProcessor)23 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LigatureSubstitutionProcessor)
24 
25   LigatureSubstitutionProcessor::LigatureSubstitutionProcessor(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success)
26 : StateTableProcessor(morphSubtableHeader, success), ligatureSubstitutionHeader(morphSubtableHeader, success)
27 {
28     if(LE_FAILURE(success)) return;
29     ligatureActionTableOffset = SWAPW(ligatureSubstitutionHeader->ligatureActionTableOffset);
30     componentTableOffset = SWAPW(ligatureSubstitutionHeader->componentTableOffset);
31     ligatureTableOffset = SWAPW(ligatureSubstitutionHeader->ligatureTableOffset);
32 
33     entryTable = LEReferenceToArrayOf<LigatureSubstitutionStateEntry>(stHeader, success, entryTableOffset, LE_UNBOUNDED_ARRAY);
34 }
35 
~LigatureSubstitutionProcessor()36 LigatureSubstitutionProcessor::~LigatureSubstitutionProcessor()
37 {
38 }
39 
beginStateTable()40 void LigatureSubstitutionProcessor::beginStateTable()
41 {
42     m = -1;
43 }
44 
processStateEntry(LEGlyphStorage & glyphStorage,le_int32 & currGlyph,EntryTableIndex index)45 ByteOffset LigatureSubstitutionProcessor::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex index)
46 {
47   LEErrorCode success = LE_NO_ERROR;
48   const LigatureSubstitutionStateEntry *entry = entryTable.getAlias(index, success);
49 
50     ByteOffset newState = SWAPW(entry->newStateOffset);
51     le_int16 flags = SWAPW(entry->flags);
52 
53     if (flags & lsfSetComponent) {
54         if (++m >= nComponents) {
55             m = 0;
56         }
57 
58         componentStack[m] = currGlyph;
59     } else if ( m == -1) {
60         // bad font- skip this glyph.
61         currGlyph++;
62         return newState;
63     }
64 
65     ByteOffset actionOffset = flags & lsfActionOffsetMask;
66 
67     if (actionOffset != 0) {
68       LEReferenceTo<LigatureActionEntry> ap(stHeader, success, actionOffset);
69         LigatureActionEntry action;
70         le_int32 offset, i = 0;
71         le_int32 stack[nComponents];
72         le_int16 mm = -1;
73 
74         do {
75             le_uint32 componentGlyph = componentStack[m--];
76 
77             action = SWAPL(*ap.getAlias());
78             ap.addObject(success); // ap++
79 
80             if (m < 0) {
81                 m = nComponents - 1;
82             }
83 
84             offset = action & lafComponentOffsetMask;
85             if (offset != 0) {
86               LEReferenceToArrayOf<le_int16> offsetTable(stHeader, success, 2 * SignExtend(offset, lafComponentOffsetMask), LE_UNBOUNDED_ARRAY);
87 
88               if(LE_FAILURE(success)) {
89                   currGlyph++;
90                   LE_DEBUG_BAD_FONT("off end of ligature substitution header");
91                   return newState; // get out! bad font
92               }
93               if(componentGlyph > (le_uint32)glyphStorage.getGlyphCount()) {
94                 LE_DEBUG_BAD_FONT("preposterous componentGlyph");
95                 currGlyph++;
96                 return newState; // get out! bad font
97               }
98               i += SWAPW(offsetTable.getObject(LE_GET_GLYPH(glyphStorage[componentGlyph]), success));
99 
100                 if (action & (lafLast | lafStore))  {
101                   LEReferenceTo<TTGlyphID> ligatureOffset(stHeader, success, i);
102                   TTGlyphID ligatureGlyph = SWAPW(*ligatureOffset.getAlias());
103 
104                   glyphStorage[componentGlyph] = LE_SET_GLYPH(glyphStorage[componentGlyph], ligatureGlyph);
105                   if(mm==nComponents) {
106                     LE_DEBUG_BAD_FONT("exceeded nComponents");
107                     mm--; // don't overrun the stack.
108                   }
109                   stack[++mm] = componentGlyph;
110                   i = 0;
111                 } else {
112                   glyphStorage[componentGlyph] = LE_SET_GLYPH(glyphStorage[componentGlyph], 0xFFFF);
113                 }
114             }
115 #if LE_ASSERT_BAD_FONT
116             if(m<0) {
117               LE_DEBUG_BAD_FONT("m<0")
118             }
119 #endif
120         } while (!(action & lafLast)  && (m>=0) ); // stop if last bit is set, or if run out of items
121 
122         while (mm >= 0) {
123           if (++m >= nComponents) {
124             m = 0;
125           }
126 
127           componentStack[m] = stack[mm--];
128         }
129     }
130 
131     if (!(flags & lsfDontAdvance)) {
132         // should handle reverse too!
133         currGlyph += 1;
134     }
135 
136     return newState;
137 }
138 
endStateTable()139 void LigatureSubstitutionProcessor::endStateTable()
140 {
141 }
142 
143 U_NAMESPACE_END
144