void LayoutEngine::adjustMarkGlyphs(LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success) { float xAdjust = 0; le_int32 p, glyphCount = glyphStorage.getGlyphCount(); if (LE_FAILURE(success)) { return; } if (markFilter == NULL) { success = LE_ILLEGAL_ARGUMENT_ERROR; return; } float ignore, prev; glyphStorage.getGlyphPosition(0, prev, ignore, success); for (p = 0; p < glyphCount; p += 1) { float next, xAdvance; glyphStorage.getGlyphPosition(p + 1, next, ignore, success); xAdvance = next - prev; glyphStorage.adjustPosition(p, xAdjust, 0, success); if (markFilter->accept(glyphStorage[p])) { xAdjust -= xAdvance; } prev = next; } glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success); }
// Input: glyphs // Output: positions void LayoutEngine::positionGlyphs(LEGlyphStorage &glyphStorage, float x, float y, LEErrorCode &success) { if (LE_FAILURE(success)) { return; } glyphStorage.allocatePositions(success); if (LE_FAILURE(success)) { return; } le_int32 i, glyphCount = glyphStorage.getGlyphCount(); for (i = 0; i < glyphCount; i += 1) { LEPoint advance; glyphStorage.setPosition(i, x, y, success); fFontInstance->getGlyphAdvance(glyphStorage[i], advance); x += advance.fX; y += advance.fY; } glyphStorage.setPosition(glyphCount, x, y, success); }
le_int32 OpenTypeLayoutEngine::glyphPostProcessing(LEGlyphStorage &tempGlyphStorage, LEGlyphStorage &glyphStorage, LEErrorCode &success) { if (LE_FAILURE(success)) { return 0; } glyphStorage.adoptGlyphArray(tempGlyphStorage); glyphStorage.adoptCharIndicesArray(tempGlyphStorage); glyphStorage.adoptAuxDataArray(tempGlyphStorage); glyphStorage.adoptGlyphCount(tempGlyphStorage); return glyphStorage.getGlyphCount(); }
void SimpleArrayProcessor::process(LEGlyphStorage &glyphStorage) { le_int32 glyphCount = glyphStorage.getGlyphCount(); le_int32 glyph; for (glyph = 0; glyph < glyphCount; glyph += 1) { LEGlyphID thisGlyph = glyphStorage[glyph]; if (LE_GET_GLYPH(thisGlyph) < 0xFFFF) { TTGlyphID newGlyph = SWAPW(simpleArrayLookupTable->valueArray[LE_GET_GLYPH(thisGlyph)]); glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); } } }
void SingleTableProcessor::process(LEGlyphStorage &glyphStorage) { const LookupSingle *entries = singleTableLookupTable->entries; le_int32 glyph; le_int32 glyphCount = glyphStorage.getGlyphCount(); for (glyph = 0; glyph < glyphCount; glyph += 1) { const LookupSingle *lookupSingle = singleTableLookupTable->lookupSingle(entries, glyphStorage[glyph]); if (lookupSingle != NULL) { glyphStorage[glyph] = SWAPW(lookupSingle->value); } } }
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); } } }
void SingleTableProcessor2::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) { if(LE_FAILURE(success)) return; const LookupSingle *entries = singleTableLookupTable->entries; le_int32 glyph; le_int32 glyphCount = glyphStorage.getGlyphCount(); for (glyph = 0; glyph < glyphCount; glyph += 1) { const LookupSingle *lookupSingle = singleTableLookupTable->lookupSingle(singleTableLookupTable, entries, glyphStorage[glyph], success); if (lookupSingle != NULL) { glyphStorage[glyph] = SWAPW(lookupSingle->value); } } }
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; }
void SimpleArrayProcessor2::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) { le_int32 glyphCount = glyphStorage.getGlyphCount(); le_int32 glyph; if (LE_FAILURE(success)) return; for (glyph = 0; glyph < glyphCount; glyph += 1) { LEGlyphID thisGlyph = glyphStorage[glyph]; if (LE_GET_GLYPH(thisGlyph) < 0xFFFF) { TTGlyphID newGlyph = SWAPW(valueArray(LE_GET_GLYPH(thisGlyph),success)); glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); } } }
void TrimmedArrayProcessor::process(LEGlyphStorage &glyphStorage) { le_int32 glyphCount = glyphStorage.getGlyphCount(); le_int32 glyph; for (glyph = 0; glyph < glyphCount; glyph += 1) { LEGlyphID thisGlyph = glyphStorage[glyph]; TTGlyphID ttGlyph = (TTGlyphID) LE_GET_GLYPH(thisGlyph); if ((ttGlyph > firstGlyph) && (ttGlyph < lastGlyph)) { TTGlyphID newGlyph = SWAPW(trimmedArrayLookupTable->valueArray[ttGlyph - firstGlyph]); glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); } } }
void TrimmedArrayProcessor2::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) { if(LE_FAILURE(success)) return; le_int32 glyphCount = glyphStorage.getGlyphCount(); le_int32 glyph; for (glyph = 0; glyph < glyphCount; glyph += 1) { LEGlyphID thisGlyph = glyphStorage[glyph]; TTGlyphID ttGlyph = (TTGlyphID) LE_GET_GLYPH(thisGlyph); if ((ttGlyph > firstGlyph) && (ttGlyph < lastGlyph)) { TTGlyphID newGlyph = SWAPW(valueArray(ttGlyph - firstGlyph, success)); glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); } } }
void SegmentSingleProcessor::process(LEGlyphStorage &glyphStorage) { const LookupSegment *segments = segmentSingleLookupTable->segments; le_int32 glyphCount = glyphStorage.getGlyphCount(); le_int32 glyph; for (glyph = 0; glyph < glyphCount; glyph += 1) { LEGlyphID thisGlyph = glyphStorage[glyph]; const LookupSegment *lookupSegment = segmentSingleLookupTable->lookupSegment(segments, thisGlyph); if (lookupSegment != NULL) { TTGlyphID newGlyph = (TTGlyphID) LE_GET_GLYPH(thisGlyph) + SWAPW(lookupSegment->value); glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); } } }
void LayoutEngine::adjustMarkGlyphs(const LEUnicode chars[], le_int32 charCount, le_bool reverse, LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success) { float xAdjust = 0; le_int32 c = 0, direction = 1, p; le_int32 glyphCount = glyphStorage.getGlyphCount(); if (LE_FAILURE(success)) { return; } if (markFilter == NULL) { success = LE_ILLEGAL_ARGUMENT_ERROR; return; } if (reverse) { c = glyphCount - 1; direction = -1; } float ignore, prev; glyphStorage.getGlyphPosition(0, prev, ignore, success); for (p = 0; p < charCount; p += 1, c += direction) { float next, xAdvance; glyphStorage.getGlyphPosition(p + 1, next, ignore, success); xAdvance = next - prev; _LETRACE("p#%d (%.2f,%.2f)", p, xAdvance, 0); glyphStorage.adjustPosition(p, xAdjust, 0, success); if (markFilter->accept(chars[c], success)) { xAdjust -= xAdvance; } prev = next; } glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success); }
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::process(LEGlyphStorage &glyphStorage, GlyphPositionAdjustments *glyphPositionAdjustments, le_bool rightToLeft, const 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); le_int32 newGlyphCount = glyphCount; for (le_uint16 order = 0; order < lookupOrderCount; order += 1) { le_uint16 lookup = lookupOrderArray[order]; FeatureMask selectMask = lookupSelectArray[lookup]; if (selectMask != 0) { const LookupTable *lookupTable = lookupListTable->getLookupTable(lookup); le_uint16 lookupFlags = SWAPW(lookupTable->lookupFlags); glyphIterator.reset(lookupFlags, selectMask); while (glyphIterator.findFeatureTag()) { applyLookupTable(lookupTable, &glyphIterator, fontInstance, success); if (LE_FAILURE(success)) { return 0; } } newGlyphCount = glyphIterator.applyInsertions(); } } return newGlyphCount; }
void SegmentArrayProcessor::process(LEGlyphStorage &glyphStorage) { const LookupSegment *segments = segmentArrayLookupTable->segments; le_int32 glyphCount = glyphStorage.getGlyphCount(); le_int32 glyph; for (glyph = 0; glyph < glyphCount; glyph += 1) { LEGlyphID thisGlyph = glyphStorage[glyph]; const LookupSegment *lookupSegment = segmentArrayLookupTable->lookupSegment(segments, thisGlyph); if (lookupSegment != NULL) { TTGlyphID firstGlyph = SWAPW(lookupSegment->firstGlyph); le_int16 offset = SWAPW(lookupSegment->value); if (offset != 0) { TTGlyphID *glyphArray = (TTGlyphID *) ((char *) subtableHeader + offset); TTGlyphID newGlyph = SWAPW(glyphArray[LE_GET_GLYPH(thisGlyph) - firstGlyph]); glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); } } } }
le_int32 LayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEGlyphStorage &glyphStorage, LEErrorCode &success) { if (LE_FAILURE(success)) { return 0; } if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { success = LE_ILLEGAL_ARGUMENT_ERROR; return 0; } LEUnicode *outChars = NULL; le_int32 outCharCount = characterProcessing(chars, offset, count, max, rightToLeft, outChars, glyphStorage, success); if (outChars != NULL) { mapCharsToGlyphs(outChars, 0, outCharCount, rightToLeft, rightToLeft, TRUE, glyphStorage, success); LE_DELETE_ARRAY(outChars); // FIXME: a subclass may have allocated this, in which case this delete might not work... } else { mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, TRUE, glyphStorage, success); } return glyphStorage.getGlyphCount(); }
// apply GPOS table, if any void OpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, LEGlyphStorage &glyphStorage, LEErrorCode &success) { if (LE_FAILURE(success)) { return; } if (chars == NULL || offset < 0 || count < 0) { success = LE_ILLEGAL_ARGUMENT_ERROR; return; } le_int32 glyphCount = glyphStorage.getGlyphCount(); if (glyphCount > 0 && fGPOSTable != NULL) { GlyphPositionAdjustments *adjustments = new GlyphPositionAdjustments(glyphCount); le_int32 i; if (adjustments == NULL) { success = LE_MEMORY_ALLOCATION_ERROR; return; } #if 0 // Don't need to do this if we allocate // the adjustments array w/ new... for (i = 0; i < glyphCount; i += 1) { adjustments->setXPlacement(i, 0); adjustments->setYPlacement(i, 0); adjustments->setXAdvance(i, 0); adjustments->setYAdvance(i, 0); adjustments->setBaseOffset(i, -1); } #endif fGPOSTable->process(glyphStorage, adjustments, reverse, fScriptTag, fLangSysTag, fGDEFTable, success, fFontInstance, fFeatureOrder); float xAdjust = 0, yAdjust = 0; for (i = 0; i < glyphCount; i += 1) { float xAdvance = adjustments->getXAdvance(i); float yAdvance = adjustments->getYAdvance(i); float xPlacement = 0; float yPlacement = 0; #if 0 // This is where separate kerning adjustments // should get applied. xAdjust += xKerning; yAdjust += yKerning; #endif for (le_int32 base = i; base >= 0; base = adjustments->getBaseOffset(base)) { xPlacement += adjustments->getXPlacement(base); yPlacement += adjustments->getYPlacement(base); } xPlacement = fFontInstance->xUnitsToPoints(xPlacement); yPlacement = fFontInstance->yUnitsToPoints(yPlacement); glyphStorage.adjustPosition(i, xAdjust + xPlacement, -(yAdjust + yPlacement), success); xAdjust += fFontInstance->xUnitsToPoints(xAdvance); yAdjust += fFontInstance->yUnitsToPoints(yAdvance); } glyphStorage.adjustPosition(glyphCount, xAdjust, -yAdjust, success); delete adjustments; } #if 0 // Don't know why this is here... LE_DELETE_ARRAY(fFeatureTags); fFeatureTags = NULL; #endif }
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(); }
ByteOffset LigatureSubstitutionProcessor::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex index) { LEErrorCode success = LE_NO_ERROR; const LigatureSubstitutionStateEntry *entry = entryTable.getAlias(index, success); ByteOffset newState = SWAPW(entry->newStateOffset); le_int16 flags = SWAPW(entry->flags); if (flags & lsfSetComponent) { if (++m >= nComponents) { m = 0; } componentStack[m] = currGlyph; } else if ( m == -1) { // bad font- skip this glyph. currGlyph++; return newState; } ByteOffset actionOffset = flags & lsfActionOffsetMask; if (actionOffset != 0) { LEReferenceTo<LigatureActionEntry> ap(stHeader, success, actionOffset); LigatureActionEntry action; le_int32 offset, i = 0; le_int32 stack[nComponents]; le_int16 mm = -1; do { le_uint32 componentGlyph = componentStack[m--]; action = SWAPL(*ap.getAlias()); ap.addObject(success); // ap++ if (m < 0) { m = nComponents - 1; } offset = action & lafComponentOffsetMask; if (offset != 0) { LEReferenceToArrayOf<le_int16> offsetTable(stHeader, success, 2 * SignExtend(offset, lafComponentOffsetMask), LE_UNBOUNDED_ARRAY); if(LE_FAILURE(success)) { currGlyph++; LE_DEBUG_BAD_FONT("off end of ligature substitution header"); return newState; // get out! bad font } if(componentGlyph > glyphStorage.getGlyphCount()) { LE_DEBUG_BAD_FONT("preposterous componentGlyph"); currGlyph++; return newState; // get out! bad font } i += SWAPW(offsetTable.getObject(LE_GET_GLYPH(glyphStorage[componentGlyph]), success)); if (action & (lafLast | lafStore)) { LEReferenceTo<TTGlyphID> ligatureOffset(stHeader, success, i); TTGlyphID ligatureGlyph = SWAPW(*ligatureOffset.getAlias()); 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--]; } }
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 if (LE_FAILURE(success)) { currGlyph+= dir; return nextStateIndex; } ap.addObject(ligActionIndex, success); LEReferenceToArrayOf<TTGlyphID> ligatureTable(stHeader, success, ligatureOffset, LE_UNBOUNDED_ARRAY); LigatureActionEntry action; le_int32 offset, i = 0, j = 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_uint32 componentGlyph = componentStack[m--]; // pop off if (j++ > 0) { ap.addObject(success); } if (LE_FAILURE(success)) { currGlyph+= dir; return nextStateIndex; } action = SWAPL(*ap.getAlias()); if (m < 0) { m = nComponents - 1; } offset = action & lafComponentOffsetMask; if (offset != 0) { if(componentGlyph >= glyphStorage.getGlyphCount()) { 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 (LE_FAILURE(success)) { currGlyph+= dir; return nextStateIndex; } if (action & (lafLast | lafStore)) { TTGlyphID ligatureGlyph = SWAPW(ligatureTable(i,success)); if (LE_FAILURE(success)) { currGlyph+= dir; return nextStateIndex; } 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 (LE_SUCCESS(success) && !(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--]; } }
// apply GPOS table, if any void OpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, LEGlyphStorage &glyphStorage, LEErrorCode &success) { if (LE_FAILURE(success)) { return; } if (chars == NULL || offset < 0 || count < 0) { success = LE_ILLEGAL_ARGUMENT_ERROR; return; } le_int32 glyphCount = glyphStorage.getGlyphCount(); if (glyphCount == 0) { return; } if (fGPOSTable != NULL) { GlyphPositionAdjustments *adjustments = new GlyphPositionAdjustments(glyphCount); le_int32 i; if (adjustments == NULL) { success = LE_MEMORY_ALLOCATION_ERROR; return; } #if 0 // Don't need to do this if we allocate // the adjustments array w/ new... for (i = 0; i < glyphCount; i += 1) { adjustments->setXPlacement(i, 0); adjustments->setYPlacement(i, 0); adjustments->setXAdvance(i, 0); adjustments->setYAdvance(i, 0); adjustments->setBaseOffset(i, -1); } #endif if (fGPOSTable != NULL) { if (fScriptTagV2 != nullScriptTag && fGPOSTable->coversScriptAndLanguage(fScriptTagV2,fLangSysTag)) { fGPOSTable->process(glyphStorage, adjustments, reverse, fScriptTagV2, fLangSysTag, fGDEFTable, success, fFontInstance, fFeatureMap, fFeatureMapCount, fFeatureOrder); } else { fGPOSTable->process(glyphStorage, adjustments, reverse, fScriptTag, fLangSysTag, fGDEFTable, success, fFontInstance, fFeatureMap, fFeatureMapCount, fFeatureOrder); } } else if ( fTypoFlags & 0x1 ) { static const le_uint32 kernTableTag = LE_KERN_TABLE_TAG; KernTable kt(fFontInstance, getFontTable(kernTableTag)); kt.process(glyphStorage); } float xAdjust = 0, yAdjust = 0; for (i = 0; i < glyphCount; i += 1) { float xAdvance = adjustments->getXAdvance(i); float yAdvance = adjustments->getYAdvance(i); float xPlacement = 0; float yPlacement = 0; #if 0 // This is where separate kerning adjustments // should get applied. xAdjust += xKerning; yAdjust += yKerning; #endif for (le_int32 base = i; base >= 0; base = adjustments->getBaseOffset(base)) { xPlacement += adjustments->getXPlacement(base); yPlacement += adjustments->getYPlacement(base); } xPlacement = fFontInstance->xUnitsToPoints(xPlacement); yPlacement = fFontInstance->yUnitsToPoints(yPlacement); glyphStorage.adjustPosition(i, xAdjust + xPlacement, -(yAdjust + yPlacement), success); xAdjust += fFontInstance->xUnitsToPoints(xAdvance); yAdjust += fFontInstance->yUnitsToPoints(yAdvance); } glyphStorage.adjustPosition(glyphCount, xAdjust, -yAdjust, success); delete adjustments; } else { // if there was no GPOS table, maybe there's non-OpenType kerning we can use // Google Patch: disable this. Causes problems with Tamil. // Umesh says layout is poor both with and without the change, but // worse with the change. See ocean/imageprocessing/layout_test_unittest.cc // Public ICU ticket for this problem is #7742 // LayoutEngine::adjustGlyphPositions(chars, offset, count, reverse, glyphStorage, success); } LEGlyphID zwnj = fFontInstance->mapCharToGlyph(0x200C); if (zwnj != 0x0000) { for (le_int32 g = 0; g < glyphCount; g += 1) { LEGlyphID glyph = glyphStorage[g]; if (glyph == zwnj) { glyphStorage[g] = LE_SET_GLYPH(glyph, 0xFFFF); } } } #if 0 // Don't know why this is here... LE_DELETE_ARRAY(fFeatureTags); fFeatureTags = NULL; #endif }
// apply GPOS table, if any void OpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, LEGlyphStorage &glyphStorage, LEErrorCode &success) { if (LE_FAILURE(success)) { return; } if (chars == NULL || offset < 0 || count < 0) { success = LE_ILLEGAL_ARGUMENT_ERROR; return; } le_int32 glyphCount = glyphStorage.getGlyphCount(); if (glyphCount == 0) { return; } if (!fGPOSTable.isEmpty()) { GlyphPositionAdjustments *adjustments = new GlyphPositionAdjustments(glyphCount); le_int32 i; if (adjustments == NULL) { success = LE_MEMORY_ALLOCATION_ERROR; return; } #if 0 // Don't need to do this if we allocate // the adjustments array w/ new... for (i = 0; i < glyphCount; i += 1) { adjustments->setXPlacement(i, 0); adjustments->setYPlacement(i, 0); adjustments->setXAdvance(i, 0); adjustments->setYAdvance(i, 0); adjustments->setBaseOffset(i, -1); } #endif if (!fGPOSTable.isEmpty()) { if (fScriptTagV2 != nullScriptTag && fGPOSTable->coversScriptAndLanguage(fGPOSTable, fScriptTagV2,fLangSysTag,success)) { fGPOSTable->process(fGPOSTable, glyphStorage, adjustments, reverse, fScriptTagV2, fLangSysTag, fGDEFTable, success, fFontInstance, fFeatureMap, fFeatureMapCount, fFeatureOrder); } else { fGPOSTable->process(fGPOSTable, glyphStorage, adjustments, reverse, fScriptTag, fLangSysTag, fGDEFTable, success, fFontInstance, fFeatureMap, fFeatureMapCount, fFeatureOrder); } } else if (fTypoFlags & LE_Kerning_FEATURE_FLAG) { /* kerning enabled */ LETableReference kernTable(fFontInstance, LE_KERN_TABLE_TAG, success); KernTable kt(kernTable, success); kt.process(glyphStorage, success); } float xAdjust = 0, yAdjust = 0; for (i = 0; i < glyphCount; i += 1) { float xAdvance = adjustments->getXAdvance(i); float yAdvance = adjustments->getYAdvance(i); float xPlacement = 0; float yPlacement = 0; #if 0 // This is where separate kerning adjustments // should get applied. xAdjust += xKerning; yAdjust += yKerning; #endif for (le_int32 base = i; base >= 0; base = adjustments->getBaseOffset(base)) { xPlacement += adjustments->getXPlacement(base); yPlacement += adjustments->getYPlacement(base); } xPlacement = fFontInstance->xUnitsToPoints(xPlacement); yPlacement = fFontInstance->yUnitsToPoints(yPlacement); glyphStorage.adjustPosition(i, xAdjust + xPlacement, -(yAdjust + yPlacement), success); xAdjust += fFontInstance->xUnitsToPoints(xAdvance); yAdjust += fFontInstance->yUnitsToPoints(yAdvance); } glyphStorage.adjustPosition(glyphCount, xAdjust, -yAdjust, success); delete adjustments; } else { // if there was no GPOS table, maybe there's non-OpenType kerning we can use LayoutEngine::adjustGlyphPositions(chars, offset, count, reverse, glyphStorage, success); } LEGlyphID zwnj = fFontInstance->mapCharToGlyph(0x200C); if (zwnj != 0x0000) { for (le_int32 g = 0; g < glyphCount; g += 1) { LEGlyphID glyph = glyphStorage[g]; if (glyph == zwnj) { glyphStorage[g] = LE_SET_GLYPH(glyph, 0xFFFF); } } } #if 0 // Don't know why this is here... LE_DELETE_ARRAY(fFeatureTags); fFeatureTags = NULL; #endif }