Beispiel #1
0
const LookupSingle *BinarySearchLookupTable::lookupSingle(const LETableReference &base, const LookupSingle *entries, LEGlyphID glyph, LEErrorCode &success) const
{
    le_int16  unity = SWAPW(unitSize);
    le_int16  probe = SWAPW(searchRange);
    le_int16  extra = SWAPW(rangeShift);
    TTGlyphID ttGlyph = (TTGlyphID) LE_GET_GLYPH(glyph);
    LEReferenceTo<LookupSingle> entry(base, success, entries);
    LEReferenceTo<LookupSingle> trial(entry, success, extra);

    if (!LE_SUCCESS(success)) {
        return NULL;
    }

    if (SWAPW(trial->glyph) <= ttGlyph) {
        entry = trial;
    }

    while (probe > unity && LE_SUCCESS(success)) {
        probe >>= 1;
        trial = entry;
        trial.addOffset(probe, success);

        if (SWAPW(trial->glyph) <= ttGlyph) {
            entry = trial;
        }
    }

    if (SWAPW(entry->glyph) == ttGlyph) {
      return entry.getAlias();
    }

    return NULL;
}
Beispiel #2
0
void Format3AnchorTable::getAnchor(const LEReferenceTo<Format3AnchorTable> &base, const LEFontInstance *fontInstance,
                                   LEPoint &anchor, LEErrorCode &success) const
{
    le_int16 x = SWAPW(xCoordinate);
    le_int16 y = SWAPW(yCoordinate);
    LEPoint pixels;
    Offset dtxOffset = SWAPW(xDeviceTableOffset);
    Offset dtyOffset = SWAPW(yDeviceTableOffset);

    fontInstance->transformFunits(x, y, pixels);

    if (dtxOffset != 0) {
        LEReferenceTo<DeviceTable> dt(base, success, dtxOffset);
        if (LE_SUCCESS(success)) {
            le_int16 adjx = dt->getAdjustment(dt, (le_int16) fontInstance->getXPixelsPerEm(), success);
            pixels.fX += adjx;
        }
    }

    if (dtyOffset != 0) {
        LEReferenceTo<DeviceTable> dt(base, success, dtyOffset);
        if (LE_SUCCESS(success)) {
            le_int16 adjy = dt->getAdjustment(dt, (le_int16) fontInstance->getYPixelsPerEm(), success);
            pixels.fY += adjy;
        }
    }

    fontInstance->pixelsToUnits(pixels, anchor);
}
U_NAMESPACE_BEGIN

