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