]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/layout/LookupProcessor.cpp
ICU-491.11.3.tar.gz
[apple/icu.git] / icuSources / layout / LookupProcessor.cpp
index 8dc4edc2285e903b275120cc5dc743611f3ae8a1..042958521938ffb8a07e29692957060f72dd1bb7 100644 (file)
@@ -1,7 +1,6 @@
 /*
- * %W% %E%
  *
- * (C) Copyright IBM Corp. 1998-2003 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1998-2011 - All Rights Reserved
  *
  */
 
@@ -9,25 +8,24 @@
 #include "OpenTypeUtilities.h"
 #include "LEFontInstance.h"
 #include "OpenTypeTables.h"
-#include "Features.h"
+#include "ICUFeatures.h"
 #include "Lookups.h"
 #include "ScriptAndLanguage.h"
 #include "GlyphDefinitionTables.h"
-#include "GlyphPositionAdjustments.h"
+#include "GlyphIterator.h"
 #include "LookupProcessor.h"
+#include "LEGlyphStorage.h"
 #include "LESwaps.h"
 
 U_NAMESPACE_BEGIN
 
-const LETag LookupProcessor::notSelected    = 0x00000000;
-const LETag LookupProcessor::defaultFeature = 0xFFFFFFFF;
-
-const LETag emptyTag = 0x00000000;
-
-
 le_uint32 LookupProcessor::applyLookupTable(const LookupTable *lookupTable, GlyphIterator *glyphIterator,
-                                         const LEFontInstance *fontInstance) const
+                                         const LEFontInstance *fontInstance, LEErrorCode& success) const
 {
+    if (LE_FAILURE(success)) {
+        return 0;
+    }
+
     le_uint16 lookupType = SWAPW(lookupTable->lookupType);
     le_uint16 subtableCount = SWAPW(lookupTable->subTableCount);
     le_int32 startPosition = glyphIterator->getCurrStreamPosition();
@@ -36,9 +34,9 @@ le_uint32 LookupProcessor::applyLookupTable(const LookupTable *lookupTable, Glyp
     for (le_uint16 subtable = 0; subtable < subtableCount; subtable += 1) {
         const LookupSubtable *lookupSubtable = lookupTable->getLookupSubtable(subtable);
 
-        delta = applySubtable(lookupSubtable, lookupType, glyphIterator, fontInstance);
+        delta = applySubtable(lookupSubtable, lookupType, glyphIterator, fontInstance, success);
 
-        if (delta > 0) {
+        if (delta > 0 && LE_FAILURE(success)) {
             return 1;
         }
 
@@ -48,66 +46,90 @@ le_uint32 LookupProcessor::applyLookupTable(const LookupTable *lookupTable, Glyp
     return 1;
 }
 
-void LookupProcessor::process(LEGlyphID *glyphs, GlyphPositionAdjustment *glyphPositionAdjustments, const LETag **glyphTags, le_int32 glyphCount,
+le_int32 LookupProcessor::process(LEGlyphStorage &glyphStorage, GlyphPositionAdjustments *glyphPositionAdjustments,
                               le_bool rightToLeft, const GlyphDefinitionTableHeader *glyphDefinitionTableHeader,
-                              const LEFontInstance *fontInstance) const
+                              const LEFontInstance *fontInstance, LEErrorCode& success) const
 {
+    if (LE_FAILURE(success)) {
+        return 0;
+    }    
+       
+    le_int32 glyphCount = glyphStorage.getGlyphCount();
+
     if (lookupSelectArray == NULL) {
-        return;
+        return glyphCount;
     }
 
+    GlyphIterator glyphIterator(glyphStorage, glyphPositionAdjustments,
+                                rightToLeft, 0, 0, glyphDefinitionTableHeader);
+    le_int32 newGlyphCount = glyphCount;
+
     for (le_uint16 order = 0; order < lookupOrderCount; order += 1) {
         le_uint16 lookup = lookupOrderArray[order];
-        LETag selectTag = lookupSelectArray[lookup];
+        FeatureMask selectMask = lookupSelectArray[lookup];
 
-        if (selectTag != notSelected) {
+        if (selectMask != 0) {
             const LookupTable *lookupTable = lookupListTable->getLookupTable(lookup);
+            if (!lookupTable) {
+                continue;
+            }
             le_uint16 lookupFlags = SWAPW(lookupTable->lookupFlags);
-            GlyphIterator glyphIterator(glyphs, glyphPositionAdjustments, glyphCount,
-                                  rightToLeft, lookupFlags, selectTag, glyphTags,
-                                  glyphDefinitionTableHeader);
+            
+            glyphIterator.reset(lookupFlags, selectMask);
 
             while (glyphIterator.findFeatureTag()) {
-                le_uint32 delta = 1;
-
-                while (glyphIterator.next(delta)) {
-                    delta = applyLookupTable(lookupTable, &glyphIterator, fontInstance);
+                applyLookupTable(lookupTable, &glyphIterator, fontInstance, success);
+                if (LE_FAILURE(success)) { 
+                    return 0;
                 }
             }
+
+            newGlyphCount = glyphIterator.applyInsertions();
         }
     }
+
+    return newGlyphCount;
 }
 
 le_uint32 LookupProcessor::applySingleLookup(le_uint16 lookupTableIndex, GlyphIterator *glyphIterator,
-                                          const LEFontInstance *fontInstance) const
+                                          const LEFontInstance *fontInstance, LEErrorCode& success) const
 {
+    if (LE_FAILURE(success)) {
+        return 0;
+    }    
+
     const LookupTable *lookupTable = lookupListTable->getLookupTable(lookupTableIndex);
     le_uint16 lookupFlags = SWAPW(lookupTable->lookupFlags);
     GlyphIterator tempIterator(*glyphIterator, lookupFlags);
-    le_uint32 delta = applyLookupTable(lookupTable, &tempIterator, fontInstance);
+    le_uint32 delta = applyLookupTable(lookupTable, &tempIterator, fontInstance, success);
 
     return delta;
 }
 
-le_int32 LookupProcessor::selectLookups(const FeatureTable *featureTable, LETag featureTag, le_int32 order)
+le_int32 LookupProcessor::selectLookups(const FeatureTable *featureTable, FeatureMask featureMask, le_int32 order)
 {
     le_uint16 lookupCount = featureTable? SWAPW(featureTable->lookupCount) : 0;
+    le_int32  store = order;
 
     for (le_uint16 lookup = 0; lookup < lookupCount; lookup += 1) {
         le_uint16 lookupListIndex = SWAPW(featureTable->lookupListIndexArray[lookup]);
+       if (lookupListIndex >= lookupSelectCount) {
+           continue;
+        }
 
-        lookupSelectArray[lookupListIndex] = featureTag;
-        lookupOrderArray[order + lookup]   = lookupListIndex;
+        lookupSelectArray[lookupListIndex] |= featureMask;
+        lookupOrderArray[store++] = lookupListIndex;
     }
 
-    return lookupCount;
+    return store - order;
 }
 
 LookupProcessor::LookupProcessor(const char *baseAddress,
         Offset scriptListOffset, Offset featureListOffset, Offset lookupListOffset,
-        LETag scriptTag, LETag languageTag, const LETag *featureOrder)
-    : lookupListTable(NULL), featureListTable(NULL), lookupSelectArray(NULL),
-      requiredFeatureTag(notSelected), lookupOrderArray(NULL), lookupOrderCount(0)
+        LETag scriptTag, LETag languageTag, const FeatureMap *featureMap, le_int32 featureMapCount, le_bool orderFeatures, 
+        LEErrorCode& success)
+    : lookupListTable(NULL), featureListTable(NULL), lookupSelectArray(NULL), lookupSelectCount(0),
+      lookupOrderArray(NULL), lookupOrderCount(0)
 {
     const ScriptListTable *scriptListTable = NULL;
     const LangSysTable *langSysTable = NULL;
@@ -115,6 +137,10 @@ LookupProcessor::LookupProcessor(const char *baseAddress,
     le_uint16 lookupListCount = 0;
     le_uint16 requiredFeatureIndex;
 
+    if (LE_FAILURE(success)) {
+        return;
+    } 
+
     if (scriptListOffset != 0) {
         scriptListTable = (const ScriptListTable *) (baseAddress + scriptListOffset);
         langSysTable = scriptListTable->findLanguage(scriptTag, languageTag);
@@ -140,39 +166,78 @@ LookupProcessor::LookupProcessor(const char *baseAddress,
  
     requiredFeatureIndex = SWAPW(langSysTable->reqFeatureIndex);
 
-    lookupSelectArray = LE_NEW_ARRAY(LETag, lookupListCount);
+    lookupSelectArray = LE_NEW_ARRAY(FeatureMask, lookupListCount);
+    if (lookupSelectArray == NULL) {
+        success = LE_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
 
     for (int i = 0; i < lookupListCount; i += 1) {
-        lookupSelectArray[i] = notSelected;
+        lookupSelectArray[i] = 0;
     }
+    lookupSelectCount = lookupListCount;
 
     le_int32 count, order = 0;
-    const FeatureTable *featureTable = 0;
+    le_int32 featureReferences = 0;
+    const FeatureTable *featureTable = NULL;
     LETag featureTag;
 
-    lookupOrderArray = LE_NEW_ARRAY(le_uint16, lookupListCount);
+    const FeatureTable *requiredFeatureTable = NULL;
+    LETag requiredFeatureTag = 0x00000000U;
+
+    // Count the total number of lookups referenced by all features. This will
+    // be the maximum number of entries in the lookupOrderArray. We can't use
+    // lookupListCount because some lookups might be referenced by more than
+    // one feature.
+    for (le_int32 feature = 0; feature < featureCount; feature += 1) {
+        le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]);
+
+        featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag);
+        if (!featureTable) {
+             continue;
+        }
+        featureReferences += SWAPW(featureTable->lookupCount);
+    }
 
     if (requiredFeatureIndex != 0xFFFF) {
-        featureTable = featureListTable->getFeatureTable(requiredFeatureIndex, &featureTag);
-        order += selectLookups(featureTable, defaultFeature, order);
+        requiredFeatureTable = featureListTable->getFeatureTable(requiredFeatureIndex, &requiredFeatureTag);
+        featureReferences += SWAPW(featureTable->lookupCount);
     }
 
-    if (featureOrder != NULL) {
-        if (order > 1) {
-            OpenTypeUtilities::sort(lookupOrderArray, order);
+    lookupOrderArray = LE_NEW_ARRAY(le_uint16, featureReferences);
+    if (lookupOrderArray == NULL) {
+        success = LE_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+
+    for (le_int32 f = 0; f < featureMapCount; f += 1) {
+        FeatureMap fm = featureMap[f];
+        count = 0;
+
+        // If this is the required feature, add its lookups
+        if (requiredFeatureTag == fm.tag) {
+            count += selectLookups(requiredFeatureTable, fm.mask, order);
         }
 
-        for (le_int32 tag = 0; featureOrder[tag] != emptyTag; tag += 1) {
-            featureTag = featureOrder[tag];
-            count = 0;
+        if (orderFeatures) {
+            // If we added lookups from the required feature, sort them
+            if (count > 1) {
+                OpenTypeUtilities::sort(lookupOrderArray, order);
+            }
 
             for (le_uint16 feature = 0; feature < featureCount; feature += 1) {
                 le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]);
+                // don't add the required feature to the list more than once...
+                // TODO: Do we need this check? (Spec. says required feature won't be in feature list...)
+                if (featureIndex == requiredFeatureIndex) {
+                    continue;
+                }
 
                 featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag);
 
-                if (featureTag == featureOrder[tag]) {
-                    count += selectLookups(featureTable, featureTag, order + count);
+                if (featureTag == fm.tag) {
+                    count += selectLookups(featureTable, fm.mask, order + count);
                 }
             }
 
@@ -181,19 +246,51 @@ LookupProcessor::LookupProcessor(const char *baseAddress,
             }
 
             order += count;
-        }
-    } else {
-        for (le_uint16 feature = 0; feature < featureCount; feature += 1) {
-            le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]);
+        } else {
+            for (le_uint16 feature = 0; feature < featureCount; feature += 1) {
+                le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]);
  
-            featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag);
-            count = selectLookups(featureTable, featureTag, order);
-            order += count;
+                // don't add the required feature to the list more than once...
+                // NOTE: This check is commented out because the spec. says that
+                // the required feature won't be in the feature list, and because
+                // any duplicate entries will be removed below.
+#if 0
+                if (featureIndex == requiredFeatureIndex) {
+                    continue;
+                }
+#endif
+
+                featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag);
+
+                if (featureTag == fm.tag) {
+                    order += selectLookups(featureTable, fm.mask, order);
+                }
+            }
         }
+    }
 
-        if (order > 1) {
-            OpenTypeUtilities::sort(lookupOrderArray, order);
+    if (!orderFeatures && (order > 1)) {
+        OpenTypeUtilities::sort(lookupOrderArray, order);
+
+        // If there's no specified feature order,
+        // we will apply the lookups in the order
+        // that they're in the font. If a particular
+        // lookup may be referenced by more than one feature,
+        // it will apprear in the lookupOrderArray more than
+        // once, so remove any duplicate entries in the sorted array.
+        le_int32 out = 1;
+
+        for (le_int32 in = 1; in < order; in += 1) {
+            if (lookupOrderArray[out - 1] != lookupOrderArray[in]) {
+                if (out != in) {
+                    lookupOrderArray[out] = lookupOrderArray[in];
+                }
+
+                out += 1;
+            }
         }
+
+        order = out;
     }
 
     lookupOrderCount = order;
@@ -201,12 +298,14 @@ LookupProcessor::LookupProcessor(const char *baseAddress,
 
 LookupProcessor::LookupProcessor()
 {
+       lookupOrderArray = NULL;
+       lookupSelectArray = NULL;
 }
 
 LookupProcessor::~LookupProcessor()
 {
     LE_DELETE_ARRAY(lookupOrderArray);
     LE_DELETE_ARRAY(lookupSelectArray);
-};
+}
 
 U_NAMESPACE_END