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 } } } }