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