• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * (C) Copyright IBM Corp. and others 1998-2013 - 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     if (lookupTable == NULL) {
103         success = LE_INTERNAL_ERROR;
104         return 0;
105     }
106     le_uint16 lookupFlags = SWAPW(lookupTable->lookupFlags);
107     GlyphIterator tempIterator(*glyphIterator, lookupFlags);
108     le_uint32 delta = applyLookupTable(lookupTable, &tempIterator, fontInstance, success);
109 
110     return delta;
111 }
112 
selectLookups(const FeatureTable * featureTable,FeatureMask featureMask,le_int32 order)113 le_int32 LookupProcessor::selectLookups(const FeatureTable *featureTable, FeatureMask featureMask, le_int32 order)
114 {
115     le_uint16 lookupCount = featureTable? SWAPW(featureTable->lookupCount) : 0;
116     le_int32  store = order;
117 
118     for (le_uint16 lookup = 0; lookup < lookupCount; lookup += 1) {
119         le_uint16 lookupListIndex = SWAPW(featureTable->lookupListIndexArray[lookup]);
120 	if (lookupListIndex >= lookupSelectCount) {
121 	    continue;
122         }
123 
124         lookupSelectArray[lookupListIndex] |= featureMask;
125         lookupOrderArray[store++] = lookupListIndex;
126     }
127 
128     return store - order;
129 }
130 
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)131 LookupProcessor::LookupProcessor(const char *baseAddress,
132         Offset scriptListOffset, Offset featureListOffset, Offset lookupListOffset,
133         LETag scriptTag, LETag languageTag, const FeatureMap *featureMap, le_int32 featureMapCount, le_bool orderFeatures,
134         LEErrorCode& success)
135     : lookupListTable(NULL), featureListTable(NULL), lookupSelectArray(NULL), lookupSelectCount(0),
136       lookupOrderArray(NULL), lookupOrderCount(0)
137 {
138     const ScriptListTable *scriptListTable = NULL;
139     const LangSysTable *langSysTable = NULL;
140     le_uint16 featureCount = 0;
141     le_uint16 lookupListCount = 0;
142     le_uint16 requiredFeatureIndex;
143 
144     if (LE_FAILURE(success)) {
145         return;
146     }
147 
148     if (scriptListOffset != 0) {
149         scriptListTable = (const ScriptListTable *) (baseAddress + scriptListOffset);
150         langSysTable = scriptListTable->findLanguage(scriptTag, languageTag);
151 
152         if (langSysTable != 0) {
153             featureCount = SWAPW(langSysTable->featureCount);
154         }
155     }
156 
157     if (featureListOffset != 0) {
158         featureListTable = (const FeatureListTable *) (baseAddress + featureListOffset);
159     }
160 
161     if (lookupListOffset != 0) {
162         lookupListTable = (const LookupListTable *) (baseAddress + lookupListOffset);
163         lookupListCount = SWAPW(lookupListTable->lookupCount);
164     }
165 
166     if (langSysTable == NULL || featureListTable == NULL || lookupListTable == NULL ||
167         featureCount == 0 || lookupListCount == 0) {
168         return;
169     }
170 
171     requiredFeatureIndex = SWAPW(langSysTable->reqFeatureIndex);
172 
173     lookupSelectArray = LE_NEW_ARRAY(FeatureMask, lookupListCount);
174     if (lookupSelectArray == NULL) {
175         success = LE_MEMORY_ALLOCATION_ERROR;
176         return;
177     }
178 
179     for (int i = 0; i < lookupListCount; i += 1) {
180         lookupSelectArray[i] = 0;
181     }
182     lookupSelectCount = lookupListCount;
183 
184     le_int32 count, order = 0;
185     le_int32 featureReferences = 0;
186     const FeatureTable *featureTable = NULL;
187     LETag featureTag;
188 
189     const FeatureTable *requiredFeatureTable = NULL;
190     LETag requiredFeatureTag = 0x00000000U;
191 
192     // Count the total number of lookups referenced by all features. This will
193     // be the maximum number of entries in the lookupOrderArray. We can't use
194     // lookupListCount because some lookups might be referenced by more than
195     // one feature.
196     for (le_int32 feature = 0; feature < featureCount; feature += 1) {
197         le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]);
198 
199         featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag);
200         if (!featureTable) {
201              continue;
202         }
203         featureReferences += SWAPW(featureTable->lookupCount);
204     }
205 
206     if (!featureTable) {
207         success = LE_INTERNAL_ERROR;
208         return;
209     }
210 
211     if (requiredFeatureIndex != 0xFFFF) {
212         requiredFeatureTable = featureListTable->getFeatureTable(requiredFeatureIndex, &requiredFeatureTag);
213         featureReferences += SWAPW(featureTable->lookupCount);
214     }
215 
216     lookupOrderArray = LE_NEW_ARRAY(le_uint16, featureReferences);
217     if (lookupOrderArray == NULL) {
218         success = LE_MEMORY_ALLOCATION_ERROR;
219         return;
220     }
221 
222     for (le_int32 f = 0; f < featureMapCount; f += 1) {
223         FeatureMap fm = featureMap[f];
224         count = 0;
225 
226         // If this is the required feature, add its lookups
227         if (requiredFeatureTag == fm.tag) {
228             count += selectLookups(requiredFeatureTable, fm.mask, order);
229         }
230 
231         if (orderFeatures) {
232             // If we added lookups from the required feature, sort them
233             if (count > 1) {
234                 OpenTypeUtilities::sort(lookupOrderArray, order);
235             }
236 
237             for (le_uint16 feature = 0; feature < featureCount; feature += 1) {
238                 le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]);
239 
240                 // don't add the required feature to the list more than once...
241                 // TODO: Do we need this check? (Spec. says required feature won't be in feature list...)
242                 if (featureIndex == requiredFeatureIndex) {
243                     continue;
244                 }
245 
246                 featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag);
247 
248                 if (featureTag == fm.tag) {
249                     count += selectLookups(featureTable, fm.mask, order + count);
250                 }
251             }
252 
253             if (count > 1) {
254                 OpenTypeUtilities::sort(&lookupOrderArray[order], count);
255             }
256 
257             order += count;
258         } else {
259             for (le_uint16 feature = 0; feature < featureCount; feature += 1) {
260                 le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]);
261 
262                 // don't add the required feature to the list more than once...
263                 // NOTE: This check is commented out because the spec. says that
264                 // the required feature won't be in the feature list, and because
265                 // any duplicate entries will be removed below.
266 #if 0
267                 if (featureIndex == requiredFeatureIndex) {
268                     continue;
269                 }
270 #endif
271 
272                 featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag);
273 
274                 if (featureTag == fm.tag) {
275                     order += selectLookups(featureTable, fm.mask, order);
276                 }
277             }
278         }
279     }
280 
281     if (!orderFeatures && (order > 1)) {
282         OpenTypeUtilities::sort(lookupOrderArray, order);
283 
284         // If there's no specified feature order,
285         // we will apply the lookups in the order
286         // that they're in the font. If a particular
287         // lookup may be referenced by more than one feature,
288         // it will apprear in the lookupOrderArray more than
289         // once, so remove any duplicate entries in the sorted array.
290         le_int32 out = 1;
291 
292         for (le_int32 in = 1; in < order; in += 1) {
293             if (lookupOrderArray[out - 1] != lookupOrderArray[in]) {
294                 if (out != in) {
295                     lookupOrderArray[out] = lookupOrderArray[in];
296                 }
297 
298                 out += 1;
299             }
300         }
301 
302         order = out;
303     }
304 
305     lookupOrderCount = order;
306 }
307 
LookupProcessor()308 LookupProcessor::LookupProcessor()
309 {
310 	lookupOrderArray = NULL;
311 	lookupSelectArray = NULL;
312 }
313 
~LookupProcessor()314 LookupProcessor::~LookupProcessor()
315 {
316     LE_DELETE_ARRAY(lookupOrderArray);
317     LE_DELETE_ARRAY(lookupSelectArray);
318 }
319 
320 U_NAMESPACE_END
321