/* * * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved * */ #include "LETypes.h" #include "OpenTypeTables.h" #include "GlyphDefinitionTables.h" #include "GlyphPositionAdjustments.h" #include "GlyphIterator.h" #include "LEGlyphStorage.h" #include "Lookups.h" #include "LESwaps.h" U_NAMESPACE_BEGIN GlyphIterator::GlyphIterator(LEGlyphStorage &theGlyphStorage, GlyphPositionAdjustments *theGlyphPositionAdjustments, le_bool rightToLeft, le_uint16 theLookupFlags, FeatureMask theFeatureMask, const LEReferenceTo<GlyphDefinitionTableHeader> &theGlyphDefinitionTableHeader) : direction(1), position(-1), nextLimit(-1), prevLimit(-1), glyphStorage(theGlyphStorage), glyphPositionAdjustments(theGlyphPositionAdjustments), srcIndex(-1), destIndex(-1), lookupFlags(theLookupFlags), featureMask(theFeatureMask), glyphGroup(0), glyphClassDefinitionTable(), markAttachClassDefinitionTable() { LEErrorCode success = LE_NO_ERROR; // TODO le_int32 glyphCount = glyphStorage.getGlyphCount(); if (theGlyphDefinitionTableHeader.isValid()) { glyphClassDefinitionTable = theGlyphDefinitionTableHeader -> getGlyphClassDefinitionTable(theGlyphDefinitionTableHeader, success); markAttachClassDefinitionTable = theGlyphDefinitionTableHeader ->getMarkAttachClassDefinitionTable(theGlyphDefinitionTableHeader, success); } nextLimit = glyphCount; if (rightToLeft) { direction = -1; position = glyphCount; nextLimit = -1; prevLimit = glyphCount; } filterResetCache(); } GlyphIterator::GlyphIterator(GlyphIterator &that) : glyphStorage(that.glyphStorage) { direction = that.direction; position = that.position; nextLimit = that.nextLimit; prevLimit = that.prevLimit; glyphPositionAdjustments = that.glyphPositionAdjustments; srcIndex = that.srcIndex; destIndex = that.destIndex; lookupFlags = that.lookupFlags; featureMask = that.featureMask; glyphGroup = that.glyphGroup; glyphClassDefinitionTable = that.glyphClassDefinitionTable; markAttachClassDefinitionTable = that.markAttachClassDefinitionTable; filterResetCache(); } GlyphIterator::GlyphIterator(GlyphIterator &that, FeatureMask newFeatureMask) : glyphStorage(that.glyphStorage) { direction = that.direction; position = that.position; nextLimit = that.nextLimit; prevLimit = that.prevLimit; glyphPositionAdjustments = that.glyphPositionAdjustments; srcIndex = that.srcIndex; destIndex = that.destIndex; lookupFlags = that.lookupFlags; featureMask = newFeatureMask; glyphGroup = 0; glyphClassDefinitionTable = that.glyphClassDefinitionTable; markAttachClassDefinitionTable = that.markAttachClassDefinitionTable; filterResetCache(); } GlyphIterator::GlyphIterator(GlyphIterator &that, le_uint16 newLookupFlags) : glyphStorage(that.glyphStorage) { direction = that.direction; position = that.position; nextLimit = that.nextLimit; prevLimit = that.prevLimit; glyphPositionAdjustments = that.glyphPositionAdjustments; srcIndex = that.srcIndex; destIndex = that.destIndex; lookupFlags = newLookupFlags; featureMask = that.featureMask; glyphGroup = that.glyphGroup; glyphClassDefinitionTable = that.glyphClassDefinitionTable; markAttachClassDefinitionTable = that.markAttachClassDefinitionTable; filterResetCache(); } GlyphIterator::~GlyphIterator() { // nothing to do, right? } void GlyphIterator::reset(le_uint16 newLookupFlags, FeatureMask newFeatureMask) { position = prevLimit; featureMask = newFeatureMask; glyphGroup = 0; lookupFlags = newLookupFlags; filterResetCache(); } LEGlyphID *GlyphIterator::insertGlyphs(le_int32 count, LEErrorCode& success) { return glyphStorage.insertGlyphs(position, count, success); } le_int32 GlyphIterator::applyInsertions() { le_int32 newGlyphCount = glyphStorage.applyInsertions(); if (direction < 0) { prevLimit = newGlyphCount; } else { nextLimit = newGlyphCount; } return newGlyphCount; } le_int32 GlyphIterator::getCurrStreamPosition() const { return position; } le_bool GlyphIterator::isRightToLeft() const { return direction < 0; } le_bool GlyphIterator::ignoresMarks() const { return (lookupFlags & lfIgnoreMarks) != 0; } le_bool GlyphIterator::baselineIsLogicalEnd() const { return (lookupFlags & lfBaselineIsLogicalEnd) != 0; } LEGlyphID GlyphIterator::getCurrGlyphID() const { if (direction < 0) { if (position <= nextLimit || position >= prevLimit) { return 0xFFFF; } } else { if (position <= prevLimit || position >= nextLimit) { return 0xFFFF; } } return glyphStorage[position]; } void GlyphIterator::getCursiveEntryPoint(LEPoint &entryPoint) const { if (direction < 0) { if (position <= nextLimit || position >= prevLimit) { return; } } else { if (position <= prevLimit || position >= nextLimit) { return; } } glyphPositionAdjustments->getEntryPoint(position, entryPoint); } void GlyphIterator::getCursiveExitPoint(LEPoint &exitPoint) const { if (direction < 0) { if (position <= nextLimit || position >= prevLimit) { return; } } else { if (position <= prevLimit || position >= nextLimit) { return; } } glyphPositionAdjustments->getExitPoint(position, exitPoint); } void GlyphIterator::setCurrGlyphID(TTGlyphID glyphID) { LEGlyphID glyph = glyphStorage[position]; glyphStorage[position] = LE_SET_GLYPH(glyph, glyphID); } void GlyphIterator::setCurrStreamPosition(le_int32 newPosition) { if (direction < 0) { if (newPosition >= prevLimit) { position = prevLimit; return; } if (newPosition <= nextLimit) { position = nextLimit; return; } } else { if (newPosition <= prevLimit) { position = prevLimit; return; } if (newPosition >= nextLimit) { position = nextLimit; return; } } position = newPosition - direction; next(); } void GlyphIterator::setCurrGlyphBaseOffset(le_int32 baseOffset) { if (direction < 0) { if (position <= nextLimit || position >= prevLimit) { return; } } else { if (position <= prevLimit || position >= nextLimit) { return; } } glyphPositionAdjustments->setBaseOffset(position, baseOffset); } void GlyphIterator::adjustCurrGlyphPositionAdjustment(float xPlacementAdjust, float yPlacementAdjust, float xAdvanceAdjust, float yAdvanceAdjust) { if (direction < 0) { if (position <= nextLimit || position >= prevLimit) { return; } } else { if (position <= prevLimit || position >= nextLimit) { return; } } glyphPositionAdjustments->adjustXPlacement(position, xPlacementAdjust); glyphPositionAdjustments->adjustYPlacement(position, yPlacementAdjust); glyphPositionAdjustments->adjustXAdvance(position, xAdvanceAdjust); glyphPositionAdjustments->adjustYAdvance(position, yAdvanceAdjust); } void GlyphIterator::setCurrGlyphPositionAdjustment(float xPlacementAdjust, float yPlacementAdjust, float xAdvanceAdjust, float yAdvanceAdjust) { if (direction < 0) { if (position <= nextLimit || position >= prevLimit) { return; } } else { if (position <= prevLimit || position >= nextLimit) { return; } } glyphPositionAdjustments->setXPlacement(position, xPlacementAdjust); glyphPositionAdjustments->setYPlacement(position, yPlacementAdjust); glyphPositionAdjustments->setXAdvance(position, xAdvanceAdjust); glyphPositionAdjustments->setYAdvance(position, yAdvanceAdjust); } void GlyphIterator::clearCursiveEntryPoint() { if (direction < 0) { if (position <= nextLimit || position >= prevLimit) { return; } } else { if (position <= prevLimit || position >= nextLimit) { return; } } glyphPositionAdjustments->clearEntryPoint(position); } void GlyphIterator::clearCursiveExitPoint() { if (direction < 0) { if (position <= nextLimit || position >= prevLimit) { return; } } else { if (position <= prevLimit || position >= nextLimit) { return; } } glyphPositionAdjustments->clearExitPoint(position); } void GlyphIterator::setCursiveEntryPoint(LEPoint &entryPoint) { if (direction < 0) { if (position <= nextLimit || position >= prevLimit) { return; } } else { if (position <= prevLimit || position >= nextLimit) { return; } } glyphPositionAdjustments->setEntryPoint(position, entryPoint, baselineIsLogicalEnd()); } void GlyphIterator::setCursiveExitPoint(LEPoint &exitPoint) { if (direction < 0) { if (position <= nextLimit || position >= prevLimit) { return; } } else { if (position <= prevLimit || position >= nextLimit) { return; } } glyphPositionAdjustments->setExitPoint(position, exitPoint, baselineIsLogicalEnd()); } void GlyphIterator::setCursiveGlyph() { if (direction < 0) { if (position <= nextLimit || position >= prevLimit) { return; } } else { if (position <= prevLimit || position >= nextLimit) { return; } } glyphPositionAdjustments->setCursiveGlyph(position, baselineIsLogicalEnd()); } void GlyphIterator::filterResetCache(void) { filterCacheValid = FALSE; } le_bool GlyphIterator::filterGlyph(le_uint32 index) { LEGlyphID glyphID = glyphStorage[index]; if (!filterCacheValid || filterCache.id != glyphID) { filterCache.id = glyphID; le_bool &filterResult = filterCache.result; // NB: Making this a reference to accept the updated value, in case // we want more fancy cacheing in the future. if (LE_GET_GLYPH(glyphID) >= 0xFFFE) { filterResult = TRUE; } else { LEErrorCode success = LE_NO_ERROR; le_int32 glyphClass = gcdNoGlyphClass; if (glyphClassDefinitionTable.isValid()) { glyphClass = glyphClassDefinitionTable->getGlyphClass(glyphClassDefinitionTable, glyphID, success); } switch (glyphClass) { case gcdNoGlyphClass: filterResult = FALSE; break; case gcdSimpleGlyph: filterResult = (lookupFlags & lfIgnoreBaseGlyphs) != 0; break; case gcdLigatureGlyph: filterResult = (lookupFlags & lfIgnoreLigatures) != 0; break; case gcdMarkGlyph: if ((lookupFlags & lfIgnoreMarks) != 0) { filterResult = TRUE; } else { le_uint16 markAttachType = (lookupFlags & lfMarkAttachTypeMask) >> lfMarkAttachTypeShift; if ((markAttachType != 0) && (markAttachClassDefinitionTable.isValid())) { filterResult = (markAttachClassDefinitionTable -> getGlyphClass(markAttachClassDefinitionTable, glyphID, success) != markAttachType); } else { filterResult = FALSE; } } break; case gcdComponentGlyph: filterResult = ((lookupFlags & lfIgnoreBaseGlyphs) != 0); break; default: filterResult = FALSE; break; } } filterCacheValid = TRUE; } return filterCache.result; } le_bool GlyphIterator::hasFeatureTag(le_bool matchGroup) const { if (featureMask == 0) { return TRUE; } LEErrorCode success = LE_NO_ERROR; FeatureMask fm = glyphStorage.getAuxData(position, success); return ((fm & featureMask) == featureMask) && (!matchGroup || (le_int32)(fm & LE_GLYPH_GROUP_MASK) == glyphGroup); } le_bool GlyphIterator::findFeatureTag() { //glyphGroup = 0; while (nextInternal()) { if (hasFeatureTag(FALSE)) { LEErrorCode success = LE_NO_ERROR; glyphGroup = (glyphStorage.getAuxData(position, success) & LE_GLYPH_GROUP_MASK); return TRUE; } } return FALSE; } le_bool GlyphIterator::nextInternal(le_uint32 delta) { le_int32 newPosition = position; while (newPosition != nextLimit && delta > 0) { do { newPosition += direction; //fprintf(stderr,"%s:%d:%s: newPosition = %d, delta = %d\n", __FILE__, __LINE__, __FUNCTION__, newPosition, delta); } while (newPosition != nextLimit && filterGlyph(newPosition)); delta -= 1; } position = newPosition; //fprintf(stderr,"%s:%d:%s: exit position = %d, delta = %d\n", __FILE__, __LINE__, __FUNCTION__, position, delta); return position != nextLimit; } le_bool GlyphIterator::next(le_uint32 delta) { return nextInternal(delta) && hasFeatureTag(TRUE); } le_bool GlyphIterator::prevInternal(le_uint32 delta) { le_int32 newPosition = position; while (newPosition != prevLimit && delta > 0) { do { newPosition -= direction; //fprintf(stderr,"%s:%d:%s: newPosition = %d, delta = %d\n", __FILE__, __LINE__, __FUNCTION__, newPosition, delta); } while (newPosition != prevLimit && filterGlyph(newPosition)); delta -= 1; } position = newPosition; //fprintf(stderr,"%s:%d:%s: exit position = %d, delta = %d\n", __FILE__, __LINE__, __FUNCTION__, position, delta); return position != prevLimit; } le_bool GlyphIterator::prev(le_uint32 delta) { return prevInternal(delta) && hasFeatureTag(TRUE); } le_int32 GlyphIterator::getMarkComponent(le_int32 markPosition) const { le_int32 component = 0; le_int32 posn; for (posn = position; posn != markPosition; posn += direction) { if (glyphStorage[posn] == 0xFFFE) { component += 1; } } return component; } // This is basically prevInternal except that it // doesn't take a delta argument, and it doesn't // filter out 0xFFFE glyphs. le_bool GlyphIterator::findMark2Glyph() { le_int32 newPosition = position; do { newPosition -= direction; } while (newPosition != prevLimit && glyphStorage[newPosition] != 0xFFFE && filterGlyph(newPosition)); position = newPosition; return position != prevLimit; } U_NAMESPACE_END