3 * (C) Copyright IBM Corp. and others 1998-2015 - 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 LEReferenceTo
<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 LEReferenceTo
<LookupSubtable
> lookupSubtable
= lookupTable
->getLookupSubtable(lookupTable
, subtable
, success
);
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 LEReferenceTo
<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
&& LE_SUCCESS(success
); order
+= 1) {
68 le_uint16 lookup
= lookupOrderArray
[order
];
69 FeatureMask selectMask
= lookupSelectArray
[lookup
];
71 if (selectMask
!= 0) {
72 const LEReferenceTo
<LookupTable
> lookupTable
= lookupListTable
->getLookupTable(lookupListTable
, lookup
, success
);
73 if (!lookupTable
.isValid() ||LE_FAILURE(success
) ) {
76 le_uint16 lookupFlags
= SWAPW(lookupTable
->lookupFlags
);
78 glyphIterator
.reset(lookupFlags
, selectMask
);
80 while (glyphIterator
.findFeatureTag()) {
81 applyLookupTable(lookupTable
, &glyphIterator
, fontInstance
, success
);
82 if (LE_FAILURE(success
)) {
87 newGlyphCount
= glyphIterator
.applyInsertions();
94 le_uint32
LookupProcessor::applySingleLookup(le_uint16 lookupTableIndex
, GlyphIterator
*glyphIterator
,
95 const LEFontInstance
*fontInstance
, LEErrorCode
& success
) const
97 if (LE_FAILURE(success
)) {
101 const LEReferenceTo
<LookupTable
> lookupTable
= lookupListTable
->getLookupTable(lookupListTable
, lookupTableIndex
, success
);
102 if (!lookupTable
.isValid()) {
103 success
= LE_INTERNAL_ERROR
;
106 le_uint16 lookupFlags
= SWAPW(lookupTable
->lookupFlags
);
107 GlyphIterator
tempIterator(*glyphIterator
, lookupFlags
);
108 le_uint32 delta
= applyLookupTable(lookupTable
, &tempIterator
, fontInstance
, success
);
113 le_int32
LookupProcessor::selectLookups(const LEReferenceTo
<FeatureTable
> &featureTable
, FeatureMask featureMask
, le_int32 order
, LEErrorCode
&success
)
115 le_uint16 lookupCount
= featureTable
.isValid()? SWAPW(featureTable
->lookupCount
) : 0;
116 le_uint32 store
= (le_uint32
)order
;
118 LEReferenceToArrayOf
<le_uint16
> lookupListIndexArray(featureTable
, success
, featureTable
->lookupListIndexArray
, lookupCount
);
120 for (le_uint16 lookup
= 0; LE_SUCCESS(success
) && lookup
< lookupCount
; lookup
+= 1) {
121 le_uint16 lookupListIndex
= SWAPW(lookupListIndexArray
.getObject(lookup
,success
));
122 if (lookupListIndex
>= lookupSelectCount
) {
125 if (store
>= lookupOrderCount
) {
129 lookupSelectArray
[lookupListIndex
] |= featureMask
;
130 lookupOrderArray
[store
++] = lookupListIndex
;
133 return store
- order
;
136 LookupProcessor::LookupProcessor(const LETableReference
&baseAddress
,
137 Offset scriptListOffset
, Offset featureListOffset
, Offset lookupListOffset
,
138 LETag scriptTag
, LETag languageTag
, const FeatureMap
*featureMap
, le_int32 featureMapCount
, le_bool orderFeatures
,
139 LEErrorCode
& success
)
140 : lookupListTable(), featureListTable(), lookupSelectArray(NULL
), lookupSelectCount(0),
141 lookupOrderArray(NULL
), lookupOrderCount(0), fReference(baseAddress
)
143 LEReferenceTo
<ScriptListTable
> scriptListTable
;
144 LEReferenceTo
<LangSysTable
> langSysTable
;
145 le_uint16 featureCount
= 0;
146 le_uint16 lookupListCount
= 0;
147 le_uint16 requiredFeatureIndex
;
149 if (LE_FAILURE(success
)) {
153 if (scriptListOffset
!= 0) {
154 scriptListTable
= LEReferenceTo
<ScriptListTable
>(baseAddress
, success
, scriptListOffset
);
155 langSysTable
= scriptListTable
->findLanguage(scriptListTable
, scriptTag
, languageTag
, success
);
157 if (langSysTable
.isValid() && LE_SUCCESS(success
)) {
158 featureCount
= SWAPW(langSysTable
->featureCount
);
162 if (featureListOffset
!= 0) {
163 featureListTable
= LEReferenceTo
<FeatureListTable
>(baseAddress
, success
, featureListOffset
);
166 if (lookupListOffset
!= 0) {
167 lookupListTable
= LEReferenceTo
<LookupListTable
>(baseAddress
,success
, lookupListOffset
);
168 if(LE_SUCCESS(success
) && lookupListTable
.isValid()) {
169 lookupListCount
= SWAPW(lookupListTable
->lookupCount
);
173 if (langSysTable
.isEmpty() || featureListTable
.isEmpty() || lookupListTable
.isEmpty() ||
174 featureCount
== 0 || lookupListCount
== 0) {
178 if(langSysTable
.isValid()) {
179 requiredFeatureIndex
= SWAPW(langSysTable
->reqFeatureIndex
);
182 lookupSelectArray
= LE_NEW_ARRAY(FeatureMask
, lookupListCount
);
183 if (lookupSelectArray
== NULL
) {
184 success
= LE_MEMORY_ALLOCATION_ERROR
;
188 for (int i
= 0; i
< lookupListCount
; i
+= 1) {
189 lookupSelectArray
[i
] = 0;
191 lookupSelectCount
= lookupListCount
;
193 le_int32 count
, order
= 0;
194 le_uint32 featureReferences
= 0;
195 LEReferenceTo
<FeatureTable
> featureTable
;
198 LEReferenceTo
<FeatureTable
> requiredFeatureTable
;
199 LETag requiredFeatureTag
= 0x00000000U
;
201 // Count the total number of lookups referenced by all features. This will
202 // be the maximum number of entries in the lookupOrderArray. We can't use
203 // lookupListCount because some lookups might be referenced by more than
205 if(featureListTable
.isValid() && LE_SUCCESS(success
)) {
206 LEReferenceToArrayOf
<le_uint16
> featureIndexArray(langSysTable
, success
, langSysTable
->featureIndexArray
, featureCount
);
208 for (le_uint32 feature
= 0; LE_SUCCESS(success
)&&(feature
< featureCount
); feature
+= 1) {
209 le_uint16 featureIndex
= SWAPW(featureIndexArray
.getObject(feature
, success
));
211 featureTable
= featureListTable
->getFeatureTable(featureListTable
, featureIndex
, &featureTag
, success
);
212 if (!featureTable
.isValid() || LE_FAILURE(success
)) {
215 featureReferences
+= SWAPW(featureTable
->lookupCount
);
219 if (!featureTable
.isValid() || LE_FAILURE(success
)) {
220 success
= LE_INTERNAL_ERROR
;
224 if (requiredFeatureIndex
!= 0xFFFF) {
225 requiredFeatureTable
= featureListTable
->getFeatureTable(featureListTable
, requiredFeatureIndex
, &requiredFeatureTag
, success
);
226 featureReferences
+= SWAPW(requiredFeatureTable
->lookupCount
);
229 lookupOrderArray
= LE_NEW_ARRAY(le_uint16
, featureReferences
);
230 if (lookupOrderArray
== NULL
) {
231 success
= LE_MEMORY_ALLOCATION_ERROR
;
234 lookupOrderCount
= featureReferences
;
236 for (le_int32 f
= 0; f
< featureMapCount
; f
+= 1) {
237 FeatureMap fm
= featureMap
[f
];
240 // If this is the required feature, add its lookups
241 if (requiredFeatureTag
== fm
.tag
) {
242 count
+= selectLookups(requiredFeatureTable
, fm
.mask
, order
, success
);
246 // If we added lookups from the required feature, sort them
248 OpenTypeUtilities::sort(lookupOrderArray
, order
);
251 for (le_uint16 feature
= 0; feature
< featureCount
; feature
+= 1) {
252 LEReferenceToArrayOf
<le_uint16
> featureIndexArray(langSysTable
, success
, langSysTable
->featureIndexArray
, featureCount
);
253 le_uint16 featureIndex
= SWAPW(featureIndexArray
.getObject(feature
,success
));
255 // don't add the required feature to the list more than once...
256 // TODO: Do we need this check? (Spec. says required feature won't be in feature list...)
257 if (featureIndex
== requiredFeatureIndex
) {
261 featureTable
= featureListTable
->getFeatureTable(featureListTable
, featureIndex
, &featureTag
, success
);
263 if (featureTag
== fm
.tag
) {
264 count
+= selectLookups(featureTable
, fm
.mask
, order
+ count
, success
);
269 OpenTypeUtilities::sort(&lookupOrderArray
[order
], count
);
273 } else if(langSysTable
.isValid()) {
274 LEReferenceToArrayOf
<le_uint16
> featureIndexArray(langSysTable
, success
, langSysTable
->featureIndexArray
, featureCount
);
275 for (le_uint16 feature
= 0; LE_SUCCESS(success
)&& (feature
< featureCount
); feature
+= 1) {
276 le_uint16 featureIndex
= SWAPW(featureIndexArray
.getObject(feature
,success
));
278 // don't add the required feature to the list more than once...
279 // NOTE: This check is commented out because the spec. says that
280 // the required feature won't be in the feature list, and because
281 // any duplicate entries will be removed below.
283 if (featureIndex
== requiredFeatureIndex
) {
288 featureTable
= featureListTable
->getFeatureTable(featureListTable
, featureIndex
, &featureTag
, success
);
290 if (featureTag
== fm
.tag
) {
291 order
+= selectLookups(featureTable
, fm
.mask
, order
, success
);
297 if (!orderFeatures
&& (order
> 1)) {
298 OpenTypeUtilities::sort(lookupOrderArray
, order
);
300 // If there's no specified feature order,
301 // we will apply the lookups in the order
302 // that they're in the font. If a particular
303 // lookup may be referenced by more than one feature,
304 // it will apprear in the lookupOrderArray more than
305 // once, so remove any duplicate entries in the sorted array.
308 for (le_int32 in
= 1; in
< order
; in
+= 1) {
309 if (lookupOrderArray
[out
- 1] != lookupOrderArray
[in
]) {
311 lookupOrderArray
[out
] = lookupOrderArray
[in
];
321 lookupOrderCount
= order
;
324 LookupProcessor::LookupProcessor()
326 lookupOrderArray
= NULL
;
327 lookupSelectArray
= NULL
;
330 LookupProcessor::~LookupProcessor()
332 LE_DELETE_ARRAY(lookupOrderArray
);
333 LE_DELETE_ARRAY(lookupSelectArray
);