• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * (C) Copyright IBM Corp. 1998-2011 - All Rights Reserved
4  *
5  */
6 
7 #include "LETypes.h"
8 #include "OpenTypeUtilities.h"
9 #include "LEFontInstance.h"
10 #include "OpenTypeTables.h"
11 #include "ICUFeatures.h"
12 #include "Lookups.h"
13 #include "ScriptAndLanguage.h"
14 #include "GlyphDefinitionTables.h"
15 #include "GlyphIterator.h"
16 #include "LookupProcessor.h"
17 #include "LEGlyphStorage.h"
18 #include "LESwaps.h"
19 
20 U_NAMESPACE_BEGIN
21 
applyLookupTable(const LookupTable * lookupTable,GlyphIterator * glyphIterator,const LEFontInstance * fontInstance,LEErrorCode & success) const22 le_uint32 LookupProcessor::applyLookupTable(const LookupTable *lookupTable, GlyphIterator *glyphIterator,
23                                          const LEFontInstance *fontInstance, LEErrorCode& success) const
24 {
25     if (LE_FAILURE(success)) {
26         return 0;
27     }
28 
29     le_uint16 lookupType = SWAPW(lookupTable->lookupType);
30     le_uint16 subtableCount = SWAPW(lookupTable->subTableCount);
31     le_int32 startPosition = glyphIterator->getCurrStreamPosition();
32     le_uint32 delta;
33 
34     for (le_uint16 subtable = 0; subtable < subtableCount; subtable += 1) {
35         const LookupSubtable *lookupSubtable = lookupTable->getLookupSubtable(subtable);
36 
37         delta = applySubtable(lookupSubtable, lookupType, glyphIterator, fontInstance, success);
38 
39         if (delta > 0 && LE_FAILURE(success)) {
40             return 1;
41         }
42 
43         glyphIterator->setCurrStreamPosition(startPosition);
44     }
45 
46     return 1;
47 }
48 
process(LEGlyphStorage & glyphStorage,GlyphPositionAdjustments * glyphPositionAdjustments,le_bool rightToLeft,const GlyphDefinitionTableHeader * glyphDefinitionTableHeader,const LEFontInstance * fontInstance,LEErrorCode & success) const49 le_int32 LookupProcessor::process(LEGlyphStorage &glyphStorage, GlyphPositionAdjustments *glyphPositionAdjustments,
50                               le_bool rightToLeft, const GlyphDefinitionTableHeader *glyphDefinitionTableHeader,
51                               const LEFontInstance *fontInstance, LEErrorCode& success) const
52 {
53     if (LE_FAILURE(success)) {
54         return 0;
55     }
56 
57     le_int32 glyphCount = glyphStorage.getGlyphCount();
58 
59     if (lookupSelectArray == NULL) {
60         return glyphCount;
61     }
62 
63     GlyphIterator glyphIterator(glyphStorage, glyphPositionAdjustments,
64                                 rightToLeft, 0, 0, glyphDefinitionTableHeader);
65     le_int32 newGlyphCount = glyphCount;
66 
67     for (le_uint16 order = 0; order < lookupOrderCount; order += 1) {
68         le_uint16 lookup = lookupOrderArray[order];
69         FeatureMask selectMask = lookupSelectArray[lookup];
70 
71         if (selectMask != 0) {
72             const LookupTable *lookupTable = lookupListTable->getLookupTable(lookup);
73             if (!lookupTable) {
74                 continue;
75             }
76             le_uint16 lookupFlags = SWAPW(lookupTable->lookupFlags);
77 
78             glyphIterator.reset(lookupFlags, selectMask);
79 
80             while (glyphIterator.findFeatureTag()) {
81                 applyLookupTable(lookupTable, &glyphIterator, fontInstance, success);
82                 if (LE_FAILURE(success)) {
83                     return 0;
84                 }
85             }
86 
87             newGlyphCount = glyphIterator.applyInsertions();
88         }
89     }
90 
91     return newGlyphCount;
92 }
93 
applySingleLookup(le_uint16 lookupTableIndex,GlyphIterator * glyphIterator,const LEFontInstance * fontInstance,LEErrorCode & success) const94 le_uint32 LookupProcessor::applySingleLookup(le_uint16 lookupTableIndex, GlyphIterator *glyphIterator,
95                                           const LEFontInstance *fontInstance, LEErrorCode& success) const
96 {
97     if (LE_FAILURE(success)) {
98         return 0;
99     }
100 
101     const LookupTable *lookupTable = lookupListTable->getLookupTable(lookupTableIndex);
102     le_uint16 lookupFlags = SWAPW(lookupTable->lookupFlags);
103     GlyphIterator tempIterator(*glyphIterator, lookupFlags);
104     le_uint32 delta = applyLookupTable(lookupTable, &tempIterator, fontInstance, success);
105 
106     return delta;
107 }
108 
selectLookups(const FeatureTable * featureTable,FeatureMask featureMask,le_int32 order)109 le_int32 LookupProcessor::selectLookups(const FeatureTable *featureTable, FeatureMask featureMask, le_int32 order)
110 {
111     le_uint16 lookupCount = featureTable? SWAPW(featureTable->lookupCount) : 0;
112     le_int32  store = order;
113 
114     for (le_uint16 lookup = 0; lookup < lookupCount; lookup += 1) {
115         le_uint16 lookupListIndex = SWAPW(featureTable->lookupListIndexArray[lookup]);
116 	if (lookupListIndex >= lookupSelectCount) {
117 	    continue;
118         }
119 
120         lookupSelectArray[lookupListIndex] |= featureMask;
121         lookupOrderArray[store++] = lookupListIndex;
122     }
123 
124     return store - order;
125 }
126 
LookupProcessor(const char * baseAddress,Offset scriptListOffset,Offset featureListOffset,Offset lookupListOffset,LETag scriptTag,LETag languageTag,const FeatureMap * featureMap,le_int32 featureMapCount,le_bool orderFeatures,LEErrorCode & success)127 LookupProcessor::LookupProcessor(const char *baseAddress,
128         Offset scriptListOffset, Offset featureListOffset, Offset lookupListOffset,
129         LETag scriptTag, LETag languageTag, const FeatureMap *featureMap, le_int32 featureMapCount, le_bool orderFeatures,
130         LEErrorCode& success)
131     : lookupListTable(NULL), featureListTable(NULL), lookupSelectArray(NULL), lookupSelectCount(0),
132       lookupOrderArray(NULL), lookupOrderCount(0)
133 {
134     const ScriptListTable *scriptListTable = NULL;
135     const LangSysTable *langSysTable = NULL;
136     le_uint16 featureCount = 0;
137     le_uint16 lookupListCount = 0;
138     le_uint16 requiredFeatureIndex;
139 
140     if (LE_FAILURE(success)) {
141         return;
142     }
143 
144     if (scriptListOffset != 0) {
145         scriptListTable = (const ScriptListTable *) (baseAddress + scriptListOffset);
146         langSysTable = scriptListTable->findLanguage(scriptTag, languageTag);
147 
148         if (langSysTable != 0) {
149             featureCount = SWAPW(langSysTable->featureCount);
150         }
151     }
152 
153     if (featureListOffset != 0) {
154         featureListTable = (const FeatureListTable *) (baseAddress + featureListOffset);
155     }
156 
157     if (lookupListOffset != 0) {
158         lookupListTable = (const LookupListTable *) (baseAddress + lookupListOffset);
159         lookupListCount = SWAPW(lookupListTable->lookupCount);
160     }
161 
162     if (langSysTable == NULL || featureListTable == NULL || lookupListTable == NULL ||
163         featureCount == 0 || lookupListCount == 0) {
164         return;
165     }
166 
167     requiredFeatureIndex = SWAPW(langSysTable->reqFeatureIndex);
168 
169     lookupSelectArray = LE_NEW_ARRAY(FeatureMask, lookupListCount);
170     if (lookupSelectArray == NULL) {
171         success = LE_MEMORY_ALLOCATION_ERROR;
172         return;
173     }
174 
175     for (int i = 0; i < lookupListCount; i += 1) {
176         lookupSelectArray[i] = 0;
177     }
178     lookupSelectCount = lookupListCount;
179 
180     le_int32 count, order = 0;
181     le_int32 featureReferences = 0;
182     const FeatureTable *featureTable = NULL;
183     LETag featureTag;
184 
185     const FeatureTable *requiredFeatureTable = NULL;
186     LETag requiredFeatureTag = 0x00000000U;
187 
188     // Count the total number of lookups referenced by all features. This will
189     // be the maximum number of entries in the lookupOrderArray. We can't use
190     // lookupListCount because some lookups might be referenced by more than
191     // one feature.
192     for (le_int32 feature = 0; feature < featureCount; feature += 1) {
193         le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]);
194 
195         featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag);
196         if (!featureTable) {
197              continue;
198         }
199         featureReferences += SWAPW(featureTable->lookupCount);
200     }
201 
202     if (requiredFeatureIndex != 0xFFFF) {
203         requiredFeatureTable = featureListTable->getFeatureTable(requiredFeatureIndex, &requiredFeatureTag);
204         featureReferences += SWAPW(featureTable->lookupCount);
205     }
206 
207     lookupOrderArray = LE_NEW_ARRAY(le_uint16, featureReferences);
208     if (lookupOrderArray == NULL) {
209         success = LE_MEMORY_ALLOCATION_ERROR;
210         return;
211     }
212 
213     for (le_int32 f = 0; f < featureMapCount; f += 1) {
214         FeatureMap fm = featureMap[f];
215         count = 0;
216 
217         // If this is the required feature, add its lookups
218         if (requiredFeatureTag == fm.tag) {
219             count += selectLookups(requiredFeatureTable, fm.mask, order);
220         }
221 
222         if (orderFeatures) {
223             // If we added lookups from the required feature, sort them
224             if (count > 1) {
225                 OpenTypeUtilities::sort(lookupOrderArray, order);
226             }
227 
228             for (le_uint16 feature = 0; feature < featureCount; feature += 1) {
229                 le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]);
230 
231                 // don't add the required feature to the list more than once...
232                 // TODO: Do we need this check? (Spec. says required feature won't be in feature list...)
233                 if (featureIndex == requiredFeatureIndex) {
234                     continue;
235                 }
236 
237                 featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag);
238 
239                 if (featureTag == fm.tag) {
240                     count += selectLookups(featureTable, fm.mask, order + count);
241                 }
242             }
243 
244             if (count > 1) {
245                 OpenTypeUtilities::sort(&lookupOrderArray[order], count);
246             }
247 
248             order += count;
249         } else {
250             for (le_uint16 feature = 0; feature < featureCount; feature += 1) {
251                 le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]);
252 
253                 // don't add the required feature to the list more than once...
254                 // NOTE: This check is commented out because the spec. says that
255                 // the required feature won't be in the feature list, and because
256                 // any duplicate entries will be removed below.
257 #if 0
258                 if (featureIndex == requiredFeatureIndex) {
259                     continue;
260                 }
261 #endif
262 
263                 featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag);
264 
265                 if (featureTag == fm.tag) {
266                     order += selectLookups(featureTable, fm.mask, order);
267                 }
268             }
269         }
270     }
271 
272     if (!orderFeatures && (order > 1)) {
273         OpenTypeUtilities::sort(lookupOrderArray, order);
274 
275         // If there's no specified feature order,
276         // we will apply the lookups in the order
277         // that they're in the font. If a particular
278         // lookup may be referenced by more than one feature,
279         // it will apprear in the lookupOrderArray more than
280         // once, so remove any duplicate entries in the sorted array.
281         le_int32 out = 1;
282 
283         for (le_int32 in = 1; in < order; in += 1) {
284             if (lookupOrderArray[out - 1] != lookupOrderArray[in]) {
285                 if (out != in) {
286                     lookupOrderArray[out] = lookupOrderArray[in];
287                 }
288 
289                 out += 1;
290             }
291         }
292 
293         order = out;
294     }
295 
296     lookupOrderCount = order;
297 }
298 
LookupProcessor()299 LookupProcessor::LookupProcessor()
300 {
301 	lookupOrderArray = NULL;
302 	lookupSelectArray = NULL;
303 }
304 
~LookupProcessor()305 LookupProcessor::~LookupProcessor()
306 {
307     LE_DELETE_ARRAY(lookupOrderArray);
308     LE_DELETE_ARRAY(lookupSelectArray);
309 }
310 
311 U_NAMESPACE_END
312