le_uint16 LigatureSubstitutionProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index, LEErrorCode &success)
{
    const LigatureSubstitutionStateEntry2 *entry = entryTable.getAlias(index, success);
    if(LE_FAILURE(success)) return 0;

    le_uint16 nextStateIndex = SWAPW(entry->nextStateIndex);
    le_uint16 flags = SWAPW(entry->entryFlags);
    le_uint16 ligActionIndex = SWAPW(entry->ligActionIndex);
    
    if (flags & lsfSetComponent) {
        if (++m >= nComponents) {
            m = 0;
        }
        componentStack[m] = currGlyph;
    } else if ( m == -1) {
        // bad font- skip this glyph.
        //LE_DEBUG_BAD_FONT("m==-1 (componentCount went negative)")
        currGlyph+= dir;
        return nextStateIndex;
    }

    ByteOffset actionOffset = flags & lsfPerformAction;

    if (actionOffset != 0) {
        LEReferenceTo<LigatureActionEntry> ap(stHeader, success, ligActionOffset); // byte offset
        ap.addObject(ligActionIndex - 1, success);  // index offset ( one before the actual start, because we will pre-increment)
        LEReferenceToArrayOf<TTGlyphID> ligatureTable(stHeader, success, ligatureOffset, LE_UNBOUNDED_ARRAY);
        LigatureActionEntry action;
        le_int32 offset, i = 0;
        le_int32 stack[nComponents];
        le_int16 mm = -1;

        LEReferenceToArrayOf<le_uint16> componentTable(stHeader, success, componentOffset, LE_UNBOUNDED_ARRAY);
        if(LE_FAILURE(success)) {
          currGlyph+= dir;
          return nextStateIndex; // get out! bad font
        }
        
        do {
            le_int32 componentGlyph = componentStack[m--]; // pop off

            ap.addObject(success);
            action = SWAPL(*ap.getAlias());

            if (m < 0) {
                m = nComponents - 1;
            }

            offset = action & lafComponentOffsetMask;
            if (offset != 0) {
                if(componentGlyph > glyphStorage.getGlyphCount() || componentGlyph < 0) {
                  LE_DEBUG_BAD_FONT("preposterous componentGlyph");
                  currGlyph+= dir;
                  return nextStateIndex; // get out! bad font
                }
                i += SWAPW(componentTable(LE_GET_GLYPH(glyphStorage[componentGlyph]) + (SignExtend(offset, lafComponentOffsetMask)),success));
                       
                if (action & (lafLast | lafStore))  {
                  TTGlyphID ligatureGlyph = SWAPW(ligatureTable(i,success));
                    glyphStorage[componentGlyph] = LE_SET_GLYPH(glyphStorage[componentGlyph], ligatureGlyph);
                    if(mm==nComponents) {
                      LE_DEBUG_BAD_FONT("exceeded nComponents");
                      mm--; // don't overrun the stack.
                    }
                    stack[++mm] = componentGlyph;
                    i = 0;
                } else {
                    glyphStorage[componentGlyph] = LE_SET_GLYPH(glyphStorage[componentGlyph], 0xFFFF);
                }
            }
#if LE_ASSERT_BAD_FONT
            if(m<0) {
              LE_DEBUG_BAD_FONT("m<0")
            }
#endif
        } while (!(action & lafLast) && (m>=0) ); // stop if last bit is set, or if run out of items

        while (mm >= 0) {
            if (++m >= nComponents) {
                m = 0;
            }

            componentStack[m] = stack[mm--];
        }
    }
U_NAMESPACE_BEGIN

le_uint32 MultipleSubstitutionSubtable::process(GlyphIterator *glyphIterator, LEErrorCode& success, const LEGlyphFilter *filter) const
{
    if (LE_FAILURE(success)) {
        return 0;
    }

    LEGlyphID glyph = glyphIterator->getCurrGlyphID();

    // If there's a filter, we only want to do the
    // substitution if the *input* glyphs doesn't
    // exist.
    //
    // FIXME: is this always the right thing to do?
    // FIXME: should this only be done for a non-zero
    //        glyphCount?
    if (filter != NULL && filter->accept(glyph)) {
        return 0;
    }

    le_int32 coverageIndex = getGlyphCoverage(glyph);
    le_uint16 seqCount = SWAPW(sequenceCount);

    if (coverageIndex >= 0 && coverageIndex < seqCount) {
        Offset sequenceTableOffset = SWAPW(sequenceTableOffsetArray[coverageIndex]);
        const SequenceTable *sequenceTable = (const SequenceTable *) ((char *) this + sequenceTableOffset);
        le_uint16 glyphCount = SWAPW(sequenceTable->glyphCount);

        if (glyphCount == 0) {
            glyphIterator->setCurrGlyphID(0xFFFF);
            return 1;
        } else if (glyphCount == 1) {
            TTGlyphID substitute = SWAPW(sequenceTable->substituteArray[0]);

            if (filter != NULL && ! filter->accept(LE_SET_GLYPH(glyph, substitute))) {
                return 0;
            }

            glyphIterator->setCurrGlyphID(substitute);
            return 1;
        } else {
            // If there's a filter, make sure all of the output glyphs
            // exist.
            if (filter != NULL) {
                for (le_int32 i = 0; i < glyphCount; i += 1) {
                    TTGlyphID substitute = SWAPW(sequenceTable->substituteArray[i]);

                    if (! filter->accept(substitute)) {
                        return 0;
                    }
                }
            }

            LEGlyphID *newGlyphs = glyphIterator->insertGlyphs(glyphCount, success);
            if (LE_FAILURE(success)) {
                return 0;
            }

            le_int32 insert = 0, direction = 1;

            if (glyphIterator->isRightToLeft()) {
                insert = glyphCount - 1;
                direction = -1;
            }

            for (le_int32 i = 0; i < glyphCount; i += 1) {
                TTGlyphID substitute = SWAPW(sequenceTable->substituteArray[i]);

                newGlyphs[insert] = LE_SET_GLYPH(glyph, substitute);
                insert += direction;
            }

            return 1;
        }
    }

    return 0;
}
LookupProcessor::LookupProcessor(const LETableReference &baseAddress,
        Offset scriptListOffset, Offset featureListOffset, Offset lookupListOffset,
        LETag scriptTag, LETag languageTag, const FeatureMap *featureMap, le_int32 featureMapCount, le_bool orderFeatures, 
        LEErrorCode& success)
    : lookupListTable(), featureListTable(), lookupSelectArray(NULL), lookupSelectCount(0),
      lookupOrderArray(NULL), lookupOrderCount(0), fReference(baseAddress)
{
  LEReferenceTo<ScriptListTable> scriptListTable;
  LEReferenceTo<LangSysTable> langSysTable;
    le_uint16 featureCount = 0;
    le_uint16 lookupListCount = 0;
    le_uint16 requiredFeatureIndex;

    if (LE_FAILURE(success)) {
        return;
    } 

    if (scriptListOffset != 0) {
      scriptListTable = LEReferenceTo<ScriptListTable>(baseAddress, success, scriptListOffset);
      langSysTable = scriptListTable->findLanguage(scriptListTable, scriptTag, languageTag, success);

      if (langSysTable.isValid() && LE_SUCCESS(success)) {
        featureCount = SWAPW(langSysTable->featureCount);
      }
    }

    if (featureListOffset != 0) {
      featureListTable = LEReferenceTo<FeatureListTable>(baseAddress, success, featureListOffset);
    }

    if (lookupListOffset != 0) {
      lookupListTable = LEReferenceTo<LookupListTable>(baseAddress,success, lookupListOffset);
      if(LE_SUCCESS(success) && lookupListTable.isValid()) {
        lookupListCount = SWAPW(lookupListTable->lookupCount);
      }
    }
    
    if (langSysTable.isEmpty() || featureListTable.isEmpty() || lookupListTable.isEmpty() ||
        featureCount == 0 || lookupListCount == 0) {
        return;
    }
 
    if(langSysTable.isValid()) {
      requiredFeatureIndex = SWAPW(langSysTable->reqFeatureIndex);
    }

    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] = 0;
    }
    lookupSelectCount = lookupListCount;

    le_int32 count, order = 0;
    le_uint32 featureReferences = 0;
    LEReferenceTo<FeatureTable> featureTable;
    LETag featureTag;

    LEReferenceTo<FeatureTable> requiredFeatureTable;
    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.
    if(featureListTable.isValid() && LE_SUCCESS(success)) {
      LEReferenceToArrayOf<le_uint16> featureIndexArray(langSysTable, success, langSysTable->featureIndexArray, featureCount);

      for (le_uint32 feature = 0; LE_SUCCESS(success)&&(feature < featureCount); feature += 1) {
        le_uint16 featureIndex = SWAPW(featureIndexArray.getObject(feature, success));
        
        featureTable = featureListTable->getFeatureTable(featureListTable, featureIndex,  &featureTag, success); 
        if (!featureTable.isValid() || LE_FAILURE(success)) {
          continue;
        }
        featureReferences += SWAPW(featureTable->lookupCount);
      }
    }

    if (!featureTable.isValid() || LE_FAILURE(success)) {
        success = LE_INTERNAL_ERROR;
        return;
    }

    if (requiredFeatureIndex != 0xFFFF) {
      requiredFeatureTable = featureListTable->getFeatureTable(featureListTable, requiredFeatureIndex, &requiredFeatureTag, success);
      featureReferences += SWAPW(featureTable->lookupCount);
    }

    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, success);
        }

        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) {
              LEReferenceToArrayOf<le_uint16> featureIndexArray(langSysTable, success, langSysTable->featureIndexArray, featureCount);
              le_uint16 featureIndex = SWAPW(featureIndexArray.getObject(feature,success));
 
                // 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(featureListTable, featureIndex, &featureTag, success);

                if (featureTag == fm.tag) {
                  count += selectLookups(featureTable, fm.mask, order + count, success);
                }
            }

            if (count > 1) {
                OpenTypeUtilities::sort(&lookupOrderArray[order], count);
            }

            order += count;
        } else if(langSysTable.isValid()) {
          LEReferenceToArrayOf<le_uint16> featureIndexArray(langSysTable, success, langSysTable->featureIndexArray, featureCount);
          for (le_uint16 feature = 0; LE_SUCCESS(success)&& (feature < featureCount); feature += 1) {
            le_uint16 featureIndex = SWAPW(featureIndexArray.getObject(feature,success));
 
                // 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(featureListTable, featureIndex, &featureTag, success);

                if (featureTag == fm.tag) {
                  order += selectLookups(featureTable, fm.mask, order, success);
                }
            }
        }
    }

    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;
}
KernTable::KernTable(const LEFontInstance* font, const void* tableData) 
  : pairs(0), font(font)
{
  const KernTableHeader* header = (const KernTableHeader*)tableData;
  if (header == 0) {
#if DEBUG
    fprintf(stderr, "no kern data\n");
#endif
    return;
  }

#if DEBUG
  // dump first 32 bytes of header
  for (int i = 0; i < 64; ++i) {
    fprintf(stderr, "%0.2x ", ((const char*)tableData)[i]&0xff);
    if (((i+1)&0xf) == 0) {
      fprintf(stderr, "\n");
    } else if (((i+1)&0x7) == 0) {
      fprintf(stderr, "  ");
    }
  }
#endif

  if (header->version == 0 && SWAPW(header->nTables) > 0) {
    const SubtableHeader* subhead = (const SubtableHeader*)((char*)tableData + KERN_TABLE_HEADER_SIZE);

    if (subhead->version == 0) {
      coverage = SWAPW(subhead->coverage);

      if (coverage & COVERAGE_HORIZONTAL) { // only handle horizontal kerning
        const Subtable_0* table = (const Subtable_0*)((char*)subhead + KERN_SUBTABLE_HEADER_SIZE);

        nPairs        = SWAPW(table->nPairs);

#if 0   // some old fonts have bad values here...
        searchRange   = SWAPW(table->searchRange);
        entrySelector = SWAPW(table->entrySelector);
        rangeShift    = SWAPW(table->rangeShift);
#else
        entrySelector = OpenTypeUtilities::highBit(nPairs);
        searchRange   = (1 << entrySelector) * KERN_PAIRINFO_SIZE;
        rangeShift    = (nPairs * KERN_PAIRINFO_SIZE) - searchRange;
#endif

        pairs         = (const PairInfo*)((char*)table + KERN_SUBTABLE_0_HEADER_SIZE);

#if DEBUG
        fprintf(stderr, "coverage: %0.4x nPairs: %d pairs 0x%x\n", coverage, nPairs, pairs);
        fprintf(stderr, "  searchRange: %d entrySelector: %d rangeShift: %d\n", searchRange, entrySelector, rangeShift);

        {
          // dump part of the pair list
          char ids[256];

          for (int i = 256; --i >= 0;) {
            LEGlyphID id = font->mapCharToGlyph(i);

            if (id < 256) {
              ids[id] = (char)i;
            }
          }

          const PairInfo* p = pairs;

          for (i = 0; i < nPairs; ++i, p = (const PairInfo*)((char*)p+KERN_PAIRINFO_SIZE)) {
            le_uint16 left = p->left;
            le_uint16 right = p->right;

            if (left < 256 && right < 256) {
              char c = ids[left];

              if (c > 0x20 && c < 0x7f) {
                fprintf(stderr, "%c/", c & 0xff);
              } else {
                printf(stderr, "%0.2x/", c & 0xff);
              }

              c = ids[right];
              if (c > 0x20 && c < 0x7f) {
                fprintf(stderr, "%c ", c & 0xff);
              } else {
                fprintf(stderr, "%0.2x ", c & 0xff);
              }
            }
          }
        }
#endif
      }
    }
  }
}