le_uint32 PairPositioningSubtable::process(const LEReferenceTo<PairPositioningSubtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const
{
    switch(SWAPW(subtableFormat))
    {
    case 0:
        return 0;

    case 1:
    {
      const LEReferenceTo<PairPositioningFormat1Subtable> subtable(base, success, (const PairPositioningFormat1Subtable *) this);

      if(LE_SUCCESS(success))
      return subtable->process(subtable, glyphIterator, fontInstance, success);
      else
        return 0;
    }

    case 2:
    {
      const LEReferenceTo<PairPositioningFormat2Subtable> subtable(base, success, (const PairPositioningFormat2Subtable *) this);

      if(LE_SUCCESS(success))
      return subtable->process(subtable, glyphIterator, fontInstance, success);
      else
        return 0;
    }
    default:
      return 0;
    }
}
U_NAMESPACE_BEGIN

le_uint32 AlternateSubstitutionSubtable::process(const LEReferenceTo<AlternateSubstitutionSubtable> &base,
        GlyphIterator *glyphIterator, LEErrorCode &success, const LEGlyphFilter *filter) const
{
    // NOTE: For now, we'll just pick the first alternative...
    LEGlyphID glyph = glyphIterator->getCurrGlyphID();
    le_int32 coverageIndex = getGlyphCoverage(base, glyph, success);

    if (coverageIndex >= 0 && LE_SUCCESS(success)) {
        le_uint16 altSetCount = SWAPW(alternateSetCount);

        if (coverageIndex < altSetCount) {
            Offset alternateSetTableOffset = SWAPW(alternateSetTableOffsetArray[coverageIndex]);
            const LEReferenceTo<AlternateSetTable> alternateSetTable(base, success,
                    (const AlternateSetTable *) ((char *) this + alternateSetTableOffset));
            TTGlyphID alternate = SWAPW(alternateSetTable->alternateArray[0]);

            if (filter == NULL || filter->accept(LE_SET_GLYPH(glyph, alternate))) {
                glyphIterator->setCurrGlyphID(SWAPW(alternateSetTable->alternateArray[0]));
            }

            return 1;
        }

        // XXXX If we get here, the table's mal-formed...
    }

    return 0;
}
U_NAMESPACE_BEGIN

/*
    NOTE: This could be optimized somewhat by keeping track
    of the previous sequenceIndex in the loop and doing next()
    or prev() of the delta between that and the current
    sequenceIndex instead of always resetting to the front.
*/
void SubstitutionLookup::applySubstitutionLookups(
        LookupProcessor *lookupProcessor,
        SubstitutionLookupRecord *substLookupRecordArray,
        le_uint16 substCount,
        GlyphIterator *glyphIterator,
        const LEFontInstance *fontInstance,
        le_int32 position,
        LEErrorCode& success)
{
    if (LE_FAILURE(success)) {
        return;
    }

    GlyphIterator tempIterator(*glyphIterator);

    for (le_uint16 subst = 0; subst < substCount && LE_SUCCESS(success); subst += 1) {
        le_uint16 sequenceIndex = SWAPW(substLookupRecordArray[subst].sequenceIndex);
        le_uint16 lookupListIndex = SWAPW(substLookupRecordArray[subst].lookupListIndex);

        tempIterator.setCurrStreamPosition(position);
        tempIterator.next(sequenceIndex);

        lookupProcessor->applySingleLookup(lookupListIndex, &tempIterator, fontInstance, success);
    }
}
U_NAMESPACE_BEGIN

void ContextualSubstitutionBase::applySubstitutionLookups(
        const LookupProcessor *lookupProcessor,
        const SubstitutionLookupRecord *substLookupRecordArray,
        le_uint16 substCount,
        GlyphIterator *glyphIterator,
        const LEFontInstance *fontInstance,
        le_int32 position,
        LEErrorCode& success)
{
    if (LE_FAILURE(success)) { 
        return;
    }

    GlyphIterator tempIterator(*glyphIterator);

    for (le_int16 subst = 0; subst < substCount && LE_SUCCESS(success); subst += 1) {
        le_uint16 sequenceIndex = SWAPW(substLookupRecordArray[subst].sequenceIndex);
        le_uint16 lookupListIndex = SWAPW(substLookupRecordArray[subst].lookupListIndex);

        tempIterator.setCurrStreamPosition(position);
        tempIterator.next(sequenceIndex);

        lookupProcessor->applySingleLookup(lookupListIndex, &tempIterator, fontInstance, success);
    }
}
U_NAMESPACE_BEGIN

// read a 32-bit value that might only be 16-bit-aligned in memory
#define READ_LONG(code) (le_uint32)((SWAPW(*(le_uint16*)&code) << 16) + SWAPW(*(((le_uint16*)&code) + 1)))

// FIXME: should look at the format too... maybe have a sub-class for it?
le_uint32 ExtensionSubtable::process(const LEReferenceTo<ExtensionSubtable> &thisRef,
                                     const LookupProcessor *lookupProcessor, le_uint16 lookupType,
                                      GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const
{

    if (LE_FAILURE(success)) {
        return 0;
    }

    le_uint16 elt = SWAPW(extensionLookupType);

    if (elt != lookupType) {
        le_uint32 extOffset = READ_LONG(extensionOffset);
        LEReferenceTo<LookupSubtable> subtable(thisRef, success,  extOffset);

        if(LE_SUCCESS(success)) {
          return lookupProcessor->applySubtable(subtable, elt, glyphIterator, fontInstance, success);
        }
    }

    return 0;
}
void ContextualGlyphInsertionProcessor2::doInsertion(LEGlyphStorage &glyphStorage, le_int32 atGlyph, le_uint16 &index, le_uint16 count, le_bool /* isKashidaLike */, le_bool isBefore, LEErrorCode &success)
{
    if (!count)
        return;

    LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(atGlyph, count + 1, success);

    if (LE_FAILURE(success))
        return;

    for (le_uint32 glyph = 0; glyph < count + 1; glyph++)
        insertGlyphs[glyph] = 0; // undef

    // Note: Kashida vs Split Vowel seems to only affect selection and highlighting.
    // We note the flag, but do not layout different.
    // https://developer.apple.com/fonts/TTRefMan/RM06/Chap6mort.html

    le_int16 targetIndex = 0;

    if (isBefore) {
        insertGlyphs[count] = glyphStorage[atGlyph];
    } else {
        insertGlyphs[targetIndex++] = glyphStorage[atGlyph];
    }

    while(count-- && LE_SUCCESS(success)) {
        le_uint16 insertGlyph;

        if (insertionAction.getObject(index++, insertGlyph, success))
            insertGlyphs[targetIndex++] = SWAPW(insertGlyph);
    }
}
Beispiel #9
0
U_NAMESPACE_BEGIN

void AnchorTable::getAnchor(const LETableReference &base, LEGlyphID glyphID, const LEFontInstance *fontInstance,
                            LEPoint &anchor, LEErrorCode &success) const
{
    switch(SWAPW(anchorFormat)) {
    case 1:
    {
        LEReferenceTo<Format1AnchorTable> f1(base, success);
        if (LE_SUCCESS(success)) {
            f1->getAnchor(f1, fontInstance, anchor, success);
        }
        break;
    }

    case 2:
    {
        LEReferenceTo<Format2AnchorTable> f2(base, success);
        if (LE_SUCCESS(success)) {
            f2->getAnchor(f2, glyphID, fontInstance, anchor, success);
        }
        break;
    }

    case 3:
    {
        LEReferenceTo<Format3AnchorTable> f3(base, success);
        if (LE_SUCCESS(success)) {
            f3->getAnchor(f3, fontInstance, anchor, success);
        }
        break;
    }

    default:
    {
        // unknown format: just use x, y coordinate, like format 1...
        LEReferenceTo<Format1AnchorTable> f1(base, success);
        if (LE_SUCCESS(success)) {
            f1->getAnchor(f1, fontInstance, anchor, success);
        }
        break;
    }
}
}
U_NAMESPACE_BEGIN

le_uint32 CursiveAttachmentSubtable::process(const LEReferenceTo<CursiveAttachmentSubtable> &base, GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode &success) const
{
    LEGlyphID glyphID       = glyphIterator->getCurrGlyphID();
    le_int32  coverageIndex = getGlyphCoverage(base, glyphID, success);
    le_uint16 eeCount       = SWAPW(entryExitCount);

    LEReferenceToArrayOf<EntryExitRecord>
        entryExitRecordsArrayRef(base, success, entryExitRecords, eeCount);

    if (coverageIndex < 0 || coverageIndex >= eeCount || LE_FAILURE(success)) {
        glyphIterator->setCursiveGlyph();
        return 0;
    }

    LEPoint entryAnchor, exitAnchor;
    Offset entryOffset = SWAPW(entryExitRecords[coverageIndex].entryAnchor);
    Offset exitOffset  = SWAPW(entryExitRecords[coverageIndex].exitAnchor);

    if (entryOffset != 0) {
        LEReferenceTo<AnchorTable> entryAnchorTable(base, success, entryOffset);

        if( LE_SUCCESS(success) ) {
          entryAnchorTable->getAnchor(entryAnchorTable, glyphID, fontInstance, entryAnchor, success);
          glyphIterator->setCursiveEntryPoint(entryAnchor);
        }
    } else {
        //glyphIterator->clearCursiveEntryPoint();
    }

    if (exitOffset != 0) {
        LEReferenceTo<AnchorTable> exitAnchorTable(base, success, exitOffset);

        if( LE_SUCCESS(success) ) {
          exitAnchorTable->getAnchor(exitAnchorTable, glyphID, fontInstance, exitAnchor, success);
          glyphIterator->setCursiveExitPoint(exitAnchor);
        }
    } else {
        //glyphIterator->clearCursiveExitPoint();
    }

    return 1;
}
U_NAMESPACE_BEGIN

void MorphTableHeader::process(const LETableReference &base, LEGlyphStorage &glyphStorage, LEErrorCode &success) const
{
  le_uint32 chainCount = SWAPL(this->nChains);
  LEReferenceTo<ChainHeader> chainHeader(base, success, chains); // moving header
    LEReferenceToArrayOf<ChainHeader> chainHeaderArray(base, success, chains, chainCount);
    le_uint32 chain;

    for (chain = 0; LE_SUCCESS(success) && (chain < chainCount); chain += 1) {
        if (chain > 0) {
            le_uint32 chainLength = SWAPL(chainHeader->chainLength);
            if (chainLength & 0x03) { // incorrect alignment for 32 bit tables
                success = LE_MEMORY_ALLOCATION_ERROR; // as good a choice as any
                return;
            }
            chainHeader.addOffset(chainLength, success);
        }
        FeatureFlags defaultFlags = SWAPL(chainHeader->defaultFlags);
        le_int16 nFeatureEntries = SWAPW(chainHeader->nFeatureEntries);
        le_int16 nSubtables = SWAPW(chainHeader->nSubtables);
        LEReferenceTo<MorphSubtableHeader> subtableHeader =
          LEReferenceTo<MorphSubtableHeader>(chainHeader,success, &(chainHeader->featureTable[nFeatureEntries]));
        le_int16 subtable;

        for (subtable = 0; LE_SUCCESS(success) && (subtable < nSubtables); subtable += 1) {
            if (subtable > 0) {
                le_int16 length = SWAPW(subtableHeader->length);
                if (length & 0x03) { // incorrect alignment for 32 bit tables
                    success = LE_MEMORY_ALLOCATION_ERROR; // as good a choice as any
                    return;
                }
                subtableHeader.addOffset(length, success);
            }
            SubtableCoverage coverage = SWAPW(subtableHeader->coverage);
            FeatureFlags subtableFeatures = SWAPL(subtableHeader->subtableFeatures);

            // should check coverage more carefully...
            if ((coverage & scfVertical) == 0 && (subtableFeatures & defaultFlags) != 0  && LE_SUCCESS(success)) {
              subtableHeader->process(subtableHeader, glyphStorage, success);
            }
        }
    }
}
Beispiel #12
0
LEReferenceTo<ScriptTable> ScriptListTable::findScript(const LETableReference &base, LETag scriptTag, LEErrorCode &success) const
{
    if (LE_FAILURE(success) ) {
        return LEReferenceTo<ScriptTable>(); // get out
    }
    /*
     * There are some fonts that have a large, bogus value for scriptCount. To try
     * and protect against this, we use the offset in the first scriptRecord,
     * which we know has to be past the end of the scriptRecordArray, to compute
     * a value which is greater than or equal to the actual script count.
     *
     * Note: normally, the first offset will point to just after the scriptRecordArray,
     * but there's no guarantee of this, only that it's *after* the scriptRecordArray.
     * Because of this, a binary serach isn't safe, because the new count may include
     * data that's not actually in the scriptRecordArray and hence the array will appear
     * to be unsorted.
     */
    le_uint16 count = SWAPW(scriptCount);

    if (count == 0) {
        return LEReferenceTo<ScriptTable>(); // no items, no search
    }

    // attempt to construct a ref with at least one element
    LEReferenceToArrayOf<ScriptRecord> oneElementTable(base, success, &scriptRecordArray[0], 1);

    if( LE_FAILURE(success) ) {
        return LEReferenceTo<ScriptTable>(); // couldn't even read the first record - bad font.
    }

    le_uint16 limit = ((SWAPW(scriptRecordArray[0].offset) - sizeof(ScriptListTable)) / sizeof(scriptRecordArray)) + ANY_NUMBER;
    Offset scriptTableOffset = 0;


    if (count > limit) {
        // the scriptCount value is bogus; do a linear search
        // because limit may still be too large.
        LEReferenceToArrayOf<ScriptRecord> scriptRecordArrayRef(base, success, &scriptRecordArray[0], limit);
        for(le_int32 s = 0; (s < limit)&&LE_SUCCESS(success); s += 1) {
            if (SWAPT(scriptRecordArrayRef(s,success).tag) == scriptTag) {
                scriptTableOffset = SWAPW(scriptRecordArrayRef(s,success).offset);
                break;
            }
        }
    } else {
        LEReferenceToArrayOf<ScriptRecord> scriptRecordArrayRef(base, success, &scriptRecordArray[0], count);

        scriptTableOffset = OpenTypeUtilities::getTagOffset(scriptTag, scriptRecordArrayRef, success);
    }

    if (scriptTableOffset != 0) {
        return LEReferenceTo<ScriptTable>(base, success, scriptTableOffset);
    }

    return LEReferenceTo<ScriptTable>();
}
le_bool GlyphLookupTableHeader::coversScriptAndLanguage(const LETableReference &base, LETag scriptTag, LETag languageTag, LEErrorCode &success, le_bool exactMatch) const
{
  LEReferenceTo<ScriptListTable> scriptListTable(base, success, SWAPW(scriptListOffset));
  LEReferenceTo<LangSysTable> langSysTable = scriptListTable->findLanguage(scriptListTable,
                                    scriptTag, languageTag, success, exactMatch);

    // FIXME: could check featureListOffset, lookupListOffset, and lookup count...
    // Note: don't have to SWAPW langSysTable->featureCount to check for non-zero.
  return LE_SUCCESS(success)&&langSysTable.isValid() && langSysTable->featureCount != 0;
}
le_bool ScriptCompositeFontInstance::getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber, LEPoint &point) const
{
    LEErrorCode status = LE_NO_ERROR;
    le_int32 script = LE_GET_SUB_FONT(glyph);
    const LEFontInstance *font = fFontMap->getScriptFont(script, status);

    if (LE_SUCCESS(status)) {
        return font->getGlyphPoint(LE_GET_GLYPH(glyph), pointNumber, point);
    }

    return FALSE;
}
void ScriptCompositeFontInstance::getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const
{
    LEErrorCode status = LE_NO_ERROR;
    le_int32 script = LE_GET_SUB_FONT(glyph);
    const LEFontInstance *font = fFontMap->getScriptFont(script, status);

    advance.fX = 0;
    advance.fY = 0;

    if (LE_SUCCESS(status)) {
        font->getGlyphAdvance(LE_GET_GLYPH(glyph), advance);
    }
}
void SimpleArrayProcessor::process(LEGlyphStorage &glyphStorage, LEErrorCode &success)
{
    le_int32 glyphCount = glyphStorage.getGlyphCount();
    le_int32 glyph;

    LEReferenceToArrayOf<LookupValue> valueArray(simpleArrayLookupTable, success, (const LookupValue*)&simpleArrayLookupTable->valueArray, LE_UNBOUNDED_ARRAY);

    for (glyph = 0; LE_SUCCESS(success) && (glyph < glyphCount); glyph += 1) {
        LEGlyphID thisGlyph = glyphStorage[glyph];
        if (LE_GET_GLYPH(thisGlyph) < 0xFFFF) {
          TTGlyphID newGlyph = SWAPW(valueArray.getObject(LE_GET_GLYPH(thisGlyph),success));
          glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph);
        }
    }
}
le_bool ClassDefFormat2Table::hasGlyphClass(const LETableReference &base, le_int32 glyphClass, LEErrorCode &success) const
{
    if(LE_FAILURE(success)) return 0;
    le_uint16 rangeCount = SWAPW(classRangeCount);
    LEReferenceToArrayOf<GlyphRangeRecord> classRangeRecordArrayRef(base, success, &classRangeRecordArray[0], rangeCount);
    int i;

    for (i = 0; i < rangeCount && LE_SUCCESS(success); i += 1) {
      if (SWAPW(classRangeRecordArrayRef(i,success).rangeValue) == glyphClass) {
            return TRUE;
        }
    }

    return FALSE;
}
le_bool ClassDefFormat1Table::hasGlyphClass(const LETableReference &base, le_int32 glyphClass, LEErrorCode &success) const
{
    if(LE_FAILURE(success)) return 0;
    le_uint16 count = SWAPW(glyphCount);
    LEReferenceToArrayOf<le_uint16> classValueArrayRef(base, success, &classValueArray[0], count);
    int i;

    for (i = 0; LE_SUCCESS(success)&& (i < count); i += 1) {
      if (SWAPW(classValueArrayRef(i,success)) == glyphClass) {
            return TRUE;
        }
    }

    return FALSE;
}
Beispiel #19
0
le_int32 LookupProcessor::process(LEGlyphStorage &glyphStorage, GlyphPositionAdjustments *glyphPositionAdjustments,
                                  le_bool rightToLeft, const LEReferenceTo<GlyphDefinitionTableHeader> &glyphDefinitionTableHeader,
                              const LEFontInstance *fontInstance, LEErrorCode& success) const
{
    if (LE_FAILURE(success)) {
        return 0;
    }

    le_int32 glyphCount = glyphStorage.getGlyphCount();

    if (lookupSelectArray == NULL) {
        return glyphCount;
    }

    GlyphIterator glyphIterator(glyphStorage, glyphPositionAdjustments,
                                rightToLeft, 0, 0, glyphDefinitionTableHeader, success);
    le_int32 newGlyphCount = glyphCount;

    for (le_uint16 order = 0; order < lookupOrderCount && LE_SUCCESS(success); order += 1) {
        le_uint16 lookup = lookupOrderArray[order];
        FeatureMask selectMask = lookupSelectArray[lookup];

        if (selectMask != 0) {
          _LETRACE("Processing order#%d/%d", order, lookupOrderCount);
          const LEReferenceTo<LookupTable> lookupTable = lookupListTable->getLookupTable(lookupListTable, lookup, success);
          if (!lookupTable.isValid() ||LE_FAILURE(success) ) {
                continue;
            }
            le_uint16 lookupFlags = SWAPW(lookupTable->lookupFlags);

            glyphIterator.reset(lookupFlags, selectMask);

            while (glyphIterator.findFeatureTag()) {
                applyLookupTable(lookupTable, &glyphIterator, fontInstance, success);
                if (LE_FAILURE(success)) {
#if LE_TRACE
                    _LETRACE("Failure for lookup 0x%x - %s\n", lookup, u_errorName((UErrorCode)success));
#endif
                    return 0;
                }
            }

            newGlyphCount = glyphIterator.applyInsertions();
        }
    }

    return newGlyphCount;
}
le_int32 ClassDefFormat1Table::getGlyphClass(const LETableReference& base, LEGlyphID glyphID, LEErrorCode &success) const
{
    if(LE_FAILURE(success)) return 0;

    le_uint16 count = SWAPW(glyphCount);
    LEReferenceToArrayOf<le_uint16> classValueArrayRef(base, success, &classValueArray[0], count);
    TTGlyphID ttGlyphID  = (TTGlyphID) LE_GET_GLYPH(glyphID);
    TTGlyphID firstGlyph = SWAPW(startGlyph);
    TTGlyphID lastGlyph  = firstGlyph + count;

    if (LE_SUCCESS(success) && ttGlyphID >= firstGlyph && ttGlyphID < lastGlyph) {
      return SWAPW( classValueArrayRef(ttGlyphID - firstGlyph, success) );
    }

    return 0;
}
Beispiel #21
0
U_NAMESPACE_BEGIN

