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; _LETRACE("p#%d (%.2f,%.2f)", p, xAdvance, 0); glyphStorage.adjustPosition(p, xAdjust, 0, success); if (markFilter->accept(glyphStorage[p], success)) { xAdjust -= xAdvance; } prev = next; } glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success); }
// Input: characters // Output: characters, char indices, tags // Returns: output character count le_int32 ArabicOpenTypeLayoutEngine::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 (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { success = LE_ILLEGAL_ARGUMENT_ERROR; return 0; } outChars = LE_NEW_ARRAY(LEUnicode, count); if (outChars == NULL) { success = LE_MEMORY_ALLOCATION_ERROR; return 0; } glyphStorage.allocateGlyphArray(count, rightToLeft, success); glyphStorage.allocateAuxData(success); if (LE_FAILURE(success)) { LE_DELETE_ARRAY(outChars); return 0; } CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, outChars, glyphStorage); // Note: This processes the *original* character array so we can get context // for the first and last characters. This is OK because only the marks // will have been reordered, and they don't contribute to shaping. ArabicShaping::shape(chars, offset, count, max, rightToLeft, glyphStorage); return count; }
// Input: characters // Output: characters, char indices, tags // Returns: output character count le_int32 KhmerOpenTypeLayoutEngine::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 (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { success = LE_ILLEGAL_ARGUMENT_ERROR; return 0; } le_int32 worstCase = count * 3; // worst case is 3 for Khmer TODO check if 2 is enough outChars = LE_NEW_ARRAY(LEUnicode, worstCase); if (outChars == NULL) { success = LE_MEMORY_ALLOCATION_ERROR; return 0; } glyphStorage.allocateGlyphArray(worstCase, rightToLeft, success); glyphStorage.allocateAuxData(success); if (LE_FAILURE(success)) { LE_DELETE_ARRAY(outChars); return 0; } // NOTE: assumes this allocates featureTags... // (probably better than doing the worst case stuff here...) le_int32 outCharCount = KhmerReordering::reorder(&chars[offset], count, fScriptCode, outChars, glyphStorage); glyphStorage.adoptGlyphCount(outCharCount); return outCharCount; }
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 SingleTableProcessor::process(LEGlyphStorage &glyphStorage, LEErrorCode &success) { const LookupSingle *entries = singleTableLookupTable->entries; le_int32 glyph; le_int32 glyphCount = glyphStorage.getGlyphCount(); if (LE_FAILURE(success)) return; 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); } } }
void CanonShaping::reorderMarks(const LEUnicode *inChars, le_int32 charCount, le_bool rightToLeft, LEUnicode *outChars, LEGlyphStorage &glyphStorage) { LEErrorCode success = LE_NO_ERROR; LEReferenceTo<GlyphDefinitionTableHeader> gdefTable(LETableReference::kStaticData, CanonShaping::glyphDefinitionTable, CanonShaping::glyphDefinitionTableLen); LEReferenceTo<ClassDefinitionTable> classTable = gdefTable->getMarkAttachClassDefinitionTable(gdefTable, success); le_int32 *combiningClasses = LE_NEW_ARRAY(le_int32, charCount); le_int32 *indices = LE_NEW_ARRAY(le_int32, charCount); le_int32 i; for (i = 0; i < charCount; i += 1) { combiningClasses[i] = classTable->getGlyphClass(classTable, (LEGlyphID) inChars[i], success); indices[i] = i; } for (i = 0; i < charCount; i += 1) { if (combiningClasses[i] != 0) { le_int32 mark; for (mark = i; mark < charCount; mark += 1) { if (combiningClasses[mark] == 0) { break; } } sortMarks(indices, combiningClasses, i, mark); } } le_int32 out = 0, dir = 1; if (rightToLeft) { out = charCount - 1; dir = -1; } for (i = 0; i < charCount; i += 1, out += dir) { le_int32 index = indices[i]; outChars[i] = inChars[index]; glyphStorage.setCharIndex(out, index, success); } LE_DELETE_ARRAY(indices); LE_DELETE_ARRAY(combiningClasses); }
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 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); } } } }
void UnicodeArabicOpenTypeLayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool /*mirror*/, LEGlyphStorage &glyphStorage, LEErrorCode &success) { if (LE_FAILURE(success)) { return; } if (chars == NULL || offset < 0 || count < 0) { success = LE_ILLEGAL_ARGUMENT_ERROR; return; } le_int32 i, dir = 1, out = 0; if (reverse) { out = count - 1; dir = -1; } glyphStorage.allocateGlyphArray(count, reverse, success); for (i = 0; i < count; i += 1, out += dir) { glyphStorage[out] = (LEGlyphID) chars[offset + i]; } }
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(); }
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--]; } }
void IndicRearrangementProcessor::doRearrangementAction(LEGlyphStorage &glyphStorage, IndicRearrangementVerb verb) const { LEGlyphID a, b, c, d; le_int32 ia, ib, ic, id, ix, x; LEErrorCode success = LE_NO_ERROR; switch(verb) { case irvNoAction: break; case irvxA: a = glyphStorage[firstGlyph]; ia = glyphStorage.getCharIndex(firstGlyph, success); x = firstGlyph + 1; while (x <= lastGlyph) { glyphStorage[x - 1] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x - 1, ix, success); x += 1; } glyphStorage[lastGlyph] = a; glyphStorage.setCharIndex(lastGlyph, ia, success); break; case irvDx: d = glyphStorage[lastGlyph]; id = glyphStorage.getCharIndex(lastGlyph, success); x = lastGlyph - 1; while (x >= firstGlyph) { glyphStorage[x + 1] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x + 1, ix, success); x -= 1; } glyphStorage[firstGlyph] = d; glyphStorage.setCharIndex(firstGlyph, id, success); break; case irvDxA: a = glyphStorage[firstGlyph]; ia = glyphStorage.getCharIndex(firstGlyph, success); id = glyphStorage.getCharIndex(lastGlyph, success); glyphStorage[firstGlyph] = glyphStorage[lastGlyph]; glyphStorage[lastGlyph] = a; glyphStorage.setCharIndex(firstGlyph, id, success); glyphStorage.setCharIndex(lastGlyph, ia, success); break; case irvxAB: a = glyphStorage[firstGlyph]; b = glyphStorage[firstGlyph + 1]; ia = glyphStorage.getCharIndex(firstGlyph, success); ib = glyphStorage.getCharIndex(firstGlyph + 1, success); x = firstGlyph + 2; while (x <= lastGlyph) { glyphStorage[x - 2] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x - 2, ix, success); x += 1; } glyphStorage[lastGlyph - 1] = a; glyphStorage[lastGlyph] = b; glyphStorage.setCharIndex(lastGlyph - 1, ia, success); glyphStorage.setCharIndex(lastGlyph, ib, success); break; case irvxBA: a = glyphStorage[firstGlyph]; b = glyphStorage[firstGlyph + 1]; ia = glyphStorage.getCharIndex(firstGlyph, success); ib = glyphStorage.getCharIndex(firstGlyph + 1, success); x = firstGlyph + 2; while (x <= lastGlyph) { glyphStorage[x - 2] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x - 2, ix, success); x += 1; } glyphStorage[lastGlyph - 1] = b; glyphStorage[lastGlyph] = a; glyphStorage.setCharIndex(lastGlyph - 1, ib, success); glyphStorage.setCharIndex(lastGlyph, ia, success); break; case irvCDx: c = glyphStorage[lastGlyph - 1]; d = glyphStorage[lastGlyph]; ic = glyphStorage.getCharIndex(lastGlyph - 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); x = lastGlyph - 2; while (x >= firstGlyph) { glyphStorage[x + 2] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x + 2, ix, success); x -= 1; } glyphStorage[firstGlyph] = c; glyphStorage[firstGlyph + 1] = d; glyphStorage.setCharIndex(firstGlyph, ic, success); glyphStorage.setCharIndex(firstGlyph + 1, id, success); break; case irvDCx: c = glyphStorage[lastGlyph - 1]; d = glyphStorage[lastGlyph]; ic = glyphStorage.getCharIndex(lastGlyph - 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); x = lastGlyph - 2; while (x >= firstGlyph) { glyphStorage[x + 2] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x + 2, ix, success); x -= 1; } glyphStorage[firstGlyph] = d; glyphStorage[firstGlyph + 1] = c; glyphStorage.setCharIndex(firstGlyph, id, success); glyphStorage.setCharIndex(firstGlyph + 1, ic, success); break; case irvCDxA: a = glyphStorage[firstGlyph]; c = glyphStorage[lastGlyph - 1]; d = glyphStorage[lastGlyph]; ia = glyphStorage.getCharIndex(firstGlyph, success); ic = glyphStorage.getCharIndex(lastGlyph - 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); x = lastGlyph - 2; while (x > firstGlyph) { glyphStorage[x + 1] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x + 1, ix, success); x -= 1; } glyphStorage[firstGlyph] = c; glyphStorage[firstGlyph + 1] = d; glyphStorage[lastGlyph] = a; glyphStorage.setCharIndex(firstGlyph, ic, success); glyphStorage.setCharIndex(firstGlyph + 1, id, success); glyphStorage.setCharIndex(lastGlyph, ia, success); break; case irvDCxA: a = glyphStorage[firstGlyph]; c = glyphStorage[lastGlyph - 1]; d = glyphStorage[lastGlyph]; ia = glyphStorage.getCharIndex(firstGlyph, success); ic = glyphStorage.getCharIndex(lastGlyph - 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); x = lastGlyph - 2; while (x > firstGlyph) { glyphStorage[x + 1] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x + 1, ix, success); x -= 1; } glyphStorage[firstGlyph] = d; glyphStorage[firstGlyph + 1] = c; glyphStorage[lastGlyph] = a; glyphStorage.setCharIndex(firstGlyph, id, success); glyphStorage.setCharIndex(firstGlyph + 1, ic, success); glyphStorage.setCharIndex(lastGlyph, ia, success); break; case irvDxAB: a = glyphStorage[firstGlyph]; b = glyphStorage[firstGlyph + 1]; d = glyphStorage[lastGlyph]; ia = glyphStorage.getCharIndex(firstGlyph, success); ib = glyphStorage.getCharIndex(firstGlyph + 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); x = firstGlyph + 2; while (x < lastGlyph) { glyphStorage[x - 2] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x - 2, ix, success); x += 1; } glyphStorage[firstGlyph] = d; glyphStorage[lastGlyph - 1] = a; glyphStorage[lastGlyph] = b; glyphStorage.setCharIndex(firstGlyph, id, success); glyphStorage.setCharIndex(lastGlyph - 1, ia, success); glyphStorage.setCharIndex(lastGlyph, ib, success); break; case irvDxBA: a = glyphStorage[firstGlyph]; b = glyphStorage[firstGlyph + 1]; d = glyphStorage[lastGlyph]; ia = glyphStorage.getCharIndex(firstGlyph, success); ib = glyphStorage.getCharIndex(firstGlyph + 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); x = firstGlyph + 2; while (x < lastGlyph) { glyphStorage[x - 2] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x - 2, ix, success); x += 1; } glyphStorage[firstGlyph] = d; glyphStorage[lastGlyph - 1] = b; glyphStorage[lastGlyph] = a; glyphStorage.setCharIndex(firstGlyph, id, success); glyphStorage.setCharIndex(lastGlyph - 1, ib, success); glyphStorage.setCharIndex(lastGlyph, ia, success); break; case irvCDxAB: a = glyphStorage[firstGlyph]; b = glyphStorage[firstGlyph + 1]; glyphStorage[firstGlyph] = glyphStorage[lastGlyph - 1]; glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph]; glyphStorage[lastGlyph - 1] = a; glyphStorage[lastGlyph] = b; ia = glyphStorage.getCharIndex(firstGlyph, success); ib = glyphStorage.getCharIndex(firstGlyph + 1, success); ic = glyphStorage.getCharIndex(lastGlyph - 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); glyphStorage.setCharIndex(firstGlyph, ic, success); glyphStorage.setCharIndex(firstGlyph + 1, id, success); glyphStorage.setCharIndex(lastGlyph - 1, ia, success); glyphStorage.setCharIndex(lastGlyph, ib, success); break; case irvCDxBA: a = glyphStorage[firstGlyph]; b = glyphStorage[firstGlyph + 1]; glyphStorage[firstGlyph] = glyphStorage[lastGlyph - 1]; glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph]; glyphStorage[lastGlyph - 1] = b; glyphStorage[lastGlyph] = a; ia = glyphStorage.getCharIndex(firstGlyph, success); ib = glyphStorage.getCharIndex(firstGlyph + 1, success); ic = glyphStorage.getCharIndex(lastGlyph - 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); glyphStorage.setCharIndex(firstGlyph, ic, success); glyphStorage.setCharIndex(firstGlyph + 1, id, success); glyphStorage.setCharIndex(lastGlyph - 1, ib, success); glyphStorage.setCharIndex(lastGlyph, ia, success); break; case irvDCxAB: a = glyphStorage[firstGlyph]; b = glyphStorage[firstGlyph + 1]; glyphStorage[firstGlyph] = glyphStorage[lastGlyph]; glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph - 1]; glyphStorage[lastGlyph - 1] = a; glyphStorage[lastGlyph] = b; ia = glyphStorage.getCharIndex(firstGlyph, success); ib = glyphStorage.getCharIndex(firstGlyph + 1, success); ic = glyphStorage.getCharIndex(lastGlyph - 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); glyphStorage.setCharIndex(firstGlyph, id, success); glyphStorage.setCharIndex(firstGlyph + 1, ic, success); glyphStorage.setCharIndex(lastGlyph - 1, ia, success); glyphStorage.setCharIndex(lastGlyph, ib, success); break; case irvDCxBA: a = glyphStorage[firstGlyph]; b = glyphStorage[firstGlyph + 1]; glyphStorage[firstGlyph] = glyphStorage[lastGlyph]; glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph - 1]; glyphStorage[lastGlyph - 1] = b; glyphStorage[lastGlyph] = a; ia = glyphStorage.getCharIndex(firstGlyph, success); ib = glyphStorage.getCharIndex(firstGlyph + 1, success); ic = glyphStorage.getCharIndex(lastGlyph - 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); glyphStorage.setCharIndex(firstGlyph, id, success); glyphStorage.setCharIndex(firstGlyph + 1, ic, success); glyphStorage.setCharIndex(lastGlyph - 1, ib, success); glyphStorage.setCharIndex(lastGlyph, ia, success); break; default: break; } }
void IndicReordering::finalReordering(LEGlyphStorage &glyphStorage, le_int32 count) { LEErrorCode success = LE_NO_ERROR; // Reposition REPH as appropriate for ( le_int32 i = 0 ; i < count ; i++ ) { le_int32 tmpAuxData = glyphStorage.getAuxData(i,success); LEGlyphID tmpGlyph = glyphStorage.getGlyphID(i,success); if ( ( tmpGlyph != NO_GLYPH ) && (tmpAuxData & rephConsonantMask) && !(tmpAuxData & repositionedGlyphMask)) { le_bool targetPositionFound = false; le_int32 targetPosition = i+1; le_int32 baseConsonantData; while (!targetPositionFound) { tmpGlyph = glyphStorage.getGlyphID(targetPosition,success); tmpAuxData = glyphStorage.getAuxData(targetPosition,success); if ( tmpAuxData & baseConsonantMask ) { baseConsonantData = tmpAuxData; targetPositionFound = true; } else { targetPosition++; } } // Make sure we are not putting the reph into an empty hole le_bool targetPositionHasGlyph = false; while (!targetPositionHasGlyph) { tmpGlyph = glyphStorage.getGlyphID(targetPosition,success); if ( tmpGlyph != NO_GLYPH ) { targetPositionHasGlyph = true; } else { targetPosition--; } } // Make sure that REPH is positioned after any above base or post base matras // le_bool checkMatraDone = false; le_int32 checkMatraPosition = targetPosition+1; while ( !checkMatraDone ) { tmpAuxData = glyphStorage.getAuxData(checkMatraPosition,success); if ( checkMatraPosition >= count || ( (tmpAuxData ^ baseConsonantData) & LE_GLYPH_GROUP_MASK)) { checkMatraDone = true; continue; } if ( (tmpAuxData & matraMask) && (((tmpAuxData & markPositionMask) == aboveBasePosition) || ((tmpAuxData & markPositionMask) == postBasePosition))) { targetPosition = checkMatraPosition; } checkMatraPosition++; } glyphStorage.moveGlyph(i,targetPosition,repositionedGlyphMask); } } }
void ArabicShaping::shape(const LEUnicode *chars, le_int32 offset, le_int32 charCount, le_int32 charMax, le_bool rightToLeft, LEGlyphStorage &glyphStorage) { // iterate in logical order, store tags in visible order // // the effective right char is the most recently encountered // non-transparent char // // four boolean states: // the effective right char shapes // the effective right char causes left shaping // the current char shapes // the current char causes right shaping // // if both cause shaping, then // shaper.shape(errout, 2) (isolate to initial, or final to medial) // shaper.shape(out, 1) (isolate to final) ShapeType rightType = ST_NOSHAPE_NONE, leftType = ST_NOSHAPE_NONE; LEErrorCode success = LE_NO_ERROR; le_int32 i; for (i = offset - 1; i >= 0; i -= 1) { rightType = getShapeType(chars[i]); if (rightType != ST_TRANSPARENT) { break; } } for (i = offset + charCount; i < charMax; i += 1) { leftType = getShapeType(chars[i]); if (leftType != ST_TRANSPARENT) { break; } } // erout is effective right logical index le_int32 erout = -1; le_bool rightShapes = FALSE; le_bool rightCauses = (rightType & MASK_SHAPE_LEFT) != 0; le_int32 in, e, out = 0, dir = 1; if (rightToLeft) { out = charCount - 1; erout = charCount; dir = -1; } for (in = offset, e = offset + charCount; in < e; in += 1, out += dir) { LEUnicode c = chars[in]; ShapeType t = getShapeType(c); if (t == ST_NOSHAPE_NONE) { glyphStorage.setAuxData(out, NO_FEATURES, success); } else { glyphStorage.setAuxData(out, ISOL_FEATURES, success); } if ((t & MASK_TRANSPARENT) != 0) { continue; } le_bool curShapes = (t & MASK_NOSHAPE) == 0; le_bool curCauses = (t & MASK_SHAPE_RIGHT) != 0; if (rightCauses && curCauses) { if (rightShapes) { adjustTags(erout, 2, glyphStorage); } if (curShapes) { adjustTags(out, 1, glyphStorage); } } rightShapes = curShapes; rightCauses = (t & MASK_SHAPE_LEFT) != 0; erout = out; } if (rightShapes && rightCauses && (leftType & MASK_SHAPE_RIGHT) != 0) { adjustTags(erout, 2, glyphStorage); } }
void IndicRearrangementProcessor::doRearrangementAction(LEGlyphStorage &glyphStorage, IndicRearrangementVerb verb, LEErrorCode &success) const { LEGlyphID a, b, c, d; le_int32 ia, ib, ic, id, ix, x; if (LE_FAILURE(success)) return; if (verb == irvNoAction) { return; } if (firstGlyph > lastGlyph) { success = LE_INDEX_OUT_OF_BOUNDS_ERROR; return; } switch(verb) { case irvxA: if (firstGlyph == lastGlyph) break; if (firstGlyph + 1 < firstGlyph) { success = LE_INDEX_OUT_OF_BOUNDS_ERROR; break; } a = glyphStorage[firstGlyph]; ia = glyphStorage.getCharIndex(firstGlyph, success); x = firstGlyph + 1; while (x <= lastGlyph) { glyphStorage[x - 1] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x - 1, ix, success); x += 1; } glyphStorage[lastGlyph] = a; glyphStorage.setCharIndex(lastGlyph, ia, success); break; case irvDx: if (firstGlyph == lastGlyph) break; if (lastGlyph - 1 > lastGlyph) { success = LE_INDEX_OUT_OF_BOUNDS_ERROR; break; } d = glyphStorage[lastGlyph]; id = glyphStorage.getCharIndex(lastGlyph, success); x = lastGlyph - 1; while (x >= firstGlyph) { glyphStorage[x + 1] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x + 1, ix, success); x -= 1; } glyphStorage[firstGlyph] = d; glyphStorage.setCharIndex(firstGlyph, id, success); break; case irvDxA: a = glyphStorage[firstGlyph]; ia = glyphStorage.getCharIndex(firstGlyph, success); id = glyphStorage.getCharIndex(lastGlyph, success); glyphStorage[firstGlyph] = glyphStorage[lastGlyph]; glyphStorage[lastGlyph] = a; glyphStorage.setCharIndex(firstGlyph, id, success); glyphStorage.setCharIndex(lastGlyph, ia, success); break; case irvxAB: if ((firstGlyph + 2 < firstGlyph) || (lastGlyph - firstGlyph < 1)) { // difference == 1 is a no-op, < 1 is an error. success = LE_INDEX_OUT_OF_BOUNDS_ERROR; break; } a = glyphStorage[firstGlyph]; b = glyphStorage[firstGlyph + 1]; ia = glyphStorage.getCharIndex(firstGlyph, success); ib = glyphStorage.getCharIndex(firstGlyph + 1, success); x = firstGlyph + 2; while (x <= lastGlyph) { glyphStorage[x - 2] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x - 2, ix, success); x += 1; } glyphStorage[lastGlyph - 1] = a; glyphStorage[lastGlyph] = b; glyphStorage.setCharIndex(lastGlyph - 1, ia, success); glyphStorage.setCharIndex(lastGlyph, ib, success); break; case irvxBA: if ((firstGlyph + 2 < firstGlyph) || (lastGlyph - firstGlyph < 1)) { success = LE_INDEX_OUT_OF_BOUNDS_ERROR; break; } a = glyphStorage[firstGlyph]; b = glyphStorage[firstGlyph + 1]; ia = glyphStorage.getCharIndex(firstGlyph, success); ib = glyphStorage.getCharIndex(firstGlyph + 1, success); x = firstGlyph + 2; while (x <= lastGlyph) { glyphStorage[x - 2] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x - 2, ix, success); x += 1; } glyphStorage[lastGlyph - 1] = b; glyphStorage[lastGlyph] = a; glyphStorage.setCharIndex(lastGlyph - 1, ib, success); glyphStorage.setCharIndex(lastGlyph, ia, success); break; case irvCDx: if ((lastGlyph - 2 > lastGlyph) || (lastGlyph - firstGlyph < 1)) { success = LE_INDEX_OUT_OF_BOUNDS_ERROR; break; } c = glyphStorage[lastGlyph - 1]; d = glyphStorage[lastGlyph]; ic = glyphStorage.getCharIndex(lastGlyph - 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); x = lastGlyph - 2; while (x >= firstGlyph) { glyphStorage[x + 2] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x + 2, ix, success); x -= 1; } glyphStorage[firstGlyph] = c; glyphStorage[firstGlyph + 1] = d; glyphStorage.setCharIndex(firstGlyph, ic, success); glyphStorage.setCharIndex(firstGlyph + 1, id, success); break; case irvDCx: if ((lastGlyph - 2 > lastGlyph) || (lastGlyph - firstGlyph < 1)) { success = LE_INDEX_OUT_OF_BOUNDS_ERROR; break; } c = glyphStorage[lastGlyph - 1]; d = glyphStorage[lastGlyph]; ic = glyphStorage.getCharIndex(lastGlyph - 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); x = lastGlyph - 2; while (x >= firstGlyph) { glyphStorage[x + 2] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x + 2, ix, success); x -= 1; } glyphStorage[firstGlyph] = d; glyphStorage[firstGlyph + 1] = c; glyphStorage.setCharIndex(firstGlyph, id, success); glyphStorage.setCharIndex(firstGlyph + 1, ic, success); break; case irvCDxA: if ((lastGlyph - 2 > lastGlyph) || (lastGlyph - firstGlyph < 2)) { success = LE_INDEX_OUT_OF_BOUNDS_ERROR; break; } a = glyphStorage[firstGlyph]; c = glyphStorage[lastGlyph - 1]; d = glyphStorage[lastGlyph]; ia = glyphStorage.getCharIndex(firstGlyph, success); ic = glyphStorage.getCharIndex(lastGlyph - 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); x = lastGlyph - 2; while (x > firstGlyph) { glyphStorage[x + 1] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x + 1, ix, success); x -= 1; } glyphStorage[firstGlyph] = c; glyphStorage[firstGlyph + 1] = d; glyphStorage[lastGlyph] = a; glyphStorage.setCharIndex(firstGlyph, ic, success); glyphStorage.setCharIndex(firstGlyph + 1, id, success); glyphStorage.setCharIndex(lastGlyph, ia, success); break; case irvDCxA: if ((lastGlyph - 2 > lastGlyph) || (lastGlyph - firstGlyph < 2)) { success = LE_INDEX_OUT_OF_BOUNDS_ERROR; break; } a = glyphStorage[firstGlyph]; c = glyphStorage[lastGlyph - 1]; d = glyphStorage[lastGlyph]; ia = glyphStorage.getCharIndex(firstGlyph, success); ic = glyphStorage.getCharIndex(lastGlyph - 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); x = lastGlyph - 2; while (x > firstGlyph) { glyphStorage[x + 1] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x + 1, ix, success); x -= 1; } glyphStorage[firstGlyph] = d; glyphStorage[firstGlyph + 1] = c; glyphStorage[lastGlyph] = a; glyphStorage.setCharIndex(firstGlyph, id, success); glyphStorage.setCharIndex(firstGlyph + 1, ic, success); glyphStorage.setCharIndex(lastGlyph, ia, success); break; case irvDxAB: if ((firstGlyph + 2 < firstGlyph) || (lastGlyph - firstGlyph < 2)) { success = LE_INDEX_OUT_OF_BOUNDS_ERROR; break; } a = glyphStorage[firstGlyph]; b = glyphStorage[firstGlyph + 1]; d = glyphStorage[lastGlyph]; ia = glyphStorage.getCharIndex(firstGlyph, success); ib = glyphStorage.getCharIndex(firstGlyph + 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); x = firstGlyph + 2; while (x < lastGlyph) { glyphStorage[x - 2] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x - 2, ix, success); x += 1; } glyphStorage[firstGlyph] = d; glyphStorage[lastGlyph - 1] = a; glyphStorage[lastGlyph] = b; glyphStorage.setCharIndex(firstGlyph, id, success); glyphStorage.setCharIndex(lastGlyph - 1, ia, success); glyphStorage.setCharIndex(lastGlyph, ib, success); break; case irvDxBA: if ((firstGlyph + 2 < firstGlyph) || (lastGlyph - firstGlyph < 2)) { success = LE_INDEX_OUT_OF_BOUNDS_ERROR; break; } a = glyphStorage[firstGlyph]; b = glyphStorage[firstGlyph + 1]; d = glyphStorage[lastGlyph]; ia = glyphStorage.getCharIndex(firstGlyph, success); ib = glyphStorage.getCharIndex(firstGlyph + 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); x = firstGlyph + 2; while (x < lastGlyph) { glyphStorage[x - 2] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x - 2, ix, success); x += 1; } glyphStorage[firstGlyph] = d; glyphStorage[lastGlyph - 1] = b; glyphStorage[lastGlyph] = a; glyphStorage.setCharIndex(firstGlyph, id, success); glyphStorage.setCharIndex(lastGlyph - 1, ib, success); glyphStorage.setCharIndex(lastGlyph, ia, success); break; case irvCDxAB: if (lastGlyph - firstGlyph < 3) { success = LE_INDEX_OUT_OF_BOUNDS_ERROR; break; } a = glyphStorage[firstGlyph]; b = glyphStorage[firstGlyph + 1]; glyphStorage[firstGlyph] = glyphStorage[lastGlyph - 1]; glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph]; glyphStorage[lastGlyph - 1] = a; glyphStorage[lastGlyph] = b; ia = glyphStorage.getCharIndex(firstGlyph, success); ib = glyphStorage.getCharIndex(firstGlyph + 1, success); ic = glyphStorage.getCharIndex(lastGlyph - 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); glyphStorage.setCharIndex(firstGlyph, ic, success); glyphStorage.setCharIndex(firstGlyph + 1, id, success); glyphStorage.setCharIndex(lastGlyph - 1, ia, success); glyphStorage.setCharIndex(lastGlyph, ib, success); break; case irvCDxBA: if (lastGlyph - firstGlyph < 3) { success = LE_INDEX_OUT_OF_BOUNDS_ERROR; break; } a = glyphStorage[firstGlyph]; b = glyphStorage[firstGlyph + 1]; glyphStorage[firstGlyph] = glyphStorage[lastGlyph - 1]; glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph]; glyphStorage[lastGlyph - 1] = b; glyphStorage[lastGlyph] = a; ia = glyphStorage.getCharIndex(firstGlyph, success); ib = glyphStorage.getCharIndex(firstGlyph + 1, success); ic = glyphStorage.getCharIndex(lastGlyph - 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); glyphStorage.setCharIndex(firstGlyph, ic, success); glyphStorage.setCharIndex(firstGlyph + 1, id, success); glyphStorage.setCharIndex(lastGlyph - 1, ib, success); glyphStorage.setCharIndex(lastGlyph, ia, success); break; case irvDCxAB: if (lastGlyph - firstGlyph < 3) { success = LE_INDEX_OUT_OF_BOUNDS_ERROR; break; } a = glyphStorage[firstGlyph]; b = glyphStorage[firstGlyph + 1]; glyphStorage[firstGlyph] = glyphStorage[lastGlyph]; glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph - 1]; glyphStorage[lastGlyph - 1] = a; glyphStorage[lastGlyph] = b; ia = glyphStorage.getCharIndex(firstGlyph, success); ib = glyphStorage.getCharIndex(firstGlyph + 1, success); ic = glyphStorage.getCharIndex(lastGlyph - 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); glyphStorage.setCharIndex(firstGlyph, id, success); glyphStorage.setCharIndex(firstGlyph + 1, ic, success); glyphStorage.setCharIndex(lastGlyph - 1, ia, success); glyphStorage.setCharIndex(lastGlyph, ib, success); break; case irvDCxBA: if (lastGlyph - firstGlyph < 3) { success = LE_INDEX_OUT_OF_BOUNDS_ERROR; break; } a = glyphStorage[firstGlyph]; b = glyphStorage[firstGlyph + 1]; glyphStorage[firstGlyph] = glyphStorage[lastGlyph]; glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph - 1]; glyphStorage[lastGlyph - 1] = b; glyphStorage[lastGlyph] = a; ia = glyphStorage.getCharIndex(firstGlyph, success); ib = glyphStorage.getCharIndex(firstGlyph + 1, success); ic = glyphStorage.getCharIndex(lastGlyph - 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); glyphStorage.setCharIndex(firstGlyph, id, success); glyphStorage.setCharIndex(firstGlyph + 1, ic, success); glyphStorage.setCharIndex(lastGlyph - 1, ib, success); glyphStorage.setCharIndex(lastGlyph, ia, success); break; default: break; } }
void ContextualGlyphInsertionProcessor2::beginStateTable(LEGlyphStorage &glyphStorage, LEErrorCode &) { markGlyph = 0; glyphStorage.setInsertionDirection(dir == -1 ? TRUE : FALSE); }
U_NAMESPACE_BEGIN void doRearrangementAction(LEGlyphStorage &glyphStorage, le_int32 firstGlyph, le_int32 lastGlyph, IndicRearrangementVerb verb, LEErrorCode &success) { if (LE_FAILURE(success)) return; LEGlyphID a, b, c, d; le_int32 ia, ib, ic, id, ix, x; switch(verb) { case irvNoAction: break; case irvxA: a = glyphStorage[firstGlyph]; ia = glyphStorage.getCharIndex(firstGlyph, success); x = firstGlyph + 1; while (x <= lastGlyph) { glyphStorage[x - 1] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x - 1, ix, success); x += 1; } glyphStorage[lastGlyph] = a; glyphStorage.setCharIndex(lastGlyph, ia, success); break; case irvDx: d = glyphStorage[lastGlyph]; id = glyphStorage.getCharIndex(lastGlyph, success); x = lastGlyph - 1; while (x >= firstGlyph) { glyphStorage[x + 1] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x + 1, ix, success); x -= 1; } glyphStorage[firstGlyph] = d; glyphStorage.setCharIndex(firstGlyph, id, success); break; case irvDxA: a = glyphStorage[firstGlyph]; ia = glyphStorage.getCharIndex(firstGlyph, success); id = glyphStorage.getCharIndex(lastGlyph, success); glyphStorage[firstGlyph] = glyphStorage[lastGlyph]; glyphStorage[lastGlyph] = a; glyphStorage.setCharIndex(firstGlyph, id, success); glyphStorage.setCharIndex(lastGlyph, ia, success); break; case irvxAB: a = glyphStorage[firstGlyph]; b = glyphStorage[firstGlyph + 1]; ia = glyphStorage.getCharIndex(firstGlyph, success); ib = glyphStorage.getCharIndex(firstGlyph + 1, success); x = firstGlyph + 2; while (x <= lastGlyph) { glyphStorage[x - 2] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x - 2, ix, success); x += 1; } glyphStorage[lastGlyph - 1] = a; glyphStorage[lastGlyph] = b; glyphStorage.setCharIndex(lastGlyph - 1, ia, success); glyphStorage.setCharIndex(lastGlyph, ib, success); break; case irvxBA: a = glyphStorage[firstGlyph]; b = glyphStorage[firstGlyph + 1]; ia = glyphStorage.getCharIndex(firstGlyph, success); ib = glyphStorage.getCharIndex(firstGlyph + 1, success); x = firstGlyph + 2; while (x <= lastGlyph) { glyphStorage[x - 2] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x - 2, ix, success); x += 1; } glyphStorage[lastGlyph - 1] = b; glyphStorage[lastGlyph] = a; glyphStorage.setCharIndex(lastGlyph - 1, ib, success); glyphStorage.setCharIndex(lastGlyph, ia, success); break; case irvCDx: c = glyphStorage[lastGlyph - 1]; d = glyphStorage[lastGlyph]; ic = glyphStorage.getCharIndex(lastGlyph - 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); x = lastGlyph - 2; while (x >= firstGlyph) { glyphStorage[x + 2] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x + 2, ix, success); x -= 1; } glyphStorage[firstGlyph] = c; glyphStorage[firstGlyph + 1] = d; glyphStorage.setCharIndex(firstGlyph, ic, success); glyphStorage.setCharIndex(firstGlyph + 1, id, success); break; case irvDCx: c = glyphStorage[lastGlyph - 1]; d = glyphStorage[lastGlyph]; ic = glyphStorage.getCharIndex(lastGlyph - 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); x = lastGlyph - 2; while (x >= firstGlyph) { glyphStorage[x + 2] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x + 2, ix, success); x -= 1; } glyphStorage[firstGlyph] = d; glyphStorage[firstGlyph + 1] = c; glyphStorage.setCharIndex(firstGlyph, id, success); glyphStorage.setCharIndex(firstGlyph + 1, ic, success); break; case irvCDxA: a = glyphStorage[firstGlyph]; c = glyphStorage[lastGlyph - 1]; d = glyphStorage[lastGlyph]; ia = glyphStorage.getCharIndex(firstGlyph, success); ic = glyphStorage.getCharIndex(lastGlyph - 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); x = lastGlyph - 2; while (x > firstGlyph) { glyphStorage[x + 1] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x + 1, ix, success); x -= 1; } glyphStorage[firstGlyph] = c; glyphStorage[firstGlyph + 1] = d; glyphStorage[lastGlyph] = a; glyphStorage.setCharIndex(firstGlyph, ic, success); glyphStorage.setCharIndex(firstGlyph + 1, id, success); glyphStorage.setCharIndex(lastGlyph, ia, success); break; case irvDCxA: a = glyphStorage[firstGlyph]; c = glyphStorage[lastGlyph - 1]; d = glyphStorage[lastGlyph]; ia = glyphStorage.getCharIndex(firstGlyph, success); ic = glyphStorage.getCharIndex(lastGlyph - 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); x = lastGlyph - 2; while (x > firstGlyph) { glyphStorage[x + 1] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x + 1, ix, success); x -= 1; } glyphStorage[firstGlyph] = d; glyphStorage[firstGlyph + 1] = c; glyphStorage[lastGlyph] = a; glyphStorage.setCharIndex(firstGlyph, id, success); glyphStorage.setCharIndex(firstGlyph + 1, ic, success); glyphStorage.setCharIndex(lastGlyph, ia, success); break; case irvDxAB: a = glyphStorage[firstGlyph]; b = glyphStorage[firstGlyph + 1]; d = glyphStorage[lastGlyph]; ia = glyphStorage.getCharIndex(firstGlyph, success); ib = glyphStorage.getCharIndex(firstGlyph + 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); x = firstGlyph + 2; while (x < lastGlyph) { glyphStorage[x - 2] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x - 2, ix, success); x += 1; } glyphStorage[firstGlyph] = d; glyphStorage[lastGlyph - 1] = a; glyphStorage[lastGlyph] = b; glyphStorage.setCharIndex(firstGlyph, id, success); glyphStorage.setCharIndex(lastGlyph - 1, ia, success); glyphStorage.setCharIndex(lastGlyph, ib, success); break; case irvDxBA: a = glyphStorage[firstGlyph]; b = glyphStorage[firstGlyph + 1]; d = glyphStorage[lastGlyph]; ia = glyphStorage.getCharIndex(firstGlyph, success); ib = glyphStorage.getCharIndex(firstGlyph + 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); x = firstGlyph + 2; while (x < lastGlyph) { glyphStorage[x - 2] = glyphStorage[x]; ix = glyphStorage.getCharIndex(x, success); glyphStorage.setCharIndex(x - 2, ix, success); x += 1; } glyphStorage[firstGlyph] = d; glyphStorage[lastGlyph - 1] = b; glyphStorage[lastGlyph] = a; glyphStorage.setCharIndex(firstGlyph, id, success); glyphStorage.setCharIndex(lastGlyph - 1, ib, success); glyphStorage.setCharIndex(lastGlyph, ia, success); break; case irvCDxAB: a = glyphStorage[firstGlyph]; b = glyphStorage[firstGlyph + 1]; glyphStorage[firstGlyph] = glyphStorage[lastGlyph - 1]; glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph]; glyphStorage[lastGlyph - 1] = a; glyphStorage[lastGlyph] = b; ia = glyphStorage.getCharIndex(firstGlyph, success); ib = glyphStorage.getCharIndex(firstGlyph + 1, success); ic = glyphStorage.getCharIndex(lastGlyph - 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); glyphStorage.setCharIndex(firstGlyph, ic, success); glyphStorage.setCharIndex(firstGlyph + 1, id, success); glyphStorage.setCharIndex(lastGlyph - 1, ia, success); glyphStorage.setCharIndex(lastGlyph, ib, success); break; case irvCDxBA: a = glyphStorage[firstGlyph]; b = glyphStorage[firstGlyph + 1]; glyphStorage[firstGlyph] = glyphStorage[lastGlyph - 1]; glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph]; glyphStorage[lastGlyph - 1] = b; glyphStorage[lastGlyph] = a; ia = glyphStorage.getCharIndex(firstGlyph, success); ib = glyphStorage.getCharIndex(firstGlyph + 1, success); ic = glyphStorage.getCharIndex(lastGlyph - 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); glyphStorage.setCharIndex(firstGlyph, ic, success); glyphStorage.setCharIndex(firstGlyph + 1, id, success); glyphStorage.setCharIndex(lastGlyph - 1, ib, success); glyphStorage.setCharIndex(lastGlyph, ia, success); break; case irvDCxAB: a = glyphStorage[firstGlyph]; b = glyphStorage[firstGlyph + 1]; glyphStorage[firstGlyph] = glyphStorage[lastGlyph]; glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph - 1]; glyphStorage[lastGlyph - 1] = a; glyphStorage[lastGlyph] = b; ia = glyphStorage.getCharIndex(firstGlyph, success); ib = glyphStorage.getCharIndex(firstGlyph + 1, success); ic = glyphStorage.getCharIndex(lastGlyph - 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); glyphStorage.setCharIndex(firstGlyph, id, success); glyphStorage.setCharIndex(firstGlyph + 1, ic, success); glyphStorage.setCharIndex(lastGlyph - 1, ia, success); glyphStorage.setCharIndex(lastGlyph, ib, success); break; case irvDCxBA: a = glyphStorage[firstGlyph]; b = glyphStorage[firstGlyph + 1]; glyphStorage[firstGlyph] = glyphStorage[lastGlyph]; glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph - 1]; glyphStorage[lastGlyph - 1] = b; glyphStorage[lastGlyph] = a; ia = glyphStorage.getCharIndex(firstGlyph, success); ib = glyphStorage.getCharIndex(firstGlyph + 1, success); ic = glyphStorage.getCharIndex(lastGlyph - 1, success); id = glyphStorage.getCharIndex(lastGlyph, success); glyphStorage.setCharIndex(firstGlyph, id, success); glyphStorage.setCharIndex(firstGlyph + 1, ic, success); glyphStorage.setCharIndex(lastGlyph - 1, ib, success); glyphStorage.setCharIndex(lastGlyph, ia, success); break; default: break; } }
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; } const 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(scriptTag)) { CharSubstitutionFilter *substitutionFilter = new CharSubstitutionFilter(fFontInstance); const LEUnicode *inChars = &chars[offset]; LEUnicode *reordered = NULL; LEGlyphStorage fakeGlyphStorage; fakeGlyphStorage.allocateGlyphArray(count, rightToLeft, success); if (LE_FAILURE(success)) { 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) { success = LE_MEMORY_ALLOCATION_ERROR; return 0; } CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, reordered, fakeGlyphStorage); inChars = reordered; } fakeGlyphStorage.allocateAuxData(success); if (LE_FAILURE(success)) { 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(fakeGlyphStorage, rightToLeft, scriptTag, langSysTag, NULL, substitutionFilter, canonFeatureMap, canonFeatureMapCount, FALSE); out = (rightToLeft? outCharCount - 1 : 0); outChars = LE_NEW_ARRAY(LEUnicode, outCharCount); for (i = 0; i < outCharCount; i += 1, out += dir) { outChars[out] = (LEUnicode) LE_GET_GLYPH(fakeGlyphStorage[i]); } delete substitutionFilter; } return outCharCount; }
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; }
le_uint8 ThaiShaping::doTransition (StateTransition transition, LEUnicode currChar, le_int32 inputIndex, le_uint8 glyphSet, LEUnicode errorChar, LEUnicode *outputBuffer, LEGlyphStorage &glyphStorage, le_int32 &outputIndex) { LEErrorCode success = LE_NO_ERROR; switch (transition.action) { case tA: glyphStorage.setCharIndex(outputIndex, inputIndex, success); outputBuffer[outputIndex++] = currChar; break; case tC: glyphStorage.setCharIndex(outputIndex, inputIndex, success); outputBuffer[outputIndex++] = currChar; break; case tD: glyphStorage.setCharIndex(outputIndex, inputIndex, success); outputBuffer[outputIndex++] = leftAboveVowel(currChar, glyphSet); break; case tE: glyphStorage.setCharIndex(outputIndex, inputIndex, success); outputBuffer[outputIndex++] = lowerRightTone(currChar, glyphSet); break; case tF: glyphStorage.setCharIndex(outputIndex, inputIndex, success); outputBuffer[outputIndex++] = lowerLeftTone(currChar, glyphSet); break; case tG: glyphStorage.setCharIndex(outputIndex, inputIndex, success); outputBuffer[outputIndex++] = upperLeftTone(currChar, glyphSet); break; case tH: { LEUnicode cod = outputBuffer[outputIndex - 1]; LEUnicode coa = noDescenderCOD(cod, glyphSet); if (cod != coa) { outputBuffer[outputIndex - 1] = coa; glyphStorage.setCharIndex(outputIndex, inputIndex, success); outputBuffer[outputIndex++] = currChar; break; } glyphStorage.setCharIndex(outputIndex, inputIndex, success); outputBuffer[outputIndex++] = lowerBelowVowel(currChar, glyphSet); break; } case tR: glyphStorage.setCharIndex(outputIndex, inputIndex, success); outputBuffer[outputIndex++] = errorChar; glyphStorage.setCharIndex(outputIndex, inputIndex, success); outputBuffer[outputIndex++] = currChar; break; case tS: if (currChar == CH_SARA_AM) { glyphStorage.setCharIndex(outputIndex, inputIndex, success); outputBuffer[outputIndex++] = errorChar; } glyphStorage.setCharIndex(outputIndex, inputIndex, success); outputBuffer[outputIndex++] = currChar; break; default: // FIXME: if we get here, there's an error // in the state table! glyphStorage.setCharIndex(outputIndex, inputIndex, success); outputBuffer[outputIndex++] = currChar; break; } return transition.nextState; }
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--]; } }
// 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 }
void MPreFixups::apply(LEGlyphStorage &glyphStorage, LEErrorCode& leSuccess) { if (LE_FAILURE(leSuccess)) { return; } for (le_int32 fixup = 0; fixup < fFixupCount; fixup += 1) { le_int32 baseIndex = fFixupData[fixup].fBaseIndex; le_int32 mpreIndex = fFixupData[fixup].fMPreIndex; le_int32 mpreLimit = mpreIndex + 1; while (glyphStorage[baseIndex] == 0xFFFF || glyphStorage[baseIndex] == 0xFFFE) { baseIndex -= 1; } while (glyphStorage[mpreLimit] == 0xFFFF || glyphStorage[mpreLimit] == 0xFFFE) { mpreLimit += 1; } if (mpreLimit == baseIndex) { continue; } LEErrorCode success = LE_NO_ERROR; le_int32 mpreCount = mpreLimit - mpreIndex; le_int32 moveCount = baseIndex - mpreLimit; le_int32 mpreDest = baseIndex - mpreCount; LEGlyphID *mpreSave = LE_NEW_ARRAY(LEGlyphID, mpreCount); le_int32 *indexSave = LE_NEW_ARRAY(le_int32, mpreCount); if (mpreSave == NULL || indexSave == NULL) { LE_DELETE_ARRAY(mpreSave); LE_DELETE_ARRAY(indexSave); success = LE_MEMORY_ALLOCATION_ERROR; return; } le_int32 i; for (i = 0; i < mpreCount; i += 1) { mpreSave[i] = glyphStorage[mpreIndex + i]; indexSave[i] = glyphStorage.getCharIndex(mpreIndex + i, success); //charIndices[mpreIndex + i]; } for (i = 0; i < moveCount; i += 1) { LEGlyphID glyph = glyphStorage[mpreLimit + i]; le_int32 charIndex = glyphStorage.getCharIndex(mpreLimit + i, success); glyphStorage[mpreIndex + i] = glyph; glyphStorage.setCharIndex(mpreIndex + i, charIndex, success); } for (i = 0; i < mpreCount; i += 1) { glyphStorage[mpreDest + i] = mpreSave[i]; glyphStorage.setCharIndex(mpreDest, indexSave[i], success); } LE_DELETE_ARRAY(indexSave); LE_DELETE_ARRAY(mpreSave); } }