1 /* 2 * 3 * (C) Copyright IBM Corp. 1998-2010 - 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 le_uint16 lookupFlags = SWAPW(lookupTable->lookupFlags); 74 75 glyphIterator.reset(lookupFlags, selectMask); 76 77 while (glyphIterator.findFeatureTag()) { 78 applyLookupTable(lookupTable, &glyphIterator, fontInstance, success); 79 if (LE_FAILURE(success)) { 80 return 0; 81 } 82 } 83 84 newGlyphCount = glyphIterator.applyInsertions(); 85 } 86 } 87 88 return newGlyphCount; 89 } 90 91 le_uint32 LookupProcessor::applySingleLookup(le_uint16 lookupTableIndex, GlyphIterator *glyphIterator, 92 const LEFontInstance *fontInstance, LEErrorCode& success) const 93 { 94 if (LE_FAILURE(success)) { 95 return 0; 96 } 97 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); 102 103 return delta; 104 } 105 106 le_int32 LookupProcessor::selectLookups(const FeatureTable *featureTable, FeatureMask featureMask, le_int32 order) 107 { 108 le_uint16 lookupCount = featureTable? SWAPW(featureTable->lookupCount) : 0; 109 le_int32 store = order; 110 111 for (le_uint16 lookup = 0; lookup < lookupCount; lookup += 1) { 112 le_uint16 lookupListIndex = SWAPW(featureTable->lookupListIndexArray[lookup]); 113 114 lookupSelectArray[lookupListIndex] |= featureMask; 115 lookupOrderArray[store++] = lookupListIndex; 116 } 117 118 return store - order; 119 } 120 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) 127 { 128 const ScriptListTable *scriptListTable = NULL; 129 const LangSysTable *langSysTable = NULL; 130 le_uint16 featureCount = 0; 131 le_uint16 lookupListCount = 0; 132 le_uint16 requiredFeatureIndex; 133 134 if (LE_FAILURE(success)) { 135 return; 136 } 137 138 if (scriptListOffset != 0) { 139 scriptListTable = (const ScriptListTable *) (baseAddress + scriptListOffset); 140 langSysTable = scriptListTable->findLanguage(scriptTag, languageTag); 141 142 if (langSysTable != 0) { 143 featureCount = SWAPW(langSysTable->featureCount); 144 } 145 } 146 147 if (featureListOffset != 0) { 148 featureListTable = (const FeatureListTable *) (baseAddress + featureListOffset); 149 } 150 151 if (lookupListOffset != 0) { 152 lookupListTable = (const LookupListTable *) (baseAddress + lookupListOffset); 153 lookupListCount = SWAPW(lookupListTable->lookupCount); 154 } 155 156 if (langSysTable == NULL || featureListTable == NULL || lookupListTable == NULL || 157 featureCount == 0 || lookupListCount == 0) { 158 return; 159 } 160 161 requiredFeatureIndex = SWAPW(langSysTable->reqFeatureIndex); 162 163 lookupSelectArray = LE_NEW_ARRAY(FeatureMask, lookupListCount); 164 if (lookupSelectArray == NULL) { 165 success = LE_MEMORY_ALLOCATION_ERROR; 166 return; 167 } 168 169 for (int i = 0; i < lookupListCount; i += 1) { 170 lookupSelectArray[i] = 0; 171 } 172 173 le_int32 count, order = 0; 174 le_int32 featureReferences = 0; 175 const FeatureTable *featureTable = NULL; 176 LETag featureTag; 177 178 const FeatureTable *requiredFeatureTable = NULL; 179 LETag requiredFeatureTag = 0x00000000U; 180 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 184 // one feature. 185 for (le_int32 feature = 0; feature < featureCount; feature += 1) { 186 le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]); 187 188 featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag); 189 featureReferences += SWAPW(featureTable->lookupCount); 190 } 191 192 if (requiredFeatureIndex != 0xFFFF) { 193 requiredFeatureTable = featureListTable->getFeatureTable(requiredFeatureIndex, &requiredFeatureTag); 194 featureReferences += SWAPW(featureTable->lookupCount); 195 } 196 197 lookupOrderArray = LE_NEW_ARRAY(le_uint16, featureReferences); 198 if (lookupOrderArray == NULL) { 199 success = LE_MEMORY_ALLOCATION_ERROR; 200 return; 201 } 202 203 for (le_int32 f = 0; f < featureMapCount; f += 1) { 204 FeatureMap fm = featureMap[f]; 205 count = 0; 206 207 // If this is the required feature, add its lookups 208 if (requiredFeatureTag == fm.tag) { 209 count += selectLookups(requiredFeatureTable, fm.mask, order); 210 } 211 212 if (orderFeatures) { 213 // If we added lookups from the required feature, sort them 214 if (count > 1) { 215 OpenTypeUtilities::sort(lookupOrderArray, order); 216 } 217 218 for (le_uint16 feature = 0; feature < featureCount; feature += 1) { 219 le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]); 220 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) { 224 continue; 225 } 226 227 featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag); 228 229 if (featureTag == fm.tag) { 230 count += selectLookups(featureTable, fm.mask, order + count); 231 } 232 } 233 234 if (count > 1) { 235 OpenTypeUtilities::sort(&lookupOrderArray[order], count); 236 } 237 238 order += count; 239 } else { 240 for (le_uint16 feature = 0; feature < featureCount; feature += 1) { 241 le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]); 242 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. 247 #if 0 248 if (featureIndex == requiredFeatureIndex) { 249 continue; 250 } 251 #endif 252 253 featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag); 254 255 if (featureTag == fm.tag) { 256 order += selectLookups(featureTable, fm.mask, order); 257 } 258 } 259 } 260 } 261 262 if (!orderFeatures && (order > 1)) { 263 OpenTypeUtilities::sort(lookupOrderArray, order); 264 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. 271 le_int32 out = 1; 272 273 for (le_int32 in = 1; in < order; in += 1) { 274 if (lookupOrderArray[out - 1] != lookupOrderArray[in]) { 275 if (out != in) { 276 lookupOrderArray[out] = lookupOrderArray[in]; 277 } 278 279 out += 1; 280 } 281 } 282 283 order = out; 284 } 285 286 lookupOrderCount = order; 287 } 288 289 LookupProcessor::LookupProcessor() 290 { 291 lookupOrderArray = NULL; 292 lookupSelectArray = NULL; 293 } 294 295 LookupProcessor::~LookupProcessor() 296 { 297 LE_DELETE_ARRAY(lookupOrderArray); 298 LE_DELETE_ARRAY(lookupSelectArray); 299 } 300 301 U_NAMESPACE_END 302