/*
    These are the rolled-up versions of the uniform binary search.
    Someday, if we need more performance, we can un-roll them.

    Note: I put these in the base class, so they only have to
    be written once. Since the base class doesn't define the
    segment table, these routines assume that it's right after
    the binary search header.

    Another way to do this is to put each of these routines in one
    of the derived classes, and implement it in the others by casting
    the "this" pointer to the type that has the implementation.
*/
const LookupSegment *BinarySearchLookupTable::lookupSegment(const LETableReference &base, const LookupSegment *segments, LEGlyphID glyph, LEErrorCode &success) const
{

    le_int16  unity = SWAPW(unitSize);
    le_int16  probe = SWAPW(searchRange);
    le_int16  extra = SWAPW(rangeShift);
    TTGlyphID ttGlyph = (TTGlyphID) LE_GET_GLYPH(glyph);
    LEReferenceTo<LookupSegment> entry(base, success, segments);
    LEReferenceTo<LookupSegment> trial(entry, success, extra);

    if(LE_FAILURE(success)) return NULL;

    if (SWAPW(trial->lastGlyph) <= ttGlyph) {
        entry = trial;
    }

    while (probe > unity && LE_SUCCESS(success)) {
        probe >>= 1;
        trial = entry; // copy
        trial.addOffset(probe, success);

        if (SWAPW(trial->lastGlyph) <= ttGlyph) {
            entry = trial;
        }
    }

    if (SWAPW(entry->firstGlyph) <= ttGlyph) {
      return entry.getAlias();
    }

    return NULL;
}
Beispiel #22
0
void MorphSubtableHeader2::process(const LEReferenceTo<MorphSubtableHeader2> &base, LEGlyphStorage &glyphStorage, LEErrorCode &success) const
{
    SubtableProcessor2 *processor = NULL;

    switch (SWAPL(coverage) & scfTypeMask2)
    {
    case mstIndicRearrangement:
        processor = new IndicRearrangementProcessor2(base, success);
        break;

    case mstContextualGlyphSubstitution:
        processor = new ContextualGlyphSubstitutionProcessor2(base, success);
        break;

    case mstLigatureSubstitution:
        processor = new LigatureSubstitutionProcessor2(base, success);
        break;

    case mstReservedUnused:
        break;

    case mstNonContextualGlyphSubstitution:
        processor = NonContextualGlyphSubstitutionProcessor2::createInstance(base, success);
        break;

    
    case mstContextualGlyphInsertion:
        processor = new ContextualGlyphInsertionProcessor2(base, success);
        break;

    default:
        return;
        break; /*NOTREACHED*/
    }

    if (processor != NULL) {
      processor->process(glyphStorage, success);
        delete processor;
    } else {
      if(LE_SUCCESS(success)) {
        success = LE_MEMORY_ALLOCATION_ERROR; // because ptr is null and we didn't break out.
      }
    }
}
void SegmentSingleProcessor2::process(LEGlyphStorage &glyphStorage, LEErrorCode &success)
{
    const LookupSegment *segments = segmentSingleLookupTable->segments;
    le_int32 glyphCount = glyphStorage.getGlyphCount();
    le_int32 glyph;

    if (LE_FAILURE(success)) return;

    for (glyph = 0; glyph < glyphCount; glyph += 1) {
        LEGlyphID thisGlyph = glyphStorage[glyph];
        const LookupSegment *lookupSegment = segmentSingleLookupTable->lookupSegment(segmentSingleLookupTable, segments, thisGlyph, success);

        if (lookupSegment != NULL && LE_SUCCESS(success)) {
            TTGlyphID   newGlyph  = (TTGlyphID) LE_GET_GLYPH(thisGlyph) + SWAPW(lookupSegment->value);

            glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph);
        }
    }
}
le_int32 LookupProcessor::selectLookups(const LEReferenceTo<FeatureTable> &featureTable, FeatureMask featureMask, le_int32 order, LEErrorCode &success)
{
  le_uint16 lookupCount = featureTable.isValid()? SWAPW(featureTable->lookupCount) : 0;
    le_int32  store = order;
    
    LEReferenceToArrayOf<le_uint16> lookupListIndexArray(featureTable, success, featureTable->lookupListIndexArray, lookupCount);

    for (le_uint16 lookup = 0; LE_SUCCESS(success) && lookup < lookupCount; lookup += 1) {
      le_uint16 lookupListIndex = SWAPW(lookupListIndexArray.getObject(lookup,success));
      if (lookupListIndex >= lookupSelectCount) {
        continue;
      }
      
      lookupSelectArray[lookupListIndex] |= featureMask;
      lookupOrderArray[store++] = lookupListIndex;
    }

    return store - order;
}
void MorphSubtableHeader::process(const LEReferenceTo<MorphSubtableHeader> &base, LEGlyphStorage &glyphStorage, LEErrorCode &success) const
{
    SubtableProcessor *processor = NULL;

    switch (SWAPW(coverage) & scfTypeMask)
    {
    case mstIndicRearrangement:
      processor = new IndicRearrangementProcessor(base, success);
        break;

    case mstContextualGlyphSubstitution:
      processor = new ContextualGlyphSubstitutionProcessor(base, success);
        break;

    case mstLigatureSubstitution:
      processor = new LigatureSubstitutionProcessor(base, success);
        break;

    case mstReservedUnused:
        break;

    case mstNonContextualGlyphSubstitution:
      processor = NonContextualGlyphSubstitutionProcessor::createInstance(base, success);
        break;

    /*
    case mstContextualGlyphInsertion:
        processor = new ContextualGlyphInsertionProcessor(this);
        break;
    */

    default:
        break;
    }

    if (processor != NULL) {
      if(LE_SUCCESS(success)) {
        processor->process(glyphStorage, success);
      }
      delete processor;
    }
}
// FIXME: should look at the format too... maybe have a sub-class for it?
le_uint32 ExtensionSubtable::process(const LookupProcessor *lookupProcessor, le_uint16 lookupType,
                                      GlyphIterator *glyphIterator, const LEFontInstance *fontInstance, LEErrorCode& success) const
{
    const LEReferenceTo<ExtensionSubtable> thisRef(lookupProcessor->getReference(), success); // create a reference to this

    if (LE_FAILURE(success)) {
        return 0;
    }

    le_uint16 elt = SWAPW(extensionLookupType);

    if (elt != lookupType) {      
        le_uint32 extOffset = READ_LONG(extensionOffset);
        LEReferenceTo<LookupSubtable> subtable(thisRef, success, extOffset);

        if(LE_SUCCESS(success)) {
          return lookupProcessor->applySubtable(subtable, elt, glyphIterator, fontInstance, success);
        }
    }

    return 0;
}
Beispiel #27
0
U_NAMESPACE_BEGIN

