Home | History | Annotate | Download | only in layout
      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