1 /* 2 * 3 * (C) Copyright IBM Corp. 1998-2012 - 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 22 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 49 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 94 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 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 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 (!featureTable) { 203 success = LE_INTERNAL_ERROR; 204 return; 205 } 206 207 if (requiredFeatureIndex != 0xFFFF) { 208 requiredFeatureTable = featureListTable->getFeatureTable(requiredFeatureIndex, &requiredFeatureTag); 209 featureReferences += SWAPW(featureTable->lookupCount); 210 } 211 212 lookupOrderArray = LE_NEW_ARRAY(le_uint16, featureReferences); 213 if (lookupOrderArray == NULL) { 214 success = LE_MEMORY_ALLOCATION_ERROR; 215 return; 216 } 217 218 for (le_int32 f = 0; f < featureMapCount; f += 1) { 219 FeatureMap fm = featureMap[f]; 220 count = 0; 221 222 // If this is the required feature, add its lookups 223 if (requiredFeatureTag == fm.tag) { 224 count += selectLookups(requiredFeatureTable, fm.mask, order); 225 } 226 227 if (orderFeatures) { 228 // If we added lookups from the required feature, sort them 229 if (count > 1) { 230 OpenTypeUtilities::sort(lookupOrderArray, order); 231 } 232 233 for (le_uint16 feature = 0; feature < featureCount; feature += 1) { 234 le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]); 235 236 // don't add the required feature to the list more than once... 237 // TODO: Do we need this check? (Spec. says required feature won't be in feature list...) 238 if (featureIndex == requiredFeatureIndex) { 239 continue; 240 } 241 242 featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag); 243 244 if (featureTag == fm.tag) { 245 count += selectLookups(featureTable, fm.mask, order + count); 246 } 247 } 248 249 if (count > 1) { 250 OpenTypeUtilities::sort(&lookupOrderArray[order], count); 251 } 252 253 order += count; 254 } else { 255 for (le_uint16 feature = 0; feature < featureCount; feature += 1) { 256 le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]); 257 258 // don't add the required feature to the list more than once... 259 // NOTE: This check is commented out because the spec. says that 260 // the required feature won't be in the feature list, and because 261 // any duplicate entries will be removed below. 262 #if 0 263 if (featureIndex == requiredFeatureIndex) { 264 continue; 265 } 266 #endif 267 268 featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag); 269 270 if (featureTag == fm.tag) { 271 order += selectLookups(featureTable, fm.mask, order); 272 } 273 } 274 } 275 } 276 277 if (!orderFeatures && (order > 1)) { 278 OpenTypeUtilities::sort(lookupOrderArray, order); 279 280 // If there's no specified feature order, 281 // we will apply the lookups in the order 282 // that they're in the font. If a particular 283 // lookup may be referenced by more than one feature, 284 // it will apprear in the lookupOrderArray more than 285 // once, so remove any duplicate entries in the sorted array. 286 le_int32 out = 1; 287 288 for (le_int32 in = 1; in < order; in += 1) { 289 if (lookupOrderArray[out - 1] != lookupOrderArray[in]) { 290 if (out != in) { 291 lookupOrderArray[out] = lookupOrderArray[in]; 292 } 293 294 out += 1; 295 } 296 } 297 298 order = out; 299 } 300 301 lookupOrderCount = order; 302 } 303 304 LookupProcessor::LookupProcessor() 305 { 306 lookupOrderArray = NULL; 307 lookupSelectArray = NULL; 308 } 309 310 LookupProcessor::~LookupProcessor() 311 { 312 LE_DELETE_ARRAY(lookupOrderArray); 313 LE_DELETE_ARRAY(lookupSelectArray); 314 } 315 316 U_NAMESPACE_END 317