LEReferenceTo<LangSysTable> ScriptTable::findLanguage(const LETableReference& base, LETag languageTag, LEErrorCode &success, le_bool exactMatch) const
{
    le_uint16 count = SWAPW(langSysCount);
    Offset langSysTableOffset = exactMatch? 0 : SWAPW(defaultLangSysTableOffset);

    if (count > 0) {
        LEReferenceToArrayOf<TagAndOffsetRecord> langSysRecords(base, success, langSysRecordArray, count);
        Offset foundOffset =
            OpenTypeUtilities::getTagOffset(languageTag, langSysRecords, success);

        if (foundOffset != 0 && LE_SUCCESS(success)) {
            langSysTableOffset = foundOffset;
        }
    }

    if (langSysTableOffset != 0) {
        return LEReferenceTo<LangSysTable>(base, success, langSysTableOffset);
    }

    return LEReferenceTo<LangSysTable>();
}
Beispiel #28
0
le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
                LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success)
{
    if (LE_FAILURE(success)) {
        return 0;
    }

    if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
        success = LE_ILLEGAL_ARGUMENT_ERROR;
        return 0;
    }

    LEReferenceTo<GlyphSubstitutionTableHeader> canonGSUBTable((GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable);
    LETag scriptTag  = OpenTypeLayoutEngine::getScriptTag(fScriptCode);
    LETag langSysTag = OpenTypeLayoutEngine::getLangSysTag(fLanguageCode);
    le_int32 i, dir = 1, out = 0, outCharCount = count;

    if (canonGSUBTable->coversScript(canonGSUBTable,scriptTag, success) || LE_SUCCESS(success)) {
        CharSubstitutionFilter *substitutionFilter = new CharSubstitutionFilter(fFontInstance);
        if (substitutionFilter == NULL) {
            success = LE_MEMORY_ALLOCATION_ERROR;
            return 0;
        }

        const LEUnicode *inChars = &chars[offset];
        LEUnicode *reordered = NULL;
        LEGlyphStorage fakeGlyphStorage;

        fakeGlyphStorage.allocateGlyphArray(count, rightToLeft, success);

        if (LE_FAILURE(success)) {
            delete substitutionFilter;
            return 0;
        }

        // This is the cheapest way to get mark reordering only for Hebrew.
        // We could just do the mark reordering for all scripts, but most
        // of them probably don't need it...
        if (fScriptCode == hebrScriptCode) {
          reordered = LE_NEW_ARRAY(LEUnicode, count);
          
          if (reordered == NULL) {
            delete substitutionFilter;
            success = LE_MEMORY_ALLOCATION_ERROR;
            return 0;
          }
          
          CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, reordered, fakeGlyphStorage);
          inChars = reordered;
        }

        fakeGlyphStorage.allocateAuxData(success);

        if (LE_FAILURE(success)) {
            delete substitutionFilter;
            return 0;
        }

        if (rightToLeft) {
            out = count - 1;
            dir = -1;
        }

        for (i = 0; i < count; i += 1, out += dir) {
            fakeGlyphStorage[out] = (LEGlyphID) inChars[i];
            fakeGlyphStorage.setAuxData(out, canonFeatures, success);
        }

        if (reordered != NULL) {
          LE_DELETE_ARRAY(reordered);
        }

        outCharCount = canonGSUBTable->process(canonGSUBTable, fakeGlyphStorage, rightToLeft, scriptTag, langSysTag, (const GlyphDefinitionTableHeader*)NULL, substitutionFilter, canonFeatureMap, canonFeatureMapCount, FALSE, success);

        if (LE_FAILURE(success)) {
            delete substitutionFilter;
            return 0;
        }

        out = (rightToLeft? outCharCount - 1 : 0);

        /*
         * The char indices array in fakeGlyphStorage has the correct mapping
         * back to the original input characters. Save it in glyphStorage. The
         * subsequent call to glyphStoratge.allocateGlyphArray will keep this
         * array rather than allocating and initializing a new one.
         */
        glyphStorage.adoptCharIndicesArray(fakeGlyphStorage);

        outChars = LE_NEW_ARRAY(LEUnicode, outCharCount);

        if (outChars == NULL) {
            delete substitutionFilter;
            success = LE_MEMORY_ALLOCATION_ERROR;
            return 0;
        }

        for (i = 0; i < outCharCount; i += 1, out += dir) {
            outChars[out] = (LEUnicode) LE_GET_GLYPH(fakeGlyphStorage[i]);
        }

        delete substitutionFilter;
    }

    return outCharCount;
}
void StateTableProcessor2::process(LEGlyphStorage &glyphStorage, LEErrorCode &success)
{
    if (LE_FAILURE(success)) return;
    // Start at state 0
    // XXX: How do we know when to start at state 1?
    le_uint16 currentState = 0;
    le_int32 glyphCount = glyphStorage.getGlyphCount();
    
    LE_STATE_PATIENCE_INIT();

    le_int32 currGlyph = 0;
    if ((coverage & scfReverse2) != 0) {  // process glyphs in descending order
        currGlyph = glyphCount - 1;
        dir = -1;
    } else {
        dir = 1;
    }
    
    beginStateTable();
    switch (format) {
        case ltfSimpleArray: {
#ifdef TEST_FORMAT
          LEReferenceTo<SimpleArrayLookupTable> lookupTable0(classTable, success);
          if(LE_FAILURE(success)) break;
            while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) {
                if (LE_FAILURE(success)) break;
                if (LE_STATE_PATIENCE_DECR()) {
                  LE_DEBUG_BAD_FONT("patience exceeded - state table not moving")
                  break; // patience exceeded.
                }
                LookupValue classCode = classCodeOOB;
                if (currGlyph == glyphCount || currGlyph == -1) {
                    // XXX: How do we handle EOT vs. EOL?
                    classCode = classCodeEOT;
                } else {
                    LEGlyphID gid = glyphStorage[currGlyph];
                    TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid);
                    
                    if (glyphCode == 0xFFFF) {
                        classCode = classCodeDEL;
                    } else {
                        classCode = SWAPW(lookupTable0->valueArray[gid]);
                    }
                }
                EntryTableIndex2 entryTableIndex = SWAPW(stateArray(classCode + currentState * nClasses, success));
                LE_STATE_PATIENCE_CURR(le_int32, currGlyph);
                currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); // return a zero-based index instead of a byte offset
                LE_STATE_PATIENCE_INCR(currGlyph);
            }
