3 * (C) Copyright IBM Corp. 1998-2010 - All Rights Reserved
8 #include "OpenTypeUtilities.h"
9 #include "LEFontInstance.h"
10 #include "OpenTypeTables.h"
11 #include "ICUFeatures.h"
13 #include "ScriptAndLanguage.h"
14 #include "GlyphDefinitionTables.h"
15 #include "GlyphIterator.h"
16 #include "LookupProcessor.h"
17 #include "LEGlyphStorage.h"
22 le_uint32
LookupProcessor::applyLookupTable(const LookupTable
*lookupTable
, GlyphIterator
*glyphIterator
,
23 const LEFontInstance
*fontInstance
, LEErrorCode
& success
) const
25 if (LE_FAILURE(success
)) {
29 le_uint16 lookupType
= SWAPW(lookupTable
->lookupType
);
30 le_uint16 subtableCount
= SWAPW(lookupTable
->subTableCount
);
31 le_int32 startPosition
= glyphIterator
->getCurrStreamPosition();
34 for (le_uint16 subtable
= 0; subtable
< subtableCount
; subtable
+= 1) {
35 const LookupSubtable
*lookupSubtable
= lookupTable
->getLookupSubtable(subtable
);
37 delta
= applySubtable(lookupSubtable
, lookupType
, glyphIterator
, fontInstance
, success
);
39 if (delta
> 0 && LE_FAILURE(success
)) {
43 glyphIterator
->setCurrStreamPosition(startPosition
);
49 le_int32
LookupProcessor::process(LEGlyphStorage
&glyphStorage
, GlyphPositionAdjustments
*glyphPositionAdjustments
,
50 le_bool rightToLeft
, const GlyphDefinitionTableHeader
*glyphDefinitionTableHeader
,
51 const LEFontInstance
*fontInstance
, LEErrorCode
& success
) const
53 if (LE_FAILURE(success
)) {
57 le_int32 glyphCount
= glyphStorage
.getGlyphCount();
59 if (lookupSelectArray
== NULL
) {
63 GlyphIterator
glyphIterator(glyphStorage
, glyphPositionAdjustments
,
64 rightToLeft
, 0, 0, glyphDefinitionTableHeader
);
65 le_int32 newGlyphCount
= glyphCount
;
67 for (le_uint16 order
= 0; order
< lookupOrderCount
; order
+= 1) {
68 le_uint16 lookup
= lookupOrderArray
[order
];
69 FeatureMask selectMask
= lookupSelectArray
[lookup
];
71 if (selectMask
!= 0) {
72 const LookupTable
*lookupTable
= lookupListTable
->getLookupTable(lookup
);
73 le_uint16 lookupFlags
= SWAPW(lookupTable
->lookupFlags
);
75 glyphIterator
.reset(lookupFlags
, selectMask
);
77 while (glyphIterator
.findFeatureTag()) {
78 applyLookupTable(lookupTable
, &glyphIterator
, fontInstance
, success
);
79 if (LE_FAILURE(success
)) {
84 newGlyphCount
= glyphIterator
.applyInsertions();
91 le_uint32
LookupProcessor::applySingleLookup(le_uint16 lookupTableIndex
, GlyphIterator
*glyphIterator
,
92 const LEFontInstance
*fontInstance
, LEErrorCode
& success
) const
94 if (LE_FAILURE(success
)) {
98 const LookupTable
*lookupTable
= lookupListTable
->getLookupTable(lookupTableIndex
);
99 le_uint16 lookupFlags
= SWAPW(lookupTable
->lookupFlags
);
100 GlyphIterator
tempIterator(*glyphIterator
, lookupFlags
);
101 le_uint32 delta
= applyLookupTable(lookupTable
, &tempIterator
, fontInstance
, success
);
106 le_int32
LookupProcessor::selectLookups(const FeatureTable
*featureTable
, FeatureMask featureMask
, le_int32 order
)
108 le_uint16 lookupCount
= featureTable
? SWAPW(featureTable
->lookupCount
) : 0;
109 le_int32 store
= order
;
111 for (le_uint16 lookup
= 0; lookup
< lookupCount
; lookup
+= 1) {
112 le_uint16 lookupListIndex
= SWAPW(featureTable
->lookupListIndexArray
[lookup
]);
114 lookupSelectArray
[lookupListIndex
] |= featureMask
;
115 lookupOrderArray
[store
++] = lookupListIndex
;
118 return store
- order
;
121 LookupProcessor::LookupProcessor(const char *baseAddress
,
122 Offset scriptListOffset
, Offset featureListOffset
, Offset lookupListOffset
,
123 LETag scriptTag
, LETag languageTag
, const FeatureMap
*featureMap
, le_int32 featureMapCount
, le_bool orderFeatures
,
124 LEErrorCode
& success
)
125 : lookupListTable(NULL
), featureListTable(NULL
), lookupSelectArray(NULL
),
126 lookupOrderArray(NULL
), lookupOrderCount(0)
128 const ScriptListTable
*scriptListTable
= NULL
;
129 const LangSysTable
*langSysTable
= NULL
;
130 le_uint16 featureCount
= 0;
131 le_uint16 lookupListCount
= 0;
132 le_uint16 requiredFeatureIndex
;
134 if (LE_FAILURE(success
)) {
138 if (scriptListOffset
!= 0) {
139 scriptListTable
= (const ScriptListTable
*) (baseAddress
+ scriptListOffset
);
140 langSysTable
= scriptListTable
->findLanguage(scriptTag
, languageTag
);
142 if (langSysTable
!= 0) {
143 featureCount
= SWAPW(langSysTable
->featureCount
);
147 if (featureListOffset
!= 0) {
148 featureListTable
= (const FeatureListTable
*) (baseAddress
+ featureListOffset
);
151 if (lookupListOffset
!= 0) {
152 lookupListTable
= (const LookupListTable
*) (baseAddress
+ lookupListOffset
);
153 lookupListCount
= SWAPW(lookupListTable
->lookupCount
);
156 if (langSysTable
== NULL
|| featureListTable
== NULL
|| lookupListTable
== NULL
||
157 featureCount
== 0 || lookupListCount
== 0) {
161 requiredFeatureIndex
= SWAPW(langSysTable
->reqFeatureIndex
);
163 lookupSelectArray
= LE_NEW_ARRAY(FeatureMask
, lookupListCount
);
164 if (lookupSelectArray
== NULL
) {
165 success
= LE_MEMORY_ALLOCATION_ERROR
;
169 for (int i
= 0; i
< lookupListCount
; i
+= 1) {
170 lookupSelectArray
[i
] = 0;
173 le_int32 count
, order
= 0;
174 le_int32 featureReferences
= 0;
175 const FeatureTable
*featureTable
= NULL
;
178 const FeatureTable
*requiredFeatureTable
= NULL
;
179 LETag requiredFeatureTag
= 0x00000000U
;
181 // Count the total number of lookups referenced by all features. This will
182 // be the maximum number of entries in the lookupOrderArray. We can't use
183 // lookupListCount because some lookups might be referenced by more than
185 for (le_int32 feature
= 0; feature
< featureCount
; feature
+= 1) {
186 le_uint16 featureIndex
= SWAPW(langSysTable
->featureIndexArray
[feature
]);
188 featureTable
= featureListTable
->getFeatureTable(featureIndex
, &featureTag
);
189 featureReferences
+= SWAPW(featureTable
->lookupCount
);
192 if (requiredFeatureIndex
!= 0xFFFF) {
193 requiredFeatureTable
= featureListTable
->getFeatureTable(requiredFeatureIndex
, &requiredFeatureTag
);
194 featureReferences
+= SWAPW(featureTable
->lookupCount
);
197 lookupOrderArray
= LE_NEW_ARRAY(le_uint16
, featureReferences
);
198 if (lookupOrderArray
== NULL
) {
199 success
= LE_MEMORY_ALLOCATION_ERROR
;
203 for (le_int32 f
= 0; f
< featureMapCount
; f
+= 1) {
204 FeatureMap fm
= featureMap
[f
];
207 // If this is the required feature, add its lookups
208 if (requiredFeatureTag
== fm
.tag
) {
209 count
+= selectLookups(requiredFeatureTable
, fm
.mask
, order
);
213 // If we added lookups from the required feature, sort them
215 OpenTypeUtilities::sort(lookupOrderArray
, order
);
218 for (le_uint16 feature
= 0; feature
< featureCount
; feature
+= 1) {
219 le_uint16 featureIndex
= SWAPW(langSysTable
->featureIndexArray
[feature
]);
221 // don't add the required feature to the list more than once...
222 // TODO: Do we need this check? (Spec. says required feature won't be in feature list...)
223 if (featureIndex
== requiredFeatureIndex
) {
227 featureTable
= featureListTable
->getFeatureTable(featureIndex
, &featureTag
);
229 if (featureTag
== fm
.tag
) {
230 count
+= selectLookups(featureTable
, fm
.mask
, order
+ count
);
235 OpenTypeUtilities::sort(&lookupOrderArray
[order
], count
);
240 for (le_uint16 feature
= 0; feature
< featureCount
; feature
+= 1) {
241 le_uint16 featureIndex
= SWAPW(langSysTable
->featureIndexArray
[feature
]);
243 // don't add the required feature to the list more than once...
244 // NOTE: This check is commented out because the spec. says that
245 // the required feature won't be in the feature list, and because
246 // any duplicate entries will be removed below.
248 if (featureIndex
== requiredFeatureIndex
) {
253 featureTable
= featureListTable
->getFeatureTable(featureIndex
, &featureTag
);
255 if (featureTag
== fm
.tag
) {
256 order
+= selectLookups(featureTable
, fm
.mask
, order
);
262 if (!orderFeatures
&& (order
> 1)) {
263 OpenTypeUtilities::sort(lookupOrderArray
, order
);
265 // If there's no specified feature order,
266 // we will apply the lookups in the order
267 // that they're in the font. If a particular
268 // lookup may be referenced by more than one feature,
269 // it will apprear in the lookupOrderArray more than
270 // once, so remove any duplicate entries in the sorted array.
273 for (le_int32 in
= 1; in
< order
; in
+= 1) {
274 if (lookupOrderArray
[out
- 1] != lookupOrderArray
[in
]) {
276 lookupOrderArray
[out
] = lookupOrderArray
[in
];
286 lookupOrderCount
= order
;
289 LookupProcessor::LookupProcessor()
291 lookupOrderArray
= NULL
;
292 lookupSelectArray
= NULL
;
295 LookupProcessor::~LookupProcessor()
297 LE_DELETE_ARRAY(lookupOrderArray
);
298 LE_DELETE_ARRAY(lookupSelectArray
);