#endif
            break;
        }
        case ltfSegmentSingle: {
          LEReferenceTo<SegmentSingleLookupTable> lookupTable2(classTable, success);
          if(LE_FAILURE(success)) break;
            while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) {
                if (LE_FAILURE(success)) break;
                if (LE_STATE_PATIENCE_DECR()) {
                  LE_DEBUG_BAD_FONT("patience exceeded  - state table not moving")
                  break; // patience exceeded.
                }
                LookupValue classCode = classCodeOOB;
                if (currGlyph == glyphCount || currGlyph == -1) {
                    // XXX: How do we handle EOT vs. EOL?
                    classCode = classCodeEOT;
                } else {
                    LEGlyphID gid = glyphStorage[currGlyph];
                    TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid);
                    
                    if (glyphCode == 0xFFFF) {
                        classCode = classCodeDEL;
                    } else {
                      const LookupSegment *segment = 
                        lookupTable2->lookupSegment(lookupTable2, lookupTable2->segments, gid, success);
                        if (segment != NULL && LE_SUCCESS(success)) {
                            classCode = SWAPW(segment->value);
                        }
                    }
                }                
                EntryTableIndex2 entryTableIndex = SWAPW(stateArray(classCode + currentState * nClasses,success));
                LE_STATE_PATIENCE_CURR(le_int32, currGlyph);
                currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex, success);
                LE_STATE_PATIENCE_INCR(currGlyph);
            }
            break;
        }
        case ltfSegmentArray: {
          //printf("Lookup Table Format4: specific interpretation needed!\n");
            break;
        }
        case ltfSingleTable: {
            LEReferenceTo<SingleTableLookupTable> lookupTable6(classTable, success);
            while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) {
                if (LE_FAILURE(success)) break;
                if (LE_STATE_PATIENCE_DECR()) {
                  LE_DEBUG_BAD_FONT("patience exceeded - state table not moving")
                  break; // patience exceeded.
                }
                LookupValue classCode = classCodeOOB;
                if (currGlyph == glyphCount || currGlyph == -1) {
                    // XXX: How do we handle EOT vs. EOL?
                    classCode = classCodeEOT;
                } else if(currGlyph > glyphCount) {
                  // note if > glyphCount, we've run off the end (bad font)
                  currGlyph = glyphCount;
                  classCode = classCodeEOT;
                } else {
                    LEGlyphID gid = glyphStorage[currGlyph];
                    TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid);
                    
                    if (glyphCode == 0xFFFF) {
                        classCode = classCodeDEL;
                    } else {
                      const LookupSingle *segment = lookupTable6->lookupSingle(lookupTable6, lookupTable6->entries, gid, success);
                        if (segment != NULL) {
                            classCode = SWAPW(segment->value);
                        }
                    }
                }
                EntryTableIndex2 entryTableIndex = SWAPW(stateArray(classCode + currentState * nClasses, success));
                LE_STATE_PATIENCE_CURR(le_int32, currGlyph);
                currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex, success);
                LE_STATE_PATIENCE_INCR(currGlyph);
            }
            break;
        }
        case ltfTrimmedArray: {
            LEReferenceTo<TrimmedArrayLookupTable> lookupTable8(classTable, success);
            if (LE_FAILURE(success)) break;
            TTGlyphID firstGlyph = SWAPW(lookupTable8->firstGlyph);    
            TTGlyphID lastGlyph  = firstGlyph + SWAPW(lookupTable8->glyphCount);
            
            while ((dir == 1 && currGlyph <= glyphCount) || (dir == -1 && currGlyph >= -1)) {
                if(LE_STATE_PATIENCE_DECR()) {
                  LE_DEBUG_BAD_FONT("patience exceeded - state table not moving")
                  break; // patience exceeded.
                }
                       
                LookupValue classCode = classCodeOOB;
                if (currGlyph == glyphCount || currGlyph == -1) {
                    // XXX: How do we handle EOT vs. EOL?
                    classCode = classCodeEOT;
                } else {
                    TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(glyphStorage[currGlyph]);
                    if (glyphCode == 0xFFFF) {
                        classCode = classCodeDEL;
                    } else if ((glyphCode >= firstGlyph) && (glyphCode < lastGlyph)) {
                        classCode = SWAPW(lookupTable8->valueArray[glyphCode - firstGlyph]);
                    }
                }
                EntryTableIndex2 entryTableIndex = SWAPW(stateArray(classCode + currentState * nClasses, success));
                LE_STATE_PATIENCE_CURR(le_int32, currGlyph);
                currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex, success);
                LE_STATE_PATIENCE_INCR(currGlyph);
            }
            break;
        }
        default:
            break;
    }

    endStateTable();
}
Beispiel #30
0
LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success)
{
    static const le_uint32 gsubTableTag = LE_GSUB_TABLE_TAG;
    static const le_uint32 mortTableTag = LE_MORT_TABLE_TAG;
    static const le_uint32 morxTableTag = LE_MORX_TABLE_TAG;

    if (LE_FAILURE(success)) {
        return NULL;
    }

    LEReferenceTo<GlyphSubstitutionTableHeader> gsubTable(fontInstance,gsubTableTag,success);
    LayoutEngine *result = NULL;
    LETag scriptTag   = 0x00000000;
    LETag languageTag = 0x00000000;
    LETag v2ScriptTag = OpenTypeLayoutEngine::getV2ScriptTag(scriptCode);

    // Right now, only invoke V2 processing for Devanagari.  TODO: Allow more V2 scripts as they are
    // properly tested.

    if ( v2ScriptTag == dev2ScriptTag && gsubTable.isValid() && gsubTable->coversScript(gsubTable, v2ScriptTag, success )) {
      result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, TRUE, gsubTable, success);
    }
    else if (gsubTable.isValid() && gsubTable->coversScript(gsubTable, scriptTag = OpenTypeLayoutEngine::getScriptTag(scriptCode), success)) {
        switch (scriptCode) {
        case bengScriptCode:
        case devaScriptCode:
        case gujrScriptCode:
        case kndaScriptCode:
        case mlymScriptCode:
        case oryaScriptCode:
        case guruScriptCode:
        case tamlScriptCode:
        case teluScriptCode:
        case sinhScriptCode:
            result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, FALSE, gsubTable, success);
            break;

        case arabScriptCode:
            result = new ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
            break;

        case hebrScriptCode:
            // Disable hebrew ligatures since they have only archaic uses, see ticket #8318
            result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags & ~kTypoFlagLiga, gsubTable, success);
            break;

        case hangScriptCode:
            result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
            break;

        case haniScriptCode:
            languageTag = OpenTypeLayoutEngine::getLangSysTag(languageCode);

            switch (languageCode) {
            case korLanguageCode:
            case janLanguageCode:
            case zhtLanguageCode:
            case zhsLanguageCode:
              if (gsubTable->coversScriptAndLanguage(gsubTable, scriptTag, languageTag, success, TRUE)) {
                    result = new HanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
                    break;
              }

                // note: falling through to default case.
            default:
                result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
                break;
            }

            break;

        case tibtScriptCode:
            result = new TibetanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
            break;

        case khmrScriptCode:
            result = new KhmerOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
            break;

        default:
            result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success);
            break;
        }
    } else {
        LEReferenceTo<MorphTableHeader2> morxTable(fontInstance, morxTableTag, success);
        if (LE_SUCCESS(success) && morxTable.isValid() && SWAPL(morxTable->version)==0x00020000) {
          result = new GXLayoutEngine2(fontInstance, scriptCode, languageCode, morxTable, typoFlags, success);
        } else {
          LEReferenceTo<MorphTableHeader> mortTable(fontInstance, mortTableTag, success);
          if (LE_SUCCESS(success) && mortTable.isValid() && SWAPL(mortTable->version)==0x00010000) { // mort
            result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, mortTable, success);
            } else {
                switch (scriptCode) {
                    case bengScriptCode:
                    case devaScriptCode:
                    case gujrScriptCode:
                    case kndaScriptCode:
                    case mlymScriptCode:
                    case oryaScriptCode:
                    case guruScriptCode:
                    case tamlScriptCode:
                    case teluScriptCode:
                    case sinhScriptCode:
                    {
                        result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
                        break;
                    }

                    case arabScriptCode:
                        //case hebrScriptCode:
                        result = new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
                        break;

                        //case hebrScriptCode:
                        //    return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);

                    case thaiScriptCode:
                        result = new ThaiLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
                        break;

                    case hangScriptCode:
                        result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
                        break;

                    default:
                        result = new LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success);
                        break;
                }
            }
        }
    }

    if (result && LE_FAILURE(success)) {
		delete result;
		result = NULL;
	}

    if (result == NULL) {
        success = LE_MEMORY_ALLOCATION_ERROR;
    }

    return result;
}